Added europe-level aggregated plotting

This commit is contained in:
Lukas Franken 2023-05-08 22:30:17 +02:00 committed by GitHub
parent 6a102f4ab2
commit eae92c837c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -12,12 +12,10 @@
"import os\n", "import os\n",
"from pathlib import Path\n", "from pathlib import Path\n",
"import matplotlib.pyplot as plt\n", "import matplotlib.pyplot as plt\n",
"\n",
"plt.style.use(\"ggplot\")\n", "plt.style.use(\"ggplot\")\n",
"import pycountry\n", "import pycountry\n",
"import json\n", "import json\n",
"import warnings\n", "import warnings\n",
"\n",
"warnings.filterwarnings(\"ignore\")" "warnings.filterwarnings(\"ignore\")"
] ]
}, },
@ -35,11 +33,24 @@
" \"model_5\": \"elec_s_37_ec_lv1.0_Ep_new.nc\", \n", " \"model_5\": \"elec_s_37_ec_lv1.0_Ep_new.nc\", \n",
"}\n", "}\n",
"\n", "\n",
"model_choice = \"model_5\"\n",
"\n",
"data_path = Path.cwd() / \"..\" / \"..\"\n", "data_path = Path.cwd() / \"..\" / \"..\"\n",
"model_path = data_path / available_models[\"model_5\"]\n", "model_path = data_path / available_models[model_choice]\n",
"\n", "\n",
"with open(data_path / \"generation_data\" / \"generation_mapper_pypsa.json\", \"r\") as f:\n", "with open(data_path / \"generation_data\" / \"generation_mapper_pypsa.json\", \"r\") as f:\n",
" pypsa_generation_mapper = json.load(f)" " pypsa_generation_mapper = json.load(f)\n",
"\n",
"plot_path = data_path / \"plots\" / available_models[model_choice][:-3]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"os.mkdir(data_path / \"plots\" / available_models[model_choice][:-3])"
] ]
}, },
{ {
@ -74,6 +85,27 @@
"pypsa_generation_mapper" "pypsa_generation_mapper"
] ]
}, },
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"color_mapper = pd.read_csv(\"color_mapper.csv\", index_col=0).iloc[:,0]\n",
"color_mapper.loc[\"Others\"] = \"#D3D3D3\"\n",
"color_mapper.loc[\"Storage Charge\"] = \"#51dbcc\"\n",
"color_mapper.loc[\"Storage Discharge\"] = \"#51dbcc\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"color_mapper"
]
},
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
@ -84,11 +116,13 @@
"gen = set([col[6:] for col in n.generators_t.p.columns])\n", "gen = set([col[6:] for col in n.generators_t.p.columns])\n",
"\n", "\n",
"for i, country in enumerate(countries):\n", "for i, country in enumerate(countries):\n",
"\n",
" df = pd.DataFrame(index=n.generators_t.p.index)\n", " df = pd.DataFrame(index=n.generators_t.p.index)\n",
" # country_generation = [col for col in n.generators_t.p.columns if col.startswith(country)]\n", " # country_generation = [col for col in n.generators_t.p.columns if col.startswith(country)]\n",
" country_generation = n.generators.loc[n.generators.bus.str.contains(country)]\n", " country_generation = n.generators.loc[n.generators.bus.str.contains(country)]\n",
"\n", "\n",
" for key, gens in pypsa_generation_mapper.items():\n", " for key, gens in pypsa_generation_mapper.items():\n",
"\n",
" # curr_gen = country_generation.loc[\n", " # curr_gen = country_generation.loc[\n",
" # (country_generation.carrier.str.contains(tech) for tech in gens).astype(bool)].index\n", " # (country_generation.carrier.str.contains(tech) for tech in gens).astype(bool)].index\n",
" curr_gen = country_generation.loc[\n", " curr_gen = country_generation.loc[\n",
@ -100,7 +134,28 @@
" else:\n", " else:\n",
" df[key] = np.zeros(len(df))\n", " df[key] = np.zeros(len(df))\n",
"\n", "\n",
" df.to_csv(data_path / \"pypsa_data\" / (country + \".csv\"))" " df.to_csv(data_path / \"pypsa_data\" / (country+\".csv\"))\n",
" "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"total_inflow_cols = ['Solar', 'Wind Onshore', 'Nuclear', 'Lignite', 'Inflow Lines', 'Inflow Links', 'Wind Offshore', 'Biomass', 'Run of River', 'Hydro', 'Hard Coal', 'Gas', 'Oil']\n",
"total_outflow_cols = ['Outflow Links', 'Outflow Lines', 'Storage Charge']"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"total_inflow_set = set()\n",
"total_outflow_set = set()"
] ]
}, },
{ {
@ -112,14 +167,25 @@
"import seaborn as sns\n", "import seaborn as sns\n",
"from sklearn.metrics import mean_absolute_error\n", "from sklearn.metrics import mean_absolute_error\n",
"\n", "\n",
"index = n.generators_t.p.index\n",
"\n",
"pypsa_total_inflow = pd.DataFrame(np.zeros((len(index), len(total_inflow_cols))),\n",
" index=index, columns=total_inflow_cols)\n",
"entsoe_df = pd.read_csv(data_path / \"harmonised_generation_data\" / (\"prepared_DE.csv\"),\n",
" parse_dates=True,\n",
" index_col=0)\n",
"entsoe_total_inflow = pd.DataFrame(np.zeros((len(entsoe_df), len(total_inflow_cols))),\n",
" index=entsoe_df.index, columns=total_inflow_cols)\n",
"pypsa_total_outflow = pd.DataFrame(np.zeros((len(index), len(total_outflow_cols))),\n",
" index=index, columns=total_outflow_cols)\n",
"total_load = pd.Series(index=index)\n",
"\n", "\n",
"for num, country in enumerate(os.listdir(data_path / \"pypsa_data\")):\n", "for num, country in enumerate(os.listdir(data_path / \"pypsa_data\")):\n",
" # country = \"GR.csv\"\n", "\n",
" # country = \"DE.csv\"\n",
" cc = country[:2]\n", " cc = country[:2]\n",
"\n", "\n",
" country_buses = np.unique(\n", " country_buses = np.unique(n.generators.loc[n.generators.bus.str.contains(cc)].bus.values)\n",
" n.generators.loc[n.generators.bus.str.contains(cc)].bus.values\n",
" )\n",
" print(f\"Buses for country {country[:-4]}: \", country_buses)\n", " print(f\"Buses for country {country[:-4]}: \", country_buses)\n",
"\n", "\n",
" if not len(country_buses) == 1:\n", " if not len(country_buses) == 1:\n",
@ -133,11 +199,9 @@
" pypsa_df = pd.read_csv(data_path / \"pypsa_data\" / country, parse_dates=True, index_col=0)\n", " pypsa_df = pd.read_csv(data_path / \"pypsa_data\" / country, parse_dates=True, index_col=0)\n",
" \"\"\" \n", " \"\"\" \n",
" try:\n", " try:\n",
" entsoe_df = pd.read_csv(\n", " entsoe_df = pd.read_csv(data_path / \"harmonised_generation_data\" / (\"prepared_\"+country),\n",
" data_path / \"harmonised_generation_data\" / (\"prepared_\" + country),\n",
" parse_dates=True,\n", " parse_dates=True,\n",
" index_col=0,\n", " index_col=0)\n",
" )\n",
"\n", "\n",
" entsoe_df.columns = [col[:-6] for col in entsoe_df.columns]\n", " entsoe_df.columns = [col[:-6] for col in entsoe_df.columns]\n",
" entsoe_df = entsoe_df.iloc[1:]\n", " entsoe_df = entsoe_df.iloc[1:]\n",
@ -162,9 +226,7 @@
" country_gen = n.generators.loc[n.generators.bus == bus]\n", " country_gen = n.generators.loc[n.generators.bus == bus]\n",
"\n", "\n",
" for tech, pypsa_carrier in pypsa_generation_mapper.items():\n", " for tech, pypsa_carrier in pypsa_generation_mapper.items():\n",
" gens = country_gen.loc[\n", " gens = country_gen.loc[country_gen.carrier.apply(lambda c: c in pypsa_carrier)].index\n",
" country_gen.carrier.apply(lambda c: c in pypsa_carrier)\n",
" ].index\n",
" energy_inflow[tech] = n.generators_t.p[gens].sum(axis=1)\n", " energy_inflow[tech] = n.generators_t.p[gens].sum(axis=1)\n",
"\n", "\n",
" # add inflows from lines\n", " # add inflows from lines\n",
@ -187,16 +249,10 @@
"\n", "\n",
" links_flow = np.zeros(energy_inflow.shape[0])\n", " links_flow = np.zeros(energy_inflow.shape[0])\n",
" if not links0.empty:\n", " if not links0.empty:\n",
" links_flow = (\n", " links_flow = - n.links_t.p0[links0].multiply(n.links.loc[links0, \"efficiency\"]).sum(axis=1)\n",
" -n.links_t.p0[links0]\n",
" .multiply(n.links.loc[links0, \"efficiency\"])\n",
" .sum(axis=1)\n",
" )\n",
"\n", "\n",
" if not links1.empty:\n", " if not links1.empty:\n",
" links_flow -= (\n", " links_flow -= n.links_t.p1[links1].multiply(n.links.loc[links1, \"efficiency\"]).sum(axis=1)\n",
" n.links_t.p1[links1].multiply(n.links.loc[links1, \"efficiency\"]).sum(axis=1)\n",
" )\n",
"\n", "\n",
" energy_inflow[\"Inflow Links\"] = np.maximum(np.zeros_like(links_flow), links_flow)\n", " energy_inflow[\"Inflow Links\"] = np.maximum(np.zeros_like(links_flow), links_flow)\n",
" energy_outflow[\"Outflow Links\"] = np.minimum(np.zeros_like(links_flow), links_flow)\n", " energy_outflow[\"Outflow Links\"] = np.minimum(np.zeros_like(links_flow), links_flow)\n",
@ -205,29 +261,33 @@
" if not storage.empty:\n", " if not storage.empty:\n",
" storage_p = n.storage_units_t.p[storage].sum(axis=1).values\n", " storage_p = n.storage_units_t.p[storage].sum(axis=1).values\n",
" # energy_inflow[\"Storage Discharge\"] = np.maximum(np.zeros_like(links_flow), storage_p)\n", " # energy_inflow[\"Storage Discharge\"] = np.maximum(np.zeros_like(links_flow), storage_p)\n",
" energy_inflow[\"Hydro\"] = energy_inflow[\"Hydro\"].values + np.maximum(\n", " energy_inflow[\"Hydro\"] = energy_inflow[\"Hydro\"].values + np.maximum(np.zeros_like(links_flow), storage_p)\n",
" np.zeros_like(links_flow), storage_p\n", " energy_outflow[\"Storage Charge\"] = np.minimum(np.zeros_like(links_flow), storage_p)\n",
" )\n",
" energy_outflow[\"Storage Charge\"] = np.minimum(\n",
" np.zeros_like(links_flow), storage_p\n",
" )\n",
"\n", "\n",
" energy_inflow = energy_inflow.iloc[:-1].multiply(1e-3)\n", " energy_inflow = energy_inflow.iloc[:-1].multiply(1e-3)\n",
" energy_outflow = energy_outflow.iloc[:-1].multiply(1e-3)\n", " energy_outflow = energy_outflow.iloc[:-1].multiply(1e-3)\n",
" load = n.loads_t.p_set[bus].iloc[:-1].multiply(1e-3)\n", " load = n.loads_t.p_set[bus].iloc[:-1].multiply(1e-3)\n",
"\n", "\n",
" show_techs = (\n", " total_load = total_load.loc[load.index]\n",
" energy_inflow.sum()\n", " total_load = total_load + load\n",
" .sort_values(ascending=False)\n", "\n",
" .iloc[:num_techs_shown]\n", " pypsa_total_inflow = pypsa_total_inflow.loc[energy_inflow.index]\n",
" .index.tolist()\n", " pypsa_total_inflow[energy_inflow.columns] = (\n",
" pypsa_total_inflow[energy_inflow.columns] + energy_inflow\n",
" )\n", " )\n",
" others = (\n", "\n",
" energy_inflow.sum()\n", " pypsa_total_outflow = pypsa_total_outflow.loc[energy_outflow.index]\n",
" .sort_values(ascending=False)\n", " pypsa_total_outflow[energy_outflow.columns] = (\n",
" .iloc[num_techs_shown:]\n", " pypsa_total_outflow[energy_outflow.columns] + energy_outflow\n",
" .index.tolist()\n",
" )\n", " )\n",
"\n",
" entsoe_total_inflow = entsoe_total_inflow.loc[entsoe_df.index]\n",
" entsoe_total_inflow[entsoe_df.columns] = (\n",
" entsoe_total_inflow[entsoe_df.columns] + entsoe_df.fillna(0.)\n",
" )\n",
"\n",
" show_techs = energy_inflow.sum().sort_values(ascending=False).iloc[:num_techs_shown].index.tolist()\n",
" others = energy_inflow.sum().sort_values(ascending=False).iloc[num_techs_shown:].index.tolist()\n",
" # show_techs = entsoe_df.sum().sort_values(ascending=False).iloc[:num_techs_shown].index.tolist()\n", " # show_techs = entsoe_df.sum().sort_values(ascending=False).iloc[:num_techs_shown].index.tolist()\n",
"\n", "\n",
" show_techs = intersection(show_techs, entsoe_df.columns.tolist())\n", " show_techs = intersection(show_techs, entsoe_df.columns.tolist())\n",
@ -241,44 +301,24 @@
" energy_inflow[\"Others\"] = energy_inflow.drop(columns=show_techs).sum(axis=1)\n", " energy_inflow[\"Others\"] = energy_inflow.drop(columns=show_techs).sum(axis=1)\n",
"\n", "\n",
" # plot timeframe\n", " # plot timeframe\n",
" axs[0, 0].plot(\n", " axs[0,0].plot(index, load.loc[index].values, linestyle=\"--\", color=\"k\", linewidth=2, label=\"PyPSA Load\")\n",
" index,\n", " axs[0,1].plot(index, load.loc[index].values, linestyle=\"--\", color=\"k\", linewidth=2)\n",
" load.loc[index].values,\n",
" linestyle=\"--\",\n",
" color=\"k\",\n",
" linewidth=2,\n",
" label=\"PyPSA Load\",\n",
" )\n",
" axs[0, 1].plot(\n",
" index, load.loc[index].values, linestyle=\"--\", color=\"k\", linewidth=2\n",
" )\n",
"\n", "\n",
" axs[0, 1].stackplot(\n", " axs[0,1].stackplot(index,\n",
" index,\n",
" *[energy_inflow[col].loc[index].values for col in show_techs + [\"Others\"]],\n", " *[energy_inflow[col].loc[index].values for col in show_techs + [\"Others\"]],\n",
" colors=color_mapper.loc[show_techs + [\"Others\"]].tolist()\n",
" )\n", " )\n",
" axs[0, 1].stackplot(\n", " axs[0,1].stackplot(index, *[energy_outflow[col].loc[index].values for col in energy_outflow.columns],\n",
" index,\n", " colors=color_mapper.loc[energy_outflow.columns].tolist(),\n",
" *[energy_outflow[col].loc[index].values for col in energy_outflow.columns],\n", " labels=energy_outflow.columns\n",
" colors=[\"seagreen\", \"royalblue\", \"gold\"],\n",
" labels=energy_outflow.columns,\n",
" )\n", " )\n",
"\n", "\n",
" axs[0, 0].stackplot(\n", " axs[0,0].stackplot(index, *[entsoe_df[col].loc[index].values for col in show_techs + [\"Others\"]],\n",
" index,\n",
" *[entsoe_df[col].loc[index].values for col in show_techs + [\"Others\"]],\n",
" labels=show_techs+[\"Others\"],\n", " labels=show_techs+[\"Others\"],\n",
" )\n", " colors=color_mapper.loc[show_techs + [\"Others\"]].tolist())\n",
"\n", " axs[0,1].plot(index,\n",
" axs[0, 1].plot(\n", " energy_inflow.loc[index][show_techs + [\"Others\"]].sum(axis=1).values + energy_outflow.loc[index].sum(axis=1).values,\n",
" index,\n", " color=\"brown\", linestyle=\":\", linewidth=2, label=\"Accum Gen\")\n",
" energy_inflow.loc[index][show_techs + [\"Others\"]].sum(axis=1).values\n",
" + energy_outflow.loc[index].sum(axis=1).values,\n",
" color=\"brown\",\n",
" linestyle=\":\",\n",
" linewidth=2,\n",
" label=\"Accum Gen\",\n",
" )\n",
"\n", "\n",
" axs[0,0].legend()\n", " axs[0,0].legend()\n",
" axs[0,1].legend()\n", " axs[0,1].legend()\n",
@ -287,68 +327,34 @@
"\n", "\n",
" index = load.resample(coarse_freq).mean().index\n", " index = load.resample(coarse_freq).mean().index\n",
"\n", "\n",
" axs[1, 0].plot(\n", " axs[1,0].plot(index, load.resample(coarse_freq).mean().values, linestyle=\"--\", color=\"k\", linewidth=2, label=\"PyPSA Load\")\n",
" index,\n", " axs[1,1].plot(index, load.resample(coarse_freq).mean().values, linestyle=\"--\", color=\"k\", linewidth=2)\n",
" load.resample(coarse_freq).mean().values,\n", "\n",
" linestyle=\"--\",\n", " axs[1,1].stackplot(index, *[energy_inflow[col].resample(coarse_freq).mean().values for col in show_techs + [\"Others\"]],\n",
" color=\"k\",\n", " colors=color_mapper.loc[show_techs + [\"Others\"]].tolist())\n",
" linewidth=2,\n", " axs[1,1].stackplot(index, *[energy_outflow[col].resample(coarse_freq).mean().values for col in energy_outflow.columns],\n",
" label=\"PyPSA Load\",\n", " colors=color_mapper.loc[energy_outflow.columns].tolist(),\n",
" )\n", " labels=energy_outflow.columns\n",
" axs[1, 1].plot(\n",
" index,\n",
" load.resample(coarse_freq).mean().values,\n",
" linestyle=\"--\",\n",
" color=\"k\",\n",
" linewidth=2,\n",
" )\n", " )\n",
"\n", "\n",
" axs[1, 1].stackplot(\n", " axs[1,0].stackplot(index, *[entsoe_df[col].resample(coarse_freq).mean().values for col in show_techs + [\"Others\"]],\n",
" index,\n", " colors=color_mapper.loc[show_techs + [\"Others\"]].tolist(),\n",
" *[\n", " labels=show_techs+[\"Others\"])\n",
" energy_inflow[col].resample(coarse_freq).mean().values\n",
" for col in show_techs + [\"Others\"]\n",
" ],\n",
" )\n",
" axs[1, 1].stackplot(\n",
" index,\n",
" *[\n",
" energy_outflow[col].resample(coarse_freq).mean().values\n",
" for col in energy_outflow.columns\n",
" ],\n",
" colors=[\"seagreen\", \"royalblue\", \"gold\"],\n",
" labels=energy_outflow.columns,\n",
" )\n",
"\n", "\n",
" axs[1, 0].stackplot(\n", " axs[1,1].plot(index,\n",
" index,\n", " energy_inflow.resample(coarse_freq).mean()[show_techs + [\"Others\"]].sum(axis=1).values + \n",
" *[\n", " energy_outflow.resample(coarse_freq).mean().sum(axis=1).values,\n",
" entsoe_df[col].resample(coarse_freq).mean().values\n", " color=\"brown\", linestyle=\":\", linewidth=2, label=\"Accum Gen\")\n",
" for col in show_techs + [\"Others\"]\n",
" ],\n",
" labels=show_techs + [\"Others\"],\n",
" )\n",
"\n", "\n",
" axs[1, 1].plot(\n",
" index,\n",
" energy_inflow.resample(coarse_freq)\n",
" .mean()[show_techs + [\"Others\"]]\n",
" .sum(axis=1)\n",
" .values\n",
" + energy_outflow.resample(coarse_freq).mean().sum(axis=1).values,\n",
" color=\"brown\",\n",
" linestyle=\":\",\n",
" linewidth=2,\n",
" label=\"Accum Gen\",\n",
" )\n",
"\n", "\n",
" axs[1,0].legend()\n", " axs[1,0].legend()\n",
" axs[1,1].legend()\n", " axs[1,1].legend()\n",
"\n", "\n",
" y_min = pd.concat([energy_outflow.sum(axis=1)]).min()\n", "\n",
" y_max = pd.concat(\n", " y_min = pd.concat([\n",
" [energy_inflow.sum(axis=1), entsoe_df.sum(axis=1)], ignore_index=True\n", " energy_outflow.sum(axis=1)]).min()\n",
" ).max()\n", " y_max = pd.concat([\n",
" energy_inflow.sum(axis=1), entsoe_df.sum(axis=1)], ignore_index=True).max()\n",
"\n", "\n",
" for ax in axs[:2,:2].flatten():\n", " for ax in axs[:2,:2].flatten():\n",
" ax.set_ylim(y_min, y_max)\n", " ax.set_ylim(y_min, y_max)\n",
@ -362,9 +368,7 @@
" axs[2,1].set_ylabel(\"PyPSA Gen and Load [GW]\")\n", " axs[2,1].set_ylabel(\"PyPSA Gen and Load [GW]\")\n",
"\n", "\n",
" # -------------------------- electricity prices comparison ----------------------------------\n", " # -------------------------- electricity prices comparison ----------------------------------\n",
" prices_col = [\n", " prices_col = [col for col in n.buses_t.marginal_price.columns if col.startswith(country[:2])]\n",
" col for col in n.buses_t.marginal_price.columns if col.startswith(country[:2])\n",
" ]\n",
" pypsa_prices = n.buses_t.marginal_price[prices_col].mean(axis=1)\n", " pypsa_prices = n.buses_t.marginal_price[prices_col].mean(axis=1)\n",
"\n", "\n",
" full_index = pypsa_prices.index\n", " full_index = pypsa_prices.index\n",
@ -372,48 +376,27 @@
" coarse_pypsa_prices = pypsa_prices.resample(coarse_freq).mean() \n", " coarse_pypsa_prices = pypsa_prices.resample(coarse_freq).mean() \n",
" pypsa_prices = pypsa_prices.loc[start:end]\n", " pypsa_prices = pypsa_prices.loc[start:end]\n",
"\n", "\n",
" axs[0, 2].plot(\n", " axs[0,2].plot(pypsa_prices.index, pypsa_prices.values, label=\"PyPSA prices\", color=\"royalblue\")\n",
" pypsa_prices.index, pypsa_prices.values, label=\"PyPSA prices\", color=\"royalblue\"\n", " axs[1,2].plot(coarse_pypsa_prices.index, coarse_pypsa_prices.values, label=\"PyPSA prices\", color=\"royalblue\")\n",
" )\n",
" axs[1, 2].plot(\n",
" coarse_pypsa_prices.index,\n",
" coarse_pypsa_prices.values,\n",
" label=\"PyPSA prices\",\n",
" color=\"royalblue\",\n",
" )\n",
"\n", "\n",
" try:\n", " try:\n",
" entsoe_prices = pd.read_csv(\n", " entsoe_prices = pd.read_csv(data_path / \"price_data\" / country,\n",
" data_path / \"price_data\" / country,\n",
" index_col=0,\n", " index_col=0,\n",
" parse_dates=True,\n", " parse_dates=True,\n",
" ).iloc[:-1]\n", " ).iloc[:-1]\n",
"\n",
" def make_tz_time(time):\n", " def make_tz_time(time):\n",
" return pd.Timestamp(time).tz_convert(\"utc\")\n", " return pd.Timestamp(time).tz_convert(\"utc\")\n",
"\n", "\n",
" # entsoe_prices.index = pd.Series(entsoe_prices.index).apply(lambda time: make_tz_time(time))\n", " # entsoe_prices.index = pd.Series(entsoe_prices.index).apply(lambda time: make_tz_time(time))\n",
" entsoe_prices.index = full_index\n", " entsoe_prices.index = full_index\n",
" mean_abs_error = mean_absolute_error(\n", " mean_abs_error = mean_absolute_error(entsoe_prices.values,\n",
" entsoe_prices.values,\n", " n.buses_t.marginal_price[prices_col].mean(axis=1).values)\n",
" n.buses_t.marginal_price[prices_col].mean(axis=1).values,\n",
" )\n",
"\n", "\n",
" coarse_prices = entsoe_prices.resample(coarse_freq).mean()\n", " coarse_prices = entsoe_prices.resample(coarse_freq).mean()\n",
" entsoe_prices = entsoe_prices.loc[start:end]\n", " entsoe_prices = entsoe_prices.loc[start:end]\n",
"\n", "\n",
" axs[0, 2].plot(\n", " axs[0,2].plot(entsoe_prices.index, entsoe_prices.values, label=\"ENTSOE prices\", color=\"darkred\")\n",
" entsoe_prices.index,\n", " axs[1,2].plot(coarse_prices.index, coarse_prices.values, label=\"ENTSOE prices\", color=\"darkred\")\n",
" entsoe_prices.values,\n",
" label=\"ENTSOE prices\",\n",
" color=\"darkred\",\n",
" )\n",
" axs[1, 2].plot(\n",
" coarse_prices.index,\n",
" coarse_prices.values,\n",
" label=\"ENTSOE prices\",\n",
" color=\"darkred\",\n",
" )\n",
"\n", "\n",
" except FileNotFoundError:\n", " except FileNotFoundError:\n",
" mean_abs_error = None\n", " mean_abs_error = None\n",
@ -435,52 +418,33 @@
"\n", "\n",
" entsoe_ddf = entsoe_df[show_techs + [\"Others\"]].reset_index(drop=True)\n", " entsoe_ddf = entsoe_df[show_techs + [\"Others\"]].reset_index(drop=True)\n",
"\n", "\n",
" entsoe_ddf = pd.concat(\n", " entsoe_ddf = pd.concat([\n",
" [\n", " entsoe_ddf[col].sort_values(ascending=False).reset_index(drop=True) for col in entsoe_ddf.columns\n",
" entsoe_ddf[col].sort_values(ascending=False).reset_index(drop=True)\n", " ], axis=1)\n",
" for col in entsoe_ddf.columns\n",
" ],\n",
" axis=1,\n",
" )\n",
"\n", "\n",
" axs[2, 0].stackplot(\n", " axs[2,0].stackplot(range(len(entsoe_ddf)), *[entsoe_ddf[col].values for col in entsoe_ddf.columns],\n",
" range(len(entsoe_ddf)),\n", " colors=color_mapper.loc[entsoe_ddf.columns].tolist(),\n",
" *[entsoe_ddf[col].values for col in entsoe_ddf.columns],\n", " labels=entsoe_ddf.columns)\n",
" labels=entsoe_ddf.columns,\n",
" )\n",
"\n", "\n",
" pypsa_ddf = energy_inflow[show_techs + [\"Others\"]].reset_index(drop=True)\n", " pypsa_ddf = energy_inflow[show_techs + [\"Others\"]].reset_index(drop=True)\n",
" pypsa_ddf = pd.concat(\n", " pypsa_ddf = pd.concat([\n",
" [\n", " pypsa_ddf[col].sort_values(ascending=False).reset_index(drop=True) for col in pypsa_ddf.columns\n",
" pypsa_ddf[col].sort_values(ascending=False).reset_index(drop=True)\n", " ], axis=1)\n",
" for col in pypsa_ddf.columns\n",
" ],\n",
" axis=1,\n",
" )\n",
"\n", "\n",
" axs[2, 1].stackplot(\n", " axs[2,1].stackplot(range(len(pypsa_ddf)), *[pypsa_ddf[col].values for col in pypsa_ddf.columns],\n",
" range(len(pypsa_ddf)),\n", " colors=color_mapper.loc[pypsa_ddf.columns].tolist(),\n",
" *[pypsa_ddf[col].values for col in pypsa_ddf.columns],\n", " labels=pypsa_ddf.columns)\n",
" labels=pypsa_ddf.columns,\n",
" )\n",
"\n", "\n",
" ylim_max = max([pypsa_ddf.max(axis=0).sum(), entsoe_ddf.max(axis=0).sum()])\n", " ylim_max = max([pypsa_ddf.max(axis=0).sum(), entsoe_ddf.max(axis=0).sum()])\n",
"\n", "\n",
" pypsa_ddf = energy_outflow.reset_index(drop=True)\n", " pypsa_ddf = energy_outflow.reset_index(drop=True)\n",
" pypsa_ddf = pd.concat(\n", " pypsa_ddf = pd.concat([\n",
" [\n", " pypsa_ddf[col].sort_values(ascending=True).reset_index(drop=True) for col in pypsa_ddf.columns\n",
" pypsa_ddf[col].sort_values(ascending=True).reset_index(drop=True)\n", " ], axis=1)\n",
" for col in pypsa_ddf.columns\n",
" ],\n",
" axis=1,\n",
" )\n",
"\n", "\n",
" axs[2, 1].stackplot(\n", " axs[2,1].stackplot(range(len(pypsa_ddf)), *[pypsa_ddf[col].values for col in pypsa_ddf.columns],\n",
" range(len(pypsa_ddf)),\n", " colors=color_mapper.loc[pypsa_ddf.columns].tolist(),\n",
" *[pypsa_ddf[col].values for col in pypsa_ddf.columns],\n", " labels=energy_outflow.columns)\n",
" colors=[\"seagreen\", \"royalblue\", \"gold\"],\n",
" labels=energy_outflow.columns,\n",
" )\n",
"\n", "\n",
" ylim_min = energy_outflow.min(axis=0).sum()\n", " ylim_min = energy_outflow.min(axis=0).sum()\n",
"\n", "\n",
@ -488,74 +452,53 @@
" ax.legend()\n", " ax.legend()\n",
" ax.set_ylim(ylim_min, ylim_max)\n", " ax.set_ylim(ylim_min, ylim_max)\n",
"\n", "\n",
" pypsa_totals = pd.concat(\n", " pypsa_totals = pd.concat([energy_inflow[show_techs + [\"Others\"]], energy_outflow], axis=1).sum() \n",
" [energy_inflow[show_techs + [\"Others\"]], energy_outflow], axis=1\n",
" ).sum()\n",
"\n", "\n",
" entsoe_totals = entsoe_df.sum()\n", " entsoe_totals = entsoe_df.sum()\n",
" totals = pd.DataFrame(index=pypsa_totals.index) \n", " totals = pd.DataFrame(index=pypsa_totals.index) \n",
" \n", " \n",
" for tech in pypsa_totals.index:\n", " for tech in pypsa_totals.index:\n",
" if tech not in entsoe_totals.index:\n", " if tech not in entsoe_totals.index:\n",
" entsoe_totals.loc[tech] = 0.0\n", " entsoe_totals.loc[tech] = 0.\n",
"\n", "\n",
" totals[\"Pypsa\"] = pypsa_totals\n", " totals[\"Pypsa\"] = pypsa_totals\n",
" totals[\"Entsoe\"] = entsoe_totals\n", " totals[\"Entsoe\"] = entsoe_totals\n",
" totals[\"Technology\"] = totals.index\n", " totals[\"Technology\"] = totals.index\n",
"\n", "\n",
" totals = pd.concat(\n", " totals = pd.concat([\n",
" [\n", " pd.DataFrame({\"Source\": [\"PyPSA\" for _ in range(len(pypsa_totals))],\n",
" pd.DataFrame(\n",
" {\n",
" \"Source\": [\"PyPSA\" for _ in range(len(pypsa_totals))],\n",
" \"Technology\": pypsa_totals.index,\n", " \"Technology\": pypsa_totals.index,\n",
" \"Total Generation\": pypsa_totals.values,\n", " \"Total Generation\": pypsa_totals.values,\n",
" }\n", " }),\n",
" ),\n", " pd.DataFrame({\"Source\": [\"ENTSO-E\" for _ in range(len(entsoe_totals))],\n",
" pd.DataFrame(\n",
" {\n",
" \"Source\": [\"ENTSO-E\" for _ in range(len(entsoe_totals))],\n",
" \"Technology\": entsoe_totals.index,\n", " \"Technology\": entsoe_totals.index,\n",
" \"Total Generation\": entsoe_totals.values,\n", " \"Total Generation\": entsoe_totals.values,\n",
" }\n", " }),], axis=0\n",
" ),\n",
" ],\n",
" axis=0,\n",
" )\n", " )\n",
"\n", "\n",
" sns.barplot(\n", " sns.barplot(data=totals, x=\"Technology\", y=\"Total Generation\", hue=\"Source\", ax=axs[2,2],\n",
" data=totals,\n", " palette=\"dark\", alpha=.6, edgecolor=\"k\")\n",
" x=\"Technology\",\n",
" y=\"Total Generation\",\n",
" hue=\"Source\",\n",
" ax=axs[2, 2],\n",
" palette=\"dark\",\n",
" alpha=0.6,\n",
" edgecolor=\"k\",\n",
" )\n",
" \n", " \n",
" axs[2,0].set_xlabel(\"Hours\")\n", " axs[2,0].set_xlabel(\"Hours\")\n",
" axs[2,1].set_xlabel(\"Hours\")\n", " axs[2,1].set_xlabel(\"Hours\")\n",
" axs[2,2].set_ylabel(\"Total Generation [GWh]\")\n", " axs[2,2].set_ylabel(\"Total Generation [GWh]\")\n",
" axs[2, 2].set_xticks(\n", " axs[2,2].set_xticks(axs[2,2].get_xticks(), axs[2,2].get_xticklabels(), rotation=45, ha='right')\n",
" axs[2, 2].get_xticks(), axs[2, 2].get_xticklabels(), rotation=45, ha=\"right\"\n",
" )\n",
"\n", "\n",
" corrs = (\n", " corrs = (\n",
" energy_inflow.corrwith(entsoe_df)\n", " energy_inflow\n",
" .corrwith(entsoe_df)\n",
" .drop(index=\"Others\")\n", " .drop(index=\"Others\")\n",
" .dropna()\n", " .dropna()\n",
" .sort_values(ascending=False)\n", " .sort_values(ascending=False)\n",
" )\n", " )\n",
"\n", "\n",
" for col, ax in zip(corrs.index[:2].tolist() + [corrs.index[-1]], axs[3]):\n", " for col, ax in zip(corrs.index[:2].tolist() + [corrs.index[-1]], axs[3]):\n",
" ax.scatter(\n", " ax.scatter(entsoe_df[col].values,\n",
" entsoe_df[col].values,\n",
" energy_inflow[col].values,\n", " energy_inflow[col].values,\n",
" color=\"darkred\",\n", " color=\"darkred\",\n",
" alpha=0.5,\n", " alpha=0.5,\n",
" s=20,\n", " s=20,\n",
" edgecolor=\"k\",\n", " edgecolor=\"k\" \n",
" )\n", " )\n",
" ax.set_title(f\"{col}; Pearson Corr {np.around(corrs.loc[col], decimals=4)}\")\n", " ax.set_title(f\"{col}; Pearson Corr {np.around(corrs.loc[col], decimals=4)}\")\n",
" ax.set_xlabel(\"ENTSO-E Generation [GW]\")\n", " ax.set_xlabel(\"ENTSO-E Generation [GW]\")\n",
@ -564,16 +507,247 @@
" for ax in axs[:2].flatten():\n", " for ax in axs[:2].flatten():\n",
" ax.set_xlabel(\"Datetime\")\n", " ax.set_xlabel(\"Datetime\")\n",
"\n", "\n",
"\n",
" plt.tight_layout()\n", " plt.tight_layout()\n",
" plt.savefig(plot_path / (cc+\".pdf\")) \n",
" \n",
" plt.show()" " plt.show()"
] ]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# pypsa_total_inflow.to_csv(\"total_inflow_pypsa.csv\")\n",
"# pypsa_total_outflow.to_csv(\"total_outflow_pypsa.csv\")\n",
"# entsoe_total_inflow.to_csv(\"total_inflow_entsoe.csv\")\n",
"# total_load.to_csv(\"total_load.csv\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from sklearn.metrics import mean_absolute_error\n",
"from tqdm import tqdm\n",
"import pandas as pd\n",
"import matplotlib.pyplot as plt\n",
"plt.style.use(\"ggplot\")\n",
"import seaborn as sns\n",
"import numpy as np\n",
"\n",
"entsoe_total_inflow = pd.read_csv(\"total_inflow_entsoe.csv\", index_col=0, parse_dates=True)\n",
"pypsa_total_inflow = pd.read_csv(\"total_inflow_pypsa.csv\", index_col=0, parse_dates=True)\n",
"pypsa_total_outflow = pd.read_csv(\"total_outflow_pypsa.csv\", index_col=0, parse_dates=True)\n",
"total_load = pd.read_csv(\"total_load.csv\", index_col=0, parse_dates=True)\n",
"\n",
"fig, ax = plt.subplots(1, 1, figsize=(10, 6))\n",
"\n",
"# pypsa_totals = pd.concat([pypsa_total_inflow, pypsa_total_outflow], axis=1).sum() * 1e-3 \n",
"pypsa_totals = pypsa_total_inflow.drop(columns=[\"Inflow Lines\", \"Inflow Links\"]).sum() * 1e-3\n",
"\n",
"entsoe_totals = entsoe_total_inflow.drop(columns=[\"Inflow Lines\", \"Inflow Links\"]).sum() * 1e-3\n",
"totals = pd.DataFrame(index=pypsa_totals.index) \n",
"\n",
"for tech in pypsa_totals.index:\n",
" if tech not in entsoe_totals.index:\n",
" entsoe_totals.loc[tech] = 0.\n",
"\n",
"totals[\"Pypsa\"] = pypsa_totals\n",
"totals[\"Entsoe\"] = entsoe_totals\n",
"totals[\"Technology\"] = totals.index\n",
"\n",
"totals = pd.concat([\n",
" pd.DataFrame({\"Source\": [\"PyPSA\" for _ in range(len(pypsa_totals))],\n",
" \"Technology\": pypsa_totals.index,\n",
" \"Total Generation\": pypsa_totals.values,\n",
" }),\n",
" pd.DataFrame({\"Source\": [\"ENTSO-E\" for _ in range(len(entsoe_totals))],\n",
" \"Technology\": entsoe_totals.index,\n",
" \"Total Generation\": entsoe_totals.values,\n",
" }),], axis=0\n",
")\n",
"\n",
"\n",
"sns.barplot(data=totals, x=\"Technology\", y=\"Total Generation\", hue=\"Source\", ax=ax,\n",
" palette=\"dark\", alpha=.6, edgecolor=\"k\")\n",
"ax.set_ylabel(\"Total Generation [TWh]\")\n",
"ax.set_xticks(ax.get_xticks(), ax.get_xticklabels(), rotation=45, ha='right')\n",
"plt.savefig(plot_path / \"EuropeTotalGeneration.pdf\")\n",
"plt.show()\n",
"\n",
"pypsa_total_inflow = pypsa_total_inflow.drop(columns=[\"Inflow Links\", \"Inflow Lines\"])\n",
"pypsa_total_outflow = pypsa_total_outflow.drop(columns=[\"Outflow Links\", \"Outflow Lines\"])\n",
"entsoe_total_inflow = entsoe_total_inflow.drop(columns=[\"Inflow Links\", \"Inflow Lines\"])\n",
"\n",
"start = pd.Timestamp(\"2019-01-01\") # for small time frame\n",
"end = pd.Timestamp(\"2019-01-14\")\n",
"coarse_freq = \"3d\"\n",
"\n",
"index = load.loc[start:end].index\n",
"cols = pypsa_total_inflow.std(axis=0).sort_values(ascending=True).index\n",
"cols_out = pypsa_total_outflow.std(axis=0).sort_values(ascending=False).index\n",
"\n",
"fig, axs = plt.subplots(4, 2, figsize=(20, 30))\n",
"\n",
"axs[0,0].stackplot(index, *[entsoe_total_inflow[col].loc[start:end].values for col in cols],\n",
" colors=color_mapper.loc[cols].tolist(), \n",
" )\n",
"\n",
"axs[0,1].stackplot(index, *[pypsa_total_inflow[col].loc[start:end].values for col in cols],\n",
" colors=color_mapper.loc[cols].tolist(), \n",
" )\n",
"axs[0,1].stackplot(index, *[pypsa_total_outflow[col].loc[start:end].values for col in cols_out],\n",
" colors=color_mapper.loc[cols_out].tolist(), \n",
" )\n",
"\n",
"entsoe_total_inflow = entsoe_total_inflow.resample(coarse_freq).mean()\n",
"pypsa_total_inflow = pypsa_total_inflow.resample(coarse_freq).mean()\n",
"pypsa_total_outflow = pypsa_total_outflow.resample(coarse_freq).mean()\n",
"\n",
"index = pypsa_total_inflow.index\n",
"\n",
"axs[1,0].stackplot(index, *[entsoe_total_inflow[col].values for col in cols],\n",
" colors=color_mapper.loc[cols].tolist(), \n",
" )\n",
"\n",
"axs[1,1].stackplot(index, *[pypsa_total_inflow[col].values for col in cols],\n",
" colors=color_mapper.loc[cols].tolist(), \n",
" )\n",
"axs[1,1].stackplot(index, *[pypsa_total_outflow[col].values for col in cols_out],\n",
" colors=color_mapper.loc[cols_out].tolist(), \n",
" )\n",
"\n",
"for ax in axs[:3].flatten():\n",
" ax.set_ylim(-100, 400)\n",
"\n",
"\n",
"\n",
"total_entsoe_ddf = pd.concat([\n",
" entsoe_total_inflow[col]\n",
" .sort_values(ascending=False)\n",
" .reset_index(drop=True) for col in entsoe_total_inflow.columns\n",
"], axis=1)\n",
"axs[2,0].stackplot(range(len(total_entsoe_ddf)), *[total_entsoe_ddf[col].values for col in total_entsoe_ddf.columns],\n",
" colors=color_mapper.loc[total_entsoe_ddf.columns].tolist(),\n",
" labels=total_entsoe_ddf.columns)\n",
"\n",
"total_pypsa_ddf = pd.concat([\n",
" pypsa_total_inflow[col]\n",
" .sort_values(ascending=False)\n",
" .reset_index(drop=True) for col in pypsa_total_inflow.columns\n",
"], axis=1)\n",
"axs[2,1].stackplot(range(len(total_pypsa_ddf)), *[total_pypsa_ddf[col].values for col in total_pypsa_ddf.columns],\n",
" colors=color_mapper.loc[total_pypsa_ddf.columns].tolist(),\n",
" labels=total_pypsa_ddf.columns)\n",
"\n",
"total_pypsa_ddf = pd.concat([\n",
" pypsa_total_outflow[col]\n",
" .sort_values(ascending=False)\n",
" .reset_index(drop=True) for col in pypsa_total_outflow.columns\n",
"], axis=1)\n",
"axs[2,1].stackplot(range(len(total_pypsa_ddf)), *[total_pypsa_ddf[col].values for col in total_pypsa_ddf.columns],\n",
" colors=color_mapper.loc[total_pypsa_ddf.columns].tolist(),\n",
" labels=total_pypsa_ddf.columns)\n",
"axs[2,0].legend(loc='upper center', bbox_to_anchor=(0.5, -0.05),\n",
" fancybox=True, shadow=True, ncol=5)\n",
"\n",
"total_prices = (\n",
" n.buses_t.marginal_price\n",
" .multiply(n.loads_t.p_set)\n",
" .sum(axis=1)\n",
" .divide(n.loads_t.p_set.sum(axis=1))\n",
")\n",
"\n",
"total_entsoe_prices = None\n",
"\n",
"for num, country in tqdm(enumerate(os.listdir(data_path / \"pypsa_data\"))):\n",
"\n",
" cc = country[:2]\n",
" country_buses = np.unique(n.generators.loc[n.generators.bus.str.contains(cc)].bus.values)\n",
"\n",
" if not len(country_buses) == 1:\n",
" continue\n",
"\n",
" bus = country_buses[0]\n",
"\n",
" try:\n",
" entsoe_prices = pd.read_csv(data_path / \"price_data\" / country,\n",
" index_col=0,\n",
" parse_dates=True,\n",
" ).iloc[:-1]\n",
" entsoe_prices.index = n.loads_t.p_set.index\n",
" def make_tz_time(time):\n",
" return pd.Timestamp(time).tz_convert(\"utc\")\n",
"\n",
" except FileNotFoundError: \n",
" continue\n",
"\n",
" if total_entsoe_prices is None:\n",
" total_entsoe_prices = pd.Series(np.zeros(len(entsoe_prices)), index=entsoe_prices.index)\n",
"\n",
" total_entsoe_prices += entsoe_prices.iloc[:,0] * n.loads_t.p_set[bus]\n",
"\n",
"total_entsoe_prices /= n.loads_t.p_set.sum(axis=1)\n",
"\n",
"error = np.around(mean_absolute_error(total_entsoe_prices.values, total_prices.values),\n",
" decimals=2)\n",
"\n",
"axs[3,0].plot(total_prices.loc[start:end].index, total_prices.loc[start:end].values,\n",
" label=\"PyPSA Marginal Price\")\n",
"axs[3,0].plot(total_prices.loc[start:end].index, total_entsoe_prices.loc[start:end].values, \n",
" label=\"ENTSO-E\")\n",
"axs[3,1].set_title(f\"Mean Abs Error {error} [Euro/MWh]\")\n",
"axs[3,0].legend()\n",
"\n",
"total_prices = total_prices.resample(coarse_freq).mean()\n",
"total_entsoe_prices = total_entsoe_prices.resample(coarse_freq).mean()\n",
"\n",
"axs[3,1].plot(total_prices.index, total_prices.values, label=f\"PyPSA Marginal Price\")\n",
"axs[3,1].plot(total_prices.index, total_entsoe_prices.values, label=\"ENTSO-E Price\")\n",
"\n",
"axs[3,1].legend()\n",
"\n",
"for ax in axs[:3,0]:\n",
" ax.set_ylabel(\"ENTSO-E Generation [GWh]\")\n",
"for ax in axs[:3,1]:\n",
" ax.set_ylabel(\"PyPSA Generation [GWh]\")\n",
"for ax in axs[:2].flatten():\n",
" ax.set_xlabel(\"Datetime\")\n",
"for ax in axs[3]:\n",
" ax.set_xlabel(\"Datetime\")\n",
" ax.set_ylabel(\"Cost of Electricity [Euro/MWh]\")\n",
"for ax in axs[2]:\n",
" ax.set_xlabel(\"Hour\")\n",
"\n",
"plt.savefig(plot_path / \"EuropeDashboard.pdf\")\n",
"plt.show()\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
} }
], ],
"metadata": { "metadata": {
"kernelspec": { "kernelspec": {
"display_name": "", "display_name": "pypsa-eur",
"language": "python", "language": "python",
"name": "" "name": "python3"
}, },
"language_info": { "language_info": {
"codemirror_mode": { "codemirror_mode": {