|
1
|
|
|
"""The central module containing all code dealing with scenario table. |
|
2
|
|
|
""" |
|
3
|
|
|
|
|
4
|
|
|
from pathlib import Path |
|
5
|
|
|
from urllib.request import urlretrieve |
|
6
|
|
|
import shutil |
|
7
|
|
|
import zipfile |
|
8
|
|
|
|
|
9
|
|
|
from sqlalchemy import VARCHAR, Column, String |
|
10
|
|
|
from sqlalchemy.dialects.postgresql import JSONB |
|
11
|
|
|
from sqlalchemy.ext.declarative import declarative_base |
|
12
|
|
|
from sqlalchemy.orm import sessionmaker |
|
13
|
|
|
import pandas as pd |
|
14
|
|
|
|
|
15
|
|
|
from egon.data import db |
|
16
|
|
|
from egon.data.datasets import Dataset |
|
17
|
|
|
import egon.data.config |
|
18
|
|
|
import egon.data.datasets.scenario_parameters.parameters as parameters |
|
19
|
|
|
|
|
20
|
|
|
Base = declarative_base() |
|
21
|
|
|
|
|
22
|
|
|
|
|
23
|
|
|
class EgonScenario(Base): |
|
24
|
|
|
__tablename__ = "egon_scenario_parameters" |
|
25
|
|
|
__table_args__ = {"schema": "scenario"} |
|
26
|
|
|
name = Column(String, primary_key=True) |
|
27
|
|
|
global_parameters = Column(JSONB) |
|
28
|
|
|
electricity_parameters = Column(JSONB) |
|
29
|
|
|
gas_parameters = Column(JSONB) |
|
30
|
|
|
heat_parameters = Column(JSONB) |
|
31
|
|
|
mobility_parameters = Column(JSONB) |
|
32
|
|
|
description = Column(VARCHAR) |
|
33
|
|
|
|
|
34
|
|
|
|
|
35
|
|
|
def create_table(): |
|
36
|
|
|
"""Create table for scenarios |
|
37
|
|
|
Returns |
|
38
|
|
|
------- |
|
39
|
|
|
None. |
|
40
|
|
|
""" |
|
41
|
|
|
engine = db.engine() |
|
42
|
|
|
db.execute_sql("CREATE SCHEMA IF NOT EXISTS scenario;") |
|
43
|
|
|
db.execute_sql( |
|
44
|
|
|
"DROP TABLE IF EXISTS scenario.egon_scenario_parameters CASCADE;" |
|
45
|
|
|
) |
|
46
|
|
|
EgonScenario.__table__.create(bind=engine, checkfirst=True) |
|
47
|
|
|
|
|
48
|
|
|
|
|
49
|
|
|
def get_scenario_year(scenario_name): |
|
50
|
|
|
"""Derives scenarios year from scenario name. Scenario |
|
51
|
|
|
eGon100RE is an exception as year is not in the name.""" |
|
52
|
|
|
try: |
|
53
|
|
|
year = int(scenario_name[-4:]) |
|
54
|
|
|
except ValueError as e: |
|
55
|
|
|
if e.args[0] == "invalid literal for int() with base 10: '00RE'": |
|
56
|
|
|
year = 2050 # eGon100RE |
|
57
|
|
|
else: |
|
58
|
|
|
raise ValueError("The names of the scenarios do not end with the year!") |
|
59
|
|
|
return year |
|
60
|
|
|
|
|
61
|
|
|
|
|
62
|
|
|
def insert_scenarios(): |
|
63
|
|
|
"""Insert scenarios and their parameters to scenario table |
|
64
|
|
|
|
|
65
|
|
|
Returns |
|
66
|
|
|
------- |
|
67
|
|
|
None. |
|
68
|
|
|
|
|
69
|
|
|
""" |
|
70
|
|
|
|
|
71
|
|
|
db.execute_sql("DELETE FROM scenario.egon_scenario_parameters CASCADE;") |
|
72
|
|
|
|
|
73
|
|
|
session = sessionmaker(bind=db.engine())() |
|
74
|
|
|
|
|
75
|
|
|
# Scenario eGon2035 |
|
76
|
|
|
egon2035 = EgonScenario(name="eGon2035") |
|
77
|
|
|
|
|
78
|
|
|
egon2035.description = """ |
|
79
|
|
|
The mid-term scenario eGon2035 is based on scenario C 2035 of the |
|
80
|
|
|
Netzentwicklungsplan Strom 2035, Version 2021. |
|
81
|
|
|
Scenario C 2035 is characretized by an ambitious expansion of |
|
82
|
|
|
renewable energies and a higher share of sector coupling. |
|
83
|
|
|
Analogous to the Netzentwicklungsplan, the countries bordering germany |
|
84
|
|
|
are modeled based on Ten-Year Network Development Plan, Version 2020. |
|
85
|
|
|
""" |
|
86
|
|
|
egon2035.global_parameters = parameters.global_settings(egon2035.name) |
|
87
|
|
|
|
|
88
|
|
|
egon2035.electricity_parameters = parameters.electricity(egon2035.name) |
|
89
|
|
|
|
|
90
|
|
|
egon2035.gas_parameters = parameters.gas(egon2035.name) |
|
91
|
|
|
|
|
92
|
|
|
egon2035.heat_parameters = parameters.heat(egon2035.name) |
|
93
|
|
|
|
|
94
|
|
|
egon2035.mobility_parameters = parameters.mobility(egon2035.name) |
|
95
|
|
|
|
|
96
|
|
|
session.add(egon2035) |
|
97
|
|
|
|
|
98
|
|
|
session.commit() |
|
99
|
|
|
|
|
100
|
|
|
# Scenario eGon100RE |
|
101
|
|
|
egon100re = EgonScenario(name="eGon100RE") |
|
102
|
|
|
|
|
103
|
|
|
egon100re.description = """ |
|
104
|
|
|
The long-term scenario eGon100RE represents a 100% renewable |
|
105
|
|
|
energy secor in Germany. |
|
106
|
|
|
""" |
|
107
|
|
|
egon100re.global_parameters = parameters.global_settings(egon100re.name) |
|
108
|
|
|
|
|
109
|
|
|
egon100re.electricity_parameters = parameters.electricity(egon100re.name) |
|
110
|
|
|
|
|
111
|
|
|
egon100re.gas_parameters = parameters.gas(egon100re.name) |
|
112
|
|
|
|
|
113
|
|
|
egon100re.heat_parameters = parameters.heat(egon100re.name) |
|
114
|
|
|
|
|
115
|
|
|
egon100re.mobility_parameters = parameters.mobility(egon100re.name) |
|
116
|
|
|
|
|
117
|
|
|
session.add(egon100re) |
|
118
|
|
|
|
|
119
|
|
|
session.commit() |
|
120
|
|
|
|
|
121
|
|
|
# Scenario eGon2021 |
|
122
|
|
|
eGon2021 = EgonScenario(name="eGon2021") |
|
123
|
|
|
|
|
124
|
|
|
eGon2021.description = """ |
|
125
|
|
|
Status quo scenario for 2021. Note: This is NOT A COMPLETE SCENARIO |
|
126
|
|
|
and covers only some sector data required by ding0, such as demand |
|
127
|
|
|
on NUTS 3 level and generation units . |
|
128
|
|
|
""" |
|
129
|
|
|
eGon2021.global_parameters = parameters.global_settings(eGon2021.name) |
|
130
|
|
|
|
|
131
|
|
|
eGon2021.electricity_parameters = parameters.electricity(eGon2021.name) |
|
132
|
|
|
|
|
133
|
|
|
eGon2021.gas_parameters = parameters.gas(eGon2021.name) |
|
134
|
|
|
|
|
135
|
|
|
eGon2021.heat_parameters = parameters.heat(eGon2021.name) |
|
136
|
|
|
|
|
137
|
|
|
eGon2021.mobility_parameters = parameters.mobility(eGon2021.name) |
|
138
|
|
|
|
|
139
|
|
|
session.add(eGon2021) |
|
140
|
|
|
|
|
141
|
|
|
session.commit() |
|
142
|
|
|
|
|
143
|
|
|
# Scenario status2019 |
|
144
|
|
|
status2019 = EgonScenario(name="status2019") |
|
145
|
|
|
|
|
146
|
|
|
status2019.description = """ |
|
147
|
|
|
Status quo ante scenario for 2019 for validation use within the project PoWerD. |
|
148
|
|
|
""" |
|
149
|
|
|
status2019.global_parameters = parameters.global_settings(status2019.name) |
|
150
|
|
|
|
|
151
|
|
|
status2019.electricity_parameters = parameters.electricity(status2019.name) |
|
152
|
|
|
|
|
153
|
|
|
status2019.gas_parameters = parameters.gas(status2019.name) |
|
154
|
|
|
|
|
155
|
|
|
status2019.heat_parameters = parameters.heat(status2019.name) |
|
156
|
|
|
|
|
157
|
|
|
status2019.mobility_parameters = parameters.mobility(status2019.name) |
|
158
|
|
|
|
|
159
|
|
|
session.add(status2019) |
|
160
|
|
|
|
|
161
|
|
|
session.commit() |
|
162
|
|
|
|
|
163
|
|
|
# Scenario status2023 |
|
164
|
|
|
status2023 = EgonScenario(name="status2023") |
|
165
|
|
|
|
|
166
|
|
|
status2023.description = """ |
|
167
|
|
|
Status quo ante scenario for 2023. |
|
168
|
|
|
""" |
|
169
|
|
|
# TODO status2023 all settings from 2019 are used |
|
170
|
|
|
status2023.global_parameters = parameters.global_settings(status2023.name) |
|
171
|
|
|
|
|
172
|
|
|
status2023.electricity_parameters = parameters.electricity(status2019.name) |
|
173
|
|
|
|
|
174
|
|
|
status2023.gas_parameters = parameters.gas(status2019.name) |
|
175
|
|
|
|
|
176
|
|
|
status2023.heat_parameters = parameters.heat(status2019.name) |
|
177
|
|
|
|
|
178
|
|
|
status2023.mobility_parameters = parameters.mobility(status2023.name) |
|
179
|
|
|
|
|
180
|
|
|
session.add(status2023) |
|
181
|
|
|
|
|
182
|
|
|
session.commit() |
|
183
|
|
|
|
|
184
|
|
|
|
|
185
|
|
|
def get_sector_parameters(sector, scenario=None): |
|
186
|
|
|
"""Returns parameters for each sector as dictionary. |
|
187
|
|
|
|
|
188
|
|
|
If scenario=None data for all scenarios is returned as pandas.DataFrame. |
|
189
|
|
|
Otherwise the parameters of the specific scenario are returned as a dict. |
|
190
|
|
|
|
|
191
|
|
|
Parameters |
|
192
|
|
|
---------- |
|
193
|
|
|
sector : str |
|
194
|
|
|
Name of the sector. |
|
195
|
|
|
Options are: ['global', 'electricity', 'heat', 'gas', 'mobility'] |
|
196
|
|
|
scenario : str, optional |
|
197
|
|
|
Name of the scenario. The default is None. |
|
198
|
|
|
|
|
199
|
|
|
Returns |
|
200
|
|
|
------- |
|
201
|
|
|
values : dict or pandas.DataFrane |
|
202
|
|
|
List or table of parameters for the selected sector |
|
203
|
|
|
|
|
204
|
|
|
""" |
|
205
|
|
|
|
|
206
|
|
|
if scenario: |
|
207
|
|
|
if ( |
|
208
|
|
|
scenario |
|
209
|
|
|
in db.select_dataframe( |
|
210
|
|
|
"SELECT name FROM scenario.egon_scenario_parameters" |
|
211
|
|
|
).name.values |
|
212
|
|
|
): |
|
213
|
|
|
values = db.select_dataframe( |
|
214
|
|
|
f""" |
|
215
|
|
|
SELECT {sector}_parameters as val |
|
216
|
|
|
FROM scenario.egon_scenario_parameters |
|
217
|
|
|
WHERE name = '{scenario}';""" |
|
218
|
|
|
).val[0] |
|
219
|
|
|
else: |
|
220
|
|
|
print(f"Scenario name {scenario} is not valid.") |
|
221
|
|
|
else: |
|
222
|
|
|
values = pd.concat( |
|
223
|
|
|
[ |
|
224
|
|
|
pd.DataFrame( |
|
225
|
|
|
db.select_dataframe( |
|
226
|
|
|
f""" |
|
227
|
|
|
SELECT {sector}_parameters as val |
|
228
|
|
|
FROM scenario.egon_scenario_parameters |
|
229
|
|
|
WHERE name='eGon2035'""" |
|
230
|
|
|
).val[0], |
|
231
|
|
|
index=["eGon2035"], |
|
232
|
|
|
), |
|
233
|
|
|
pd.DataFrame( |
|
234
|
|
|
db.select_dataframe( |
|
235
|
|
|
f""" |
|
236
|
|
|
SELECT {sector}_parameters as val |
|
237
|
|
|
FROM scenario.egon_scenario_parameters |
|
238
|
|
|
WHERE name='eGon100RE'""" |
|
239
|
|
|
).val[0], |
|
240
|
|
|
index=["eGon100RE"], |
|
241
|
|
|
), |
|
242
|
|
|
pd.DataFrame( |
|
243
|
|
|
db.select_dataframe( |
|
244
|
|
|
f""" |
|
245
|
|
|
SELECT {sector}_parameters as val |
|
246
|
|
|
FROM scenario.egon_scenario_parameters |
|
247
|
|
|
WHERE name='eGon2021'""" |
|
248
|
|
|
).val[0], |
|
249
|
|
|
index=["eGon2021"], |
|
250
|
|
|
), |
|
251
|
|
|
], |
|
252
|
|
|
ignore_index=True, |
|
253
|
|
|
) |
|
254
|
|
|
|
|
255
|
|
|
return values |
|
|
|
|
|
|
256
|
|
|
|
|
257
|
|
|
|
|
258
|
|
|
def download_pypsa_technology_data(): |
|
259
|
|
|
"""Downlad PyPSA technology data results.""" |
|
260
|
|
|
data_path = Path(".") / "pypsa_technology_data" |
|
261
|
|
|
# Delete folder if it already exists |
|
262
|
|
|
if data_path.exists() and data_path.is_dir(): |
|
263
|
|
|
shutil.rmtree(data_path) |
|
264
|
|
|
# Get parameters from config and set download URL |
|
265
|
|
|
sources = egon.data.config.datasets()["pypsa-technology-data"]["sources"][ |
|
266
|
|
|
"zenodo" |
|
267
|
|
|
] |
|
268
|
|
|
url = f"""https://zenodo.org/record/{sources['deposit_id']}/files/{sources['file']}""" |
|
269
|
|
|
target_file = egon.data.config.datasets()["pypsa-technology-data"][ |
|
270
|
|
|
"targets" |
|
271
|
|
|
]["file"] |
|
272
|
|
|
|
|
273
|
|
|
# Retrieve files |
|
274
|
|
|
urlretrieve(url, target_file) |
|
275
|
|
|
|
|
276
|
|
|
with zipfile.ZipFile(target_file, "r") as zip_ref: |
|
277
|
|
|
zip_ref.extractall(".") |
|
278
|
|
|
|
|
279
|
|
|
|
|
280
|
|
|
class ScenarioParameters(Dataset): |
|
281
|
|
|
""" |
|
282
|
|
|
Create and fill table with central parameters for each scenario |
|
283
|
|
|
|
|
284
|
|
|
This dataset creates and fills a table in the database that includes central parameters |
|
285
|
|
|
for each scenarios. These parameters are mostly from extrernal sources, they are defined |
|
286
|
|
|
and referenced within this dataset. |
|
287
|
|
|
The table is acced by various datasets to access the parameters for all sectors. |
|
288
|
|
|
|
|
289
|
|
|
|
|
290
|
|
|
*Dependencies* |
|
291
|
|
|
* :py:func:`Setup <egon.data.datasets.database.setup>` |
|
292
|
|
|
|
|
293
|
|
|
|
|
294
|
|
|
*Resulting tables* |
|
295
|
|
|
* :py:class:`scenario.egon_scenario_parameters <egon.data.datasets.scenario_parameters.EgonScenario>` is created and filled |
|
296
|
|
|
|
|
297
|
|
|
|
|
298
|
|
|
""" |
|
299
|
|
|
|
|
300
|
|
|
#: |
|
301
|
|
|
name: str = "ScenarioParameters" |
|
302
|
|
|
#: |
|
303
|
|
|
version: str = "0.0.19" |
|
304
|
|
|
|
|
305
|
|
|
def __init__(self, dependencies): |
|
306
|
|
|
super().__init__( |
|
307
|
|
|
name=self.name, |
|
308
|
|
|
version=self.version, |
|
309
|
|
|
dependencies=dependencies, |
|
310
|
|
|
tasks=( |
|
311
|
|
|
create_table, |
|
312
|
|
|
download_pypsa_technology_data, |
|
313
|
|
|
insert_scenarios, |
|
314
|
|
|
), |
|
315
|
|
|
) |
|
316
|
|
|
|