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.18" |
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
|
|
|
|