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.
Files changed (43) hide show
  1. pyconvexity/__init__.py +87 -46
  2. pyconvexity/_version.py +1 -1
  3. pyconvexity/core/__init__.py +3 -5
  4. pyconvexity/core/database.py +111 -103
  5. pyconvexity/core/errors.py +16 -10
  6. pyconvexity/core/types.py +61 -54
  7. pyconvexity/data/__init__.py +0 -1
  8. pyconvexity/data/loaders/cache.py +65 -64
  9. pyconvexity/data/schema/01_core_schema.sql +134 -234
  10. pyconvexity/data/schema/02_data_metadata.sql +38 -168
  11. pyconvexity/data/schema/03_validation_data.sql +327 -264
  12. pyconvexity/data/sources/gem.py +169 -139
  13. pyconvexity/io/__init__.py +4 -10
  14. pyconvexity/io/excel_exporter.py +694 -480
  15. pyconvexity/io/excel_importer.py +817 -545
  16. pyconvexity/io/netcdf_exporter.py +66 -61
  17. pyconvexity/io/netcdf_importer.py +850 -619
  18. pyconvexity/models/__init__.py +109 -59
  19. pyconvexity/models/attributes.py +197 -178
  20. pyconvexity/models/carriers.py +70 -67
  21. pyconvexity/models/components.py +260 -236
  22. pyconvexity/models/network.py +202 -284
  23. pyconvexity/models/results.py +65 -55
  24. pyconvexity/models/scenarios.py +58 -88
  25. pyconvexity/solvers/__init__.py +5 -5
  26. pyconvexity/solvers/pypsa/__init__.py +3 -3
  27. pyconvexity/solvers/pypsa/api.py +150 -134
  28. pyconvexity/solvers/pypsa/batch_loader.py +165 -162
  29. pyconvexity/solvers/pypsa/builder.py +390 -291
  30. pyconvexity/solvers/pypsa/constraints.py +184 -162
  31. pyconvexity/solvers/pypsa/solver.py +968 -663
  32. pyconvexity/solvers/pypsa/storage.py +1377 -671
  33. pyconvexity/timeseries.py +63 -60
  34. pyconvexity/validation/__init__.py +14 -6
  35. pyconvexity/validation/rules.py +95 -84
  36. pyconvexity-0.4.1.dist-info/METADATA +46 -0
  37. pyconvexity-0.4.1.dist-info/RECORD +42 -0
  38. pyconvexity/data/schema/04_scenario_schema.sql +0 -122
  39. pyconvexity/data/schema/migrate_add_geometries.sql +0 -73
  40. pyconvexity-0.4.0.dist-info/METADATA +0 -138
  41. pyconvexity-0.4.0.dist-info/RECORD +0 -44
  42. {pyconvexity-0.4.0.dist-info → pyconvexity-0.4.1.dist-info}/WHEEL +0 -0
  43. {pyconvexity-0.4.0.dist-info → pyconvexity-0.4.1.dist-info}/top_level.txt +0 -0
pyconvexity/timeseries.py CHANGED
@@ -24,7 +24,7 @@ from pyconvexity.models.attributes import (
24
24
  set_timeseries_attribute,
25
25
  serialize_values_to_binary,
26
26
  deserialize_values_from_binary,
27
- get_timeseries_length_from_binary
27
+ get_timeseries_length_from_binary,
28
28
  )
29
29
 
30
30
 
@@ -32,6 +32,7 @@ from pyconvexity.models.attributes import (
32
32
  # HIGH-LEVEL TIMESERIES API
33
33
  # ============================================================================
34
34
 
35
+
35
36
  def get_timeseries(
36
37
  db_path: str,
37
38
  component_id: int,
@@ -39,14 +40,14 @@ def get_timeseries(
39
40
  scenario_id: Optional[int] = None,
40
41
  start_index: Optional[int] = None,
41
42
  end_index: Optional[int] = None,
42
- max_points: Optional[int] = None
43
+ max_points: Optional[int] = None,
43
44
  ) -> Timeseries:
44
45
  """
45
46
  Get timeseries data with efficient array-based format.
46
-
47
+
47
48
  This is the main function for retrieving timeseries data. It returns
48
49
  a Timeseries object with values as a flat array for maximum performance.
49
-
50
+
50
51
  Args:
51
52
  db_path: Path to the database file
52
53
  component_id: Component ID
@@ -55,28 +56,33 @@ def get_timeseries(
55
56
  start_index: Start index for range queries (optional)
56
57
  end_index: End index for range queries (optional)
57
58
  max_points: Maximum number of points for sampling (optional)
58
-
59
+
59
60
  Returns:
60
61
  Timeseries object with efficient array-based data
61
-
62
+
62
63
  Example:
63
64
  >>> ts = get_timeseries("model.db", component_id=123, attribute_name="p")
64
65
  >>> print(f"Length: {ts.length}, Values: {ts.values[:5]}")
65
66
  Length: 8760, Values: [100.5, 95.2, 87.3, 92.1, 88.7]
66
-
67
+
67
68
  # Get a subset of the data
68
69
  >>> ts_subset = get_timeseries("model.db", 123, "p", start_index=100, end_index=200)
69
70
  >>> print(f"Subset length: {ts_subset.length}")
70
71
  Subset length: 100
71
-
72
+
72
73
  # Sample large datasets
73
74
  >>> ts_sampled = get_timeseries("model.db", 123, "p", max_points=1000)
74
75
  >>> print(f"Sampled from {ts.length} to {ts_sampled.length} points")
75
76
  """
76
77
  with database_context(db_path, read_only=True) as conn:
77
78
  return _get_timeseries(
78
- conn, component_id, attribute_name, scenario_id,
79
- start_index, end_index, max_points
79
+ conn,
80
+ component_id,
81
+ attribute_name,
82
+ scenario_id,
83
+ start_index,
84
+ end_index,
85
+ max_points,
80
86
  )
81
87
 
82
88
 
@@ -84,23 +90,23 @@ def get_timeseries_metadata(
84
90
  db_path: str,
85
91
  component_id: int,
86
92
  attribute_name: str,
87
- scenario_id: Optional[int] = None
93
+ scenario_id: Optional[int] = None,
88
94
  ) -> TimeseriesMetadata:
89
95
  """
90
96
  Get timeseries metadata without loading the full data.
91
-
97
+
92
98
  This is useful for checking the size and properties of a timeseries
93
99
  before deciding whether to load the full data.
94
-
100
+
95
101
  Args:
96
102
  db_path: Path to the database file
97
103
  component_id: Component ID
98
104
  attribute_name: Name of the attribute
99
105
  scenario_id: Scenario ID (uses master scenario if None)
100
-
106
+
101
107
  Returns:
102
108
  TimeseriesMetadata with length and type information
103
-
109
+
104
110
  Example:
105
111
  >>> meta = get_timeseries_metadata("model.db", 123, "p")
106
112
  >>> print(f"Length: {meta.length}, Type: {meta.data_type}, Unit: {meta.unit}")
@@ -115,31 +121,31 @@ def set_timeseries(
115
121
  component_id: int,
116
122
  attribute_name: str,
117
123
  values: Union[List[float], np.ndarray, Timeseries],
118
- scenario_id: Optional[int] = None
124
+ scenario_id: Optional[int] = None,
119
125
  ) -> None:
120
126
  """
121
127
  Set timeseries data using efficient array-based format.
122
-
128
+
123
129
  This is the main function for storing timeseries data. It accepts
124
130
  various input formats and stores them efficiently in the database.
125
-
131
+
126
132
  Args:
127
133
  db_path: Path to the database file
128
134
  component_id: Component ID
129
135
  attribute_name: Name of the attribute
130
136
  values: Timeseries values as list, numpy array, or Timeseries object
131
137
  scenario_id: Scenario ID (uses master scenario if None)
132
-
138
+
133
139
  Example:
134
140
  # Set from a list
135
141
  >>> values = [100.5, 95.2, 87.3, 92.1, 88.7]
136
142
  >>> set_timeseries("model.db", 123, "p_set", values)
137
-
143
+
138
144
  # Set from numpy array
139
145
  >>> import numpy as np
140
146
  >>> values = np.random.normal(100, 10, 8760) # Hourly data for a year
141
147
  >>> set_timeseries("model.db", 123, "p_max_pu", values)
142
-
148
+
143
149
  # Set from existing Timeseries object
144
150
  >>> ts = get_timeseries("model.db", 456, "p")
145
151
  >>> set_timeseries("model.db", 123, "p_set", ts)
@@ -153,30 +159,30 @@ def set_timeseries(
153
159
  values_list = [float(v) for v in values]
154
160
  else:
155
161
  raise ValueError("values must be List[float], numpy.ndarray, or Timeseries")
156
-
162
+
157
163
  with database_context(db_path) as conn:
158
- set_timeseries_attribute(conn, component_id, attribute_name, values_list, scenario_id)
164
+ set_timeseries_attribute(
165
+ conn, component_id, attribute_name, values_list, scenario_id
166
+ )
159
167
 
160
168
 
161
169
  def get_multiple_timeseries(
162
- db_path: str,
163
- requests: List[dict],
164
- max_points: Optional[int] = None
170
+ db_path: str, requests: List[dict], max_points: Optional[int] = None
165
171
  ) -> List[Timeseries]:
166
172
  """
167
173
  Get multiple timeseries efficiently in a single database connection.
168
-
174
+
169
175
  This is more efficient than calling get_timeseries multiple times
170
176
  when you need to load many timeseries from the same database.
171
-
177
+
172
178
  Args:
173
179
  db_path: Path to the database file
174
180
  requests: List of dicts with keys: component_id, attribute_name, scenario_id (optional)
175
181
  max_points: Maximum number of points for sampling (applied to all)
176
-
182
+
177
183
  Returns:
178
184
  List of Timeseries objects in the same order as requests
179
-
185
+
180
186
  Example:
181
187
  >>> requests = [
182
188
  ... {"component_id": 123, "attribute_name": "p"},
@@ -187,19 +193,18 @@ def get_multiple_timeseries(
187
193
  >>> print(f"Loaded {len(timeseries_list)} timeseries")
188
194
  """
189
195
  results = []
190
-
196
+
191
197
  with database_context(db_path, read_only=True) as conn:
192
198
  for request in requests:
193
199
  component_id = request["component_id"]
194
200
  attribute_name = request["attribute_name"]
195
201
  scenario_id = request.get("scenario_id")
196
-
202
+
197
203
  ts = _get_timeseries(
198
- conn, component_id, attribute_name, scenario_id,
199
- None, None, max_points
204
+ conn, component_id, attribute_name, scenario_id, None, None, max_points
200
205
  )
201
206
  results.append(ts)
202
-
207
+
203
208
  return results
204
209
 
205
210
 
@@ -207,16 +212,17 @@ def get_multiple_timeseries(
207
212
  # UTILITY FUNCTIONS
208
213
  # ============================================================================
209
214
 
215
+
210
216
  def timeseries_to_numpy(timeseries: Timeseries) -> np.ndarray:
211
217
  """
212
218
  Convert Timeseries to numpy array for scientific computing.
213
-
219
+
214
220
  Args:
215
221
  timeseries: Timeseries object
216
-
222
+
217
223
  Returns:
218
224
  numpy array with float32 dtype for memory efficiency
219
-
225
+
220
226
  Example:
221
227
  >>> ts = get_timeseries("model.db", 123, "p")
222
228
  >>> arr = timeseries_to_numpy(ts)
@@ -229,53 +235,50 @@ def numpy_to_timeseries(
229
235
  array: np.ndarray,
230
236
  data_type: str = "float",
231
237
  unit: Optional[str] = None,
232
- is_input: bool = True
238
+ is_input: bool = True,
233
239
  ) -> Timeseries:
234
240
  """
235
241
  Convert numpy array to Timeseries object.
236
-
242
+
237
243
  Args:
238
244
  array: numpy array of values
239
245
  data_type: Data type string (default: "float")
240
246
  unit: Unit string (optional)
241
247
  is_input: Whether this is input data (default: True)
242
-
248
+
243
249
  Returns:
244
250
  Timeseries object
245
-
251
+
246
252
  Example:
247
253
  >>> import numpy as np
248
254
  >>> arr = np.random.normal(100, 10, 8760)
249
255
  >>> ts = numpy_to_timeseries(arr, unit="MW")
250
256
  >>> print(f"Created timeseries with {ts.length} points")
251
257
  """
252
- values = array.tolist() if hasattr(array, 'tolist') else list(array)
258
+ values = array.tolist() if hasattr(array, "tolist") else list(array)
253
259
  return Timeseries(
254
260
  values=[float(v) for v in values],
255
261
  length=len(values),
256
262
  start_index=0,
257
263
  data_type=data_type,
258
264
  unit=unit,
259
- is_input=is_input
265
+ is_input=is_input,
260
266
  )
261
267
 
262
268
 
263
269
  def validate_timeseries_alignment(
264
- db_path: str,
265
- network_id: int,
266
- values: Union[List[float], np.ndarray, Timeseries]
270
+ db_path: str, values: Union[List[float], np.ndarray, Timeseries]
267
271
  ) -> dict:
268
272
  """
269
273
  Validate that timeseries data aligns with network time periods.
270
-
274
+
271
275
  Args:
272
276
  db_path: Path to the database file
273
- network_id: Network ID
274
277
  values: Timeseries values to validate
275
-
278
+
276
279
  Returns:
277
280
  Dictionary with validation results
278
-
281
+
279
282
  Example:
280
283
  >>> values = [100.0] * 8760 # Hourly data for a year
281
284
  >>> result = validate_timeseries_alignment("model.db", 1, values)
@@ -293,35 +296,35 @@ def validate_timeseries_alignment(
293
296
  values_list = [float(v) for v in values]
294
297
  else:
295
298
  raise ValueError("values must be List[float], numpy.ndarray, or Timeseries")
296
-
299
+
297
300
  with database_context(db_path, read_only=True) as conn:
298
301
  # Get network time periods
299
302
  from pyconvexity.models.network import get_network_time_periods
303
+
300
304
  try:
301
- time_periods = get_network_time_periods(conn, network_id)
305
+ time_periods = get_network_time_periods(conn)
302
306
  expected_length = len(time_periods)
303
307
  actual_length = len(values_list)
304
-
308
+
305
309
  is_valid = actual_length == expected_length
306
310
  issues = []
307
-
311
+
308
312
  if actual_length < expected_length:
309
313
  issues.append(f"Missing {expected_length - actual_length} time periods")
310
314
  elif actual_length > expected_length:
311
315
  issues.append(f"Extra {actual_length - expected_length} time periods")
312
-
316
+
313
317
  return {
314
318
  "is_valid": is_valid,
315
319
  "expected_length": expected_length,
316
320
  "actual_length": actual_length,
317
- "issues": issues
321
+ "issues": issues,
318
322
  }
319
-
323
+
320
324
  except Exception as e:
321
325
  return {
322
326
  "is_valid": False,
323
327
  "expected_length": 0,
324
328
  "actual_length": len(values_list),
325
- "issues": [f"Failed to get network time periods: {e}"]
329
+ "issues": [f"Failed to get network time periods: {e}"],
326
330
  }
327
-
@@ -5,13 +5,21 @@ Contains data validation rules and type checking functionality.
5
5
  """
6
6
 
7
7
  from pyconvexity.validation.rules import (
8
- get_validation_rule, list_validation_rules, get_all_validation_rules,
9
- validate_static_value, validate_timeseries_alignment, parse_default_value,
10
- get_attribute_setter_info
8
+ get_validation_rule,
9
+ list_validation_rules,
10
+ get_all_validation_rules,
11
+ validate_static_value,
12
+ validate_timeseries_alignment,
13
+ parse_default_value,
14
+ get_attribute_setter_info,
11
15
  )
12
16
 
13
17
  __all__ = [
14
- "get_validation_rule", "list_validation_rules", "get_all_validation_rules",
15
- "validate_static_value", "validate_timeseries_alignment", "parse_default_value",
16
- "get_attribute_setter_info"
18
+ "get_validation_rule",
19
+ "list_validation_rules",
20
+ "get_all_validation_rules",
21
+ "validate_static_value",
22
+ "validate_timeseries_alignment",
23
+ "parse_default_value",
24
+ "get_attribute_setter_info",
17
25
  ]