1
|
|
|
from pathlib import Path |
2
|
|
|
import codecs |
3
|
|
|
import configparser |
4
|
|
|
import csv |
5
|
|
|
import datetime |
6
|
|
|
import logging |
7
|
|
|
import os |
8
|
|
|
import shutil |
9
|
|
|
import subprocess |
10
|
|
|
import sys |
11
|
|
|
|
12
|
|
|
import psycopg2 |
13
|
|
|
|
14
|
|
|
from egon.data import db, logger |
15
|
|
|
from egon.data.config import settings |
16
|
|
|
from egon.data.datasets import Dataset |
17
|
|
|
from egon.data.datasets.osmtgmod.substation import extract |
18
|
|
|
from egon.data.datasets.scenario_parameters import get_sector_parameters |
19
|
|
|
import egon.data.config |
20
|
|
|
import egon.data.subprocess as subproc |
21
|
|
|
|
22
|
|
|
|
23
|
|
|
def run(): |
24
|
|
|
sys.setrecursionlimit(5000) |
25
|
|
|
# execute osmTGmod |
26
|
|
|
|
27
|
|
|
data_config = egon.data.config.datasets() |
28
|
|
|
osm_config = data_config["openstreetmap"]["original_data"] |
29
|
|
|
|
30
|
|
|
if settings()["egon-data"]["--dataset-boundary"] == "Everything": |
31
|
|
|
target_path = osm_config["target"]["file"] |
32
|
|
|
else: |
33
|
|
|
target_path = osm_config["target"]["file_testmode"] |
34
|
|
|
|
35
|
|
|
filtered_osm_pbf_path_to_file = os.path.join( |
36
|
|
|
egon.data.__path__[0], "datasets", "osm", target_path |
37
|
|
|
) |
38
|
|
|
docker_db_config = db.credentials() |
39
|
|
|
|
40
|
|
|
osmtgmod( |
41
|
|
|
config_database=docker_db_config["POSTGRES_DB"], |
42
|
|
|
config_basepath="osmTGmod/egon-data", |
43
|
|
|
config_continue_run=False, |
44
|
|
|
filtered_osm_pbf_path_to_file=filtered_osm_pbf_path_to_file, |
45
|
|
|
docker_db_config=docker_db_config, |
46
|
|
|
) |
47
|
|
|
|
48
|
|
|
|
49
|
|
|
def import_osm_data(): |
50
|
|
|
|
51
|
|
|
osmtgmod_repos = Path(".") / "osmTGmod" |
52
|
|
|
|
53
|
|
|
# Delete repository if it already exists |
54
|
|
|
if osmtgmod_repos.exists() and osmtgmod_repos.is_dir(): |
55
|
|
|
try: |
56
|
|
|
status = subprocess.check_output( |
57
|
|
|
["git", "status"], cwd=(osmtgmod_repos).absolute() |
58
|
|
|
) |
59
|
|
|
if status.startswith( |
60
|
|
|
b"Auf Branch features/egon" |
61
|
|
|
) or status.startswith(b"On branch features/egon"): |
62
|
|
|
logger.info("OsmTGmod cloned and right branch checked out.") |
63
|
|
|
|
64
|
|
|
else: |
65
|
|
|
subproc.run( |
66
|
|
|
[ |
67
|
|
|
"git", |
68
|
|
|
"checkout", |
69
|
|
|
"features/egon", |
70
|
|
|
] |
71
|
|
|
) |
72
|
|
|
except subprocess.CalledProcessError: |
73
|
|
|
shutil.rmtree(osmtgmod_repos) |
74
|
|
|
subproc.run( |
75
|
|
|
[ |
76
|
|
|
"git", |
77
|
|
|
"clone", |
78
|
|
|
"--single-branch", |
79
|
|
|
"--branch", |
80
|
|
|
"features/egon", |
81
|
|
|
"https://github.com/openego/osmTGmod.git", |
82
|
|
|
] |
83
|
|
|
) |
84
|
|
|
else: |
85
|
|
|
|
86
|
|
|
subproc.run( |
87
|
|
|
[ |
88
|
|
|
"git", |
89
|
|
|
"clone", |
90
|
|
|
"--single-branch", |
91
|
|
|
"--branch", |
92
|
|
|
"features/egon", |
93
|
|
|
"https://github.com/openego/osmTGmod.git", |
94
|
|
|
] |
95
|
|
|
) |
96
|
|
|
|
97
|
|
|
data_config = egon.data.config.datasets() |
98
|
|
|
osm_config = data_config["openstreetmap"]["original_data"] |
99
|
|
|
|
100
|
|
|
if settings()["egon-data"]["--dataset-boundary"] == "Everything": |
101
|
|
|
target_path = osm_config["target"]["file"] |
102
|
|
|
else: |
103
|
|
|
target_path = osm_config["target"]["file_testmode"] |
104
|
|
|
|
105
|
|
|
filtered_osm_pbf_path_to_file = Path(".") / "openstreetmap" / target_path |
106
|
|
|
|
107
|
|
|
docker_db_config = db.credentials() |
108
|
|
|
config_database = docker_db_config["POSTGRES_DB"] |
109
|
|
|
config_basepath = "osmTGmod/egon-data" |
110
|
|
|
|
111
|
|
|
config = configparser.ConfigParser() |
112
|
|
|
config.read(config_basepath + ".cfg") |
113
|
|
|
config["postgres_server"]["host"] = docker_db_config["HOST"] |
114
|
|
|
config["postgres_server"]["port"] = docker_db_config["PORT"] |
115
|
|
|
config["postgres_server"]["user"] = docker_db_config["POSTGRES_USER"] |
116
|
|
|
config["postgres_server"]["password"] = docker_db_config[ |
117
|
|
|
"POSTGRES_PASSWORD" |
118
|
|
|
] |
119
|
|
|
|
120
|
|
|
logging.info("Creating status table ...") |
121
|
|
|
db.execute_sql( |
122
|
|
|
""" |
123
|
|
|
DROP TABLE IF EXISTS _db_status; |
124
|
|
|
CREATE TABLE _db_status (module TEXT, status BOOLEAN); |
125
|
|
|
INSERT INTO _db_status (module, status) VALUES ('grid_model', FALSE); |
126
|
|
|
""" |
127
|
|
|
) |
128
|
|
|
|
129
|
|
|
logging.info("Status table created.") |
130
|
|
|
|
131
|
|
|
# egon-specific, in order to not fill up the results schema, |
132
|
|
|
# it is dropped before creation |
133
|
|
|
logging.info("Dropping osmtgmod_results schema if exists") |
134
|
|
|
db.execute_sql("DROP SCHEMA IF EXISTS osmtgmod_results CASCADE;") |
135
|
|
|
|
136
|
|
|
logging.info("Loading functions and result schema ...") |
137
|
|
|
scripts = [ |
138
|
|
|
"sql-scripts/extensions.sql", |
139
|
|
|
"sql-scripts/functions.sql", |
140
|
|
|
"sql-scripts/admin_boundaries.sql", |
141
|
|
|
"sql-scripts/electrical_properties.sql", |
142
|
|
|
"sql-scripts/build_up_db.sql", |
143
|
|
|
] |
144
|
|
|
for script in scripts: |
145
|
|
|
logging.info("Running script {0} ...".format(script)) |
146
|
|
|
with codecs.open( |
147
|
|
|
os.path.join("osmTGmod", script), "r", "utf-8-sig" |
148
|
|
|
) as fd: |
149
|
|
|
sqlfile = fd.read() |
150
|
|
|
db.execute_sql(sqlfile) |
151
|
|
|
logging.info("Done.") |
152
|
|
|
|
153
|
|
|
db.execute_sql( |
154
|
|
|
"""UPDATE _db_status SET status = TRUE |
155
|
|
|
WHERE module = 'grid_model'; """ |
156
|
|
|
) |
157
|
|
|
|
158
|
|
|
logging.info("osmTGmod-database successfully built up!") |
159
|
|
|
|
160
|
|
|
logging.info("Importing OSM-data to database.") |
161
|
|
|
|
162
|
|
|
logging.info("Using pdf file: {}".format(filtered_osm_pbf_path_to_file)) |
163
|
|
|
logging.info( |
164
|
|
|
f"""Assuming osmosis is avaliable at |
165
|
|
|
{config['osm_data']['osmosis_path_to_binary']}""" |
166
|
|
|
) |
167
|
|
|
|
168
|
|
|
# create directory to store osmosis' temp files |
169
|
|
|
osmosis_temp_dir = Path("osmTGmod") / "osmosis_temp/" |
170
|
|
|
if not os.path.exists(osmosis_temp_dir): |
171
|
|
|
os.mkdir(osmosis_temp_dir) |
172
|
|
|
|
173
|
|
|
subproc.run( |
174
|
|
|
"JAVACMD_OPTIONS='%s' %s --read-pbf %s --write-pgsql \ |
175
|
|
|
database=%s host=%s user=%s password=%s" |
176
|
|
|
% ( |
177
|
|
|
f"-Djava.io.tmpdir={osmosis_temp_dir}", |
178
|
|
|
os.path.join( |
179
|
|
|
"osmTGmod", config["osm_data"]["osmosis_path_to_binary"] |
180
|
|
|
), |
181
|
|
|
filtered_osm_pbf_path_to_file, |
182
|
|
|
config_database, |
183
|
|
|
config["postgres_server"]["host"] |
184
|
|
|
+ ":" |
185
|
|
|
+ config["postgres_server"]["port"], |
186
|
|
|
config["postgres_server"]["user"], |
187
|
|
|
config["postgres_server"]["password"], |
188
|
|
|
), |
189
|
|
|
shell=True, |
190
|
|
|
) |
191
|
|
|
logging.info("Importing OSM-Data...") |
192
|
|
|
|
193
|
|
|
# After updating OSM-Data, power_tables (for editing) |
194
|
|
|
# have to be updated as well |
195
|
|
|
logging.info("Creating power-tables...") |
196
|
|
|
db.execute_sql("SELECT otg_create_power_tables ();") |
197
|
|
|
|
198
|
|
|
# Update OSM Metadata |
199
|
|
|
logging.info("Updating OSM metadata") |
200
|
|
|
v_date = datetime.datetime.now().strftime("%Y-%m-%d") |
201
|
|
|
db.execute_sql(f"UPDATE osm_metadata SET imported = '{v_date}'") |
202
|
|
|
logging.info("OSM data imported to database successfully.") |
203
|
|
|
|
204
|
|
|
|
205
|
|
|
def osmtgmod( |
206
|
|
|
config_database="egon-data", |
207
|
|
|
config_basepath="osmTGmod/egon-data", |
208
|
|
|
config_continue_run=False, |
209
|
|
|
filtered_osm_pbf_path_to_file=None, |
210
|
|
|
docker_db_config=None, |
211
|
|
|
): |
212
|
|
|
|
213
|
|
|
if ("germany-21" in filtered_osm_pbf_path_to_file) | ( |
214
|
|
|
"germany-22" in filtered_osm_pbf_path_to_file |
215
|
|
|
): |
216
|
|
|
""" |
217
|
|
|
Manually add under construction substation expansion in Garenfeld |
218
|
|
|
to existing substation. (see:) |
219
|
|
|
""" |
220
|
|
|
print("Manually updating geometry of substation in Garenfeld") |
221
|
|
|
db.execute_sql( |
222
|
|
|
"""DROP TRIGGER IF EXISTS |
223
|
|
|
power_ways_update ON power_ways CASCADE """ |
224
|
|
|
) |
225
|
|
|
|
226
|
|
|
db.execute_sql( |
227
|
|
|
""" |
228
|
|
|
UPDATE power_ways |
229
|
|
|
SET way = (SELECT ST_SetSRID(ST_AsText( |
230
|
|
|
'0102000000160000001612D5004A081E4020A8644A35B349407B0ACA' |
231
|
|
|
'7E27071E405F23EE563BB34940287CB60E0E061E4055A4C2D842B34940352FE29' |
232
|
|
|
'6EA051E4017940E7B46B34940C0D02346CF051E4042EBE1CB44B34940D67E219A' |
233
|
|
|
'2F051E40FECF06054AB349407F964A442F031E40C2F441F471B34940A8A544676' |
234
|
|
|
'1021E40AB9412CA8FB349409C4848881E021E40B7BA08C691B34940B22D4E1430' |
235
|
|
|
'001E40CE913856BDB34940E2810B122C001E40898CAEAFDBB349402CDAF043480' |
236
|
|
|
'11E40ED678C32F0B349402FE640E25C041E405A86F21AF1B3494061D525C46F04' |
237
|
|
|
'1E40ABEF60C892B34940DC2F9FAC18061E400D33D9E495B349401FD7868A71061' |
238
|
|
|
'E40D2D8A89894B3494083932353F4061E40077360DE88B34940624ED02687071E' |
239
|
|
|
'404F08782D7CB349405000C5C892091E403EFBDBAF4CB349403DDBFEF04E091E4' |
240
|
|
|
'0658D7A8846B349405AD5928E72081E405BE8EF4A37B349401612D5004A081E40' |
241
|
|
|
'20A8644A35B34940'), 4326)) |
242
|
|
|
WHERE name = 'Garenfeld' |
243
|
|
|
AND id = 24667346 |
244
|
|
|
""" |
245
|
|
|
) |
246
|
|
|
|
247
|
|
|
# ============================================================== |
248
|
|
|
# Setup logging |
249
|
|
|
# ============================================================== |
250
|
|
|
# log = logging.getLogger() |
251
|
|
|
# log.setLevel(logging.INFO) |
252
|
|
|
# logformat = logging.Formatter( |
253
|
|
|
# "%(asctime)s %(message)s", "%m/%d/%Y %H:%M:%S" |
254
|
|
|
# ) |
255
|
|
|
# sh = logging.StreamHandler() |
256
|
|
|
# sh.setFormatter(logformat) |
257
|
|
|
# log.addHandler(sh) |
258
|
|
|
# logging.info("\n\n======================\nego_otg\n======================") |
259
|
|
|
# logging.info("Logging to standard output...") |
260
|
|
|
# # catch up some log messages from evaluation of command line arguments |
261
|
|
|
# logging.info("Database: {}".format(config_database)) |
262
|
|
|
# logging.info( |
263
|
|
|
# "Path for configuration file and results: {}".format(config_basepath) |
264
|
|
|
# ) |
265
|
|
|
# ============================================================== |
266
|
|
|
# read configuration from file and create folder structure |
267
|
|
|
# ============================================================== |
268
|
|
|
logging.info( |
269
|
|
|
( |
270
|
|
|
"Taking db connection credentials from eGon-data " |
271
|
|
|
"with respect to the given docker_db_config variable" |
272
|
|
|
) |
273
|
|
|
) |
274
|
|
|
config = configparser.ConfigParser() |
275
|
|
|
config.read(config_basepath + ".cfg") |
276
|
|
|
config["postgres_server"]["host"] = docker_db_config["HOST"] |
277
|
|
|
config["postgres_server"]["port"] = docker_db_config["PORT"] |
278
|
|
|
config["postgres_server"]["user"] = docker_db_config["POSTGRES_USER"] |
279
|
|
|
config["postgres_server"]["password"] = docker_db_config[ |
280
|
|
|
"POSTGRES_PASSWORD" |
281
|
|
|
] |
282
|
|
|
|
283
|
|
|
# Setting osmTGmod folder structure: |
284
|
|
|
logging.info("Checking/Creating file directories") |
285
|
|
|
input_data_dir = os.path.join(config_basepath, "input_data") |
286
|
|
|
result_dir = os.path.join(config_basepath, "results") |
287
|
|
|
# Basic folders are created if not existent |
288
|
|
|
if not os.path.exists(input_data_dir): |
289
|
|
|
os.makedirs(input_data_dir) |
290
|
|
|
if not os.path.exists(result_dir): |
291
|
|
|
os.makedirs(result_dir) |
292
|
|
|
# start logging to file |
293
|
|
|
# logfile = os.path.join(config_basepath, config_database + ".log") |
294
|
|
|
# fh = logging.FileHandler(logfile) |
295
|
|
|
# fh.setFormatter(logformat) |
296
|
|
|
# log.addHandler(fh) |
297
|
|
|
# logging.info("Logging to file '{0}' is set up".format(logfile)) |
298
|
|
|
# logging.info( |
299
|
|
|
# "Now logging both to standard output and to file '{0}'...".format( |
300
|
|
|
# logfile |
301
|
|
|
# ) |
302
|
|
|
# ) |
303
|
|
|
logging.info("\n\n======================\nego_otg\n======================") |
304
|
|
|
# copy config file |
305
|
|
|
logging.info( |
306
|
|
|
"Copying configuration file to '{0}'.".format( |
307
|
|
|
os.path.join(config_basepath, config_database + ".cfg") |
308
|
|
|
) |
309
|
|
|
) |
310
|
|
|
os.system( |
311
|
|
|
"cp {0} {1}".format( |
312
|
|
|
config_basepath + ".cfg", |
313
|
|
|
os.path.join(config_basepath, config_database + ".cfg"), |
314
|
|
|
) |
315
|
|
|
) |
316
|
|
|
|
317
|
|
|
# Connects to new Database |
318
|
|
|
logging.info("Connecting to database {} ...".format(config_database)) |
319
|
|
|
conn = psycopg2.connect( |
320
|
|
|
host=config["postgres_server"]["host"], |
321
|
|
|
port=config["postgres_server"]["port"], |
322
|
|
|
database=config_database, |
323
|
|
|
user=config["postgres_server"]["user"], |
324
|
|
|
password=config["postgres_server"]["password"], |
325
|
|
|
) |
326
|
|
|
|
327
|
|
|
cur = conn.cursor() |
328
|
|
|
|
329
|
|
|
min_voltage = 110000 |
330
|
|
|
|
331
|
|
|
if not config_continue_run: |
332
|
|
|
logging.info("Setting min_voltage...") |
333
|
|
|
cur.execute( |
334
|
|
|
""" |
335
|
|
|
UPDATE abstr_values |
336
|
|
|
SET val_int = %s |
337
|
|
|
WHERE val_description = 'min_voltage'""", |
338
|
|
|
(min_voltage,), |
339
|
|
|
) |
340
|
|
|
conn.commit() |
341
|
|
|
|
342
|
|
|
logging.info("Setting main_station...") |
343
|
|
|
cur.execute( |
344
|
|
|
""" |
345
|
|
|
UPDATE abstr_values |
346
|
|
|
SET val_int = %s |
347
|
|
|
WHERE val_description = 'main_station'""", |
348
|
|
|
(config.getint("abstraction", "main_station"),), |
349
|
|
|
) |
350
|
|
|
conn.commit() |
351
|
|
|
|
352
|
|
|
logging.info("Setting graph_dfs...") |
353
|
|
|
cur.execute( |
354
|
|
|
""" |
355
|
|
|
UPDATE abstr_values |
356
|
|
|
SET val_bool = %s |
357
|
|
|
WHERE val_description = 'graph_dfs'""", |
358
|
|
|
(config.getboolean("abstraction", "graph_dfs"),), |
359
|
|
|
) |
360
|
|
|
conn.commit() |
361
|
|
|
|
362
|
|
|
logging.info("Setting conn_subgraphs...") |
363
|
|
|
cur.execute( |
364
|
|
|
""" |
365
|
|
|
UPDATE abstr_values |
366
|
|
|
SET val_bool = %s |
367
|
|
|
WHERE val_description = 'conn_subgraphs'""", |
368
|
|
|
(config.getboolean("abstraction", "conn_subgraphs"),), |
369
|
|
|
) |
370
|
|
|
conn.commit() |
371
|
|
|
|
372
|
|
|
logging.info("Setting transfer_busses...") |
373
|
|
|
cur.execute( |
374
|
|
|
""" |
375
|
|
|
UPDATE abstr_values |
376
|
|
|
SET val_bool = %s |
377
|
|
|
WHERE val_description = 'transfer_busses'""", |
378
|
|
|
(config.getboolean("abstraction", "transfer_busses"),), |
379
|
|
|
) |
380
|
|
|
conn.commit() |
381
|
|
|
|
382
|
|
|
# setting transfer busses |
383
|
|
|
path_for_transfer_busses = input_data_dir + "/transfer_busses.csv" |
384
|
|
|
logging.info( |
385
|
|
|
"Reading transfer busses from file {} ...".format( |
386
|
|
|
path_for_transfer_busses |
387
|
|
|
) |
388
|
|
|
) |
389
|
|
|
logging.info("Deleting all entries from transfer_busses table ...") |
390
|
|
|
cur.execute( |
391
|
|
|
""" |
392
|
|
|
DELETE FROM transfer_busses; |
393
|
|
|
""" |
394
|
|
|
) |
395
|
|
|
conn.commit() |
396
|
|
|
|
397
|
|
|
with open(path_for_transfer_busses, "w") as this_file: |
398
|
|
|
cur.copy_expert( |
399
|
|
|
"""COPY transfer_busses_complete to |
400
|
|
|
STDOUT WITH CSV HEADER""", |
401
|
|
|
this_file, |
402
|
|
|
) |
403
|
|
|
conn.commit() |
404
|
|
|
|
405
|
|
|
reader = csv.reader(open(path_for_transfer_busses, "r")) |
406
|
|
|
next(reader, None) # Skips header |
407
|
|
|
logging.info("Copying transfer-busses from CSV to database...") |
408
|
|
|
for row in reader: |
409
|
|
|
osm_id = str(row[8]) |
410
|
|
|
if osm_id[:1] == "w": |
411
|
|
|
object_type = "way" |
412
|
|
|
elif osm_id[:1] == "n": |
413
|
|
|
object_type = "node" |
414
|
|
|
else: |
415
|
|
|
object_type = None |
416
|
|
|
osm_id_int = int(osm_id[1:]) |
417
|
|
|
center_geom = str(row[3]) |
418
|
|
|
cur.execute( |
419
|
|
|
""" |
420
|
|
|
INSERT INTO transfer_busses (osm_id, object_type, |
421
|
|
|
center_geom) |
422
|
|
|
VALUES (%s, %s, %s); |
423
|
|
|
""", |
424
|
|
|
(osm_id_int, object_type, center_geom), |
425
|
|
|
) |
426
|
|
|
conn.commit() |
427
|
|
|
logging.info("All transfer busses imported successfully") |
428
|
|
|
|
429
|
|
|
# Execute power_script |
430
|
|
|
logging.info( |
431
|
|
|
( |
432
|
|
|
"Preparing execution of abstraction script " |
433
|
|
|
"'sql-scripts/power_script.sql' ..." |
434
|
|
|
) |
435
|
|
|
) |
436
|
|
|
with codecs.open( |
437
|
|
|
"osmTGmod/sql-scripts/power_script.sql", "r", "utf-8-sig" |
438
|
|
|
) as fd: |
439
|
|
|
sqlfile = fd.read() |
440
|
|
|
# remove lines starting with "--" (comments), tabulators and empty line |
441
|
|
|
# beware: comments in C-like style (such as /* comment */) arn't parsed! |
442
|
|
|
sqlfile_without_comments = "".join( |
443
|
|
|
[ |
444
|
|
|
( |
445
|
|
|
line.lstrip().split("--")[0] + "\n" |
446
|
|
|
if not line.lstrip().split("--")[0] == "" |
447
|
|
|
else "" |
448
|
|
|
) |
449
|
|
|
for line in sqlfile.split("\n") |
450
|
|
|
] |
451
|
|
|
) |
452
|
|
|
|
453
|
|
|
logging.info("Stating execution of power script...") |
454
|
|
|
config_continue_run_at = -1 |
455
|
|
|
|
456
|
|
|
if not config_continue_run: # debugging - to be removed |
457
|
|
|
cur.execute( |
458
|
|
|
"""drop table if exists debug;create table debug |
459
|
|
|
(step_before int,max_bus_id int, num_bus int,max_branch_id int, |
460
|
|
|
num_branch int, num_110_bus int, num_220_bus int, |
461
|
|
|
num_380_bus int)""" |
462
|
|
|
) |
463
|
|
|
conn.commit() |
464
|
|
|
|
465
|
|
|
# split sqlfile in commands seperated by ";", while not considering |
466
|
|
|
# symbols for splitting if "escaped" by single quoted strings. |
467
|
|
|
# Drop everything after last semicolon. |
468
|
|
|
for i, command in enumerate( |
469
|
|
|
"'".join( |
470
|
|
|
[ |
471
|
|
|
segment.replace(";", "§") if i % 2 == 0 else segment |
472
|
|
|
for i, segment in enumerate( |
473
|
|
|
sqlfile_without_comments.split("'") |
474
|
|
|
) |
475
|
|
|
] |
476
|
|
|
).split("§")[:-1] |
477
|
|
|
): |
478
|
|
|
|
479
|
|
|
if i >= config_continue_run_at: |
480
|
|
|
logging.info( |
481
|
|
|
"Executing SQL statement {0}:{1}\n".format(i, command) |
482
|
|
|
) |
483
|
|
|
try: |
484
|
|
|
cur.execute(command) |
485
|
|
|
conn.commit() |
486
|
|
|
except: |
487
|
|
|
logging.exception( |
488
|
|
|
( |
489
|
|
|
"Exception raised with command {0}. " |
490
|
|
|
"Check data and code " |
491
|
|
|
"and restart with 'python ego_otg.py {1} {0}'." |
492
|
|
|
).format(i, config_database) |
493
|
|
|
) |
494
|
|
|
sys.exit() |
495
|
|
|
if i > 16: # debugging - to be removed |
496
|
|
|
cur.execute( |
497
|
|
|
"""insert into debug values ({0}, |
498
|
|
|
(select max(id) from bus_data),(select count(*) |
499
|
|
|
from bus_data),(select max(branch_id) |
500
|
|
|
from branch_data),(select count(*) |
501
|
|
|
from branch_data),(select count(*) |
502
|
|
|
from bus_data where voltage = 110000), |
503
|
|
|
(select count (*) from bus_data where voltage = 220000), |
504
|
|
|
(select count (*) |
505
|
|
|
from bus_data where voltage = 380000))""".format( |
506
|
|
|
i |
507
|
|
|
) |
508
|
|
|
) |
509
|
|
|
conn.commit() |
510
|
|
|
|
511
|
|
|
logging.info("Power-script executed successfully.") |
512
|
|
|
|
513
|
|
|
logging.info("Saving Results...") |
514
|
|
|
cur.execute("SELECT otg_save_results ();") |
515
|
|
|
conn.commit() |
516
|
|
|
|
517
|
|
|
logging.info("Abstraction process complete!") |
518
|
|
|
|
519
|
|
|
# ============================================================== |
520
|
|
|
# Write results |
521
|
|
|
# ============================================================== |
522
|
|
|
logging.info("Writing results") |
523
|
|
|
|
524
|
|
|
tables = ["bus_data", "branch_data", "dcline_data", "results_metadata"] |
525
|
|
|
for table in tables: |
526
|
|
|
logging.info("writing %s..." % table) |
527
|
|
|
filename = os.path.join(result_dir, table + ".csv") |
528
|
|
|
logging.info( |
529
|
|
|
"Writing contents of table {0} to {1}...".format(table, filename) |
530
|
|
|
) |
531
|
|
|
query = "SELECT * FROM osmtgmod_results.%s " % (table,) |
532
|
|
|
outputquery = "COPY ({0}) TO STDOUT WITH DELIMITER \ |
533
|
|
|
',' CSV HEADER".format( |
534
|
|
|
query |
535
|
|
|
) |
536
|
|
|
with open(filename, encoding="utf-8", mode="w") as fh: |
537
|
|
|
cur.copy_expert(outputquery, fh) |
538
|
|
|
|
539
|
|
|
logging.info("All tables written!") |
540
|
|
|
|
541
|
|
|
logging.info("EXECUTION FINISHED SUCCESSFULLY!") |
542
|
|
|
|
543
|
|
|
|
544
|
|
|
def to_pypsa(): |
545
|
|
|
db.execute_sql( |
546
|
|
|
""" |
547
|
|
|
-- CLEAN UP OF TABLES |
548
|
|
|
DELETE FROM grid.egon_etrago_bus |
549
|
|
|
WHERE carrier = 'AC'; |
550
|
|
|
DELETE FROM grid.egon_etrago_line; |
551
|
|
|
DELETE FROM grid.egon_etrago_transformer; |
552
|
|
|
""" |
553
|
|
|
) |
554
|
|
|
|
555
|
|
|
# for scenario_name in ["'eGon2035'", "'eGon100RE'", "'status2019'"]: |
556
|
|
|
scenario_list = egon.data.config.settings()["egon-data"]["--scenarios"] |
557
|
|
|
scenario_list = [ |
558
|
|
|
f"'{scn}'" if not scn[1] == "'" else scn for scn in scenario_list |
559
|
|
|
] |
560
|
|
|
for scenario_name in scenario_list: |
561
|
|
|
|
562
|
|
|
# TODO maybe not needed anymore? |
563
|
|
|
capital_cost = get_sector_parameters( |
564
|
|
|
"electricity", scenario_name.replace("'", "") |
565
|
|
|
)["capital_cost"] |
566
|
|
|
lifetime = get_sector_parameters( |
567
|
|
|
"electricity", scenario_name.replace("'", "") |
568
|
|
|
)["lifetime"] |
569
|
|
|
db.execute_sql( |
570
|
|
|
f""" |
571
|
|
|
-- BUS DATA |
572
|
|
|
INSERT INTO grid.egon_etrago_bus (scn_name, bus_id, v_nom, |
573
|
|
|
geom, x, y, carrier, country) |
574
|
|
|
SELECT |
575
|
|
|
{scenario_name}, |
576
|
|
|
bus_i AS bus_id, |
577
|
|
|
base_kv AS v_nom, |
578
|
|
|
geom, |
579
|
|
|
ST_X(geom) as x, |
580
|
|
|
ST_Y(geom) as y, |
581
|
|
|
'AC' as carrier, |
582
|
|
|
cntr_id |
583
|
|
|
FROM osmtgmod_results.bus_data |
584
|
|
|
WHERE result_id = 1; |
585
|
|
|
|
586
|
|
|
|
587
|
|
|
-- BRANCH DATA |
588
|
|
|
INSERT INTO grid.egon_etrago_line (scn_name, line_id, bus0, |
589
|
|
|
bus1, x, r, b, s_nom, s_nom_min, s_nom_extendable, |
590
|
|
|
cables, v_nom, |
591
|
|
|
geom, topo, carrier) |
592
|
|
|
SELECT |
593
|
|
|
{scenario_name}, |
594
|
|
|
branch_id AS line_id, |
595
|
|
|
f_bus AS bus0, |
596
|
|
|
t_bus AS bus1, |
597
|
|
|
br_x AS x, |
598
|
|
|
br_r AS r, |
599
|
|
|
br_b as b, |
600
|
|
|
rate_a as s_nom, |
601
|
|
|
rate_a as s_nom_min, |
602
|
|
|
TRUE, |
603
|
|
|
cables, |
604
|
|
|
branch_voltage/1000 as v_nom, |
605
|
|
|
geom, |
606
|
|
|
topo, |
607
|
|
|
'AC' as carrier |
608
|
|
|
FROM osmtgmod_results.branch_data |
609
|
|
|
WHERE result_id = 1 and (link_type = 'line' or |
610
|
|
|
link_type = 'cable'); |
611
|
|
|
|
612
|
|
|
|
613
|
|
|
-- TRANSFORMER DATA |
614
|
|
|
INSERT INTO grid.egon_etrago_transformer (scn_name, |
615
|
|
|
trafo_id, bus0, bus1, x, |
616
|
|
|
s_nom, s_nom_min, s_nom_extendable, tap_ratio, |
617
|
|
|
phase_shift, geom, topo) |
618
|
|
|
SELECT |
619
|
|
|
{scenario_name}, |
620
|
|
|
branch_id AS trafo_id, |
621
|
|
|
f_bus AS bus0, |
622
|
|
|
t_bus AS bus1, |
623
|
|
|
br_x/(100 * rate_a) AS x, --- change base from 100MVA (osmtgmod) to the its individual s_nom (pypsa) |
624
|
|
|
rate_a as s_nom, |
625
|
|
|
rate_a as s_nom_min, |
626
|
|
|
TRUE, |
627
|
|
|
tap AS tap_ratio, |
628
|
|
|
shift AS phase_shift, |
629
|
|
|
geom, |
630
|
|
|
topo |
631
|
|
|
FROM osmtgmod_results.branch_data |
632
|
|
|
WHERE result_id = 1 and link_type = 'transformer'; |
633
|
|
|
|
634
|
|
|
|
635
|
|
|
-- per unit to absolute values |
636
|
|
|
|
637
|
|
|
UPDATE grid.egon_etrago_line a |
638
|
|
|
SET |
639
|
|
|
r = r * (((SELECT v_nom |
640
|
|
|
FROM grid.egon_etrago_bus b |
641
|
|
|
WHERE bus_id=bus1 |
642
|
|
|
AND a.scn_name = b.scn_name |
643
|
|
|
)*1000)^2 / (100 * 10^6)), |
644
|
|
|
x = x * (((SELECT v_nom |
645
|
|
|
FROM grid.egon_etrago_bus b |
646
|
|
|
WHERE bus_id=bus1 |
647
|
|
|
AND a.scn_name = b.scn_name |
648
|
|
|
)*1000)^2 / (100 * 10^6)), |
649
|
|
|
b = b * (((SELECT v_nom |
650
|
|
|
FROM grid.egon_etrago_bus b |
651
|
|
|
WHERE bus_id=bus1 |
652
|
|
|
AND a.scn_name = b.scn_name |
653
|
|
|
)*1000)^2 / (100 * 10^6)) |
654
|
|
|
WHERE scn_name = {scenario_name}; |
655
|
|
|
|
656
|
|
|
-- calculate line length (in km) from geoms |
657
|
|
|
|
658
|
|
|
UPDATE grid.egon_etrago_line a |
659
|
|
|
SET |
660
|
|
|
length = result.length |
661
|
|
|
FROM |
662
|
|
|
(SELECT b.line_id, st_length(b.geom,false)/1000 as length |
663
|
|
|
from grid.egon_etrago_line b) |
664
|
|
|
as result |
665
|
|
|
WHERE a.line_id = result.line_id |
666
|
|
|
AND scn_name = {scenario_name}; |
667
|
|
|
|
668
|
|
|
-- set capital costs for eHV-lines |
669
|
|
|
UPDATE grid.egon_etrago_line |
670
|
|
|
SET capital_cost = {capital_cost['ac_ehv_overhead_line']} * length |
671
|
|
|
WHERE v_nom > 110 |
672
|
|
|
AND scn_name = {scenario_name}; |
673
|
|
|
|
674
|
|
|
-- set capital costs for HV-lines |
675
|
|
|
UPDATE grid.egon_etrago_line |
676
|
|
|
SET capital_cost = {capital_cost['ac_hv_overhead_line']} * length |
677
|
|
|
WHERE v_nom = 110 |
678
|
|
|
AND scn_name = {scenario_name}; |
679
|
|
|
|
680
|
|
|
-- set capital costs for transformers |
681
|
|
|
UPDATE grid.egon_etrago_transformer a |
682
|
|
|
SET capital_cost = {capital_cost['transformer_380_220']} |
683
|
|
|
WHERE (a.bus0 IN ( |
684
|
|
|
SELECT bus_id FROM grid.egon_etrago_bus |
685
|
|
|
WHERE v_nom = 380) |
686
|
|
|
AND a.bus1 IN ( |
687
|
|
|
SELECT bus_id FROM grid.egon_etrago_bus |
688
|
|
|
WHERE v_nom = 220)) |
689
|
|
|
OR (a.bus0 IN ( |
690
|
|
|
SELECT bus_id FROM grid.egon_etrago_bus |
691
|
|
|
WHERE v_nom = 220) |
692
|
|
|
AND a.bus1 IN ( |
693
|
|
|
SELECT bus_id FROM grid.egon_etrago_bus |
694
|
|
|
WHERE v_nom = 380)) |
695
|
|
|
AND scn_name = {scenario_name}; |
696
|
|
|
|
697
|
|
|
UPDATE grid.egon_etrago_transformer a |
698
|
|
|
SET capital_cost = {capital_cost['transformer_380_110']} |
699
|
|
|
WHERE (a.bus0 IN ( |
700
|
|
|
SELECT bus_id FROM grid.egon_etrago_bus |
701
|
|
|
WHERE v_nom = 380) |
702
|
|
|
AND a.bus1 IN ( |
703
|
|
|
SELECT bus_id FROM grid.egon_etrago_bus |
704
|
|
|
WHERE v_nom = 110)) |
705
|
|
|
OR (a.bus0 IN ( |
706
|
|
|
SELECT bus_id FROM grid.egon_etrago_bus |
707
|
|
|
WHERE v_nom = 110) |
708
|
|
|
AND a.bus1 IN ( |
709
|
|
|
SELECT bus_id FROM grid.egon_etrago_bus |
710
|
|
|
WHERE v_nom = 380)) |
711
|
|
|
AND scn_name = {scenario_name}; |
712
|
|
|
|
713
|
|
|
UPDATE grid.egon_etrago_transformer a |
714
|
|
|
SET capital_cost = {capital_cost['transformer_220_110']} |
715
|
|
|
WHERE (a.bus0 IN ( |
716
|
|
|
SELECT bus_id FROM grid.egon_etrago_bus |
717
|
|
|
WHERE v_nom = 220) |
718
|
|
|
AND a.bus1 IN ( |
719
|
|
|
SELECT bus_id FROM grid.egon_etrago_bus |
720
|
|
|
WHERE v_nom = 110)) |
721
|
|
|
OR (a.bus0 IN ( |
722
|
|
|
SELECT bus_id FROM grid.egon_etrago_bus |
723
|
|
|
WHERE v_nom = 110) |
724
|
|
|
AND a.bus1 IN ( |
725
|
|
|
SELECT bus_id FROM grid.egon_etrago_bus |
726
|
|
|
WHERE v_nom = 220)) |
727
|
|
|
AND scn_name = {scenario_name}; |
728
|
|
|
|
729
|
|
|
-- set lifetime for eHV-lines |
730
|
|
|
UPDATE grid.egon_etrago_line |
731
|
|
|
SET lifetime = {lifetime['ac_ehv_overhead_line']} |
732
|
|
|
WHERE v_nom > 110 |
733
|
|
|
AND scn_name = {scenario_name}; |
734
|
|
|
|
735
|
|
|
-- set capital costs for HV-lines |
736
|
|
|
UPDATE grid.egon_etrago_line |
737
|
|
|
SET lifetime = {lifetime['ac_hv_overhead_line']} |
738
|
|
|
WHERE v_nom = 110 |
739
|
|
|
AND scn_name = {scenario_name}; |
740
|
|
|
|
741
|
|
|
-- set capital costs for transformers |
742
|
|
|
UPDATE grid.egon_etrago_transformer a |
743
|
|
|
SET lifetime = {lifetime['transformer_380_220']} |
744
|
|
|
WHERE (a.bus0 IN ( |
745
|
|
|
SELECT bus_id FROM grid.egon_etrago_bus |
746
|
|
|
WHERE v_nom = 380) |
747
|
|
|
AND a.bus1 IN ( |
748
|
|
|
SELECT bus_id FROM grid.egon_etrago_bus |
749
|
|
|
WHERE v_nom = 220)) |
750
|
|
|
OR (a.bus0 IN ( |
751
|
|
|
SELECT bus_id FROM grid.egon_etrago_bus |
752
|
|
|
WHERE v_nom = 220) |
753
|
|
|
AND a.bus1 IN ( |
754
|
|
|
SELECT bus_id FROM grid.egon_etrago_bus |
755
|
|
|
WHERE v_nom = 380)) |
756
|
|
|
AND scn_name = {scenario_name}; |
757
|
|
|
|
758
|
|
|
UPDATE grid.egon_etrago_transformer a |
759
|
|
|
SET lifetime = {lifetime['transformer_380_110']} |
760
|
|
|
WHERE (a.bus0 IN ( |
761
|
|
|
SELECT bus_id FROM grid.egon_etrago_bus |
762
|
|
|
WHERE v_nom = 380) |
763
|
|
|
AND a.bus1 IN ( |
764
|
|
|
SELECT bus_id FROM grid.egon_etrago_bus |
765
|
|
|
WHERE v_nom = 110)) |
766
|
|
|
OR (a.bus0 IN ( |
767
|
|
|
SELECT bus_id FROM grid.egon_etrago_bus |
768
|
|
|
WHERE v_nom = 110) |
769
|
|
|
AND a.bus1 IN ( |
770
|
|
|
SELECT bus_id FROM grid.egon_etrago_bus |
771
|
|
|
WHERE v_nom = 380)) |
772
|
|
|
AND scn_name = {scenario_name}; |
773
|
|
|
|
774
|
|
|
UPDATE grid.egon_etrago_transformer a |
775
|
|
|
SET lifetime = {lifetime['transformer_220_110']} |
776
|
|
|
WHERE (a.bus0 IN ( |
777
|
|
|
SELECT bus_id FROM grid.egon_etrago_bus |
778
|
|
|
WHERE v_nom = 220) |
779
|
|
|
AND a.bus1 IN ( |
780
|
|
|
SELECT bus_id FROM grid.egon_etrago_bus |
781
|
|
|
WHERE v_nom = 110)) |
782
|
|
|
OR (a.bus0 IN ( |
783
|
|
|
SELECT bus_id FROM grid.egon_etrago_bus |
784
|
|
|
WHERE v_nom = 110) |
785
|
|
|
AND a.bus1 IN ( |
786
|
|
|
SELECT bus_id FROM grid.egon_etrago_bus |
787
|
|
|
WHERE v_nom = 220)) |
788
|
|
|
AND scn_name = {scenario_name}; |
789
|
|
|
|
790
|
|
|
-- delete buses without connection to AC grid and generation or |
791
|
|
|
-- load assigned |
792
|
|
|
|
793
|
|
|
DELETE FROM grid.egon_etrago_bus |
794
|
|
|
WHERE scn_name={scenario_name} |
795
|
|
|
AND carrier = 'AC' |
796
|
|
|
AND bus_id NOT IN |
797
|
|
|
(SELECT bus0 FROM grid.egon_etrago_line WHERE |
798
|
|
|
scn_name={scenario_name}) |
799
|
|
|
AND bus_id NOT IN |
800
|
|
|
(SELECT bus1 FROM grid.egon_etrago_line WHERE |
801
|
|
|
scn_name={scenario_name}) |
802
|
|
|
AND bus_id NOT IN |
803
|
|
|
(SELECT bus0 FROM grid.egon_etrago_transformer |
804
|
|
|
WHERE scn_name={scenario_name}) |
805
|
|
|
AND bus_id NOT IN |
806
|
|
|
(SELECT bus1 FROM grid.egon_etrago_transformer |
807
|
|
|
WHERE scn_name={scenario_name}); |
808
|
|
|
""" |
809
|
|
|
) |
810
|
|
|
|
811
|
|
|
|
812
|
|
|
def fix_transformer_snom(): |
813
|
|
|
db.execute_sql( |
814
|
|
|
""" |
815
|
|
|
UPDATE grid.egon_etrago_transformer AS t |
816
|
|
|
SET s_nom = CAST( |
817
|
|
|
LEAST( |
818
|
|
|
(SELECT SUM(COALESCE(l.s_nom,0)) |
819
|
|
|
FROM grid.egon_etrago_line AS l |
820
|
|
|
WHERE (l.bus0 = t.bus0 OR l.bus1 = t.bus0) |
821
|
|
|
AND l.scn_name = t.scn_name), |
822
|
|
|
(SELECT SUM(COALESCE(l.s_nom,0)) |
823
|
|
|
FROM grid.egon_etrago_line AS l |
824
|
|
|
WHERE (l.bus0 = t.bus1 OR l.bus1 = t.bus1) |
825
|
|
|
AND l.scn_name = t.scn_name) |
826
|
|
|
) AS smallint |
827
|
|
|
); |
828
|
|
|
""") |
829
|
|
|
|
830
|
|
|
|
831
|
|
|
class Osmtgmod(Dataset): |
832
|
|
|
""" |
833
|
|
|
Run the tool osmtgmod to generate transmission grid topology |
834
|
|
|
|
835
|
|
|
Executes the tool osmtgmod which create a electricity grid topology based |
836
|
|
|
on OSM data for the voltage levels 110 - 380 kV. For further information |
837
|
|
|
on osmtgmod please refer our `osmtgmod fork. <https://github.com/openego/osmTGmod>`_ |
838
|
|
|
Standard electrical line parameters are added to the grid topology and |
839
|
|
|
resulting data on buses, lines and transformers are exported to the data |
840
|
|
|
base. |
841
|
|
|
|
842
|
|
|
*Dependencies* |
843
|
|
|
* :py:class:`ScenarioParameters <egon.data.datasets.scenario_parameters.ScenarioParameters>` |
844
|
|
|
* :py:class:`EtragoSetup <egon.data.datasets.etrago_setup.EtragoSetup>` |
845
|
|
|
* :py:class:`SubstationExtraction <egon.data.datasets.substation.SubstationExtraction>` |
846
|
|
|
* :py:class:`OpenStreetMap <egon.data.datasets.osm.OpenStreetMap>` |
847
|
|
|
|
848
|
|
|
*Resulting tables* |
849
|
|
|
* :py:class:`grid.egon_etrago_bus <egon.data.datasets.etrago_setup.EgonPfHvBus>` is extended |
850
|
|
|
* :py:class:`grid.egon_etrago_line <egon.data.datasets.etrago_setup.EgonPfHvLine>` is extended |
851
|
|
|
* :py:class:`grid.egon_etrago_transformer <egon.data.datasets.etrago_setup.EgonPfHvTransformer>` is extended |
852
|
|
|
|
853
|
|
|
""" |
854
|
|
|
|
855
|
|
|
#: |
856
|
|
|
name: str = "Osmtgmod" |
857
|
|
|
#: |
858
|
|
|
version: str = "0.0.7" |
859
|
|
|
|
860
|
|
|
def __init__(self, dependencies): |
861
|
|
|
super().__init__( |
862
|
|
|
name=self.name, |
863
|
|
|
version=self.version, |
864
|
|
|
dependencies=dependencies, |
865
|
|
|
tasks=( |
866
|
|
|
import_osm_data, |
867
|
|
|
run, |
868
|
|
|
{ |
869
|
|
|
extract, |
870
|
|
|
to_pypsa, |
871
|
|
|
}, |
872
|
|
|
fix_transformer_snom, |
873
|
|
|
), |
874
|
|
|
) |
875
|
|
|
|