pyconvexity 0.4.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.

Files changed (42) hide show
  1. pyconvexity/__init__.py +226 -0
  2. pyconvexity/_version.py +1 -0
  3. pyconvexity/core/__init__.py +60 -0
  4. pyconvexity/core/database.py +485 -0
  5. pyconvexity/core/errors.py +106 -0
  6. pyconvexity/core/types.py +400 -0
  7. pyconvexity/data/README.md +101 -0
  8. pyconvexity/data/__init__.py +17 -0
  9. pyconvexity/data/loaders/__init__.py +3 -0
  10. pyconvexity/data/loaders/cache.py +213 -0
  11. pyconvexity/data/schema/01_core_schema.sql +420 -0
  12. pyconvexity/data/schema/02_data_metadata.sql +120 -0
  13. pyconvexity/data/schema/03_validation_data.sql +506 -0
  14. pyconvexity/data/sources/__init__.py +5 -0
  15. pyconvexity/data/sources/gem.py +442 -0
  16. pyconvexity/io/__init__.py +26 -0
  17. pyconvexity/io/excel_exporter.py +1226 -0
  18. pyconvexity/io/excel_importer.py +1381 -0
  19. pyconvexity/io/netcdf_exporter.py +197 -0
  20. pyconvexity/io/netcdf_importer.py +1833 -0
  21. pyconvexity/models/__init__.py +195 -0
  22. pyconvexity/models/attributes.py +730 -0
  23. pyconvexity/models/carriers.py +159 -0
  24. pyconvexity/models/components.py +611 -0
  25. pyconvexity/models/network.py +503 -0
  26. pyconvexity/models/results.py +148 -0
  27. pyconvexity/models/scenarios.py +234 -0
  28. pyconvexity/solvers/__init__.py +29 -0
  29. pyconvexity/solvers/pypsa/__init__.py +24 -0
  30. pyconvexity/solvers/pypsa/api.py +460 -0
  31. pyconvexity/solvers/pypsa/batch_loader.py +307 -0
  32. pyconvexity/solvers/pypsa/builder.py +675 -0
  33. pyconvexity/solvers/pypsa/constraints.py +405 -0
  34. pyconvexity/solvers/pypsa/solver.py +1509 -0
  35. pyconvexity/solvers/pypsa/storage.py +2048 -0
  36. pyconvexity/timeseries.py +330 -0
  37. pyconvexity/validation/__init__.py +25 -0
  38. pyconvexity/validation/rules.py +312 -0
  39. pyconvexity-0.4.3.dist-info/METADATA +47 -0
  40. pyconvexity-0.4.3.dist-info/RECORD +42 -0
  41. pyconvexity-0.4.3.dist-info/WHEEL +5 -0
  42. pyconvexity-0.4.3.dist-info/top_level.txt +1 -0
@@ -0,0 +1,197 @@
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
+
17
+ class NetCDFModelExporter:
18
+ """Export network model to PyPSA NetCDF format"""
19
+
20
+ def __init__(self):
21
+ self.logger = logging.getLogger(__name__)
22
+
23
+ def export_to_netcdf(
24
+ self,
25
+ db_path: str,
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 (single network per database).
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
+ output_path: Path where to save the NetCDF file
39
+ scenario_id: Optional scenario ID (NULL for base network)
40
+ progress_callback: Optional callback for progress updates
41
+
42
+ Returns:
43
+ Dictionary with export results and statistics
44
+ """
45
+ try:
46
+ if progress_callback:
47
+ progress_callback(0, "Starting NetCDF export...")
48
+
49
+ # Build PyPSA network from database using existing infrastructure
50
+ if progress_callback:
51
+ progress_callback(10, "Building PyPSA network from database...")
52
+
53
+ network = build_pypsa_network(
54
+ db_path=db_path,
55
+ scenario_id=scenario_id,
56
+ progress_callback=self._wrap_progress_callback(
57
+ progress_callback, 10, 80
58
+ ),
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
+ output_directory: str,
90
+ scenario_id: Optional[int] = None,
91
+ progress_callback: Optional[Callable[[int, str], None]] = None,
92
+ ) -> Dict[str, Any]:
93
+ """
94
+ Export network from database to PyPSA CSV format (single network per database).
95
+
96
+ Args:
97
+ db_path: Path to the database file
98
+ output_directory: Directory where to save CSV files
99
+ scenario_id: Optional scenario ID (NULL for base network)
100
+ progress_callback: Optional callback for progress updates
101
+
102
+ Returns:
103
+ Dictionary with export results and statistics
104
+ """
105
+ try:
106
+ if progress_callback:
107
+ progress_callback(0, "Starting CSV export...")
108
+
109
+ # Ensure output directory exists
110
+ Path(output_directory).mkdir(parents=True, exist_ok=True)
111
+
112
+ # Build PyPSA network from database using existing infrastructure
113
+ if progress_callback:
114
+ progress_callback(10, "Building PyPSA network from database...")
115
+
116
+ network = build_pypsa_network(
117
+ db_path=db_path,
118
+ scenario_id=scenario_id,
119
+ progress_callback=self._wrap_progress_callback(
120
+ progress_callback, 10, 80
121
+ ),
122
+ )
123
+
124
+ if progress_callback:
125
+ progress_callback(80, "Exporting to CSV...")
126
+
127
+ # Export to CSV using PyPSA's built-in method
128
+ network.export_to_csv_folder(output_directory)
129
+
130
+ if progress_callback:
131
+ progress_callback(100, "CSV export completed")
132
+
133
+ # Get statistics
134
+ stats = self._get_network_stats(network)
135
+
136
+ return {
137
+ "success": True,
138
+ "message": f"Network exported to CSV: {output_directory}",
139
+ "output_directory": output_directory,
140
+ "stats": stats,
141
+ }
142
+
143
+ except Exception as e:
144
+ self.logger.error(f"CSV export failed: {e}", exc_info=True)
145
+ if progress_callback:
146
+ progress_callback(None, f"Export failed: {str(e)}")
147
+ raise
148
+
149
+ def _wrap_progress_callback(
150
+ self,
151
+ callback: Optional[Callable[[int, str], None]],
152
+ start_percent: int,
153
+ end_percent: int,
154
+ ) -> Optional[Callable[[int, str], None]]:
155
+ """
156
+ Wrap a progress callback to map progress from one range to another
157
+
158
+ Args:
159
+ callback: Original callback function
160
+ start_percent: Starting percentage for the wrapped range
161
+ end_percent: Ending percentage for the wrapped range
162
+
163
+ Returns:
164
+ Wrapped callback function or None if original callback is None
165
+ """
166
+ if callback is None:
167
+ return None
168
+
169
+ def wrapped_callback(progress: Optional[int], message: Optional[str]):
170
+ if progress is not None:
171
+ # Map progress from 0-100 to start_percent-end_percent
172
+ mapped_progress = start_percent + (
173
+ progress * (end_percent - start_percent) // 100
174
+ )
175
+ callback(mapped_progress, message)
176
+ else:
177
+ callback(progress, message)
178
+
179
+ return wrapped_callback
180
+
181
+ def _get_network_stats(self, network: "pypsa.Network") -> Dict[str, int]:
182
+ """Get component counts from the network"""
183
+ return {
184
+ "buses": len(network.buses),
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,
197
+ }