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