gridfm-datakit 0.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- gridfm_datakit/__init__.py +10 -0
- gridfm_datakit/cli.py +32 -0
- gridfm_datakit/generate.py +449 -0
- gridfm_datakit/grids/__init__.py +0 -0
- gridfm_datakit/interactive.py +538 -0
- gridfm_datakit/load_profiles/__init__.py +0 -0
- gridfm_datakit/network.py +94 -0
- gridfm_datakit/perturbations/__init__.py +0 -0
- gridfm_datakit/perturbations/load_perturbation.py +507 -0
- gridfm_datakit/perturbations/topology_perturbation.py +222 -0
- gridfm_datakit/process/__init__.py +0 -0
- gridfm_datakit/process/process_network.py +489 -0
- gridfm_datakit/process/solvers.py +290 -0
- gridfm_datakit/save.py +225 -0
- gridfm_datakit/utils/__init__.py +0 -0
- gridfm_datakit/utils/config.py +7 -0
- gridfm_datakit/utils/param_handler.py +250 -0
- gridfm_datakit/utils/stats.py +183 -0
- gridfm_datakit/utils/utils.py +30 -0
- gridfm_datakit-0.0.1.dist-info/METADATA +169 -0
- gridfm_datakit-0.0.1.dist-info/RECORD +25 -0
- gridfm_datakit-0.0.1.dist-info/WHEEL +5 -0
- gridfm_datakit-0.0.1.dist-info/entry_points.txt +2 -0
- gridfm_datakit-0.0.1.dist-info/licenses/LICENSE +201 -0
- gridfm_datakit-0.0.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"""gridfm-datakit - A library for generating synthetic power grid data."""
|
|
2
|
+
|
|
3
|
+
from gridfm_datakit.generate import (
|
|
4
|
+
generate_power_flow_data,
|
|
5
|
+
generate_power_flow_data_distributed,
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
__version__ = "0.1.0"
|
|
9
|
+
|
|
10
|
+
__all__ = ["generate_power_flow_data", "generate_power_flow_data_distributed"]
|
gridfm_datakit/cli.py
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Command-line interface for generating power flow data."""
|
|
3
|
+
|
|
4
|
+
import argparse
|
|
5
|
+
from gridfm_datakit.generate import (
|
|
6
|
+
generate_power_flow_data_distributed,
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def main():
|
|
11
|
+
"""Command-line interface for the data generation script."""
|
|
12
|
+
parser = argparse.ArgumentParser(
|
|
13
|
+
description="Generate power flow data for grid analysis",
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
parser.add_argument(
|
|
17
|
+
"config",
|
|
18
|
+
type=str,
|
|
19
|
+
help="Path to config file",
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
args = parser.parse_args()
|
|
23
|
+
file_paths = generate_power_flow_data_distributed(args.config)
|
|
24
|
+
|
|
25
|
+
print("\nData generation complete.")
|
|
26
|
+
print("Generated files:")
|
|
27
|
+
for key, path in file_paths.items():
|
|
28
|
+
print(f"- {key}: {path}")
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
if __name__ == "__main__":
|
|
32
|
+
main()
|
|
@@ -0,0 +1,449 @@
|
|
|
1
|
+
"""Main data generation module for gridfm_datakit."""
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
import os
|
|
5
|
+
from gridfm_datakit.save import (
|
|
6
|
+
save_edge_params,
|
|
7
|
+
save_bus_params,
|
|
8
|
+
save_branch_idx_removed,
|
|
9
|
+
save_node_edge_data,
|
|
10
|
+
)
|
|
11
|
+
from gridfm_datakit.process.process_network import (
|
|
12
|
+
network_preprocessing,
|
|
13
|
+
process_scenario,
|
|
14
|
+
process_scenario_contingency,
|
|
15
|
+
process_scenario_chunk,
|
|
16
|
+
)
|
|
17
|
+
from gridfm_datakit.utils.stats import plot_stats, Stats
|
|
18
|
+
from gridfm_datakit.utils.param_handler import (
|
|
19
|
+
NestedNamespace,
|
|
20
|
+
get_load_scenario_generator,
|
|
21
|
+
initialize_generator,
|
|
22
|
+
)
|
|
23
|
+
from gridfm_datakit.network import (
|
|
24
|
+
load_net_from_pp,
|
|
25
|
+
load_net_from_file,
|
|
26
|
+
load_net_from_pglib,
|
|
27
|
+
)
|
|
28
|
+
from gridfm_datakit.perturbations.load_perturbation import (
|
|
29
|
+
load_scenarios_to_df,
|
|
30
|
+
plot_load_scenarios_combined,
|
|
31
|
+
)
|
|
32
|
+
from pandapower.auxiliary import pandapowerNet
|
|
33
|
+
import gc
|
|
34
|
+
from datetime import datetime
|
|
35
|
+
from tqdm import tqdm
|
|
36
|
+
from multiprocessing import Pool, Manager
|
|
37
|
+
import shutil
|
|
38
|
+
from gridfm_datakit.utils.utils import write_ram_usage_distributed, Tee
|
|
39
|
+
import yaml
|
|
40
|
+
from typing import List, Tuple, Any, Dict, Optional, Union
|
|
41
|
+
import sys
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _setup_environment(
|
|
45
|
+
config: Union[str, Dict, NestedNamespace],
|
|
46
|
+
) -> Tuple[NestedNamespace, str, Dict[str, str]]:
|
|
47
|
+
"""Setup the environment for data generation.
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
config: Configuration can be provided in three ways:
|
|
51
|
+
1. Path to a YAML config file (str)
|
|
52
|
+
2. Configuration dictionary (Dict)
|
|
53
|
+
3. NestedNamespace object (NestedNamespace)
|
|
54
|
+
|
|
55
|
+
Returns:
|
|
56
|
+
Tuple of (args, base_path, file_paths)
|
|
57
|
+
"""
|
|
58
|
+
# Load config from file if a path is provided
|
|
59
|
+
if isinstance(config, str):
|
|
60
|
+
with open(config, "r") as f:
|
|
61
|
+
config = yaml.safe_load(f)
|
|
62
|
+
|
|
63
|
+
# Convert dict to NestedNamespace if needed
|
|
64
|
+
if isinstance(config, dict):
|
|
65
|
+
args = NestedNamespace(**config)
|
|
66
|
+
else:
|
|
67
|
+
args = config
|
|
68
|
+
|
|
69
|
+
# Setup output directory
|
|
70
|
+
base_path = os.path.join(args.settings.data_dir, args.network.name, "raw")
|
|
71
|
+
if os.path.exists(base_path) and args.settings.overwrite:
|
|
72
|
+
shutil.rmtree(base_path)
|
|
73
|
+
os.makedirs(base_path, exist_ok=True)
|
|
74
|
+
|
|
75
|
+
# Setup file paths
|
|
76
|
+
file_paths = {
|
|
77
|
+
"tqdm_log": os.path.join(base_path, "tqdm.log"),
|
|
78
|
+
"error_log": os.path.join(base_path, "error.log"),
|
|
79
|
+
"args_log": os.path.join(base_path, "args.log"),
|
|
80
|
+
"node_data": os.path.join(base_path, "pf_node.csv"),
|
|
81
|
+
"edge_data": os.path.join(base_path, "pf_edge.csv"),
|
|
82
|
+
"branch_indices": os.path.join(base_path, "branch_idx_removed.csv"),
|
|
83
|
+
"edge_params": os.path.join(base_path, "edge_params.csv"),
|
|
84
|
+
"bus_params": os.path.join(base_path, "bus_params.csv"),
|
|
85
|
+
"scenarios": os.path.join(base_path, f"scenarios_{args.load.generator}.csv"),
|
|
86
|
+
"scenarios_plot": os.path.join(
|
|
87
|
+
base_path,
|
|
88
|
+
f"scenarios_{args.load.generator}.html",
|
|
89
|
+
),
|
|
90
|
+
"scenarios_log": os.path.join(
|
|
91
|
+
base_path,
|
|
92
|
+
f"scenarios_{args.load.generator}.log",
|
|
93
|
+
),
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
# Initialize logs
|
|
97
|
+
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
98
|
+
for log_file in [
|
|
99
|
+
file_paths["tqdm_log"],
|
|
100
|
+
file_paths["error_log"],
|
|
101
|
+
file_paths["scenarios_log"],
|
|
102
|
+
file_paths["args_log"],
|
|
103
|
+
]:
|
|
104
|
+
with open(log_file, "a") as f:
|
|
105
|
+
f.write(f"\nNew generation started at {timestamp}\n")
|
|
106
|
+
if log_file == file_paths["args_log"]:
|
|
107
|
+
yaml.dump(config if isinstance(config, dict) else vars(config), f)
|
|
108
|
+
|
|
109
|
+
return args, base_path, file_paths
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def _prepare_network_and_scenarios(
|
|
113
|
+
args: NestedNamespace,
|
|
114
|
+
file_paths: Dict[str, str],
|
|
115
|
+
) -> Tuple[pandapowerNet, Any]:
|
|
116
|
+
"""Prepare the network and generate load scenarios.
|
|
117
|
+
|
|
118
|
+
Args:
|
|
119
|
+
args: Configuration object
|
|
120
|
+
file_paths: Dictionary of file paths
|
|
121
|
+
|
|
122
|
+
Returns:
|
|
123
|
+
Tuple of (network, scenarios)
|
|
124
|
+
"""
|
|
125
|
+
# Load network
|
|
126
|
+
if args.network.source == "pandapower":
|
|
127
|
+
net = load_net_from_pp(args.network.name)
|
|
128
|
+
elif args.network.source == "pglib":
|
|
129
|
+
net = load_net_from_pglib(args.network.name)
|
|
130
|
+
elif args.network.source == "file":
|
|
131
|
+
net = load_net_from_file(
|
|
132
|
+
os.path.join(args.network.network_dir, args.network.name) + ".m",
|
|
133
|
+
)
|
|
134
|
+
else:
|
|
135
|
+
raise ValueError("Invalid grid source!")
|
|
136
|
+
|
|
137
|
+
network_preprocessing(net)
|
|
138
|
+
assert (net.sgen["scaling"] == 1).all(), "Scaling factor >1 not supported yet!"
|
|
139
|
+
|
|
140
|
+
# Generate load scenarios
|
|
141
|
+
load_scenario_generator = get_load_scenario_generator(args.load)
|
|
142
|
+
scenarios = load_scenario_generator(
|
|
143
|
+
net,
|
|
144
|
+
args.load.scenarios,
|
|
145
|
+
file_paths["scenarios_log"],
|
|
146
|
+
)
|
|
147
|
+
scenarios_df = load_scenarios_to_df(scenarios)
|
|
148
|
+
scenarios_df.to_csv(file_paths["scenarios"], index=False)
|
|
149
|
+
plot_load_scenarios_combined(scenarios_df, file_paths["scenarios_plot"])
|
|
150
|
+
save_edge_params(net, file_paths["edge_params"])
|
|
151
|
+
save_bus_params(net, file_paths["bus_params"])
|
|
152
|
+
|
|
153
|
+
return net, scenarios
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def _save_generated_data(
|
|
157
|
+
net: pandapowerNet,
|
|
158
|
+
csv_data: List,
|
|
159
|
+
adjacency_lists: List,
|
|
160
|
+
branch_idx_removed: List,
|
|
161
|
+
global_stats: Optional[Stats],
|
|
162
|
+
file_paths: Dict[str, str],
|
|
163
|
+
base_path: str,
|
|
164
|
+
args: NestedNamespace,
|
|
165
|
+
) -> None:
|
|
166
|
+
"""Save the generated data to files.
|
|
167
|
+
|
|
168
|
+
Args:
|
|
169
|
+
net: Pandapower network
|
|
170
|
+
csv_data: List of CSV data
|
|
171
|
+
adjacency_lists: List of adjacency lists
|
|
172
|
+
branch_idx_removed: List of removed branch indices
|
|
173
|
+
global_stats: Optional statistics object
|
|
174
|
+
file_paths: Dictionary of file paths
|
|
175
|
+
base_path: Base output directory
|
|
176
|
+
args: Configuration object
|
|
177
|
+
"""
|
|
178
|
+
if len(adjacency_lists) > 0:
|
|
179
|
+
save_node_edge_data(
|
|
180
|
+
net,
|
|
181
|
+
file_paths["node_data"],
|
|
182
|
+
file_paths["edge_data"],
|
|
183
|
+
csv_data,
|
|
184
|
+
adjacency_lists,
|
|
185
|
+
mode=args.settings.mode,
|
|
186
|
+
)
|
|
187
|
+
save_branch_idx_removed(branch_idx_removed, file_paths["branch_indices"])
|
|
188
|
+
if not args.settings.no_stats and global_stats:
|
|
189
|
+
global_stats.save(base_path)
|
|
190
|
+
plot_stats(base_path)
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def generate_power_flow_data(
|
|
194
|
+
config: Union[str, Dict, NestedNamespace],
|
|
195
|
+
) -> Dict[str, str]:
|
|
196
|
+
"""Generate power flow data based on the provided configuration using sequential processing.
|
|
197
|
+
|
|
198
|
+
Args:
|
|
199
|
+
config: Configuration can be provided in three ways:
|
|
200
|
+
1. Path to a YAML config file (str)
|
|
201
|
+
2. Configuration dictionary (Dict)
|
|
202
|
+
3. NestedNamespace object (NestedNamespace)
|
|
203
|
+
The config must include settings, network, load, and topology_perturbation configurations.
|
|
204
|
+
|
|
205
|
+
Returns:
|
|
206
|
+
Dictionary containing paths to generated files:
|
|
207
|
+
{
|
|
208
|
+
'node_data': path to node data CSV,
|
|
209
|
+
'edge_data': path to edge data CSV,
|
|
210
|
+
'branch_indices': path to branch indices CSV,
|
|
211
|
+
'edge_params': path to edge parameters CSV,
|
|
212
|
+
'bus_params': path to bus parameters CSV,
|
|
213
|
+
'scenarios': path to scenarios CSV,
|
|
214
|
+
'scenarios_plot': path to scenarios plot HTML,
|
|
215
|
+
'scenarios_log': path to scenarios log
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
Note:
|
|
219
|
+
The function creates several output files in the specified data directory:
|
|
220
|
+
|
|
221
|
+
- tqdm.log: Progress tracking
|
|
222
|
+
- error.log: Error messages
|
|
223
|
+
- args.log: Configuration parameters
|
|
224
|
+
- pf_node.csv: Node data
|
|
225
|
+
- pf_edge.csv: Edge data
|
|
226
|
+
- branch_idx_removed.csv: Removed branch indices
|
|
227
|
+
- edge_params.csv: Edge parameters
|
|
228
|
+
- bus_params.csv: Bus parameters
|
|
229
|
+
- scenarios_{generator}.csv: Load scenarios
|
|
230
|
+
- scenarios_{generator}.html: Scenario plots
|
|
231
|
+
- scenarios_{generator}.log: Scenario generation log
|
|
232
|
+
"""
|
|
233
|
+
# Setup environment
|
|
234
|
+
args, base_path, file_paths = _setup_environment(config)
|
|
235
|
+
|
|
236
|
+
# Prepare network and scenarios
|
|
237
|
+
net, scenarios = _prepare_network_and_scenarios(args, file_paths)
|
|
238
|
+
|
|
239
|
+
# Initialize topology generator and data structures
|
|
240
|
+
generator = initialize_generator(args.topology_perturbation, net)
|
|
241
|
+
csv_data = []
|
|
242
|
+
adjacency_lists = []
|
|
243
|
+
branch_idx_removed = []
|
|
244
|
+
global_stats = Stats() if not args.settings.no_stats else None
|
|
245
|
+
|
|
246
|
+
# Process scenarios sequentially
|
|
247
|
+
with open(file_paths["tqdm_log"], "a") as f:
|
|
248
|
+
with tqdm(
|
|
249
|
+
total=args.load.scenarios,
|
|
250
|
+
desc="Processing scenarios",
|
|
251
|
+
file=Tee(sys.stdout, f),
|
|
252
|
+
miniters=5,
|
|
253
|
+
) as pbar:
|
|
254
|
+
for scenario_index in range(args.load.scenarios):
|
|
255
|
+
# Process the scenario
|
|
256
|
+
if args.settings.mode == "pf":
|
|
257
|
+
csv_data, adjacency_lists, branch_idx_removed, global_stats = (
|
|
258
|
+
process_scenario(
|
|
259
|
+
net,
|
|
260
|
+
scenarios,
|
|
261
|
+
scenario_index,
|
|
262
|
+
generator,
|
|
263
|
+
args.settings.no_stats,
|
|
264
|
+
csv_data,
|
|
265
|
+
adjacency_lists,
|
|
266
|
+
branch_idx_removed,
|
|
267
|
+
global_stats,
|
|
268
|
+
file_paths["error_log"],
|
|
269
|
+
)
|
|
270
|
+
)
|
|
271
|
+
elif args.settings.mode == "contingency":
|
|
272
|
+
csv_data, adjacency_lists, branch_idx_removed, global_stats = (
|
|
273
|
+
process_scenario_contingency(
|
|
274
|
+
net,
|
|
275
|
+
scenarios,
|
|
276
|
+
scenario_index,
|
|
277
|
+
generator,
|
|
278
|
+
args.settings.no_stats,
|
|
279
|
+
csv_data,
|
|
280
|
+
adjacency_lists,
|
|
281
|
+
branch_idx_removed,
|
|
282
|
+
global_stats,
|
|
283
|
+
file_paths["error_log"],
|
|
284
|
+
)
|
|
285
|
+
)
|
|
286
|
+
|
|
287
|
+
pbar.update(1)
|
|
288
|
+
|
|
289
|
+
# Save final data
|
|
290
|
+
_save_generated_data(
|
|
291
|
+
net,
|
|
292
|
+
csv_data,
|
|
293
|
+
adjacency_lists,
|
|
294
|
+
branch_idx_removed,
|
|
295
|
+
global_stats,
|
|
296
|
+
file_paths,
|
|
297
|
+
base_path,
|
|
298
|
+
args,
|
|
299
|
+
)
|
|
300
|
+
return file_paths
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
def generate_power_flow_data_distributed(
|
|
304
|
+
config: Union[str, Dict, NestedNamespace],
|
|
305
|
+
) -> Dict[str, str]:
|
|
306
|
+
"""Generate power flow data based on the provided configuration using distributed processing.
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
Args:
|
|
310
|
+
config: Configuration can be provided in three ways:
|
|
311
|
+
1. Path to a YAML config file (str)
|
|
312
|
+
2. Configuration dictionary (Dict)
|
|
313
|
+
3. NestedNamespace object (NestedNamespace)
|
|
314
|
+
The config must include settings, network, load, and topology_perturbation configurations.
|
|
315
|
+
|
|
316
|
+
Returns:
|
|
317
|
+
Dictionary containing paths to generated files:
|
|
318
|
+
{
|
|
319
|
+
'node_data': path to node data CSV,
|
|
320
|
+
'edge_data': path to edge data CSV,
|
|
321
|
+
'branch_indices': path to branch indices CSV,
|
|
322
|
+
'edge_params': path to edge parameters CSV,
|
|
323
|
+
'bus_params': path to bus parameters CSV,
|
|
324
|
+
'scenarios': path to scenarios CSV,
|
|
325
|
+
'scenarios_plot': path to scenarios plot HTML,
|
|
326
|
+
'scenarios_log': path to scenarios log
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
Note:
|
|
330
|
+
The function creates several output files in the specified data directory:
|
|
331
|
+
|
|
332
|
+
- tqdm.log: Progress tracking
|
|
333
|
+
- error.log: Error messages
|
|
334
|
+
- args.log: Configuration parameters
|
|
335
|
+
- pf_node.csv: Node data
|
|
336
|
+
- pf_edge.csv: Edge data
|
|
337
|
+
- branch_idx_removed.csv: Removed branch indices
|
|
338
|
+
- edge_params.csv: Edge parameters
|
|
339
|
+
- bus_params.csv: Bus parameters
|
|
340
|
+
- scenarios_{generator}.csv: Load scenarios
|
|
341
|
+
- scenarios_{generator}.html: Scenario plots
|
|
342
|
+
- scenarios_{generator}.log: Scenario generation log
|
|
343
|
+
"""
|
|
344
|
+
# Setup environment
|
|
345
|
+
args, base_path, file_paths = _setup_environment(config)
|
|
346
|
+
|
|
347
|
+
# Prepare network and scenarios
|
|
348
|
+
net, scenarios = _prepare_network_and_scenarios(args, file_paths)
|
|
349
|
+
|
|
350
|
+
# Initialize topology generator
|
|
351
|
+
generator = initialize_generator(args.topology_perturbation, net)
|
|
352
|
+
|
|
353
|
+
# Setup multiprocessing
|
|
354
|
+
manager = Manager()
|
|
355
|
+
progress_queue = manager.Queue()
|
|
356
|
+
|
|
357
|
+
# Process scenarios in chunks
|
|
358
|
+
large_chunks = np.array_split(
|
|
359
|
+
range(args.load.scenarios),
|
|
360
|
+
np.ceil(args.load.scenarios / args.settings.large_chunk_size).astype(int),
|
|
361
|
+
)
|
|
362
|
+
|
|
363
|
+
with open(file_paths["tqdm_log"], "a") as f:
|
|
364
|
+
with tqdm(
|
|
365
|
+
total=args.load.scenarios,
|
|
366
|
+
desc="Processing scenarios",
|
|
367
|
+
file=Tee(sys.stdout, f),
|
|
368
|
+
miniters=5,
|
|
369
|
+
) as pbar:
|
|
370
|
+
for large_chunk_index, large_chunk in enumerate(large_chunks):
|
|
371
|
+
write_ram_usage_distributed(f)
|
|
372
|
+
chunk_size = len(large_chunk)
|
|
373
|
+
scenario_chunks = np.array_split(
|
|
374
|
+
large_chunk,
|
|
375
|
+
args.settings.num_processes,
|
|
376
|
+
)
|
|
377
|
+
|
|
378
|
+
tasks = [
|
|
379
|
+
(
|
|
380
|
+
args.settings.mode,
|
|
381
|
+
chunk[0],
|
|
382
|
+
chunk[-1] + 1,
|
|
383
|
+
scenarios,
|
|
384
|
+
net,
|
|
385
|
+
progress_queue,
|
|
386
|
+
generator,
|
|
387
|
+
args.settings.no_stats,
|
|
388
|
+
file_paths["error_log"],
|
|
389
|
+
)
|
|
390
|
+
for chunk in scenario_chunks
|
|
391
|
+
]
|
|
392
|
+
|
|
393
|
+
# Run parallel processing
|
|
394
|
+
with Pool(processes=args.settings.num_processes) as pool:
|
|
395
|
+
results = [
|
|
396
|
+
pool.apply_async(process_scenario_chunk, task) for task in tasks
|
|
397
|
+
]
|
|
398
|
+
|
|
399
|
+
# Update progress
|
|
400
|
+
completed = 0
|
|
401
|
+
while completed < chunk_size:
|
|
402
|
+
progress_queue.get()
|
|
403
|
+
pbar.update(1)
|
|
404
|
+
completed += 1
|
|
405
|
+
|
|
406
|
+
# Gather results
|
|
407
|
+
csv_data = []
|
|
408
|
+
adjacency_lists = []
|
|
409
|
+
branch_idx_removed = []
|
|
410
|
+
global_stats = Stats() if not args.settings.no_stats else None
|
|
411
|
+
|
|
412
|
+
for result in results:
|
|
413
|
+
(
|
|
414
|
+
e,
|
|
415
|
+
traceback,
|
|
416
|
+
local_csv_data,
|
|
417
|
+
local_adjacency_lists,
|
|
418
|
+
local_branch_idx_removed,
|
|
419
|
+
local_stats,
|
|
420
|
+
) = result.get()
|
|
421
|
+
if isinstance(e, Exception):
|
|
422
|
+
print(f"Error in process_scenario_chunk: {e}")
|
|
423
|
+
print(traceback)
|
|
424
|
+
sys.exit(1)
|
|
425
|
+
csv_data.extend(local_csv_data)
|
|
426
|
+
adjacency_lists.extend(local_adjacency_lists)
|
|
427
|
+
branch_idx_removed.extend(local_branch_idx_removed)
|
|
428
|
+
if not args.settings.no_stats and local_stats:
|
|
429
|
+
global_stats.merge(local_stats)
|
|
430
|
+
|
|
431
|
+
pool.close()
|
|
432
|
+
pool.join()
|
|
433
|
+
|
|
434
|
+
# Save processed data
|
|
435
|
+
_save_generated_data(
|
|
436
|
+
net,
|
|
437
|
+
csv_data,
|
|
438
|
+
adjacency_lists,
|
|
439
|
+
branch_idx_removed,
|
|
440
|
+
global_stats,
|
|
441
|
+
file_paths,
|
|
442
|
+
base_path,
|
|
443
|
+
args,
|
|
444
|
+
)
|
|
445
|
+
|
|
446
|
+
del csv_data, adjacency_lists, global_stats
|
|
447
|
+
gc.collect()
|
|
448
|
+
|
|
449
|
+
return file_paths
|
|
File without changes
|