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.

Files changed (35) hide show
  1. pyconvexity/__init__.py +30 -6
  2. pyconvexity/_version.py +1 -1
  3. pyconvexity/data/README.md +101 -0
  4. pyconvexity/data/__init__.py +18 -0
  5. pyconvexity/data/__pycache__/__init__.cpython-313.pyc +0 -0
  6. pyconvexity/data/loaders/__init__.py +3 -0
  7. pyconvexity/data/loaders/__pycache__/__init__.cpython-313.pyc +0 -0
  8. pyconvexity/data/loaders/__pycache__/cache.cpython-313.pyc +0 -0
  9. pyconvexity/data/loaders/cache.py +212 -0
  10. pyconvexity/data/sources/__init__.py +5 -0
  11. pyconvexity/data/sources/__pycache__/__init__.cpython-313.pyc +0 -0
  12. pyconvexity/data/sources/__pycache__/gem.cpython-313.pyc +0 -0
  13. pyconvexity/data/sources/gem.py +412 -0
  14. pyconvexity/io/__init__.py +32 -0
  15. pyconvexity/io/excel_exporter.py +991 -0
  16. pyconvexity/io/excel_importer.py +1112 -0
  17. pyconvexity/io/netcdf_exporter.py +192 -0
  18. pyconvexity/io/netcdf_importer.py +599 -0
  19. pyconvexity/models/__init__.py +7 -0
  20. pyconvexity/models/attributes.py +3 -1
  21. pyconvexity/models/components.py +3 -0
  22. pyconvexity/models/scenarios.py +177 -0
  23. pyconvexity/solvers/__init__.py +29 -0
  24. pyconvexity/solvers/pypsa/__init__.py +24 -0
  25. pyconvexity/solvers/pypsa/api.py +398 -0
  26. pyconvexity/solvers/pypsa/batch_loader.py +311 -0
  27. pyconvexity/solvers/pypsa/builder.py +656 -0
  28. pyconvexity/solvers/pypsa/constraints.py +321 -0
  29. pyconvexity/solvers/pypsa/solver.py +1255 -0
  30. pyconvexity/solvers/pypsa/storage.py +2207 -0
  31. {pyconvexity-0.1.1.dist-info → pyconvexity-0.1.3.dist-info}/METADATA +5 -2
  32. pyconvexity-0.1.3.dist-info/RECORD +45 -0
  33. pyconvexity-0.1.1.dist-info/RECORD +0 -20
  34. {pyconvexity-0.1.1.dist-info → pyconvexity-0.1.3.dist-info}/WHEEL +0 -0
  35. {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
+ }