pyconvexity 0.4.0__py3-none-any.whl → 0.4.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.
- pyconvexity/__init__.py +87 -46
- pyconvexity/_version.py +1 -1
- pyconvexity/core/__init__.py +3 -5
- pyconvexity/core/database.py +111 -103
- pyconvexity/core/errors.py +16 -10
- pyconvexity/core/types.py +61 -54
- pyconvexity/data/__init__.py +0 -1
- pyconvexity/data/loaders/cache.py +65 -64
- pyconvexity/data/schema/01_core_schema.sql +134 -234
- pyconvexity/data/schema/02_data_metadata.sql +38 -168
- pyconvexity/data/schema/03_validation_data.sql +327 -264
- pyconvexity/data/sources/gem.py +169 -139
- pyconvexity/io/__init__.py +4 -10
- pyconvexity/io/excel_exporter.py +694 -480
- pyconvexity/io/excel_importer.py +817 -545
- pyconvexity/io/netcdf_exporter.py +66 -61
- pyconvexity/io/netcdf_importer.py +850 -619
- pyconvexity/models/__init__.py +109 -59
- pyconvexity/models/attributes.py +197 -178
- pyconvexity/models/carriers.py +70 -67
- pyconvexity/models/components.py +260 -236
- pyconvexity/models/network.py +202 -284
- pyconvexity/models/results.py +65 -55
- pyconvexity/models/scenarios.py +58 -88
- pyconvexity/solvers/__init__.py +5 -5
- pyconvexity/solvers/pypsa/__init__.py +3 -3
- pyconvexity/solvers/pypsa/api.py +150 -134
- pyconvexity/solvers/pypsa/batch_loader.py +165 -162
- pyconvexity/solvers/pypsa/builder.py +390 -291
- pyconvexity/solvers/pypsa/constraints.py +184 -162
- pyconvexity/solvers/pypsa/solver.py +968 -663
- pyconvexity/solvers/pypsa/storage.py +1377 -671
- pyconvexity/timeseries.py +63 -60
- pyconvexity/validation/__init__.py +14 -6
- pyconvexity/validation/rules.py +95 -84
- pyconvexity-0.4.1.dist-info/METADATA +46 -0
- pyconvexity-0.4.1.dist-info/RECORD +42 -0
- pyconvexity/data/schema/04_scenario_schema.sql +0 -122
- pyconvexity/data/schema/migrate_add_geometries.sql +0 -73
- pyconvexity-0.4.0.dist-info/METADATA +0 -138
- pyconvexity-0.4.0.dist-info/RECORD +0 -44
- {pyconvexity-0.4.0.dist-info → pyconvexity-0.4.1.dist-info}/WHEEL +0 -0
- {pyconvexity-0.4.0.dist-info → pyconvexity-0.4.1.dist-info}/top_level.txt +0 -0
|
@@ -13,180 +13,185 @@ from pyconvexity.solvers.pypsa import build_pypsa_network
|
|
|
13
13
|
|
|
14
14
|
logger = logging.getLogger(__name__)
|
|
15
15
|
|
|
16
|
+
|
|
16
17
|
class NetCDFModelExporter:
|
|
17
18
|
"""Export network model to PyPSA NetCDF format"""
|
|
18
|
-
|
|
19
|
+
|
|
19
20
|
def __init__(self):
|
|
20
21
|
self.logger = logging.getLogger(__name__)
|
|
21
|
-
|
|
22
|
+
|
|
22
23
|
def export_to_netcdf(
|
|
23
24
|
self,
|
|
24
25
|
db_path: str,
|
|
25
|
-
network_id: int,
|
|
26
26
|
output_path: str,
|
|
27
27
|
scenario_id: Optional[int] = None,
|
|
28
|
-
progress_callback: Optional[Callable[[int, str], None]] = None
|
|
28
|
+
progress_callback: Optional[Callable[[int, str], None]] = None,
|
|
29
29
|
) -> Dict[str, Any]:
|
|
30
30
|
"""
|
|
31
|
-
Export network from database to PyPSA NetCDF format
|
|
32
|
-
|
|
31
|
+
Export network from database to PyPSA NetCDF format (single network per database).
|
|
32
|
+
|
|
33
33
|
This method leverages the existing pyconvexity PyPSA infrastructure to build
|
|
34
34
|
a network from the database and then export it to NetCDF format.
|
|
35
|
-
|
|
35
|
+
|
|
36
36
|
Args:
|
|
37
37
|
db_path: Path to the database file
|
|
38
|
-
network_id: ID of the network to export
|
|
39
38
|
output_path: Path where to save the NetCDF file
|
|
40
|
-
scenario_id: Optional scenario ID (
|
|
39
|
+
scenario_id: Optional scenario ID (NULL for base network)
|
|
41
40
|
progress_callback: Optional callback for progress updates
|
|
42
|
-
|
|
41
|
+
|
|
43
42
|
Returns:
|
|
44
43
|
Dictionary with export results and statistics
|
|
45
44
|
"""
|
|
46
45
|
try:
|
|
47
46
|
if progress_callback:
|
|
48
47
|
progress_callback(0, "Starting NetCDF export...")
|
|
49
|
-
|
|
48
|
+
|
|
50
49
|
# Build PyPSA network from database using existing infrastructure
|
|
51
50
|
if progress_callback:
|
|
52
51
|
progress_callback(10, "Building PyPSA network from database...")
|
|
53
|
-
|
|
52
|
+
|
|
54
53
|
network = build_pypsa_network(
|
|
55
54
|
db_path=db_path,
|
|
56
|
-
network_id=network_id,
|
|
57
55
|
scenario_id=scenario_id,
|
|
58
|
-
progress_callback=self._wrap_progress_callback(
|
|
56
|
+
progress_callback=self._wrap_progress_callback(
|
|
57
|
+
progress_callback, 10, 80
|
|
58
|
+
),
|
|
59
59
|
)
|
|
60
|
-
|
|
60
|
+
|
|
61
61
|
if progress_callback:
|
|
62
62
|
progress_callback(80, "Exporting to NetCDF...")
|
|
63
|
-
|
|
63
|
+
|
|
64
64
|
# Export to NetCDF using PyPSA's built-in method
|
|
65
65
|
network.export_to_netcdf(output_path)
|
|
66
|
-
|
|
66
|
+
|
|
67
67
|
if progress_callback:
|
|
68
68
|
progress_callback(100, "NetCDF export completed")
|
|
69
|
-
|
|
69
|
+
|
|
70
70
|
# Get statistics
|
|
71
71
|
stats = self._get_network_stats(network)
|
|
72
|
-
|
|
72
|
+
|
|
73
73
|
return {
|
|
74
74
|
"success": True,
|
|
75
75
|
"message": f"Network exported to NetCDF: {output_path}",
|
|
76
76
|
"output_path": output_path,
|
|
77
|
-
"stats": stats
|
|
77
|
+
"stats": stats,
|
|
78
78
|
}
|
|
79
|
-
|
|
79
|
+
|
|
80
80
|
except Exception as e:
|
|
81
81
|
self.logger.error(f"NetCDF export failed: {e}", exc_info=True)
|
|
82
82
|
if progress_callback:
|
|
83
83
|
progress_callback(None, f"Export failed: {str(e)}")
|
|
84
84
|
raise
|
|
85
|
-
|
|
85
|
+
|
|
86
86
|
def export_to_csv(
|
|
87
87
|
self,
|
|
88
88
|
db_path: str,
|
|
89
|
-
network_id: int,
|
|
90
89
|
output_directory: str,
|
|
91
90
|
scenario_id: Optional[int] = None,
|
|
92
|
-
progress_callback: Optional[Callable[[int, str], None]] = None
|
|
91
|
+
progress_callback: Optional[Callable[[int, str], None]] = None,
|
|
93
92
|
) -> Dict[str, Any]:
|
|
94
93
|
"""
|
|
95
|
-
Export network from database to PyPSA CSV format
|
|
96
|
-
|
|
94
|
+
Export network from database to PyPSA CSV format (single network per database).
|
|
95
|
+
|
|
97
96
|
Args:
|
|
98
97
|
db_path: Path to the database file
|
|
99
|
-
network_id: ID of the network to export
|
|
100
98
|
output_directory: Directory where to save CSV files
|
|
101
|
-
scenario_id: Optional scenario ID (
|
|
99
|
+
scenario_id: Optional scenario ID (NULL for base network)
|
|
102
100
|
progress_callback: Optional callback for progress updates
|
|
103
|
-
|
|
101
|
+
|
|
104
102
|
Returns:
|
|
105
103
|
Dictionary with export results and statistics
|
|
106
104
|
"""
|
|
107
105
|
try:
|
|
108
106
|
if progress_callback:
|
|
109
107
|
progress_callback(0, "Starting CSV export...")
|
|
110
|
-
|
|
108
|
+
|
|
111
109
|
# Ensure output directory exists
|
|
112
110
|
Path(output_directory).mkdir(parents=True, exist_ok=True)
|
|
113
|
-
|
|
111
|
+
|
|
114
112
|
# Build PyPSA network from database using existing infrastructure
|
|
115
113
|
if progress_callback:
|
|
116
114
|
progress_callback(10, "Building PyPSA network from database...")
|
|
117
|
-
|
|
115
|
+
|
|
118
116
|
network = build_pypsa_network(
|
|
119
117
|
db_path=db_path,
|
|
120
|
-
network_id=network_id,
|
|
121
118
|
scenario_id=scenario_id,
|
|
122
|
-
progress_callback=self._wrap_progress_callback(
|
|
119
|
+
progress_callback=self._wrap_progress_callback(
|
|
120
|
+
progress_callback, 10, 80
|
|
121
|
+
),
|
|
123
122
|
)
|
|
124
|
-
|
|
123
|
+
|
|
125
124
|
if progress_callback:
|
|
126
125
|
progress_callback(80, "Exporting to CSV...")
|
|
127
|
-
|
|
126
|
+
|
|
128
127
|
# Export to CSV using PyPSA's built-in method
|
|
129
128
|
network.export_to_csv_folder(output_directory)
|
|
130
|
-
|
|
129
|
+
|
|
131
130
|
if progress_callback:
|
|
132
131
|
progress_callback(100, "CSV export completed")
|
|
133
|
-
|
|
132
|
+
|
|
134
133
|
# Get statistics
|
|
135
134
|
stats = self._get_network_stats(network)
|
|
136
|
-
|
|
135
|
+
|
|
137
136
|
return {
|
|
138
137
|
"success": True,
|
|
139
138
|
"message": f"Network exported to CSV: {output_directory}",
|
|
140
139
|
"output_directory": output_directory,
|
|
141
|
-
"stats": stats
|
|
140
|
+
"stats": stats,
|
|
142
141
|
}
|
|
143
|
-
|
|
142
|
+
|
|
144
143
|
except Exception as e:
|
|
145
144
|
self.logger.error(f"CSV export failed: {e}", exc_info=True)
|
|
146
145
|
if progress_callback:
|
|
147
146
|
progress_callback(None, f"Export failed: {str(e)}")
|
|
148
147
|
raise
|
|
149
|
-
|
|
148
|
+
|
|
150
149
|
def _wrap_progress_callback(
|
|
151
|
-
self,
|
|
152
|
-
callback: Optional[Callable[[int, str], None]],
|
|
153
|
-
start_percent: int,
|
|
154
|
-
end_percent: int
|
|
150
|
+
self,
|
|
151
|
+
callback: Optional[Callable[[int, str], None]],
|
|
152
|
+
start_percent: int,
|
|
153
|
+
end_percent: int,
|
|
155
154
|
) -> Optional[Callable[[int, str], None]]:
|
|
156
155
|
"""
|
|
157
156
|
Wrap a progress callback to map progress from one range to another
|
|
158
|
-
|
|
157
|
+
|
|
159
158
|
Args:
|
|
160
159
|
callback: Original callback function
|
|
161
160
|
start_percent: Starting percentage for the wrapped range
|
|
162
161
|
end_percent: Ending percentage for the wrapped range
|
|
163
|
-
|
|
162
|
+
|
|
164
163
|
Returns:
|
|
165
164
|
Wrapped callback function or None if original callback is None
|
|
166
165
|
"""
|
|
167
166
|
if callback is None:
|
|
168
167
|
return None
|
|
169
|
-
|
|
168
|
+
|
|
170
169
|
def wrapped_callback(progress: Optional[int], message: Optional[str]):
|
|
171
170
|
if progress is not None:
|
|
172
171
|
# Map progress from 0-100 to start_percent-end_percent
|
|
173
|
-
mapped_progress = start_percent + (
|
|
172
|
+
mapped_progress = start_percent + (
|
|
173
|
+
progress * (end_percent - start_percent) // 100
|
|
174
|
+
)
|
|
174
175
|
callback(mapped_progress, message)
|
|
175
176
|
else:
|
|
176
177
|
callback(progress, message)
|
|
177
|
-
|
|
178
|
+
|
|
178
179
|
return wrapped_callback
|
|
179
|
-
|
|
180
|
-
def _get_network_stats(self, network:
|
|
180
|
+
|
|
181
|
+
def _get_network_stats(self, network: "pypsa.Network") -> Dict[str, int]:
|
|
181
182
|
"""Get component counts from the network"""
|
|
182
183
|
return {
|
|
183
184
|
"buses": len(network.buses),
|
|
184
|
-
"generators":
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
"
|
|
188
|
-
"
|
|
189
|
-
"
|
|
190
|
-
"
|
|
191
|
-
|
|
185
|
+
"generators": (
|
|
186
|
+
len(network.generators) if hasattr(network, "generators") else 0
|
|
187
|
+
),
|
|
188
|
+
"loads": len(network.loads) if hasattr(network, "loads") else 0,
|
|
189
|
+
"lines": len(network.lines) if hasattr(network, "lines") else 0,
|
|
190
|
+
"links": len(network.links) if hasattr(network, "links") else 0,
|
|
191
|
+
"storage_units": (
|
|
192
|
+
len(network.storage_units) if hasattr(network, "storage_units") else 0
|
|
193
|
+
),
|
|
194
|
+
"stores": len(network.stores) if hasattr(network, "stores") else 0,
|
|
195
|
+
"carriers": len(network.carriers) if hasattr(network, "carriers") else 0,
|
|
196
|
+
"snapshots": len(network.snapshots) if hasattr(network, "snapshots") else 0,
|
|
192
197
|
}
|