pyconvexity 0.4.8__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 +241 -0
- pyconvexity/_version.py +1 -0
- pyconvexity/core/__init__.py +60 -0
- pyconvexity/core/database.py +485 -0
- pyconvexity/core/errors.py +106 -0
- pyconvexity/core/types.py +400 -0
- pyconvexity/dashboard.py +265 -0
- pyconvexity/data/README.md +101 -0
- pyconvexity/data/__init__.py +17 -0
- pyconvexity/data/loaders/__init__.py +3 -0
- pyconvexity/data/loaders/cache.py +213 -0
- pyconvexity/data/schema/01_core_schema.sql +420 -0
- pyconvexity/data/schema/02_data_metadata.sql +120 -0
- pyconvexity/data/schema/03_validation_data.sql +507 -0
- pyconvexity/data/sources/__init__.py +5 -0
- pyconvexity/data/sources/gem.py +442 -0
- pyconvexity/io/__init__.py +26 -0
- pyconvexity/io/excel_exporter.py +1226 -0
- pyconvexity/io/excel_importer.py +1381 -0
- pyconvexity/io/netcdf_exporter.py +191 -0
- pyconvexity/io/netcdf_importer.py +1802 -0
- pyconvexity/models/__init__.py +195 -0
- pyconvexity/models/attributes.py +730 -0
- pyconvexity/models/carriers.py +159 -0
- pyconvexity/models/components.py +611 -0
- pyconvexity/models/network.py +503 -0
- pyconvexity/models/results.py +148 -0
- pyconvexity/models/scenarios.py +234 -0
- pyconvexity/solvers/__init__.py +29 -0
- pyconvexity/solvers/pypsa/__init__.py +30 -0
- pyconvexity/solvers/pypsa/api.py +446 -0
- pyconvexity/solvers/pypsa/batch_loader.py +296 -0
- pyconvexity/solvers/pypsa/builder.py +655 -0
- pyconvexity/solvers/pypsa/clearing_price.py +678 -0
- pyconvexity/solvers/pypsa/constraints.py +405 -0
- pyconvexity/solvers/pypsa/solver.py +1442 -0
- pyconvexity/solvers/pypsa/storage.py +2096 -0
- pyconvexity/timeseries.py +330 -0
- pyconvexity/validation/__init__.py +25 -0
- pyconvexity/validation/rules.py +312 -0
- pyconvexity-0.4.8.dist-info/METADATA +148 -0
- pyconvexity-0.4.8.dist-info/RECORD +44 -0
- pyconvexity-0.4.8.dist-info/WHEEL +5 -0
- pyconvexity-0.4.8.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,420 @@
|
|
|
1
|
+
-- ============================================================================
|
|
2
|
+
-- CORE ENERGY NETWORK SCHEMA (SIMPLIFIED)
|
|
3
|
+
-- Single-network-per-file design for desktop SQLite
|
|
4
|
+
-- Optimized for fast timeseries access and simple Rust/Python API
|
|
5
|
+
-- Version 3.1.0 - Single network + Sparse scenarios + Raw timeseries
|
|
6
|
+
-- ============================================================================
|
|
7
|
+
|
|
8
|
+
-- ============================================================================
|
|
9
|
+
-- NETWORK METADATA
|
|
10
|
+
-- ============================================================================
|
|
11
|
+
|
|
12
|
+
-- Network metadata - single row per database file
|
|
13
|
+
CREATE TABLE network_metadata (
|
|
14
|
+
name TEXT NOT NULL,
|
|
15
|
+
description TEXT,
|
|
16
|
+
|
|
17
|
+
-- Time axis definition (single source of truth)
|
|
18
|
+
time_start DATETIME NOT NULL,
|
|
19
|
+
time_end DATETIME NOT NULL,
|
|
20
|
+
time_interval TEXT NOT NULL, -- ISO 8601 duration (PT1H, PT30M, PT2H, etc.)
|
|
21
|
+
|
|
22
|
+
-- Network-level flags
|
|
23
|
+
locked BOOLEAN DEFAULT 0, -- Prevent accidental edits to base network
|
|
24
|
+
|
|
25
|
+
-- Metadata
|
|
26
|
+
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
27
|
+
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
28
|
+
|
|
29
|
+
CONSTRAINT valid_time_range CHECK (time_end > time_start)
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
-- Network time periods - optimized storage using computed timestamps
|
|
33
|
+
CREATE TABLE network_time_periods (
|
|
34
|
+
period_count INTEGER NOT NULL, -- Total number of periods (e.g., 8760 for hourly year)
|
|
35
|
+
start_timestamp INTEGER NOT NULL, -- Unix timestamp of first period
|
|
36
|
+
interval_seconds INTEGER NOT NULL, -- Seconds between periods (3600 for hourly)
|
|
37
|
+
|
|
38
|
+
CONSTRAINT valid_period_count CHECK (period_count > 0),
|
|
39
|
+
CONSTRAINT valid_interval CHECK (interval_seconds > 0)
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
-- ============================================================================
|
|
43
|
+
-- CARRIERS - ENERGY TYPES
|
|
44
|
+
-- ============================================================================
|
|
45
|
+
|
|
46
|
+
-- Carriers table - energy carriers (electricity, gas, heat, etc.)
|
|
47
|
+
CREATE TABLE carriers (
|
|
48
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
49
|
+
name TEXT NOT NULL UNIQUE,
|
|
50
|
+
|
|
51
|
+
-- Carrier properties from PyPSA reference
|
|
52
|
+
co2_emissions REAL DEFAULT 0.0, -- tonnes/MWh
|
|
53
|
+
color TEXT, -- Plotting color
|
|
54
|
+
nice_name TEXT, -- Display name
|
|
55
|
+
max_growth REAL DEFAULT NULL, -- MW - can be infinite
|
|
56
|
+
max_relative_growth REAL DEFAULT 0.0, -- MW
|
|
57
|
+
curtailable BOOLEAN DEFAULT TRUE, -- Whether the carrier can be curtailed
|
|
58
|
+
|
|
59
|
+
-- Metadata
|
|
60
|
+
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
61
|
+
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
-- ============================================================================
|
|
65
|
+
-- UNIFIED COMPONENT SYSTEM
|
|
66
|
+
-- ============================================================================
|
|
67
|
+
|
|
68
|
+
-- Components table - unified table for all network components
|
|
69
|
+
CREATE TABLE components (
|
|
70
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
71
|
+
component_type TEXT NOT NULL, -- 'BUS', 'GENERATOR', 'LOAD', 'LINE', 'LINK', 'STORAGE_UNIT', 'STORE', 'UNMET_LOAD', 'CONSTRAINT', 'TRANSFORMER', 'SHUNT_IMPEDANCE'
|
|
72
|
+
name TEXT NOT NULL UNIQUE,
|
|
73
|
+
|
|
74
|
+
-- Geographic location (optional)
|
|
75
|
+
latitude REAL,
|
|
76
|
+
longitude REAL,
|
|
77
|
+
geometry TEXT, -- GeoJSON geometry (Point, LineString, Polygon, etc.)
|
|
78
|
+
|
|
79
|
+
-- Energy carrier reference
|
|
80
|
+
carrier_id INTEGER,
|
|
81
|
+
|
|
82
|
+
-- Bus connections
|
|
83
|
+
bus_id INTEGER, -- Single bus connection
|
|
84
|
+
bus0_id INTEGER, -- First bus for lines/links
|
|
85
|
+
bus1_id INTEGER, -- Second bus for lines/links
|
|
86
|
+
|
|
87
|
+
-- Metadata
|
|
88
|
+
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
89
|
+
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
90
|
+
|
|
91
|
+
CONSTRAINT fk_components_carrier
|
|
92
|
+
FOREIGN KEY (carrier_id) REFERENCES carriers(id),
|
|
93
|
+
CONSTRAINT fk_components_bus
|
|
94
|
+
FOREIGN KEY (bus_id) REFERENCES components(id),
|
|
95
|
+
CONSTRAINT fk_components_bus0
|
|
96
|
+
FOREIGN KEY (bus0_id) REFERENCES components(id),
|
|
97
|
+
CONSTRAINT fk_components_bus1
|
|
98
|
+
FOREIGN KEY (bus1_id) REFERENCES components(id),
|
|
99
|
+
CONSTRAINT valid_component_type
|
|
100
|
+
CHECK (component_type IN ('BUS', 'GENERATOR', 'LOAD', 'LINE', 'LINK', 'STORAGE_UNIT', 'STORE', 'UNMET_LOAD', 'CONSTRAINT', 'TRANSFORMER', 'SHUNT_IMPEDANCE'))
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
-- Essential indexes only
|
|
104
|
+
CREATE INDEX idx_components_type ON components(component_type);
|
|
105
|
+
CREATE INDEX idx_components_name ON components(name);
|
|
106
|
+
CREATE INDEX idx_components_bus ON components(bus_id);
|
|
107
|
+
CREATE INDEX idx_components_bus0 ON components(bus0_id);
|
|
108
|
+
CREATE INDEX idx_components_bus1 ON components(bus1_id);
|
|
109
|
+
|
|
110
|
+
-- ============================================================================
|
|
111
|
+
-- ATTRIBUTE VALIDATION SYSTEM
|
|
112
|
+
-- ============================================================================
|
|
113
|
+
|
|
114
|
+
-- Attribute validation rules table
|
|
115
|
+
CREATE TABLE attribute_validation_rules (
|
|
116
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
117
|
+
component_type TEXT NOT NULL,
|
|
118
|
+
attribute_name TEXT NOT NULL,
|
|
119
|
+
display_name TEXT,
|
|
120
|
+
|
|
121
|
+
-- Validation rules
|
|
122
|
+
data_type TEXT NOT NULL, -- 'float', 'boolean', 'string', 'int'
|
|
123
|
+
unit TEXT,
|
|
124
|
+
default_value TEXT,
|
|
125
|
+
allowed_storage_types TEXT NOT NULL, -- 'static', 'timeseries', 'static_or_timeseries'
|
|
126
|
+
is_required BOOLEAN DEFAULT FALSE,
|
|
127
|
+
is_input BOOLEAN DEFAULT TRUE,
|
|
128
|
+
description TEXT,
|
|
129
|
+
|
|
130
|
+
-- Constraints
|
|
131
|
+
min_value REAL,
|
|
132
|
+
max_value REAL,
|
|
133
|
+
allowed_values TEXT, -- JSON array
|
|
134
|
+
|
|
135
|
+
-- Grouping
|
|
136
|
+
group_name TEXT DEFAULT 'other',
|
|
137
|
+
to_save BOOLEAN DEFAULT TRUE,
|
|
138
|
+
|
|
139
|
+
CONSTRAINT uq_validation_rule
|
|
140
|
+
UNIQUE (component_type, attribute_name),
|
|
141
|
+
CONSTRAINT valid_component_type_validation
|
|
142
|
+
CHECK (component_type IN ('BUS', 'GENERATOR', 'LOAD', 'LINE', 'LINK', 'STORAGE_UNIT', 'STORE', 'UNMET_LOAD', 'CONSTRAINT', 'TRANSFORMER', 'SHUNT_IMPEDANCE')),
|
|
143
|
+
CONSTRAINT valid_data_type
|
|
144
|
+
CHECK (data_type IN ('float', 'boolean', 'string', 'int')),
|
|
145
|
+
CONSTRAINT valid_allowed_storage_types
|
|
146
|
+
CHECK (allowed_storage_types IN ('static', 'timeseries', 'static_or_timeseries')),
|
|
147
|
+
CONSTRAINT valid_group_name
|
|
148
|
+
CHECK (group_name IN ('basic', 'capacity', 'power_limits', 'energy', 'unit_commitment', 'ramping', 'costs', 'electrical'))
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
-- Essential indexes only
|
|
152
|
+
CREATE INDEX idx_validation_component_type ON attribute_validation_rules(component_type);
|
|
153
|
+
CREATE INDEX idx_validation_lookup ON attribute_validation_rules(component_type, attribute_name);
|
|
154
|
+
|
|
155
|
+
-- ============================================================================
|
|
156
|
+
-- SCENARIOS - SPARSE OVERRIDE APPROACH
|
|
157
|
+
-- ============================================================================
|
|
158
|
+
|
|
159
|
+
-- Scenarios table - represents alternative scenarios
|
|
160
|
+
-- Base network has NO scenario (scenario_id = NULL in attributes)
|
|
161
|
+
-- Supports both deterministic what-if scenarios (probability = NULL) and stochastic scenarios (probability set)
|
|
162
|
+
-- System scenarios (is_system_scenario = TRUE) are reserved for special purposes like "Actual" values
|
|
163
|
+
CREATE TABLE scenarios (
|
|
164
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
165
|
+
name TEXT NOT NULL UNIQUE,
|
|
166
|
+
description TEXT,
|
|
167
|
+
probability REAL DEFAULT NULL, -- For stochastic optimization (NULL = deterministic what-if)
|
|
168
|
+
|
|
169
|
+
-- System scenario flags
|
|
170
|
+
is_system_scenario BOOLEAN DEFAULT FALSE, -- TRUE = system-reserved, cannot delete, excluded from solves
|
|
171
|
+
system_purpose TEXT DEFAULT NULL, -- 'actual' for actual/measured values, NULL for user scenarios
|
|
172
|
+
|
|
173
|
+
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
174
|
+
|
|
175
|
+
CONSTRAINT valid_probability
|
|
176
|
+
CHECK (probability IS NULL OR (probability >= 0 AND probability <= 1)),
|
|
177
|
+
CONSTRAINT valid_system_purpose
|
|
178
|
+
CHECK (system_purpose IS NULL OR system_purpose IN ('actual'))
|
|
179
|
+
);
|
|
180
|
+
|
|
181
|
+
-- ============================================================================
|
|
182
|
+
-- SYSTEM SCENARIO MANAGEMENT
|
|
183
|
+
-- ============================================================================
|
|
184
|
+
|
|
185
|
+
-- Trigger to auto-create the "Actual" system scenario when network_metadata is created
|
|
186
|
+
CREATE TRIGGER create_actual_scenario_on_network_create
|
|
187
|
+
AFTER INSERT ON network_metadata
|
|
188
|
+
FOR EACH ROW
|
|
189
|
+
WHEN NOT EXISTS (SELECT 1 FROM scenarios WHERE system_purpose = 'actual')
|
|
190
|
+
BEGIN
|
|
191
|
+
INSERT INTO scenarios (name, description, is_system_scenario, system_purpose)
|
|
192
|
+
VALUES ('Actual', 'Actual/measured values for validation and comparison', TRUE, 'actual');
|
|
193
|
+
END;
|
|
194
|
+
|
|
195
|
+
-- Trigger to prevent deletion of system scenarios
|
|
196
|
+
CREATE TRIGGER prevent_system_scenario_deletion
|
|
197
|
+
BEFORE DELETE ON scenarios
|
|
198
|
+
FOR EACH ROW
|
|
199
|
+
WHEN OLD.is_system_scenario = TRUE
|
|
200
|
+
BEGIN
|
|
201
|
+
SELECT RAISE(ABORT, 'Cannot delete system scenarios');
|
|
202
|
+
END;
|
|
203
|
+
|
|
204
|
+
-- Trigger to prevent modification of system scenario flags
|
|
205
|
+
CREATE TRIGGER prevent_system_scenario_modification
|
|
206
|
+
BEFORE UPDATE ON scenarios
|
|
207
|
+
FOR EACH ROW
|
|
208
|
+
WHEN OLD.is_system_scenario = TRUE AND (
|
|
209
|
+
NEW.is_system_scenario != OLD.is_system_scenario OR
|
|
210
|
+
NEW.system_purpose != OLD.system_purpose
|
|
211
|
+
)
|
|
212
|
+
BEGIN
|
|
213
|
+
SELECT RAISE(ABORT, 'Cannot modify system scenario flags');
|
|
214
|
+
END;
|
|
215
|
+
|
|
216
|
+
-- ============================================================================
|
|
217
|
+
-- UNIFIED COMPONENT ATTRIBUTES - SPARSE SCENARIOS + RAW TIMESERIES
|
|
218
|
+
-- ============================================================================
|
|
219
|
+
|
|
220
|
+
-- Component attributes - sparse scenario overrides
|
|
221
|
+
-- scenario_id = NULL → Base network (editable)
|
|
222
|
+
-- scenario_id = 1 → Scenario 1 (overrides base, read-only)
|
|
223
|
+
CREATE TABLE component_attributes (
|
|
224
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
225
|
+
component_id INTEGER NOT NULL,
|
|
226
|
+
attribute_name TEXT NOT NULL,
|
|
227
|
+
|
|
228
|
+
-- Scenario support - NULL = base network, non-NULL = scenario override
|
|
229
|
+
scenario_id INTEGER, -- NULLABLE!
|
|
230
|
+
|
|
231
|
+
-- Storage type
|
|
232
|
+
storage_type TEXT NOT NULL CHECK (storage_type IN ('static', 'timeseries')),
|
|
233
|
+
|
|
234
|
+
-- Value storage
|
|
235
|
+
static_value TEXT, -- JSON-encoded static value (all data types)
|
|
236
|
+
timeseries_data BLOB, -- Raw f32 array (NOT Parquet!)
|
|
237
|
+
|
|
238
|
+
-- Cached metadata
|
|
239
|
+
data_type TEXT NOT NULL,
|
|
240
|
+
unit TEXT,
|
|
241
|
+
is_input BOOLEAN DEFAULT TRUE,
|
|
242
|
+
|
|
243
|
+
-- Metadata
|
|
244
|
+
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
245
|
+
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
246
|
+
|
|
247
|
+
CONSTRAINT fk_attributes_component
|
|
248
|
+
FOREIGN KEY (component_id) REFERENCES components(id) ON DELETE CASCADE,
|
|
249
|
+
CONSTRAINT fk_attributes_scenario
|
|
250
|
+
FOREIGN KEY (scenario_id) REFERENCES scenarios(id) ON DELETE CASCADE,
|
|
251
|
+
|
|
252
|
+
-- Storage validation
|
|
253
|
+
CONSTRAINT check_exactly_one_storage_type CHECK (
|
|
254
|
+
(storage_type = 'static' AND static_value IS NOT NULL AND timeseries_data IS NULL) OR
|
|
255
|
+
(storage_type = 'timeseries' AND static_value IS NULL AND timeseries_data IS NOT NULL)
|
|
256
|
+
),
|
|
257
|
+
|
|
258
|
+
-- Unique per component/attribute/scenario (NULL scenario counts as unique value)
|
|
259
|
+
CONSTRAINT uq_component_attribute_scenario
|
|
260
|
+
UNIQUE (component_id, attribute_name, scenario_id)
|
|
261
|
+
);
|
|
262
|
+
|
|
263
|
+
-- Essential indexes only
|
|
264
|
+
CREATE INDEX idx_attributes_lookup ON component_attributes(
|
|
265
|
+
component_id, attribute_name, scenario_id
|
|
266
|
+
);
|
|
267
|
+
CREATE INDEX idx_attributes_scenario ON component_attributes(scenario_id);
|
|
268
|
+
|
|
269
|
+
-- ============================================================================
|
|
270
|
+
-- SCENARIO CACHE - MATERIALIZED VIEW FOR FAST SCENARIO COUNTING
|
|
271
|
+
-- ============================================================================
|
|
272
|
+
|
|
273
|
+
-- Scenario cache - stores precomputed scenario counts and details
|
|
274
|
+
-- This is a materialized view that's kept in sync via application code
|
|
275
|
+
-- Updated transactionally whenever attribute values change
|
|
276
|
+
CREATE TABLE IF NOT EXISTS attribute_scenario_cache (
|
|
277
|
+
component_id INTEGER NOT NULL,
|
|
278
|
+
attribute_name TEXT NOT NULL,
|
|
279
|
+
|
|
280
|
+
-- Cached computed values
|
|
281
|
+
scenario_count INTEGER NOT NULL DEFAULT 1, -- Display count (includes synthetic base)
|
|
282
|
+
has_base_value BOOLEAN NOT NULL DEFAULT FALSE, -- TRUE if base network has value
|
|
283
|
+
has_scenario_values BOOLEAN NOT NULL DEFAULT FALSE, -- TRUE if any scenarios have values
|
|
284
|
+
|
|
285
|
+
-- Scenario details for dropdown (JSON array)
|
|
286
|
+
-- Format: [{scenario_id: 0, scenario_name: "Base", value: "123", has_value: true}, ...]
|
|
287
|
+
scenario_details TEXT,
|
|
288
|
+
|
|
289
|
+
-- Metadata
|
|
290
|
+
last_updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
291
|
+
|
|
292
|
+
PRIMARY KEY (component_id, attribute_name),
|
|
293
|
+
CONSTRAINT fk_scenario_cache_component
|
|
294
|
+
FOREIGN KEY (component_id) REFERENCES components(id) ON DELETE CASCADE
|
|
295
|
+
);
|
|
296
|
+
|
|
297
|
+
-- Index for fast component-based lookups
|
|
298
|
+
CREATE INDEX IF NOT EXISTS idx_scenario_cache_component
|
|
299
|
+
ON attribute_scenario_cache(component_id);
|
|
300
|
+
|
|
301
|
+
-- Index for bulk table loads
|
|
302
|
+
CREATE INDEX IF NOT EXISTS idx_scenario_cache_component_type
|
|
303
|
+
ON attribute_scenario_cache(component_id, attribute_name);
|
|
304
|
+
|
|
305
|
+
-- NOTES:
|
|
306
|
+
-- This cache is maintained by application code (Rust) in the same transaction
|
|
307
|
+
-- as attribute writes. This ensures ACID guarantees - the cache can never be
|
|
308
|
+
-- stale or inconsistent with the actual data.
|
|
309
|
+
--
|
|
310
|
+
-- Cache logic:
|
|
311
|
+
-- - If has_scenario_values: scenario_count = num_scenarios + 1 (always include base)
|
|
312
|
+
-- - If only has_base_value: scenario_count = 1 (no indicator shown)
|
|
313
|
+
-- - If neither: scenario_count = 0 (no values at all)
|
|
314
|
+
|
|
315
|
+
-- ============================================================================
|
|
316
|
+
-- VALIDATION TRIGGERS
|
|
317
|
+
-- ============================================================================
|
|
318
|
+
|
|
319
|
+
-- Trigger to validate attributes against rules on insert
|
|
320
|
+
CREATE TRIGGER validate_component_attribute_insert
|
|
321
|
+
BEFORE INSERT ON component_attributes
|
|
322
|
+
FOR EACH ROW
|
|
323
|
+
WHEN NOT EXISTS (
|
|
324
|
+
SELECT 1 FROM components c
|
|
325
|
+
JOIN attribute_validation_rules avr ON c.component_type = avr.component_type
|
|
326
|
+
WHERE c.id = NEW.component_id
|
|
327
|
+
AND avr.attribute_name = NEW.attribute_name
|
|
328
|
+
)
|
|
329
|
+
BEGIN
|
|
330
|
+
SELECT RAISE(ABORT, 'Attribute is not defined for this component type');
|
|
331
|
+
END;
|
|
332
|
+
|
|
333
|
+
-- Trigger to validate storage type on insert
|
|
334
|
+
CREATE TRIGGER validate_storage_type_insert
|
|
335
|
+
BEFORE INSERT ON component_attributes
|
|
336
|
+
FOR EACH ROW
|
|
337
|
+
WHEN EXISTS (
|
|
338
|
+
SELECT 1 FROM components c
|
|
339
|
+
JOIN attribute_validation_rules avr ON c.component_type = avr.component_type
|
|
340
|
+
WHERE c.id = NEW.component_id
|
|
341
|
+
AND avr.attribute_name = NEW.attribute_name
|
|
342
|
+
AND avr.allowed_storage_types != 'static_or_timeseries'
|
|
343
|
+
AND avr.allowed_storage_types != NEW.storage_type
|
|
344
|
+
)
|
|
345
|
+
BEGIN
|
|
346
|
+
SELECT RAISE(ABORT, 'Storage type not allowed for this attribute');
|
|
347
|
+
END;
|
|
348
|
+
|
|
349
|
+
-- Trigger to update timestamps
|
|
350
|
+
CREATE TRIGGER update_component_attributes_timestamp
|
|
351
|
+
BEFORE UPDATE ON component_attributes
|
|
352
|
+
FOR EACH ROW
|
|
353
|
+
BEGIN
|
|
354
|
+
UPDATE component_attributes
|
|
355
|
+
SET updated_at = CURRENT_TIMESTAMP
|
|
356
|
+
WHERE id = NEW.id;
|
|
357
|
+
END;
|
|
358
|
+
|
|
359
|
+
-- Trigger to update component timestamps when attributes change
|
|
360
|
+
CREATE TRIGGER update_component_timestamp_on_attribute_change
|
|
361
|
+
AFTER INSERT ON component_attributes
|
|
362
|
+
FOR EACH ROW
|
|
363
|
+
BEGIN
|
|
364
|
+
UPDATE components
|
|
365
|
+
SET updated_at = CURRENT_TIMESTAMP
|
|
366
|
+
WHERE id = NEW.component_id;
|
|
367
|
+
END;
|
|
368
|
+
|
|
369
|
+
-- ============================================================================
|
|
370
|
+
-- NETWORK CONFIGURATION
|
|
371
|
+
-- ============================================================================
|
|
372
|
+
|
|
373
|
+
-- Network configuration parameters with scenario support
|
|
374
|
+
CREATE TABLE network_config (
|
|
375
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
376
|
+
scenario_id INTEGER, -- NULL for network defaults
|
|
377
|
+
|
|
378
|
+
param_name TEXT NOT NULL,
|
|
379
|
+
param_type TEXT NOT NULL,
|
|
380
|
+
param_value TEXT NOT NULL,
|
|
381
|
+
param_description TEXT,
|
|
382
|
+
|
|
383
|
+
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
384
|
+
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
385
|
+
|
|
386
|
+
CONSTRAINT fk_network_config_scenario
|
|
387
|
+
FOREIGN KEY (scenario_id) REFERENCES scenarios(id) ON DELETE CASCADE,
|
|
388
|
+
CONSTRAINT uq_network_config_param
|
|
389
|
+
UNIQUE (scenario_id, param_name),
|
|
390
|
+
CONSTRAINT valid_param_type
|
|
391
|
+
CHECK (param_type IN ('boolean', 'real', 'integer', 'string', 'json'))
|
|
392
|
+
);
|
|
393
|
+
|
|
394
|
+
CREATE INDEX idx_network_config_lookup ON network_config(scenario_id, param_name);
|
|
395
|
+
|
|
396
|
+
-- ============================================================================
|
|
397
|
+
-- SYSTEM METADATA
|
|
398
|
+
-- ============================================================================
|
|
399
|
+
|
|
400
|
+
-- System metadata table for schema version tracking and system-level settings
|
|
401
|
+
CREATE TABLE system_metadata (
|
|
402
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
403
|
+
key TEXT NOT NULL UNIQUE,
|
|
404
|
+
value TEXT NOT NULL,
|
|
405
|
+
description TEXT,
|
|
406
|
+
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
407
|
+
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
408
|
+
);
|
|
409
|
+
|
|
410
|
+
CREATE INDEX idx_system_metadata_key ON system_metadata(key);
|
|
411
|
+
|
|
412
|
+
-- Initialize system metadata with schema version
|
|
413
|
+
INSERT INTO system_metadata (key, value, description)
|
|
414
|
+
VALUES ('schema_version', '3.1.0', 'Database schema version');
|
|
415
|
+
|
|
416
|
+
-- ============================================================================
|
|
417
|
+
-- SCHEMA VERSION
|
|
418
|
+
-- ============================================================================
|
|
419
|
+
|
|
420
|
+
PRAGMA user_version = 31; -- Schema version 3.1
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
-- ============================================================================
|
|
2
|
+
-- DATA STORAGE AND METADATA SCHEMA
|
|
3
|
+
-- Essential tables for data storage and solve results
|
|
4
|
+
-- Version 3.1.0 - Simplified for single-network-per-file
|
|
5
|
+
-- ============================================================================
|
|
6
|
+
|
|
7
|
+
-- ============================================================================
|
|
8
|
+
-- GENERIC DATA STORAGE
|
|
9
|
+
-- ============================================================================
|
|
10
|
+
|
|
11
|
+
-- Generic data store for arbitrary network-level data
|
|
12
|
+
CREATE TABLE network_data_store (
|
|
13
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
14
|
+
category TEXT NOT NULL, -- 'config', 'results', 'statistics', 'scripts', etc.
|
|
15
|
+
name TEXT NOT NULL,
|
|
16
|
+
data_format TEXT DEFAULT 'json', -- 'json', 'csv', 'binary', 'text'
|
|
17
|
+
data BLOB NOT NULL,
|
|
18
|
+
metadata TEXT, -- JSON metadata
|
|
19
|
+
checksum TEXT,
|
|
20
|
+
|
|
21
|
+
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
22
|
+
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
23
|
+
|
|
24
|
+
CONSTRAINT uq_datastore_category_name
|
|
25
|
+
UNIQUE (category, name),
|
|
26
|
+
CONSTRAINT valid_data_format
|
|
27
|
+
CHECK (data_format IN ('json', 'csv', 'binary', 'text', 'yaml', 'toml'))
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
CREATE INDEX idx_datastore_category ON network_data_store(category);
|
|
31
|
+
|
|
32
|
+
-- ============================================================================
|
|
33
|
+
-- DOCUMENTATION AND NOTES
|
|
34
|
+
-- ============================================================================
|
|
35
|
+
|
|
36
|
+
-- Network-level notes
|
|
37
|
+
CREATE TABLE network_notes (
|
|
38
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
39
|
+
title TEXT NOT NULL,
|
|
40
|
+
content TEXT,
|
|
41
|
+
tags TEXT, -- JSON array
|
|
42
|
+
note_type TEXT DEFAULT 'note',
|
|
43
|
+
priority INTEGER DEFAULT 0,
|
|
44
|
+
|
|
45
|
+
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
46
|
+
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
47
|
+
|
|
48
|
+
CONSTRAINT valid_note_type
|
|
49
|
+
CHECK (note_type IN ('note', 'todo', 'warning', 'info', 'doc'))
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
-- Component-specific notes
|
|
53
|
+
CREATE TABLE component_notes (
|
|
54
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
55
|
+
component_id INTEGER NOT NULL,
|
|
56
|
+
title TEXT NOT NULL,
|
|
57
|
+
content TEXT,
|
|
58
|
+
tags TEXT,
|
|
59
|
+
note_type TEXT DEFAULT 'note',
|
|
60
|
+
priority INTEGER DEFAULT 0,
|
|
61
|
+
|
|
62
|
+
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
63
|
+
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
64
|
+
|
|
65
|
+
CONSTRAINT fk_component_notes_component
|
|
66
|
+
FOREIGN KEY (component_id) REFERENCES components(id) ON DELETE CASCADE,
|
|
67
|
+
CONSTRAINT valid_component_note_type
|
|
68
|
+
CHECK (note_type IN ('note', 'todo', 'warning', 'info', 'doc'))
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
CREATE INDEX idx_component_notes_component ON component_notes(component_id);
|
|
72
|
+
|
|
73
|
+
-- ============================================================================
|
|
74
|
+
-- SOLVE RESULTS AND STATISTICS
|
|
75
|
+
-- ============================================================================
|
|
76
|
+
|
|
77
|
+
-- Network solve results - stores solver outputs per scenario
|
|
78
|
+
CREATE TABLE network_solve_results (
|
|
79
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
80
|
+
scenario_id INTEGER, -- NULL for base network, non-NULL for scenario
|
|
81
|
+
|
|
82
|
+
-- Solve metadata
|
|
83
|
+
solved_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
84
|
+
solver_name TEXT NOT NULL,
|
|
85
|
+
solve_type TEXT NOT NULL,
|
|
86
|
+
solve_status TEXT NOT NULL,
|
|
87
|
+
objective_value REAL,
|
|
88
|
+
solve_time_seconds REAL,
|
|
89
|
+
|
|
90
|
+
-- Results stored as JSON
|
|
91
|
+
results_json TEXT NOT NULL,
|
|
92
|
+
metadata_json TEXT,
|
|
93
|
+
|
|
94
|
+
-- Only one result per scenario (including NULL for base network)
|
|
95
|
+
UNIQUE (scenario_id),
|
|
96
|
+
|
|
97
|
+
FOREIGN KEY (scenario_id) REFERENCES scenarios(id) ON DELETE CASCADE
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
CREATE INDEX idx_solve_results_scenario ON network_solve_results(scenario_id);
|
|
101
|
+
|
|
102
|
+
-- Year-based solve results for capacity expansion analysis
|
|
103
|
+
CREATE TABLE network_solve_results_by_year (
|
|
104
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
105
|
+
scenario_id INTEGER, -- NULL for base network
|
|
106
|
+
year INTEGER NOT NULL,
|
|
107
|
+
|
|
108
|
+
results_json TEXT NOT NULL,
|
|
109
|
+
metadata_json TEXT,
|
|
110
|
+
|
|
111
|
+
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
112
|
+
|
|
113
|
+
CONSTRAINT fk_solve_results_year_scenario
|
|
114
|
+
FOREIGN KEY (scenario_id) REFERENCES scenarios(id) ON DELETE CASCADE,
|
|
115
|
+
CONSTRAINT uq_solve_results_year_unique
|
|
116
|
+
UNIQUE (scenario_id, year),
|
|
117
|
+
CONSTRAINT valid_year CHECK (year >= 1900 AND year <= 2100)
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
CREATE INDEX idx_solve_results_year_scenario ON network_solve_results_by_year(scenario_id);
|