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
@@ -2,7 +2,7 @@
2
2
  -- PYPSA ATTRIBUTE VALIDATION RULES
3
3
  -- Complete set of validation rules for all component types
4
4
  -- Based on PyPSA component attribute definitions
5
- -- Updated to use simplified 5-group system: basic, power, economics, control, other
5
+ -- Updated to use new 10-group system: basic, capacity, power_limits, energy, unit_commitment, ramping, costs, electrical, energy, outputs
6
6
  -- Version 2.2.0
7
7
  -- ============================================================================
8
8
 
@@ -13,189 +13,189 @@ DELETE FROM attribute_validation_rules;
13
13
  -- BUS ATTRIBUTES
14
14
  -- ============================================================================
15
15
 
16
- -- BUS attributes from buses.csv (PyPSA reference) - Updated to simplified groups
16
+ -- BUS attributes from buses.csv (PyPSA reference) - Updated to new 10-group system
17
17
  INSERT INTO attribute_validation_rules (component_type, attribute_name, display_name, data_type, unit, default_value, allowed_storage_types, is_required, is_input, description, min_value, max_value, group_name, to_save) VALUES
18
18
  -- Input attributes for BUS
19
- ('BUS', 'v_nom', 'Nominal Voltage', 'float', 'kV', '1', 'static', FALSE, TRUE, 'Nominal voltage', 0, NULL, 'power', FALSE),
20
- ('BUS', 'type', 'Bus Type', 'string', 'n/a', 'n/a', 'static', FALSE, TRUE, 'Placeholder for bus type. Not yet implemented.', NULL, NULL, 'basic', FALSE),
21
- ('BUS', 'x', 'X Coordinate', 'float', 'n/a', '0', 'static', FALSE, TRUE, 'Position (e.g. longitude); the Spatial Reference System Identifier (SRID) is set in network.srid.', NULL, NULL, 'other', FALSE),
22
- ('BUS', 'y', 'Y Coordinate', 'float', 'n/a', '0', 'static', FALSE, TRUE, 'Position (e.g. latitude); the Spatial Reference System Identifier (SRID) is set in network.srid.', NULL, NULL, 'other', FALSE),
23
- ('BUS', 'carrier', 'Energy Carrier', 'string', 'n/a', 'AC', 'static', FALSE, TRUE, 'Energy carrier: can be "AC" or "DC" for electrical buses, or "heat" or "gas".', NULL, NULL, 'basic', FALSE),
24
- ('BUS', 'unit', 'Unit', 'string', 'n/a', 'None', 'static', FALSE, TRUE, 'Unit of the bus'' carrier if the implicitly assumed unit ("MW") is inappropriate (e.g. "t/h", "MWh_th/h"). Only descriptive. Does not influence any PyPSA functions.', NULL, NULL, 'basic', FALSE),
25
- ('BUS', 'v_mag_pu_set', 'Voltage Magnitude Setpoint', 'float', 'per unit', '1', 'static_or_timeseries', FALSE, TRUE, 'Voltage magnitude set point, per unit of v_nom.', 0, NULL, 'power', FALSE),
26
- ('BUS', 'v_mag_pu_min', 'Min Voltage Magnitude', 'float', 'per unit', '0', 'static', FALSE, TRUE, 'Minimum desired voltage, per unit of v_nom. This is a placeholder attribute and is not currently used by any PyPSA functions.', 0, NULL, 'power', FALSE),
27
- ('BUS', 'v_mag_pu_max', 'Max Voltage Magnitude', 'float', 'per unit', 'inf', 'static', FALSE, TRUE, 'Maximum desired voltage, per unit of v_nom. This is a placeholder attribute and is not currently used by any PyPSA functions.', 0, NULL, 'power', FALSE),
19
+ ('BUS', 'v_nom', 'Nominal Voltage', 'float', 'kV', '1', 'static', TRUE, TRUE, 'The standard or average voltage of a bus in the network.', 0, NULL, 'electrical', FALSE),
20
+ ('BUS', 'type', 'Type', 'string', 'n/a', 'n/a', 'static', FALSE, TRUE, 'Placeholder. Not yet implemented.', NULL, NULL, 'basic', FALSE),
21
+ ('BUS', 'x', 'Longitude', 'float', 'n/a', '0', 'static', TRUE, TRUE, 'Longitude; A measurement of angular distance, expressed in degrees, east or west of the Prime Meridian.', NULL, NULL, 'basic', FALSE),
22
+ ('BUS', 'y', 'Latitude', 'float', 'n/a', '0', 'static', TRUE, TRUE, 'Latitude; A measurement of angular distance, expressed in degrees, north or south of the Equator.', NULL, NULL, 'basic', FALSE),
23
+ ('BUS', 'carrier', 'Carrier', 'string', 'n/a', 'AC', 'static', TRUE, TRUE, 'Carrier: can be "AC" or "DC" for electrical buses, or "heat" or "gas" for thermal buses.', NULL, NULL, 'basic', FALSE),
24
+ ('BUS', 'unit', 'Unit', 'string', 'n/a', 'None', 'static', FALSE, TRUE, 'Unit of the bus'' carrier if the implicitly assumed unit ("MW") is inappropriate (e.g. "t/h", "MWh_th/h"). Only descriptive. Does not influence any functions.', NULL, NULL, 'basic', FALSE),
25
+ ('BUS', 'v_mag_pu_set', 'Voltage Magnitude Setpoint', 'float', 'per unit', '1', 'static_or_timeseries', FALSE, TRUE, 'Voltage magnitude set point, per unit of the nominal voltage (v_nom).', 0, NULL, 'electrical', FALSE),
26
+ ('BUS', 'v_mag_pu_min', 'Min Voltage Magnitude', 'float', 'per unit', '0', 'static', FALSE, TRUE, 'Minimum desired voltage, per unit of the nominal voltage (v_nom). This is a placeholder attribute and is not currently used by any functions.', 0, NULL, 'electrical', FALSE),
27
+ ('BUS', 'v_mag_pu_max', 'Max Voltage Magnitude', 'float', 'per unit', 'inf', 'static', FALSE, TRUE, 'Maximum desired voltage, per unit of the nominal voltage (v_nom). This is a placeholder attribute and is not currently used by any functions.', 0, NULL, 'electrical', FALSE),
28
28
  -- Output attributes for BUS
29
- ('BUS', 'control', 'Control Strategy', 'string', 'n/a', 'PQ', 'static', FALSE, FALSE, 'P,Q,V control strategy for PF, must be "PQ", "PV" or "Slack". Note that this attribute is an output inherited from the controls of the generators attached to the bus; setting it directly on the bus will not have any effect.', NULL, NULL, 'control', FALSE),
30
- ('BUS', 'generator', 'Slack Generator', 'string', 'n/a', 'n/a', 'static', FALSE, FALSE, 'Name of slack generator attached to slack bus.', NULL, NULL, 'control', FALSE),
31
- ('BUS', 'sub_network', 'Sub-Network', 'string', 'n/a', 'n/a', 'static', FALSE, FALSE, 'Name of connected sub-network to which bus belongs. This attribute is set by PyPSA in the function network.determine_network_topology(); do not set it directly by hand.', NULL, NULL, 'other', FALSE),
32
- ('BUS', 'p', 'Active Power', 'float', 'MW', '0', 'timeseries', FALSE, FALSE, 'active power at bus (positive if net generation at bus)', NULL, NULL, 'power', TRUE),
33
- ('BUS', 'q', 'Reactive Power', 'float', 'MVar', '0', 'timeseries', FALSE, FALSE, 'reactive power (positive if net generation at bus)', NULL, NULL, 'power', TRUE),
34
- ('BUS', 'v_mag_pu', 'Voltage Magnitude', 'float', 'per unit', '1', 'timeseries', FALSE, FALSE, 'Voltage magnitude, per unit of v_nom', NULL, NULL, 'power', TRUE),
35
- ('BUS', 'v_ang', 'Voltage Angle', 'float', 'radians', '0', 'timeseries', FALSE, FALSE, 'Voltage angle', NULL, NULL, 'power', TRUE),
36
- ('BUS', 'marginal_price', 'Marginal Price', 'float', 'currency/MWh', '0', 'timeseries', FALSE, FALSE, 'Locational marginal price from LOPF from power balance constraint', NULL, NULL, 'economics', TRUE);
29
+ ('BUS', 'control', 'Control Strategy', 'string', 'n/a', 'PQ', 'static', FALSE, FALSE, 'P,Q,V control strategy for PF, must be "PQ", "PV" or "Slack". Note that this attribute is an output inherited from the controls of the generators attached to the bus; setting it directly on the bus will not have any effect.', NULL, NULL, 'electrical', FALSE),
30
+ ('BUS', 'generator', 'Slack Generator', 'string', 'n/a', 'n/a', 'static', FALSE, FALSE, 'Name of slack generator attached to slack bus.', NULL, NULL, 'electrical', FALSE),
31
+ ('BUS', 'sub_network', 'Sub-Network', 'string', 'n/a', 'n/a', 'static', FALSE, FALSE, 'Name of connected sub-network to which bus belongs. This attribute is set by PyPSA in the function network.determine_network_topology(); do not set it directly by hand.', NULL, NULL, 'basic', FALSE),
32
+ ('BUS', 'p', 'Active Power', 'float', 'MW', '0', 'timeseries', FALSE, FALSE, 'active power at bus (positive if net generation at bus)', NULL, NULL, 'electrical', TRUE),
33
+ ('BUS', 'q', 'Reactive Power', 'float', 'MVar', '0', 'timeseries', FALSE, FALSE, 'reactive power (positive if net generation at bus)', NULL, NULL, 'electrical', TRUE),
34
+ ('BUS', 'v_mag_pu', 'Voltage Magnitude', 'float', 'per unit', '1', 'timeseries', FALSE, FALSE, 'Voltage magnitude, per unit of v_nom', NULL, NULL, 'electrical', TRUE),
35
+ ('BUS', 'v_ang', 'Voltage Angle', 'float', 'radians', '0', 'timeseries', FALSE, FALSE, 'Voltage angle', NULL, NULL, 'electrical', TRUE),
36
+ ('BUS', 'marginal_price', 'Marginal Price', 'float', 'currency/MWh', '0', 'timeseries', FALSE, FALSE, 'Locational marginal price from LOPF from power balance constraint', NULL, NULL, 'costs', TRUE);
37
37
 
38
38
  -- ============================================================================
39
39
  -- GENERATOR ATTRIBUTES
40
40
  -- ============================================================================
41
41
 
42
- -- GENERATOR attributes from generators.csv (PyPSA reference) - Updated to simplified groups
42
+ -- GENERATOR attributes from generators.csv (PyPSA reference) - Updated to new 10-group system
43
43
  INSERT INTO attribute_validation_rules (component_type, attribute_name, display_name, data_type, unit, default_value, allowed_storage_types, is_required, is_input, description, min_value, max_value, group_name) VALUES
44
44
  -- Input attributes for GENERATOR
45
- ('GENERATOR', 'control', 'Control Strategy', 'string', 'n/a', 'PQ', 'static', FALSE, TRUE, 'P,Q,V control strategy for PF, must be "PQ", "PV" or "Slack".', NULL, NULL, 'control'),
46
- ('GENERATOR', 'type', 'Generator Type', 'string', 'n/a', 'n/a', 'static', FALSE, TRUE, 'Placeholder for generator type. Not yet implemented.', NULL, NULL, 'basic'),
47
- ('GENERATOR', 'p_nom', 'Nominal Power', 'float', 'MW', '0', 'static', FALSE, TRUE, 'Nominal power for limits in optimization.', 0, NULL, 'power'),
48
- ('GENERATOR', 'p_nom_mod', 'Nominal Power Module', 'float', 'MW', '0', 'static', FALSE, TRUE, 'Nominal power of the generator module.', 0, NULL, 'power'),
49
- ('GENERATOR', 'p_nom_extendable', 'Extendable Capacity', 'boolean', 'n/a', 'False', 'static', FALSE, TRUE, 'Switch to allow capacity p_nom to be extended in optimization.', NULL, NULL, 'power'),
50
- ('GENERATOR', 'p_nom_min', 'Min Nominal Power', 'float', 'MW', '0', 'static', FALSE, TRUE, 'If p_nom is extendable in optimization, set its minimum value.', 0, NULL, 'power'),
51
- ('GENERATOR', 'p_nom_max', 'Max Nominal Power', 'float', 'MW', 'inf', 'static', FALSE, TRUE, 'If p_nom is extendable in optimization, set its maximum value (e.g. limited by technical potential).', 0, NULL, 'power'),
52
- ('GENERATOR', 'p_min_pu', 'Min Capacity Factor', 'float', 'per unit', '0', 'static_or_timeseries', FALSE, TRUE, 'The minimum output for each snapshot per unit of p_nom for the optimization (e.g. for variable renewable generators this can change due to weather conditions and compulsory feed-in; for conventional generators it represents a minimal dispatch). Note that if comittable is False and p_min_pu > 0, this represents a must-run condition.', 0, NULL, 'power'),
53
- ('GENERATOR', 'p_max_pu', 'Max Capacity Factor', 'float', 'per unit', '1', 'static_or_timeseries', FALSE, TRUE, 'The maximum output for each snapshot per unit of p_nom for the optimization (e.g. for variable renewable generators this can change due to weather conditions; for conventional generators it represents a maximum dispatch).', 0, 1, 'power'),
54
- ('GENERATOR', 'p_set', 'Active Power Setpoint', 'float', 'MW', '0', 'static_or_timeseries', FALSE, TRUE, 'active power set point (for PF)', NULL, NULL, 'power'),
55
- ('GENERATOR', 'e_sum_min', 'Min Energy Sum', 'float', 'MWh', '-inf', 'static', FALSE, TRUE, 'The minimum total energy produced during a single optimization horizon.', NULL, NULL, 'power'),
56
- ('GENERATOR', 'e_sum_max', 'Max Energy Sum', 'float', 'MWh', 'inf', 'static', FALSE, TRUE, 'The maximum total energy produced during a single optimization horizon.', NULL, NULL, 'power'),
57
- ('GENERATOR', 'q_set', 'Reactive Power Setpoint', 'float', 'MVar', '0', 'static_or_timeseries', FALSE, TRUE, 'reactive power set point (for PF)', NULL, NULL, 'power'),
58
- ('GENERATOR', 'sign', 'Power Sign', 'float', 'n/a', '1', 'static', FALSE, TRUE, 'power sign', NULL, NULL, 'power'),
59
- ('GENERATOR', 'carrier', 'Energy Carrier', 'string', 'n/a', 'n/a', 'static', FALSE, TRUE, 'Prime mover energy carrier (e.g. coal, gas, wind, solar); required for global constraints on primary energy in optimization', NULL, NULL, 'basic'),
60
- ('GENERATOR', 'marginal_cost', 'Marginal Cost', 'float', 'currency/MWh', '0', 'static_or_timeseries', FALSE, TRUE, 'Marginal cost of production of 1 MWh.', 0, NULL, 'economics'),
61
- ('GENERATOR', 'marginal_cost_quadratic', 'Quadratic Marginal Cost', 'float', 'currency/MWh', '0', 'static_or_timeseries', FALSE, TRUE, 'Quadratic marginal cost of production of 1 MWh.', 0, NULL, 'economics'),
62
- ('GENERATOR', 'capital_cost', 'Capital Cost', 'float', 'currency/MW', '0', 'static', FALSE, TRUE, 'Fixed period costs of extending p_nom by 1 MW, including periodized investment costs and periodic fixed O&M costs (e.g. annuitized investment costs).', 0, NULL, 'economics'),
63
- ('GENERATOR', 'active', 'Active', 'boolean', 'n/a', 'True', 'static', FALSE, TRUE, 'Whether to consider the component in basic functionality or not', NULL, NULL, 'basic'),
64
- ('GENERATOR', 'build_year', 'Build Year', 'int', 'year', '0', 'static', FALSE, TRUE, 'build year', 0, 3000, 'economics'),
65
- ('GENERATOR', 'lifetime', 'Lifetime', 'float', 'years', 'inf', 'static', FALSE, TRUE, 'lifetime', 0, NULL, 'economics'),
66
- ('GENERATOR', 'efficiency', 'Efficiency', 'float', 'per unit', '1', 'static_or_timeseries', FALSE, TRUE, 'Ratio between primary energy and electrical energy, e.g. takes value 0.4 MWh_elec/MWh_thermal for gas. This is required for global constraints on primary energy in optimization.', 0, 1, 'power'),
67
- ('GENERATOR', 'committable', 'Committable', 'boolean', 'n/a', 'False', 'static', FALSE, TRUE, 'Use unit commitment (only possible if p_nom is not extendable).', NULL, NULL, 'control'),
68
- ('GENERATOR', 'start_up_cost', 'Start-up Cost', 'float', 'currency', '0', 'static', FALSE, TRUE, 'Cost to start up the generator. Only read if committable is True.', 0, NULL, 'control'),
69
- ('GENERATOR', 'shut_down_cost', 'Shutdown Cost', 'float', 'currency', '0', 'static', FALSE, TRUE, 'Cost to shut down the generator. Only read if committable is True.', 0, NULL, 'control'),
70
- ('GENERATOR', 'stand_by_cost', 'Stand-by Cost', 'float', 'currency/h', '0', 'static_or_timeseries', FALSE, TRUE, 'Stand-by cost for operating the generator at null power output.', 0, NULL, 'control'),
71
- ('GENERATOR', 'min_up_time', 'Min Up Time', 'int', 'snapshots', '0', 'static', FALSE, TRUE, 'Minimum number of snapshots for status to be 1. Only read if committable is True.', 0, NULL, 'control'),
72
- ('GENERATOR', 'min_down_time', 'Min Down Time', 'int', 'snapshots', '0', 'static', FALSE, TRUE, 'Minimum number of snapshots for status to be 0. Only read if committable is True.', 0, NULL, 'control'),
73
- ('GENERATOR', 'up_time_before', 'Up Time Before', 'int', 'snapshots', '1', 'static', FALSE, TRUE, 'Number of snapshots that the generator was online before network.snapshots start. Only read if committable is True and min_up_time is non-zero.', 0, NULL, 'control'),
74
- ('GENERATOR', 'down_time_before', 'Down Time Before', 'int', 'snapshots', '0', 'static', FALSE, TRUE, 'Number of snapshots that the generator was offline before network.snapshots start. Only read if committable is True and min_down_time is non-zero.', 0, NULL, 'control'),
75
- ('GENERATOR', 'ramp_limit_up', 'Ramp Up Limit', 'float', 'per unit', '1', 'static_or_timeseries', FALSE, TRUE, 'Maximum active power increase from one snapshot to the next, per unit of the nominal power. Ignored if 1.', NULL, NULL, 'control'),
76
- ('GENERATOR', 'ramp_limit_down', 'Ramp Down Limit', 'float', 'per unit', '1', 'static_or_timeseries', FALSE, TRUE, 'Maximum active power decrease from one snapshot to the next, per unit of the nominal power. Ignored if 1.', NULL, NULL, 'control'),
77
- ('GENERATOR', 'ramp_limit_start_up', 'Ramp Up at Start', 'float', 'per unit', '1', 'static', FALSE, TRUE, 'Maximum active power increase at start up, per unit of the nominal power. Only read if committable is True.', NULL, NULL, 'control'),
78
- ('GENERATOR', 'ramp_limit_shut_down', 'Ramp Down at Shutdown', 'float', 'per unit', '1', 'static', FALSE, TRUE, 'Maximum active power decrease at shut down, per unit of the nominal power. Only read if committable is True.', NULL, NULL, 'control'),
79
- ('GENERATOR', 'weight', 'Weight', 'float', 'n/a', '1', 'static', FALSE, TRUE, 'Weighting of a generator. Only used for network clustering.', NULL, NULL, 'other'),
45
+ ('GENERATOR', 'control', 'Control Strategy', 'string', 'n/a', 'PQ', 'static', FALSE, TRUE, 'Power flow control mode: "PQ" (fixed active and reactive power), "PV" (fixed active power and voltage magnitude), or "Slack" (balances system power, typically one per network).', NULL, NULL, 'electrical'),
46
+ ('GENERATOR', 'type', 'Type', 'string', 'n/a', 'n/a', 'static', FALSE, TRUE, 'Placeholder for generator type. Not yet implemented.', NULL, NULL, 'basic'),
47
+ ('GENERATOR', 'p_nom', 'Nominal Power', 'float', 'MW', '0', 'static', TRUE, TRUE, 'The maximum rated capacity of the generator in MW. This sets the upper limit for power output in all calculations.', 0, NULL, 'capacity'),
48
+ ('GENERATOR', 'p_nom_mod', 'Nominal Power Module', 'float', 'MW', '0', 'static', FALSE, TRUE, 'The unit size for capacity expansion. When extending the nominal power (p_nom), it can only be increased in multiples of this module size.', 0, NULL, 'capacity'),
49
+ ('GENERATOR', 'p_nom_extendable', 'Extendable Capacity', 'boolean', 'n/a', 'False', 'static', FALSE, TRUE, 'Switch to allow the nominal power (p_nom) to be extended in optimization.', NULL, NULL, 'capacity'),
50
+ ('GENERATOR', 'p_nom_min', 'Min Nominal Power', 'float', 'MW', '0', 'static', FALSE, TRUE, 'If the nominal power (p_nom) is extendable in optimization, set its minimum value.', 0, NULL, 'capacity'),
51
+ ('GENERATOR', 'p_nom_max', 'Max Nominal Power', 'float', 'MW', 'inf', 'static', FALSE, TRUE, 'If the nominal power (p_nom) is extendable in optimization, set its maximum value (e.g. limited by technical potential).', 0, NULL, 'capacity'),
52
+ ('GENERATOR', 'p_min_pu', 'Min Capacity Factor', 'float', 'per unit', '0', 'static_or_timeseries', FALSE, TRUE, 'The minimum output for each snapshot per unit of the nominal power (p_nom) for the optimization (e.g. for variable renewable generators this can change due to weather conditions and compulsory feed-in; for conventional generators it represents a minimal dispatch). Note that if committable is False and the min capacity factor (p_min_pu) > 0, this represents a must-run condition.', 0, NULL, 'power_limits'),
53
+ ('GENERATOR', 'p_max_pu', 'Max Capacity Factor', 'float', 'per unit', '1', 'static_or_timeseries', FALSE, TRUE, 'The maximum output for each snapshot per unit of the nominal power (p_nom) for the optimization (e.g. for variable renewable generators this can change due to weather conditions; for conventional generators it represents a maximum dispatch).', 0, 1, 'power_limits'),
54
+ ('GENERATOR', 'p_set', 'Active Power Setpoint', 'float', 'MW', '0', 'static_or_timeseries', FALSE, TRUE, 'Fixed active power output that the generator must produce. Used when the generator output is predetermined rather than optimized.', NULL, NULL, 'power_limits'),
55
+ ('GENERATOR', 'e_sum_min', 'Min Energy Sum', 'float', 'MWh', '-inf', 'static', FALSE, TRUE, 'The minimum total energy that must be produced over the entire time period being optimized (the optimization horizon).', NULL, NULL, 'energy'),
56
+ ('GENERATOR', 'e_sum_max', 'Max Energy Sum', 'float', 'MWh', 'inf', 'static', FALSE, TRUE, 'The maximum total energy that can be produced over the entire time period being optimized (the optimization horizon).', NULL, NULL, 'energy'),
57
+ ('GENERATOR', 'q_set', 'Reactive Power Setpoint', 'float', 'MVar', '0', 'static_or_timeseries', FALSE, TRUE, 'Fixed reactive power output that the generator must produce. Used when the reactive power output is predetermined rather than optimized.', NULL, NULL, 'power_limits'),
58
+ ('GENERATOR', 'sign', 'Power Sign', 'float', 'n/a', '1', 'static', FALSE, TRUE, 'Power flow direction convention: 1 for generation (positive power flows into the network), -1 for consumption (positive power flows out of the network).', NULL, NULL, 'power_limits'),
59
+ ('GENERATOR', 'carrier', 'Carrier', 'string', 'n/a', 'n/a', 'static', TRUE, TRUE, 'Prime mover Carrier (e.g. coal, gas, wind, solar); required for global constraints on primary energy in optimization', NULL, NULL, 'basic'),
60
+ ('GENERATOR', 'marginal_cost', 'Marginal Cost', 'float', 'currency/MWh', '0', 'static_or_timeseries', TRUE, TRUE, 'The variable cost of producing one additional MWh of electricity. Used by the optimizer to determine the economic dispatch order of generators (lower cost generators are dispatched first).', 0, NULL, 'costs'),
61
+ ('GENERATOR', 'marginal_cost_quadratic', 'Quadratic Marginal Cost', 'float', 'currency/MWh', '0', 'static_or_timeseries', FALSE, TRUE, 'Quadratic term for non-linear cost curves. When set, the total cost includes a quadratic component that increases with the square of output, modeling increasing marginal costs at higher generation levels.', 0, NULL, 'costs'),
62
+ ('GENERATOR', 'capital_cost', 'Capital Cost', 'float', 'currency/MW', '0', 'static', FALSE, TRUE, 'The cost per MW of adding new capacity. Includes investment costs (spread over the planning period) and fixed operations & maintenance costs. Only relevant when extendable capacity (p_nom_extendable) is True.', 0, NULL, 'costs'),
63
+ ('GENERATOR', 'active', 'Active', 'boolean', 'n/a', 'True', 'static', FALSE, TRUE, 'Whether this generator is active and should be included in network calculations. Set to False to temporarily disable the generator without deleting it.', NULL, NULL, 'basic'),
64
+ ('GENERATOR', 'build_year', 'Build Year', 'int', 'year', '0', 'static', FALSE, TRUE, 'The year when the generator can be built or commissioned. Essential for multi-year capacity expansion planning models, which determine optimal investment timing and generator retirement schedules.', 0, 3000, 'capacity'),
65
+ ('GENERATOR', 'lifetime', 'Lifetime', 'float', 'years', 'inf', 'static', FALSE, TRUE, 'The operational lifetime of the generator in years. Essential for multi-year capacity expansion planning models, which use this to determine when generators retire (build year (build_year) + lifetime). Set to "inf" for generators that never retire.', 0, NULL, 'capacity'),
66
+ ('GENERATOR', 'efficiency', 'Efficiency', 'float', 'per unit', '1', 'static_or_timeseries', FALSE, TRUE, 'Ratio between primary energy and electrical energy, e.g. takes value 0.4 MWh_elec/MWh_thermal for gas. This is required for global constraints on primary energy in optimization.', 0, 1, 'energy'),
67
+ ('GENERATOR', 'committable', 'Committable', 'boolean', 'n/a', 'False', 'static', FALSE, TRUE, 'Enable unit commitment, allowing the generator to be turned on or off with associated start-up and shutdown costs. Only available when the nominal power (p_nom) is not extendable.', NULL, NULL, 'unit_commitment'),
68
+ ('GENERATOR', 'start_up_cost', 'Start-up Cost', 'float', 'currency', '0', 'static', FALSE, TRUE, 'Cost to start up the generator. Only read if committable (committable) is True.', 0, NULL, 'unit_commitment'),
69
+ ('GENERATOR', 'shut_down_cost', 'Shutdown Cost', 'float', 'currency', '0', 'static', FALSE, TRUE, 'Cost to shut down the generator. Only read if committable (committable) is True.', 0, NULL, 'unit_commitment'),
70
+ ('GENERATOR', 'stand_by_cost', 'Stand-by Cost', 'float', 'currency/h', '0', 'static_or_timeseries', FALSE, TRUE, 'Stand-by cost for operating the generator at null power output.', 0, NULL, 'unit_commitment'),
71
+ ('GENERATOR', 'min_up_time', 'Min Up Time', 'int', 'snapshots', '0', 'static', FALSE, TRUE, 'Minimum number of snapshots for status to be 1. Only read if committable (committable) is True.', 0, NULL, 'unit_commitment'),
72
+ ('GENERATOR', 'min_down_time', 'Min Down Time', 'int', 'snapshots', '0', 'static', FALSE, TRUE, 'Minimum number of snapshots for status to be 0. Only read if committable (committable) is True.', 0, NULL, 'unit_commitment'),
73
+ ('GENERATOR', 'up_time_before', 'Up Time Before', 'int', 'snapshots', '1', 'static', FALSE, TRUE, 'Number of snapshots that the generator was online before network.snapshots start. Only read if committable (committable) is True and min up time (min_up_time) is non-zero.', 0, NULL, 'unit_commitment'),
74
+ ('GENERATOR', 'down_time_before', 'Down Time Before', 'int', 'snapshots', '0', 'static', FALSE, TRUE, 'Number of snapshots that the generator was offline before network.snapshots start. Only read if committable (committable) is True and min down time (min_down_time) is non-zero.', 0, NULL, 'unit_commitment'),
75
+ ('GENERATOR', 'ramp_limit_up', 'Ramp Up Limit', 'float', 'per unit', '1', 'static_or_timeseries', FALSE, TRUE, 'Maximum active power increase from one snapshot to the next, per unit of the nominal power (p_nom). Ignored if 1.', NULL, NULL, 'ramping'),
76
+ ('GENERATOR', 'ramp_limit_down', 'Ramp Down Limit', 'float', 'per unit', '1', 'static_or_timeseries', FALSE, TRUE, 'Maximum active power decrease from one snapshot to the next, per unit of the nominal power (p_nom). Ignored if 1.', NULL, NULL, 'ramping'),
77
+ ('GENERATOR', 'ramp_limit_start_up', 'Ramp Up at Start', 'float', 'per unit', '1', 'static', FALSE, TRUE, 'Maximum active power increase at start up, per unit of the nominal power (p_nom). Only read if committable (committable) is True.', NULL, NULL, 'ramping'),
78
+ ('GENERATOR', 'ramp_limit_shut_down', 'Ramp Down at Shutdown', 'float', 'per unit', '1', 'static', FALSE, TRUE, 'Maximum active power decrease at shut down, per unit of the nominal power (p_nom). Only read if committable (committable) is True.', NULL, NULL, 'ramping'),
79
+ ('GENERATOR', 'weight', 'Weight', 'float', 'n/a', '1', 'static', FALSE, TRUE, 'Weighting factor used when aggregating or clustering multiple generators into representative units. Higher weights indicate generators that should be prioritized in clustering algorithms.', NULL, NULL, 'basic'),
80
80
  -- Output attributes for GENERATOR (from PyPSA generators.csv lines 38-46)
81
- ('GENERATOR', 'p', 'Active Power', 'float', 'MW', '0', 'timeseries', FALSE, FALSE, 'active power at bus (positive if net generation)', NULL, NULL, 'power'),
82
- ('GENERATOR', 'q', 'Reactive Power', 'float', 'MVar', '0', 'timeseries', FALSE, FALSE, 'reactive power (positive if net generation)', NULL, NULL, 'power'),
83
- ('GENERATOR', 'p_nom_opt', 'Optimised Nominal Power', 'float', 'MW', '0', 'static', FALSE, FALSE, 'Optimised nominal power.', 0, NULL, 'power'),
84
- ('GENERATOR', 'status', 'Status', 'float', 'n/a', '1', 'timeseries', FALSE, FALSE, 'Status (1 is on, 0 is off). Only outputted if committable is True.', NULL, NULL, 'control'),
85
- ('GENERATOR', 'mu_upper', 'Shadow Price Upper', 'float', 'currency/MWh', '0', 'timeseries', FALSE, FALSE, 'Shadow price of upper p_nom limit', NULL, NULL, 'economics'),
86
- ('GENERATOR', 'mu_lower', 'Shadow Price Lower', 'float', 'currency/MWh', '0', 'timeseries', FALSE, FALSE, 'Shadow price of lower p_nom limit', NULL, NULL, 'economics'),
87
- ('GENERATOR', 'mu_p_set', 'Shadow Price P Set', 'float', 'currency/MWh', '0', 'timeseries', FALSE, FALSE, 'Shadow price of fixed power generation p_set', NULL, NULL, 'economics'),
88
- ('GENERATOR', 'mu_ramp_limit_up', 'Shadow Price Ramp Up', 'float', 'currency/MWh', '0', 'timeseries', FALSE, FALSE, 'Shadow price of upper ramp up limit', NULL, NULL, 'economics'),
89
- ('GENERATOR', 'mu_ramp_limit_down', 'Shadow Price Ramp Down', 'float', 'currency/MWh', '0', 'timeseries', FALSE, FALSE, 'Shadow price of lower ramp down limit', NULL, NULL, 'economics');
81
+ ('GENERATOR', 'p', 'Active Power', 'float', 'MW', '0', 'timeseries', FALSE, FALSE, 'active power at bus (positive if net generation)', NULL, NULL, 'electrical'),
82
+ ('GENERATOR', 'q', 'Reactive Power', 'float', 'MVar', '0', 'timeseries', FALSE, FALSE, 'reactive power (positive if net generation)', NULL, NULL, 'electrical'),
83
+ ('GENERATOR', 'p_nom_opt', 'Optimised Nominal Power', 'float', 'MW', '0', 'static', FALSE, FALSE, 'Optimised nominal power (p_nom).', 0, NULL, 'capacity'),
84
+ ('GENERATOR', 'status', 'Status', 'float', 'n/a', '1', 'timeseries', FALSE, FALSE, 'Status (1 is on, 0 is off). Only outputted if committable (committable) is True.', NULL, NULL, 'unit_commitment'),
85
+ ('GENERATOR', 'mu_upper', 'Shadow Price Upper', 'float', 'currency/MWh', '0', 'timeseries', FALSE, FALSE, 'Shadow price of upper nominal power (p_nom) limit', NULL, NULL, 'costs'),
86
+ ('GENERATOR', 'mu_lower', 'Shadow Price Lower', 'float', 'currency/MWh', '0', 'timeseries', FALSE, FALSE, 'Shadow price of lower nominal power (p_nom) limit', NULL, NULL, 'costs'),
87
+ ('GENERATOR', 'mu_p_set', 'Shadow Price P Set', 'float', 'currency/MWh', '0', 'timeseries', FALSE, FALSE, 'Shadow price of fixed power generation active power setpoint (p_set)', NULL, NULL, 'costs'),
88
+ ('GENERATOR', 'mu_ramp_limit_up', 'Shadow Price Ramp Up', 'float', 'currency/MWh', '0', 'timeseries', FALSE, FALSE, 'Shadow price of upper ramp up limit', NULL, NULL, 'ramping'),
89
+ ('GENERATOR', 'mu_ramp_limit_down', 'Shadow Price Ramp Down', 'float', 'currency/MWh', '0', 'timeseries', FALSE, FALSE, 'Shadow price of lower ramp down limit', NULL, NULL, 'ramping');
90
90
 
91
91
  -- ============================================================================
92
92
  -- LOAD ATTRIBUTES
93
93
  -- ============================================================================
94
94
 
95
- -- LOAD attributes from loads.csv (PyPSA reference) - Updated to simplified groups
95
+ -- LOAD attributes from loads.csv (PyPSA reference) - Updated to new 10-group system
96
96
  INSERT INTO attribute_validation_rules (component_type, attribute_name, display_name, data_type, unit, default_value, allowed_storage_types, is_required, is_input, description, min_value, max_value, group_name) VALUES
97
97
  -- Input attributes for LOAD
98
- ('LOAD', 'carrier', 'Energy Carrier', 'string', 'n/a', 'n/a', 'static', FALSE, TRUE, 'Energy carrier: can be "AC" or "DC" for electrical buses, or "heat" or "gas".', NULL, NULL, 'basic'),
99
- ('LOAD', 'type', 'Load Type', 'string', 'n/a', 'n/a', 'static', FALSE, TRUE, 'Placeholder for load type. Not yet implemented.', NULL, NULL, 'basic'),
100
- ('LOAD', 'p_set', 'Active Power Demand', 'float', 'MW', '0', 'static_or_timeseries', FALSE, TRUE, 'Active power consumption (positive if the load is consuming power).', NULL, NULL, 'power'),
101
- ('LOAD', 'q_set', 'Reactive Power Demand', 'float', 'MVar', '0', 'static_or_timeseries', FALSE, TRUE, 'Reactive power consumption (positive if the load is inductive).', NULL, NULL, 'power'),
102
- ('LOAD', 'sign', 'Power Sign', 'float', 'n/a', '-1', 'static', FALSE, TRUE, 'power sign (opposite sign to generator)', NULL, NULL, 'power'),
103
- ('LOAD', 'active', 'Active', 'boolean', 'n/a', 'True', 'static', FALSE, TRUE, 'Whether to consider the component in common functionalities or not', NULL, NULL, 'basic'),
98
+ ('LOAD', 'carrier', 'Carrier', 'string', 'n/a', 'n/a', 'static', FALSE, TRUE, 'Carrier type for the load: "AC" or "DC" for electrical loads, or "heat" or "gas" for thermal loads. Used for categorization and energy balance constraints.', NULL, NULL, 'basic'),
99
+ ('LOAD', 'type', 'Type', 'string', 'n/a', 'n/a', 'static', FALSE, TRUE, 'Placeholder for load type. Not yet implemented.', NULL, NULL, 'basic'),
100
+ ('LOAD', 'p_set', 'Active Power Demand', 'float', 'MW', '0', 'static_or_timeseries', TRUE, TRUE, 'The active power demand of the load in MW. This is the real power that the load consumes from the network. Can be static or time-varying.', NULL, NULL, 'power_limits'),
101
+ ('LOAD', 'q_set', 'Reactive Power Demand', 'float', 'MVar', '0', 'static_or_timeseries', FALSE, TRUE, 'The reactive power demand of the load in MVar. Positive values indicate inductive loads (lagging power factor), negative values indicate capacitive loads (leading power factor). Can be static or time-varying.', NULL, NULL, 'power_limits'),
102
+ ('LOAD', 'sign', 'Power Sign', 'float', 'n/a', '-1', 'static', FALSE, TRUE, 'Power flow direction convention: -1 for loads (positive power flows out of the network), 1 for generation (positive power flows into the network). Typically -1 for loads.', NULL, NULL, 'power_limits'),
103
+ ('LOAD', 'active', 'Active', 'boolean', 'n/a', 'True', 'static', FALSE, TRUE, 'Whether this load is active and should be included in network calculations. Set to False to temporarily disable the load without deleting it.', NULL, NULL, 'basic'),
104
104
  -- Output attributes for LOAD (PyPSA load outputs)
105
- ('LOAD', 'p', 'Active Power', 'float', 'MW', '0', 'timeseries', FALSE, FALSE, 'active power consumption (positive if consuming)', NULL, NULL, 'power'),
106
- ('LOAD', 'q', 'Reactive Power', 'float', 'MVar', '0', 'timeseries', FALSE, FALSE, 'reactive power consumption (positive if consuming)', NULL, NULL, 'power');
105
+ ('LOAD', 'p', 'Active Power', 'float', 'MW', '0', 'timeseries', FALSE, FALSE, 'active power consumption (positive if consuming)', NULL, NULL, 'electrical'),
106
+ ('LOAD', 'q', 'Reactive Power', 'float', 'MVar', '0', 'timeseries', FALSE, FALSE, 'reactive power consumption (positive if consuming)', NULL, NULL, 'electrical');
107
107
 
108
108
  -- ============================================================================
109
109
  -- LINE ATTRIBUTES
110
110
  -- ============================================================================
111
111
 
112
- -- LINE attributes from lines.csv (PyPSA reference) - Updated to simplified groups
112
+ -- LINE attributes from lines.csv (PyPSA reference) - Updated to new 10-group system
113
113
  INSERT INTO attribute_validation_rules (component_type, attribute_name, display_name, data_type, unit, default_value, allowed_storage_types, is_required, is_input, description, min_value, max_value, group_name) VALUES
114
114
  -- Input attributes for LINE
115
- ('LINE', 'type', 'Line Type', 'string', 'n/a', '', 'static', FALSE, TRUE, 'Name of line standard type. If this is not an empty string "", then the line standard type impedance parameters are multiplied with the line length and divided/multiplied by num_parallel to compute x, r, etc. This will override any values set in r, x, and b. If the string is empty, PyPSA will simply read r, x, etc.', NULL, NULL, 'basic'),
116
- ('LINE', 'x', 'Series Reactance', 'float', 'Ohm', '0', 'static', FALSE, TRUE, 'Series reactance, must be non-zero for AC branch in linear power flow. If the line has series inductance L in Henries then x = 2πfL where f is the frequency in Hertz. Series impedance z = r + jx must be non-zero for the non-linear power flow. Ignored if type defined.', 0, NULL, 'power'),
117
- ('LINE', 'r', 'Series Resistance', 'float', 'Ohm', '0', 'static', FALSE, TRUE, 'Series resistance, must be non-zero for DC branch in linear power flow. Series impedance z = r + jx must be non-zero for the non-linear power flow. Ignored if type defined.', 0, NULL, 'power'),
118
- ('LINE', 'g', 'Shunt Conductance', 'float', 'Siemens', '0', 'static', FALSE, TRUE, 'Shunt conductivity. Shunt admittance is y = g + jb.', 0, NULL, 'power'),
119
- ('LINE', 'b', 'Shunt Susceptance', 'float', 'Siemens', '0', 'static', FALSE, TRUE, 'Shunt susceptance. If the line has shunt capacitance C in Farads then b = 2πfC where f is the frequency in Hertz. Shunt admittance is y = g + jb. Ignored if type defined.', NULL, NULL, 'power'),
120
- ('LINE', 's_nom', 'Nominal Apparent Power', 'float', 'MVA', '0', 'static', FALSE, TRUE, 'Limit of apparent power which can pass through branch.', 0, NULL, 'power'),
121
- ('LINE', 's_nom_mod', 'Nominal Power Module', 'float', 'MVA', '0', 'static', FALSE, TRUE, 'Unit size of line expansion of s_nom.', 0, NULL, 'power'),
122
- ('LINE', 's_nom_extendable', 'Extendable Capacity', 'boolean', 'n/a', 'False', 'static', FALSE, TRUE, 'Switch to allow capacity s_nom to be extended in OPF.', NULL, NULL, 'power'),
123
- ('LINE', 's_nom_min', 'Min Nominal Power', 'float', 'MVA', '0', 'static', FALSE, TRUE, 'If s_nom is extendable in OPF, set its minimum value.', 0, NULL, 'power'),
124
- ('LINE', 's_nom_max', 'Max Nominal Power', 'float', 'MVA', 'inf', 'static', FALSE, TRUE, 'If s_nom is extendable in OPF, set its maximum value (e.g. limited by potential).', 0, NULL, 'power'),
125
- ('LINE', 's_max_pu', 'Max Power Factor', 'float', 'per unit', '1', 'static_or_timeseries', FALSE, TRUE, 'The maximum allowed absolute flow per unit of s_nom for the OPF (e.g. can be set <1 to approximate n-1 factor, or can be time-varying to represent weather-dependent dynamic line rating for overhead lines).', 0, 1, 'power'),
126
- ('LINE', 'capital_cost', 'Capital Cost', 'float', 'currency/MVA', '0', 'static', FALSE, TRUE, 'Fixed period costs of extending s_nom by 1 MVA, including periodized investment costs and periodic fixed O&M costs (e.g. annuitized investment costs).', 0, NULL, 'economics'),
127
- ('LINE', 'active', 'Active', 'boolean', 'n/a', 'True', 'static', FALSE, TRUE, 'Whether to consider the component in basic functionality or not', NULL, NULL, 'basic'),
128
- ('LINE', 'build_year', 'Build Year', 'int', 'year', '0', 'static', FALSE, TRUE, 'build year', 0, 3000, 'economics'),
129
- ('LINE', 'lifetime', 'Lifetime', 'float', 'years', 'inf', 'static', FALSE, TRUE, 'lifetime', 0, NULL, 'economics'),
130
- ('LINE', 'length', 'Line Length', 'float', 'km', '0', 'static', FALSE, TRUE, 'Length of line used when "type" is set, also useful for calculating the capital cost.', 0, NULL, 'power'),
131
- ('LINE', 'carrier', 'Energy Carrier', 'string', 'n/a', '', 'static', FALSE, TRUE, 'Type of current, "AC" is the only valid value', NULL, NULL, 'basic'),
132
- ('LINE', 'terrain_factor', 'Terrain Factor', 'float', 'per unit', '1', 'static', FALSE, TRUE, 'Terrain factor for increasing capital cost.', 0, NULL, 'power'),
133
- ('LINE', 'num_parallel', 'Number of Parallel Lines', 'float', 'n/a', '1', 'static', FALSE, TRUE, 'When "type" is set, this is the number of parallel lines (can also be fractional). If "type" is empty "" this value is ignored.', 1, NULL, 'power'),
134
- ('LINE', 'v_ang_min', 'Min Voltage Angle Diff', 'float', 'Degrees', '-inf', 'static', FALSE, TRUE, 'Minimum voltage angle difference across the line. This is a placeholder attribute and is not currently used by any PyPSA functions.', NULL, NULL, 'power'),
135
- ('LINE', 'v_ang_max', 'Max Voltage Angle Diff', 'float', 'Degrees', 'inf', 'static', FALSE, TRUE, 'Maximum voltage angle difference across the line. This is a placeholder attribute and is not currently used by any PyPSA functions.', NULL, NULL, 'power'),
115
+ ('LINE', 'type', 'Type', 'string', 'n/a', '', 'static', FALSE, TRUE, 'Name of a predefined line standard type. If set, the line standard impedance parameters are automatically calculated from the line length (length) and number of parallel lines (num_parallel), overriding any manually set values for series reactance (x), series resistance (r), and shunt susceptance (b). Leave empty to manually specify impedance parameters.', NULL, NULL, 'basic'),
116
+ ('LINE', 'x', 'Series Reactance', 'float', 'Ohm', '0', 'static', TRUE, TRUE, 'The series reactance of the line in Ohms. Must be non-zero for AC lines in power flow calculations. If the line has series inductance L in Henries, then x = 2πfL where f is the frequency in Hertz. The series impedance is z = r + jx. Ignored if line type (type) is set.', 0, NULL, 'electrical'),
117
+ ('LINE', 'r', 'Series Resistance', 'float', 'Ohm', '0', 'static', FALSE, TRUE, 'The series resistance of the line in Ohms. Must be non-zero for DC lines in power flow calculations. The series impedance is z = r + jx. Ignored if line type (type) is set.', 0, NULL, 'electrical'),
118
+ ('LINE', 'g', 'Shunt Conductance', 'float', 'Siemens', '0', 'static', FALSE, TRUE, 'The shunt conductance of the line in Siemens. The shunt admittance is y = g + jb, where b is the shunt susceptance (b).', 0, NULL, 'electrical'),
119
+ ('LINE', 'b', 'Shunt Susceptance', 'float', 'Siemens', '0', 'static', FALSE, TRUE, 'The shunt susceptance of the line in Siemens. If the line has shunt capacitance C in Farads, then b = 2πfC where f is the frequency in Hertz. The shunt admittance is y = g + jb, where g is the shunt conductance (g). Ignored if line type (type) is set.', NULL, NULL, 'electrical'),
120
+ ('LINE', 's_nom', 'Nominal Apparent Power', 'float', 'MVA', '0', 'static', TRUE, TRUE, 'The maximum apparent power capacity of the line in MVA. This sets the thermal limit for power flow through the line.', 0, NULL, 'capacity'),
121
+ ('LINE', 's_nom_mod', 'Nominal Power Module', 'float', 'MVA', '0', 'static', FALSE, TRUE, 'The unit size for capacity expansion. When extending the nominal apparent power (s_nom), it can only be increased in multiples of this module size.', 0, NULL, 'capacity'),
122
+ ('LINE', 's_nom_extendable', 'Extendable Capacity', 'boolean', 'n/a', 'False', 'static', FALSE, TRUE, 'Switch to allow the nominal apparent power (s_nom) to be extended in optimization.', NULL, NULL, 'capacity'),
123
+ ('LINE', 's_nom_min', 'Min Nominal Power', 'float', 'MVA', '0', 'static', FALSE, TRUE, 'If the nominal apparent power (s_nom) is extendable in optimization, set its minimum value.', 0, NULL, 'capacity'),
124
+ ('LINE', 's_nom_max', 'Max Nominal Power', 'float', 'MVA', 'inf', 'static', FALSE, TRUE, 'If the nominal apparent power (s_nom) is extendable in optimization, set its maximum value (e.g. limited by technical potential or right-of-way constraints).', 0, NULL, 'capacity'),
125
+ ('LINE', 's_max_pu', 'Max Power Factor', 'float', 'per unit', '1', 'static_or_timeseries', FALSE, TRUE, 'The maximum allowed absolute flow per unit of the nominal apparent power (s_nom). Can be set less than 1 to account for security margins (e.g., n-1 contingency), or can be time-varying to represent weather-dependent dynamic line rating for overhead lines.', 0, 1, 'power_limits'),
126
+ ('LINE', 'capital_cost', 'Capital Cost', 'float', 'currency/MVA', '0', 'static', FALSE, TRUE, 'The cost per MVA of adding new line capacity. Includes investment costs (spread over the planning period) and fixed operations & maintenance costs. Only relevant when extendable capacity (s_nom_extendable) is True.', 0, NULL, 'costs'),
127
+ ('LINE', 'active', 'Active', 'boolean', 'n/a', 'True', 'static', FALSE, TRUE, 'Whether this line is active and should be included in network calculations. Set to False to temporarily disable the line without deleting it.', NULL, NULL, 'basic'),
128
+ ('LINE', 'build_year', 'Build Year', 'int', 'year', '0', 'static', FALSE, TRUE, 'The year when the line can be built or commissioned. Essential for multi-year capacity expansion planning models, which determine optimal investment timing and line retirement schedules.', 0, 3000, 'capacity'),
129
+ ('LINE', 'lifetime', 'Lifetime', 'float', 'years', 'inf', 'static', FALSE, TRUE, 'The operational lifetime of the line in years. Essential for multi-year capacity expansion planning models, which use this to determine when lines retire (build year (build_year) + lifetime). Set to "inf" for lines that never retire.', 0, NULL, 'capacity'),
130
+ ('LINE', 'length', 'Line Length', 'float', 'km', '0', 'static', FALSE, TRUE, 'The physical length of the line in kilometers. Required when line type (type) is set to calculate impedance parameters automatically. Also used for calculating capital costs.', 0, NULL, 'electrical'),
131
+ ('LINE', 'carrier', 'Carrier', 'string', 'n/a', '', 'static', FALSE, TRUE, 'Carrier type for the line. Must be "AC" (alternating current) as lines only support AC transmission.', NULL, NULL, 'basic'),
132
+ ('LINE', 'terrain_factor', 'Terrain Factor', 'float', 'per unit', '1', 'static', FALSE, TRUE, 'Multiplier for capital cost to account for difficult terrain. Values greater than 1 increase the capital cost (capital_cost) to reflect higher construction costs in challenging terrain (e.g., mountains, water crossings).', 0, NULL, 'electrical'),
133
+ ('LINE', 'num_parallel', 'Number of Parallel Lines', 'float', 'n/a', '1', 'static', FALSE, TRUE, 'The number of parallel transmission circuits (can be fractional). When line type (type) is set, this is used to calculate the total impedance (more parallel lines reduce effective impedance). If line type (type) is empty, this value is ignored.', 1, NULL, 'electrical'),
134
+ ('LINE', 'v_ang_min', 'Min Voltage Angle Diff', 'float', 'Degrees', '-inf', 'static', FALSE, TRUE, 'Minimum voltage angle difference across the line in degrees. This is a placeholder attribute and is not currently used by any functions.', NULL, NULL, 'electrical'),
135
+ ('LINE', 'v_ang_max', 'Max Voltage Angle Diff', 'float', 'Degrees', 'inf', 'static', FALSE, TRUE, 'Maximum voltage angle difference across the line in degrees. This is a placeholder attribute and is not currently used by any functions.', NULL, NULL, 'electrical'),
136
136
  -- Output attributes for LINE (PyPSA line outputs)
137
- ('LINE', 'p0', 'Active Power Bus0', 'float', 'MW', '0', 'timeseries', FALSE, FALSE, 'active power at bus0 (positive if power flows from bus0 to bus1)', NULL, NULL, 'power'),
138
- ('LINE', 'p1', 'Active Power Bus1', 'float', 'MW', '0', 'timeseries', FALSE, FALSE, 'active power at bus1 (positive if power flows from bus1 to bus0)', NULL, NULL, 'power'),
139
- ('LINE', 'q0', 'Reactive Power Bus0', 'float', 'MVar', '0', 'timeseries', FALSE, FALSE, 'reactive power at bus0', NULL, NULL, 'power'),
140
- ('LINE', 'q1', 'Reactive Power Bus1', 'float', 'MVar', '0', 'timeseries', FALSE, FALSE, 'reactive power at bus1', NULL, NULL, 'power'),
141
- ('LINE', 's_nom_opt', 'Optimised Apparent Power', 'float', 'MVA', '0', 'static', FALSE, FALSE, 'Optimised apparent power limit.', 0, NULL, 'power'),
142
- ('LINE', 'mu_upper', 'Shadow Price Upper', 'float', 'currency/MVA', '0', 'timeseries', FALSE, FALSE, 'Shadow price of upper s_nom limit', NULL, NULL, 'economics'),
143
- ('LINE', 'mu_lower', 'Shadow Price Lower', 'float', 'currency/MVA', '0', 'timeseries', FALSE, FALSE, 'Shadow price of lower s_nom limit', NULL, NULL, 'economics'),
144
- ('LINE', 'sub_network', 'Sub-Network', 'string', 'n/a', 'n/a', 'static', FALSE, FALSE, 'Name of connected sub-network to which line belongs. This attribute is set by PyPSA.', NULL, NULL, 'other'),
145
- ('LINE', 'x_pu', 'Per Unit Reactance', 'float', 'per unit', '0', 'static', FALSE, FALSE, 'Per unit series reactance calculated by PyPSA from x and bus.v_nom', NULL, NULL, 'power'),
146
- ('LINE', 'r_pu', 'Per Unit Resistance', 'float', 'per unit', '0', 'static', FALSE, FALSE, 'Per unit series resistance calculated by PyPSA from r and bus.v_nom', NULL, NULL, 'power'),
147
- ('LINE', 'g_pu', 'Per Unit Conductance', 'float', 'per unit', '0', 'static', FALSE, FALSE, 'Per unit shunt conductivity calculated by PyPSA from g and bus.v_nom', NULL, NULL, 'power'),
148
- ('LINE', 'b_pu', 'Per Unit Susceptance', 'float', 'per unit', '0', 'static', FALSE, FALSE, 'Per unit shunt susceptance calculated by PyPSA from b and bus.v_nom', NULL, NULL, 'power'),
149
- ('LINE', 'x_pu_eff', 'Effective Per Unit Reactance', 'float', 'per unit', '0', 'static', FALSE, FALSE, 'Effective per unit series reactance for linear power flow', NULL, NULL, 'power'),
150
- ('LINE', 'r_pu_eff', 'Effective Per Unit Resistance', 'float', 'per unit', '0', 'static', FALSE, FALSE, 'Effective per unit series resistance for linear power flow', NULL, NULL, 'power');
137
+ ('LINE', 'p0', 'Active Power Bus0', 'float', 'MW', '0', 'timeseries', FALSE, FALSE, 'active power at bus0 (positive if power flows from bus0 to bus1)', NULL, NULL, 'electrical'),
138
+ ('LINE', 'p1', 'Active Power Bus1', 'float', 'MW', '0', 'timeseries', FALSE, FALSE, 'active power at bus1 (positive if power flows from bus1 to bus0)', NULL, NULL, 'electrical'),
139
+ ('LINE', 'q0', 'Reactive Power Bus0', 'float', 'MVar', '0', 'timeseries', FALSE, FALSE, 'reactive power at bus0', NULL, NULL, 'electrical'),
140
+ ('LINE', 'q1', 'Reactive Power Bus1', 'float', 'MVar', '0', 'timeseries', FALSE, FALSE, 'reactive power at bus1', NULL, NULL, 'electrical'),
141
+ ('LINE', 's_nom_opt', 'Optimised Apparent Power', 'float', 'MVA', '0', 'static', FALSE, FALSE, 'Optimised nominal apparent power (s_nom) from capacity expansion optimization.', 0, NULL, 'capacity'),
142
+ ('LINE', 'mu_upper', 'Shadow Price Upper', 'float', 'currency/MVA', '0', 'timeseries', FALSE, FALSE, 'Shadow price of upper nominal apparent power (s_nom) limit', NULL, NULL, 'costs'),
143
+ ('LINE', 'mu_lower', 'Shadow Price Lower', 'float', 'currency/MVA', '0', 'timeseries', FALSE, FALSE, 'Shadow price of lower nominal apparent power (s_nom) limit', NULL, NULL, 'costs'),
144
+ ('LINE', 'sub_network', 'Sub-Network', 'string', 'n/a', 'n/a', 'static', FALSE, FALSE, 'Name of connected sub-network to which line belongs. This attribute is set by PyPSA.', NULL, NULL, 'basic'),
145
+ ('LINE', 'x_pu', 'Per Unit Reactance', 'float', 'per unit', '0', 'static', FALSE, FALSE, 'Per unit series reactance calculated from the series reactance (x) and the nominal voltage (v_nom) of the connected buses.', NULL, NULL, 'electrical'),
146
+ ('LINE', 'r_pu', 'Per Unit Resistance', 'float', 'per unit', '0', 'static', FALSE, FALSE, 'Per unit series resistance calculated from the series resistance (r) and the nominal voltage (v_nom) of the connected buses.', NULL, NULL, 'electrical'),
147
+ ('LINE', 'g_pu', 'Per Unit Conductance', 'float', 'per unit', '0', 'static', FALSE, FALSE, 'Per unit shunt conductance calculated from the shunt conductance (g) and the nominal voltage (v_nom) of the connected buses.', NULL, NULL, 'electrical'),
148
+ ('LINE', 'b_pu', 'Per Unit Susceptance', 'float', 'per unit', '0', 'static', FALSE, FALSE, 'Per unit shunt susceptance calculated from the shunt susceptance (b) and the nominal voltage (v_nom) of the connected buses.', NULL, NULL, 'electrical'),
149
+ ('LINE', 'x_pu_eff', 'Effective Per Unit Reactance', 'float', 'per unit', '0', 'static', FALSE, FALSE, 'Effective per unit series reactance for linear power flow', NULL, NULL, 'electrical'),
150
+ ('LINE', 'r_pu_eff', 'Effective Per Unit Resistance', 'float', 'per unit', '0', 'static', FALSE, FALSE, 'Effective per unit series resistance for linear power flow', NULL, NULL, 'electrical');
151
151
 
152
152
  -- ============================================================================
153
153
  -- LINK ATTRIBUTES
154
154
  -- ============================================================================
155
155
 
156
- -- LINK attributes from links.csv (PyPSA reference) - Updated to simplified groups
156
+ -- LINK attributes from links.csv (PyPSA reference) - Updated to new 10-group system
157
157
  INSERT INTO attribute_validation_rules (component_type, attribute_name, display_name, data_type, unit, default_value, allowed_storage_types, is_required, is_input, description, min_value, max_value, group_name) VALUES
158
158
  -- Input attributes for LINK
159
- ('LINK', 'type', 'Link Type', 'string', 'n/a', 'n/a', 'static', FALSE, TRUE, 'Placeholder for link type. Not yet implemented.', NULL, NULL, 'basic'),
160
- ('LINK', 'carrier', 'Energy Carrier', 'string', 'n/a', '', 'static', FALSE, TRUE, 'Energy carrier transported by the link: can be "DC" for electrical HVDC links, or "heat" or "gas" etc.', NULL, NULL, 'basic'),
161
- ('LINK', 'efficiency', 'Transfer Efficiency', 'float', 'per unit', '1', 'static_or_timeseries', FALSE, TRUE, 'Efficiency of power transfer from bus0 to bus1. (Can be time-dependent to represent temperature-dependent Coefficient of Performance of a heat pump from an electric to a heat bus.)', 0, 1, 'power'),
162
- ('LINK', 'active', 'Active', 'boolean', 'n/a', 'True', 'static', FALSE, TRUE, 'Whether to consider the component in basic functionality or not', NULL, NULL, 'basic'),
163
- ('LINK', 'build_year', 'Build Year', 'int', 'year', '0', 'static', FALSE, TRUE, 'build year', 0, 3000, 'economics'),
164
- ('LINK', 'lifetime', 'Lifetime', 'float', 'years', 'inf', 'static', FALSE, TRUE, 'lifetime', 0, NULL, 'economics'),
165
- ('LINK', 'p_nom', 'Nominal Power', 'float', 'MW', '0', 'static', FALSE, TRUE, 'Limit of active power which can pass through link.', 0, NULL, 'power'),
166
- ('LINK', 'p_nom_mod', 'Nominal Power Module', 'float', 'MW', '0', 'static', FALSE, TRUE, 'Limit of active power of the link module.', 0, NULL, 'power'),
167
- ('LINK', 'p_nom_extendable', 'Extendable Capacity', 'boolean', 'n/a', 'False', 'static', FALSE, TRUE, 'Switch to allow capacity p_nom to be extended.', NULL, NULL, 'power'),
168
- ('LINK', 'p_nom_min', 'Min Nominal Power', 'float', 'MW', '0', 'static', FALSE, TRUE, 'If p_nom is extendable, set its minimum value.', 0, NULL, 'power'),
169
- ('LINK', 'p_nom_max', 'Max Nominal Power', 'float', 'MW', 'inf', 'static', FALSE, TRUE, 'If p_nom is extendable, set its maximum value (e.g. limited by potential).', 0, NULL, 'power'),
170
- ('LINK', 'p_set', 'Power Setpoint', 'float', 'MW', '0', 'static_or_timeseries', FALSE, TRUE, 'The dispatch set point for p0 of the link in PF.', NULL, NULL, 'power'),
171
- ('LINK', 'p_min_pu', 'Min Capacity Factor', 'float', 'per unit of p_nom', '0', 'static_or_timeseries', FALSE, TRUE, 'Minimal dispatch (can also be negative) per unit of p_nom for the link.', NULL, NULL, 'power'),
172
- ('LINK', 'p_max_pu', 'Max Capacity Factor', 'float', 'per unit of p_nom', '1', 'static_or_timeseries', FALSE, TRUE, 'Maximal dispatch (can also be negative) per unit of p_nom for the link.', NULL, NULL, 'power'),
173
- ('LINK', 'capital_cost', 'Capital Cost', 'float', 'currency/MW', '0', 'static', FALSE, TRUE, 'Fixed period costs of extending p_nom by 1 MW, including periodized investment costs and periodic fixed O&M costs (e.g. annuitized investment costs).', 0, NULL, 'economics'),
174
- ('LINK', 'marginal_cost', 'Marginal Cost', 'float', 'currency/MWh', '0', 'static_or_timeseries', FALSE, TRUE, 'Marginal cost of transfering 1 MWh (before efficiency losses) from bus0 to bus1. NB: marginal cost only makes sense if p_max_pu >= 0.', 0, NULL, 'economics'),
175
- ('LINK', 'marginal_cost_quadratic', 'Quadratic Marginal Cost', 'float', 'currency/MWh', '0', 'static_or_timeseries', FALSE, TRUE, 'Quadratic marginal cost for transferring 1 MWh (before efficiency losses) from bus0 to bus1.', 0, NULL, 'economics'),
176
- ('LINK', 'stand_by_cost', 'Stand-by Cost', 'float', 'currency/h', '0', 'static_or_timeseries', FALSE, TRUE, 'Stand-by cost for operating the link at null power flow.', 0, NULL, 'control'),
177
- ('LINK', 'length', 'Link Length', 'float', 'km', '0', 'static', FALSE, TRUE, 'Length of line, useful for calculating the capital cost.', 0, NULL, 'power'),
178
- ('LINK', 'terrain_factor', 'Terrain Factor', 'float', 'per unit', '1', 'static', FALSE, TRUE, 'Terrain factor for increasing capital cost.', 0, NULL, 'power'),
179
- ('LINK', 'committable', 'Committable', 'boolean', 'n/a', 'False', 'static', FALSE, TRUE, 'Use unit commitment (only possible if p_nom is not extendable).', NULL, NULL, 'control'),
180
- ('LINK', 'start_up_cost', 'Start-up Cost', 'float', 'currency', '0', 'static', FALSE, TRUE, 'Cost to start up the link. Only read if committable is True.', 0, NULL, 'control'),
181
- ('LINK', 'shut_down_cost', 'Shutdown Cost', 'float', 'currency', '0', 'static', FALSE, TRUE, 'Cost to shut down the link. Only read if committable is True.', 0, NULL, 'control'),
182
- ('LINK', 'min_up_time', 'Min Up Time', 'int', 'snapshots', '0', 'static', FALSE, TRUE, 'Minimum number of snapshots for status to be 1. Only read if committable is True.', 0, NULL, 'control'),
183
- ('LINK', 'min_down_time', 'Min Down Time', 'int', 'snapshots', '0', 'static', FALSE, TRUE, 'Minimum number of snapshots for status to be 0. Only read if committable is True.', 0, NULL, 'control'),
184
- ('LINK', 'up_time_before', 'Up Time Before', 'int', 'snapshots', '1', 'static', FALSE, TRUE, 'Number of snapshots that the link was online before network.snapshots start. Only read if committable is True and min_up_time is non-zero.', 0, NULL, 'control'),
185
- ('LINK', 'down_time_before', 'Down Time Before', 'int', 'snapshots', '0', 'static', FALSE, TRUE, 'Number of snapshots that the link was offline before network.snapshots start. Only read if committable is True and min_down_time is non-zero.', 0, NULL, 'control'),
186
- ('LINK', 'ramp_limit_up', 'Ramp Up Limit', 'float', 'per unit', '1', 'static_or_timeseries', FALSE, TRUE, 'Maximum increase from one snapshot to the next, per unit of the bus0 unit. Ignored if 1.', NULL, NULL, 'control'),
187
- ('LINK', 'ramp_limit_down', 'Ramp Down Limit', 'float', 'per unit', '1', 'static_or_timeseries', FALSE, TRUE, 'Maximum decrease from one snapshot to the next, per unit of the bus0 unit. Ignored if 1.', NULL, NULL, 'control'),
188
- ('LINK', 'ramp_limit_start_up', 'Ramp Up at Start', 'float', 'per unit', '1', 'static', FALSE, TRUE, 'Maximumincrease at start up, per unit of bus0 unit. Only read if committable is True.', NULL, NULL, 'control'),
159
+ ('LINK', 'type', 'Type', 'string', 'n/a', 'n/a', 'static', FALSE, TRUE, 'Placeholder for link type. Not yet implemented.', NULL, NULL, 'basic'),
160
+ ('LINK', 'carrier', 'Carrier', 'string', 'n/a', '', 'static', FALSE, TRUE, 'Carrier type transported by the link: "DC" for electrical HVDC links, or "heat" or "gas" for thermal links. Used for categorization and energy balance constraints.', NULL, NULL, 'basic'),
161
+ ('LINK', 'efficiency', 'Transfer Efficiency', 'float', 'per unit', '1', 'static_or_timeseries', FALSE, TRUE, 'The efficiency of power transfer from bus0 to bus1. A value of 1.0 means no losses, while lower values represent transmission losses. Can be time-varying to model temperature-dependent performance (e.g., heat pump Coefficient of Performance).', 0, 1, 'energy'),
162
+ ('LINK', 'active', 'Active', 'boolean', 'n/a', 'True', 'static', FALSE, TRUE, 'Whether this link is active and should be included in network calculations. Set to False to temporarily disable the link without deleting it.', NULL, NULL, 'basic'),
163
+ ('LINK', 'build_year', 'Build Year', 'int', 'year', '0', 'static', FALSE, TRUE, 'The year when the link can be built or commissioned. Essential for multi-year capacity expansion planning models, which determine optimal investment timing and link retirement schedules.', 0, 3000, 'capacity'),
164
+ ('LINK', 'lifetime', 'Lifetime', 'float', 'years', 'inf', 'static', FALSE, TRUE, 'The operational lifetime of the link in years. Essential for multi-year capacity expansion planning models, which use this to determine when links retire (build year (build_year) + lifetime). Set to "inf" for links that never retire.', 0, NULL, 'capacity'),
165
+ ('LINK', 'p_nom', 'Nominal Power', 'float', 'MW', '0', 'static', TRUE, TRUE, 'The maximum active power capacity of the link in MW. This sets the limit for power flow through the link.', 0, NULL, 'capacity'),
166
+ ('LINK', 'p_nom_mod', 'Nominal Power Module', 'float', 'MW', '0', 'static', FALSE, TRUE, 'The unit size for capacity expansion. When extending the nominal power (p_nom), it can only be increased in multiples of this module size.', 0, NULL, 'capacity'),
167
+ ('LINK', 'p_nom_extendable', 'Extendable Capacity', 'boolean', 'n/a', 'False', 'static', FALSE, TRUE, 'Switch to allow the nominal power (p_nom) to be extended in optimization.', NULL, NULL, 'capacity'),
168
+ ('LINK', 'p_nom_min', 'Min Nominal Power', 'float', 'MW', '0', 'static', FALSE, TRUE, 'If the nominal power (p_nom) is extendable in optimization, set its minimum value.', 0, NULL, 'capacity'),
169
+ ('LINK', 'p_nom_max', 'Max Nominal Power', 'float', 'MW', 'inf', 'static', FALSE, TRUE, 'If the nominal power (p_nom) is extendable in optimization, set its maximum value (e.g. limited by technical potential or right-of-way constraints).', 0, NULL, 'capacity'),
170
+ ('LINK', 'p_set', 'Power Setpoint', 'float', 'MW', '0', 'static_or_timeseries', FALSE, TRUE, 'Fixed active power flow that the link must transfer from bus0 to bus1. Used when the link power flow is predetermined rather than optimized.', NULL, NULL, 'power_limits'),
171
+ ('LINK', 'p_min_pu', 'Min Capacity Factor', 'float', 'per unit of p_nom', '0', 'static_or_timeseries', FALSE, TRUE, 'The minimum power flow per unit of the nominal power (p_nom). Negative values allow reverse flow (from bus1 to bus0). Can be static or time-varying.', NULL, NULL, 'power_limits'),
172
+ ('LINK', 'p_max_pu', 'Max Capacity Factor', 'float', 'per unit of p_nom', '1', 'static_or_timeseries', FALSE, TRUE, 'The maximum power flow per unit of the nominal power (p_nom). Negative values allow reverse flow (from bus1 to bus0). Can be static or time-varying.', NULL, NULL, 'power_limits'),
173
+ ('LINK', 'capital_cost', 'Capital Cost', 'float', 'currency/MW', '0', 'static', FALSE, TRUE, 'The cost per MW of adding new link capacity. Includes investment costs (spread over the planning period) and fixed operations & maintenance costs. Only relevant when extendable capacity (p_nom_extendable) is True.', 0, NULL, 'costs'),
174
+ ('LINK', 'marginal_cost', 'Marginal Cost', 'float', 'currency/MWh', '0', 'static_or_timeseries', FALSE, TRUE, 'The variable cost of transferring 1 MWh from bus0 to bus1 (before efficiency losses). Used by the optimizer to determine economic dispatch. Only meaningful if the max capacity factor (p_max_pu) >= 0 (unidirectional flow).', 0, NULL, 'costs'),
175
+ ('LINK', 'marginal_cost_quadratic', 'Quadratic Marginal Cost', 'float', 'currency/MWh', '0', 'static_or_timeseries', FALSE, TRUE, 'Quadratic term for non-linear cost curves. When set, the total cost includes a quadratic component that increases with the square of power flow, modeling increasing marginal costs at higher transfer levels.', 0, NULL, 'costs'),
176
+ ('LINK', 'stand_by_cost', 'Stand-by Cost', 'float', 'currency/h', '0', 'static_or_timeseries', FALSE, TRUE, 'Stand-by cost for operating the link at null power flow.', 0, NULL, 'unit_commitment'),
177
+ ('LINK', 'length', 'Link Length', 'float', 'km', '0', 'static', FALSE, TRUE, 'The physical length of the link in kilometers. Used for calculating capital costs, especially for transmission lines or pipelines.', 0, NULL, 'electrical'),
178
+ ('LINK', 'terrain_factor', 'Terrain Factor', 'float', 'per unit', '1', 'static', FALSE, TRUE, 'Multiplier for capital cost to account for difficult terrain. Values greater than 1 increase the capital cost (capital_cost) to reflect higher construction costs in challenging terrain (e.g., mountains, water crossings).', 0, NULL, 'electrical'),
179
+ ('LINK', 'committable', 'Committable', 'boolean', 'n/a', 'False', 'static', FALSE, TRUE, 'Enable unit commitment, allowing the link to be turned on or off with associated start-up and shutdown costs. Only available when the nominal power (p_nom) is not extendable.', NULL, NULL, 'unit_commitment'),
180
+ ('LINK', 'start_up_cost', 'Start-up Cost', 'float', 'currency', '0', 'static', FALSE, TRUE, 'Cost to start up the link. Only read if committable (committable) is True.', 0, NULL, 'unit_commitment'),
181
+ ('LINK', 'shut_down_cost', 'Shutdown Cost', 'float', 'currency', '0', 'static', FALSE, TRUE, 'Cost to shut down the link. Only read if committable (committable) is True.', 0, NULL, 'unit_commitment'),
182
+ ('LINK', 'min_up_time', 'Min Up Time', 'int', 'snapshots', '0', 'static', FALSE, TRUE, 'Minimum number of snapshots for status to be 1. Only read if committable (committable) is True.', 0, NULL, 'unit_commitment'),
183
+ ('LINK', 'min_down_time', 'Min Down Time', 'int', 'snapshots', '0', 'static', FALSE, TRUE, 'Minimum number of snapshots for status to be 0. Only read if committable (committable) is True.', 0, NULL, 'unit_commitment'),
184
+ ('LINK', 'up_time_before', 'Up Time Before', 'int', 'snapshots', '1', 'static', FALSE, TRUE, 'Number of snapshots that the link was online before network.snapshots start. Only read if committable (committable) is True and min up time (min_up_time) is non-zero.', 0, NULL, 'unit_commitment'),
185
+ ('LINK', 'down_time_before', 'Down Time Before', 'int', 'snapshots', '0', 'static', FALSE, TRUE, 'Number of snapshots that the link was offline before network.snapshots start. Only read if committable (committable) is True and min down time (min_down_time) is non-zero.', 0, NULL, 'unit_commitment'),
186
+ ('LINK', 'ramp_limit_up', 'Ramp Up Limit', 'float', 'per unit', '1', 'static_or_timeseries', FALSE, TRUE, 'Maximum power flow increase from one snapshot to the next, per unit of the nominal power (p_nom). Ignored if 1.', NULL, NULL, 'ramping'),
187
+ ('LINK', 'ramp_limit_down', 'Ramp Down Limit', 'float', 'per unit', '1', 'static_or_timeseries', FALSE, TRUE, 'Maximum power flow decrease from one snapshot to the next, per unit of the nominal power (p_nom). Ignored if 1.', NULL, NULL, 'ramping'),
188
+ ('LINK', 'ramp_limit_start_up', 'Ramp Up at Start', 'float', 'per unit', '1', 'static', FALSE, TRUE, 'Maximum power flow increase at start up, per unit of the nominal power (p_nom). Only read if committable (committable) is True.', NULL, NULL, 'ramping'),
189
189
  -- Output attributes for LINK (PyPSA link outputs)
190
- ('LINK', 'p0', 'Active Power Bus0', 'float', 'MW', '0', 'timeseries', FALSE, FALSE, 'active power at bus0 (positive if power flows from bus0 to bus1)', NULL, NULL, 'power'),
191
- ('LINK', 'p1', 'Active Power Bus1', 'float', 'MW', '0', 'timeseries', FALSE, FALSE, 'active power at bus1 (positive if power flows from bus1 to bus0)', NULL, NULL, 'power'),
192
- ('LINK', 'p_nom_opt', 'Optimised Nominal Power', 'float', 'MW', '0', 'static', FALSE, FALSE, 'Optimised nominal power.', 0, NULL, 'power'),
193
- ('LINK', 'status', 'Status', 'float', 'n/a', '1', 'timeseries', FALSE, FALSE, 'Status (1 is on, 0 is off). Only outputted if committable is True.', NULL, NULL, 'control'),
194
- ('LINK', 'mu_upper', 'Shadow Price Upper', 'float', 'currency/MW', '0', 'timeseries', FALSE, FALSE, 'Shadow price of upper p_nom limit', NULL, NULL, 'economics'),
195
- ('LINK', 'mu_lower', 'Shadow Price Lower', 'float', 'currency/MW', '0', 'timeseries', FALSE, FALSE, 'Shadow price of lower p_nom limit', NULL, NULL, 'economics'),
196
- ('LINK', 'mu_p_set', 'Shadow Price P Set', 'float', 'currency/MWh', '0', 'timeseries', FALSE, FALSE, 'Shadow price of fixed power transmission p_set', NULL, NULL, 'economics'),
197
- ('LINK', 'mu_ramp_limit_up', 'Shadow Price Ramp Up', 'float', 'currency/MWh', '0', 'timeseries', FALSE, FALSE, 'Shadow price of upper ramp up limit', NULL, NULL, 'economics'),
198
- ('LINK', 'mu_ramp_limit_down', 'Shadow Price Ramp Down', 'float', 'currency/MWh', '0', 'timeseries', FALSE, FALSE, 'Shadow price of lower ramp down limit', NULL, NULL, 'economics');
190
+ ('LINK', 'p0', 'Active Power Bus0', 'float', 'MW', '0', 'timeseries', FALSE, FALSE, 'active power at bus0 (positive if power flows from bus0 to bus1)', NULL, NULL, 'electrical'),
191
+ ('LINK', 'p1', 'Active Power Bus1', 'float', 'MW', '0', 'timeseries', FALSE, FALSE, 'active power at bus1 (positive if power flows from bus1 to bus0)', NULL, NULL, 'electrical'),
192
+ ('LINK', 'p_nom_opt', 'Optimised Nominal Power', 'float', 'MW', '0', 'static', FALSE, FALSE, 'Optimised nominal power (p_nom) from capacity expansion optimization.', 0, NULL, 'capacity'),
193
+ ('LINK', 'status', 'Status', 'float', 'n/a', '1', 'timeseries', FALSE, FALSE, 'Status (1 is on, 0 is off). Only outputted if committable (committable) is True.', NULL, NULL, 'unit_commitment'),
194
+ ('LINK', 'mu_upper', 'Shadow Price Upper', 'float', 'currency/MW', '0', 'timeseries', FALSE, FALSE, 'Shadow price of upper nominal power (p_nom) limit', NULL, NULL, 'costs'),
195
+ ('LINK', 'mu_lower', 'Shadow Price Lower', 'float', 'currency/MW', '0', 'timeseries', FALSE, FALSE, 'Shadow price of lower nominal power (p_nom) limit', NULL, NULL, 'costs'),
196
+ ('LINK', 'mu_p_set', 'Shadow Price P Set', 'float', 'currency/MWh', '0', 'timeseries', FALSE, FALSE, 'Shadow price of fixed power transmission power setpoint (p_set)', NULL, NULL, 'costs'),
197
+ ('LINK', 'mu_ramp_limit_up', 'Shadow Price Ramp Up', 'float', 'currency/MWh', '0', 'timeseries', FALSE, FALSE, 'Shadow price of upper ramp up limit', NULL, NULL, 'ramping'),
198
+ ('LINK', 'mu_ramp_limit_down', 'Shadow Price Ramp Down', 'float', 'currency/MWh', '0', 'timeseries', FALSE, FALSE, 'Shadow price of lower ramp down limit', NULL, NULL, 'ramping');
199
199
 
200
200
  -- ============================================================================
201
201
  -- UNMET_LOAD ATTRIBUTES
@@ -204,45 +204,45 @@ INSERT INTO attribute_validation_rules (component_type, attribute_name, display_
204
204
  -- UNMET_LOAD attributes - same as GENERATOR but with specific defaults and restrictions - Updated to simplified groups
205
205
  INSERT INTO attribute_validation_rules (component_type, attribute_name, display_name, data_type, unit, default_value, allowed_storage_types, is_required, is_input, description, min_value, max_value, group_name) VALUES
206
206
  -- Input attributes for UNMET_LOAD (same as GENERATOR)
207
- ('UNMET_LOAD', 'control', 'Control Strategy', 'string', 'n/a', 'PQ', 'static', FALSE, TRUE, 'P,Q,V control strategy for PF, must be "PQ", "PV" or "Slack".', NULL, NULL, 'control'),
208
- ('UNMET_LOAD', 'type', 'Unmet Load Type', 'string', 'n/a', 'n/a', 'static', FALSE, TRUE, 'Placeholder for generator type. Not yet implemented.', NULL, NULL, 'basic'),
209
- ('UNMET_LOAD', 'p_nom', 'Nominal Power', 'float', 'MW', '10000000', 'static', FALSE, TRUE, 'Nominal power for limits in OPF. Set very high for unmet load.', 0, NULL, 'power'),
210
- ('UNMET_LOAD', 'p_nom_extendable', 'Extendable Capacity', 'boolean', 'n/a', 'False', 'static', FALSE, TRUE, 'Switch to allow capacity p_nom to be extended in OPF.', NULL, NULL, 'power'),
211
- ('UNMET_LOAD', 'p_nom_min', 'Min Nominal Power', 'float', 'MW', '0', 'static', FALSE, TRUE, 'If p_nom is extendable in OPF, set its minimum value.', 0, NULL, 'power'),
212
- ('UNMET_LOAD', 'p_nom_max', 'Max Nominal Power', 'float', 'MW', 'inf', 'static', FALSE, TRUE, 'If p_nom is extendable in OPF, set its maximum value (e.g. limited by potential).', 0, NULL, 'power'),
213
- ('UNMET_LOAD', 'p_min_pu', 'Min Capacity Factor', 'float', 'per unit', '0', 'static_or_timeseries', FALSE, TRUE, 'The minimum output for each snapshot per unit of p_nom for the OPF.', 0, 1, 'power'),
214
- ('UNMET_LOAD', 'p_max_pu', 'Max Capacity Factor', 'float', 'per unit', '1', 'static_or_timeseries', FALSE, TRUE, 'The maximum output for each snapshot per unit of p_nom for the OPF.', 0, 1, 'power'),
215
- ('UNMET_LOAD', 'p_set', 'Active Power Setpoint', 'float', 'MW', '0', 'static_or_timeseries', FALSE, TRUE, 'active power set point (for PF)', NULL, NULL, 'power'),
216
- ('UNMET_LOAD', 'q_set', 'Reactive Power Setpoint', 'float', 'MVar', '0', 'static_or_timeseries', FALSE, TRUE, 'reactive power set point (for PF)', NULL, NULL, 'power'),
217
- ('UNMET_LOAD', 'sign', 'Power Sign', 'float', 'n/a', '1', 'static', FALSE, TRUE, 'power sign', NULL, NULL, 'power'),
218
- ('UNMET_LOAD', 'carrier', 'Energy Carrier', 'string', 'n/a', 'n/a', 'static', FALSE, TRUE, 'Prime mover energy carrier (e.g. coal, gas, wind, solar); required for global constraints on primary energy in OPF', NULL, NULL, 'basic'),
219
- ('UNMET_LOAD', 'marginal_cost', 'Marginal Cost (Penalty)', 'float', 'currency/MWh', '100000000', 'static_or_timeseries', FALSE, TRUE, 'Marginal cost of production of 1 MWh. Set very high for unmet load penalty.', 0, NULL, 'economics'),
220
- ('UNMET_LOAD', 'build_year', 'Build Year', 'int', 'year', '0', 'static', FALSE, TRUE, 'Year when generator can be built in the optimize branch.', NULL, NULL, 'economics'),
221
- ('UNMET_LOAD', 'lifetime', 'Lifetime', 'float', 'years', 'inf', 'static', FALSE, TRUE, 'Expected lifetime in years.', 0, NULL, 'economics'),
222
- ('UNMET_LOAD', 'capital_cost', 'Capital Cost', 'float', 'currency/MW', '0', 'static_or_timeseries', FALSE, TRUE, 'Capital cost of extending p_nom by 1 MW.', 0, NULL, 'economics'),
223
- ('UNMET_LOAD', 'efficiency', 'Efficiency', 'float', 'per unit', '1', 'static_or_timeseries', FALSE, TRUE, 'Ratio between primary energy and electrical energy. Use as energy consumption if negative.', NULL, NULL, 'power'),
224
- ('UNMET_LOAD', 'committable', 'Committable', 'boolean', 'n/a', 'False', 'static', FALSE, TRUE, 'Switch to allow the unit to be turned on or off with start up costs.', NULL, NULL, 'control'),
225
- ('UNMET_LOAD', 'start_up_cost', 'Start-up Cost', 'float', 'currency', '0', 'static', FALSE, TRUE, 'Start up cost when unit goes from offline to online status.', 0, NULL, 'control'),
226
- ('UNMET_LOAD', 'shut_down_cost', 'Shutdown Cost', 'float', 'currency', '0', 'static', FALSE, TRUE, 'Shut down cost when unit goes from online to offline status.', 0, NULL, 'control'),
227
- ('UNMET_LOAD', 'min_up_time', 'Min Up Time', 'int', 'snapshots', '0', 'static', FALSE, TRUE, 'Minimum number of snapshots for status to be 1. Only read if committable is True.', 0, NULL, 'control'),
228
- ('UNMET_LOAD', 'min_down_time', 'Min Down Time', 'int', 'snapshots', '0', 'static', FALSE, TRUE, 'Minimum number of snapshots for status to be 0. Only read if committable is True.', 0, NULL, 'control'),
229
- ('UNMET_LOAD', 'up_time_before', 'Up Time Before', 'int', 'snapshots', '1', 'static', FALSE, TRUE, 'Number of snapshots that the generator was online before network.snapshots start. Only read if committable is True and min_up_time is non-zero.', 0, NULL, 'control'),
230
- ('UNMET_LOAD', 'down_time_before', 'Down Time Before', 'int', 'snapshots', '0', 'static', FALSE, TRUE, 'Number of snapshots that the generator was offline before network.snapshots start. Only read if committable is True and min_down_time is non-zero.', 0, NULL, 'control'),
231
- ('UNMET_LOAD', 'ramp_limit_up', 'Ramp Up Limit', 'float', 'per unit', '1', 'static_or_timeseries', FALSE, TRUE, 'Maximum increase from one snapshot to the next, per unit of p_nom. Ignored if 1.', NULL, NULL, 'control'),
232
- ('UNMET_LOAD', 'ramp_limit_down', 'Ramp Down Limit', 'float', 'per unit', '1', 'static_or_timeseries', FALSE, TRUE, 'Maximum decrease from one snapshot to the next, per unit of p_nom. Ignored if 1.', NULL, NULL, 'control'),
233
- ('UNMET_LOAD', 'ramp_limit_start_up', 'Ramp Up at Start', 'float', 'per unit', '1', 'static', FALSE, TRUE, 'Maximum increase at start up, per unit of p_nom. Only read if committable is True.', NULL, NULL, 'control'),
234
- ('UNMET_LOAD', 'ramp_limit_shut_down', 'Ramp Down at Shutdown', 'float', 'per unit', '1', 'static', FALSE, TRUE, 'Maximum decrease at shut down, per unit of p_nom. Only read if committable is True.', NULL, NULL, 'control'),
235
- ('UNMET_LOAD', 'active', 'Active', 'boolean', 'n/a', 'True', 'static', FALSE, TRUE, 'Switch to enable/disable this unmet load component.', NULL, NULL, 'basic'),
207
+ ('UNMET_LOAD', 'control', 'Control Strategy', 'string', 'n/a', 'PQ', 'static', FALSE, TRUE, 'Power flow control mode: "PQ" (fixed active and reactive power), "PV" (fixed active power and voltage magnitude), or "Slack" (balances system power, typically one per network).', NULL, NULL, 'electrical'),
208
+ ('UNMET_LOAD', 'type', 'Type', 'string', 'n/a', 'n/a', 'static', FALSE, TRUE, 'Placeholder for unmet load type. Not yet implemented.', NULL, NULL, 'basic'),
209
+ ('UNMET_LOAD', 'p_nom', 'Nominal Power', 'float', 'MW', '10000000', 'static', FALSE, TRUE, 'The maximum rated capacity in MW. For unmet load, this is typically set very high (e.g., 10000000 MW) to allow the optimizer to serve any unmet demand. This sets the upper limit for power output in all calculations.', 0, NULL, 'capacity'),
210
+ ('UNMET_LOAD', 'p_nom_extendable', 'Extendable Capacity', 'boolean', 'n/a', 'False', 'static', FALSE, TRUE, 'Switch to allow the nominal power (p_nom) to be extended in optimization.', NULL, NULL, 'capacity'),
211
+ ('UNMET_LOAD', 'p_nom_min', 'Min Nominal Power', 'float', 'MW', '0', 'static', FALSE, TRUE, 'If the nominal power (p_nom) is extendable in optimization, set its minimum value.', 0, NULL, 'capacity'),
212
+ ('UNMET_LOAD', 'p_nom_max', 'Max Nominal Power', 'float', 'MW', 'inf', 'static', FALSE, TRUE, 'If the nominal power (p_nom) is extendable in optimization, set its maximum value (e.g. limited by technical potential).', 0, NULL, 'capacity'),
213
+ ('UNMET_LOAD', 'p_min_pu', 'Min Capacity Factor', 'float', 'per unit', '0', 'static_or_timeseries', FALSE, TRUE, 'The minimum output for each snapshot per unit of the nominal power (p_nom) for the optimization. Note that if committable (committable) is False and the min capacity factor (p_min_pu) > 0, this represents a must-run condition.', 0, 1, 'power_limits'),
214
+ ('UNMET_LOAD', 'p_max_pu', 'Max Capacity Factor', 'float', 'per unit', '1', 'static_or_timeseries', FALSE, TRUE, 'The maximum output for each snapshot per unit of the nominal power (p_nom) for the optimization.', 0, 1, 'power_limits'),
215
+ ('UNMET_LOAD', 'p_set', 'Active Power Setpoint', 'float', 'MW', '0', 'static_or_timeseries', FALSE, TRUE, 'Fixed active power output that the unmet load generator must produce. Used when the output is predetermined rather than optimized.', NULL, NULL, 'power_limits'),
216
+ ('UNMET_LOAD', 'q_set', 'Reactive Power Setpoint', 'float', 'MVar', '0', 'static_or_timeseries', FALSE, TRUE, 'Fixed reactive power output that the unmet load generator must produce. Used when the reactive power output is predetermined rather than optimized.', NULL, NULL, 'power_limits'),
217
+ ('UNMET_LOAD', 'sign', 'Power Sign', 'float', 'n/a', '1', 'static', FALSE, TRUE, 'Power flow direction convention: 1 for generation (positive power flows into the network), -1 for consumption (positive power flows out of the network).', NULL, NULL, 'power_limits'),
218
+ ('UNMET_LOAD', 'carrier', 'Carrier', 'string', 'n/a', 'n/a', 'static', FALSE, TRUE, 'Prime mover Carrier (e.g. coal, gas, wind, solar); required for global constraints on primary energy in optimization', NULL, NULL, 'basic'),
219
+ ('UNMET_LOAD', 'marginal_cost', 'Marginal Cost (Penalty)', 'float', 'currency/MWh', '100000000', 'static_or_timeseries', FALSE, TRUE, 'The variable cost of producing one additional MWh of electricity. For unmet load, this is typically set very high (e.g., 100000000 currency/MWh) as a penalty cost to discourage the optimizer from using this generator unless absolutely necessary. Used by the optimizer to determine the economic dispatch order (lower cost generators are dispatched first).', 0, NULL, 'costs'),
220
+ ('UNMET_LOAD', 'build_year', 'Build Year', 'int', 'year', '0', 'static', FALSE, TRUE, 'The year when the unmet load generator can be built or commissioned. Essential for multi-year capacity expansion planning models, which determine optimal investment timing and generator retirement schedules.', 0, 3000, 'capacity'),
221
+ ('UNMET_LOAD', 'lifetime', 'Lifetime', 'float', 'years', 'inf', 'static', FALSE, TRUE, 'The operational lifetime of the unmet load generator in years. Essential for multi-year capacity expansion planning models, which use this to determine when generators retire (build year (build_year) + lifetime). Set to "inf" for generators that never retire.', 0, NULL, 'capacity'),
222
+ ('UNMET_LOAD', 'capital_cost', 'Capital Cost', 'float', 'currency/MW', '0', 'static_or_timeseries', FALSE, TRUE, 'The cost per MW of adding new capacity. Includes investment costs (spread over the planning period) and fixed operations & maintenance costs. Only relevant when extendable capacity (p_nom_extendable) is True.', 0, NULL, 'costs'),
223
+ ('UNMET_LOAD', 'efficiency', 'Efficiency', 'float', 'per unit', '1', 'static_or_timeseries', FALSE, TRUE, 'Ratio between primary energy and electrical energy, e.g. takes value 0.4 MWh_elec/MWh_thermal for gas. This is required for global constraints on primary energy in optimization.', 0, 1, 'energy'),
224
+ ('UNMET_LOAD', 'committable', 'Committable', 'boolean', 'n/a', 'False', 'static', FALSE, TRUE, 'Enable unit commitment, allowing the unmet load generator to be turned on or off with associated start-up and shutdown costs. Only available when the nominal power (p_nom) is not extendable.', NULL, NULL, 'unit_commitment'),
225
+ ('UNMET_LOAD', 'start_up_cost', 'Start-up Cost', 'float', 'currency', '0', 'static', FALSE, TRUE, 'Cost to start up the unmet load generator. Only read if committable (committable) is True.', 0, NULL, 'unit_commitment'),
226
+ ('UNMET_LOAD', 'shut_down_cost', 'Shutdown Cost', 'float', 'currency', '0', 'static', FALSE, TRUE, 'Cost to shut down the unmet load generator. Only read if committable (committable) is True.', 0, NULL, 'unit_commitment'),
227
+ ('UNMET_LOAD', 'min_up_time', 'Min Up Time', 'int', 'snapshots', '0', 'static', FALSE, TRUE, 'Minimum number of snapshots for status to be 1. Only read if committable (committable) is True.', 0, NULL, 'unit_commitment'),
228
+ ('UNMET_LOAD', 'min_down_time', 'Min Down Time', 'int', 'snapshots', '0', 'static', FALSE, TRUE, 'Minimum number of snapshots for status to be 0. Only read if committable (committable) is True.', 0, NULL, 'unit_commitment'),
229
+ ('UNMET_LOAD', 'up_time_before', 'Up Time Before', 'int', 'snapshots', '1', 'static', FALSE, TRUE, 'Number of snapshots that the unmet load generator was online before network.snapshots start. Only read if committable (committable) is True and min up time (min_up_time) is non-zero.', 0, NULL, 'unit_commitment'),
230
+ ('UNMET_LOAD', 'down_time_before', 'Down Time Before', 'int', 'snapshots', '0', 'static', FALSE, TRUE, 'Number of snapshots that the unmet load generator was offline before network.snapshots start. Only read if committable (committable) is True and min down time (min_down_time) is non-zero.', 0, NULL, 'unit_commitment'),
231
+ ('UNMET_LOAD', 'ramp_limit_up', 'Ramp Up Limit', 'float', 'per unit', '1', 'static_or_timeseries', FALSE, TRUE, 'Maximum active power increase from one snapshot to the next, per unit of the nominal power (p_nom). Ignored if 1.', NULL, NULL, 'ramping'),
232
+ ('UNMET_LOAD', 'ramp_limit_down', 'Ramp Down Limit', 'float', 'per unit', '1', 'static_or_timeseries', FALSE, TRUE, 'Maximum active power decrease from one snapshot to the next, per unit of the nominal power (p_nom). Ignored if 1.', NULL, NULL, 'ramping'),
233
+ ('UNMET_LOAD', 'ramp_limit_start_up', 'Ramp Up at Start', 'float', 'per unit', '1', 'static', FALSE, TRUE, 'Maximum active power increase at start up, per unit of the nominal power (p_nom). Only read if committable (committable) is True.', NULL, NULL, 'ramping'),
234
+ ('UNMET_LOAD', 'ramp_limit_shut_down', 'Ramp Down at Shutdown', 'float', 'per unit', '1', 'static', FALSE, TRUE, 'Maximum active power decrease at shut down, per unit of the nominal power (p_nom). Only read if committable (committable) is True.', NULL, NULL, 'ramping'),
235
+ ('UNMET_LOAD', 'active', 'Active', 'boolean', 'n/a', 'True', 'static', FALSE, TRUE, 'Whether this unmet load generator is active and should be included in network calculations. Set to False to temporarily disable the generator without deleting it.', NULL, NULL, 'basic'),
236
236
  -- Output attributes for UNMET_LOAD (same as GENERATOR since PyPSA treats them as generators)
237
- ('UNMET_LOAD', 'p', 'Active Power', 'float', 'MW', '0', 'timeseries', FALSE, FALSE, 'active power at bus (positive if net generation)', NULL, NULL, 'power'),
238
- ('UNMET_LOAD', 'q', 'Reactive Power', 'float', 'MVar', '0', 'timeseries', FALSE, FALSE, 'reactive power (positive if net generation)', NULL, NULL, 'power'),
239
- ('UNMET_LOAD', 'p_nom_opt', 'Optimised Nominal Power', 'float', 'MW', '0', 'static', FALSE, FALSE, 'Optimised nominal power.', 0, NULL, 'power'),
240
- ('UNMET_LOAD', 'status', 'Status', 'float', 'n/a', '1', 'timeseries', FALSE, FALSE, 'Status (1 is on, 0 is off). Only outputted if committable is True.', NULL, NULL, 'control'),
241
- ('UNMET_LOAD', 'mu_upper', 'Shadow Price Upper', 'float', 'currency/MWh', '0', 'timeseries', FALSE, FALSE, 'Shadow price of upper p_nom limit', NULL, NULL, 'economics'),
242
- ('UNMET_LOAD', 'mu_lower', 'Shadow Price Lower', 'float', 'currency/MWh', '0', 'timeseries', FALSE, FALSE, 'Shadow price of lower p_nom limit', NULL, NULL, 'economics'),
243
- ('UNMET_LOAD', 'mu_p_set', 'Shadow Price P Set', 'float', 'currency/MWh', '0', 'timeseries', FALSE, FALSE, 'Shadow price of fixed power generation p_set', NULL, NULL, 'economics'),
244
- ('UNMET_LOAD', 'mu_ramp_limit_up', 'Shadow Price Ramp Up', 'float', 'currency/MWh', '0', 'timeseries', FALSE, FALSE, 'Shadow price of upper ramp up limit', NULL, NULL, 'economics'),
245
- ('UNMET_LOAD', 'mu_ramp_limit_down', 'Shadow Price Ramp Down', 'float', 'currency/MWh', '0', 'timeseries', FALSE, FALSE, 'Shadow price of lower ramp down limit', NULL, NULL, 'economics');
237
+ ('UNMET_LOAD', 'p', 'Active Power', 'float', 'MW', '0', 'timeseries', FALSE, FALSE, 'active power at bus (positive if net generation)', NULL, NULL, 'electrical'),
238
+ ('UNMET_LOAD', 'q', 'Reactive Power', 'float', 'MVar', '0', 'timeseries', FALSE, FALSE, 'reactive power (positive if net generation)', NULL, NULL, 'electrical'),
239
+ ('UNMET_LOAD', 'p_nom_opt', 'Optimised Nominal Power', 'float', 'MW', '0', 'static', FALSE, FALSE, 'Optimised nominal power (p_nom) from capacity expansion optimization.', 0, NULL, 'capacity'),
240
+ ('UNMET_LOAD', 'status', 'Status', 'float', 'n/a', '1', 'timeseries', FALSE, FALSE, 'Status (1 is on, 0 is off). Only outputted if committable (committable) is True.', NULL, NULL, 'unit_commitment'),
241
+ ('UNMET_LOAD', 'mu_upper', 'Shadow Price Upper', 'float', 'currency/MWh', '0', 'timeseries', FALSE, FALSE, 'Shadow price of upper nominal power (p_nom) limit', NULL, NULL, 'costs'),
242
+ ('UNMET_LOAD', 'mu_lower', 'Shadow Price Lower', 'float', 'currency/MWh', '0', 'timeseries', FALSE, FALSE, 'Shadow price of lower nominal power (p_nom) limit', NULL, NULL, 'costs'),
243
+ ('UNMET_LOAD', 'mu_p_set', 'Shadow Price P Set', 'float', 'currency/MWh', '0', 'timeseries', FALSE, FALSE, 'Shadow price of fixed power generation active power setpoint (p_set)', NULL, NULL, 'costs'),
244
+ ('UNMET_LOAD', 'mu_ramp_limit_up', 'Shadow Price Ramp Up', 'float', 'currency/MWh', '0', 'timeseries', FALSE, FALSE, 'Shadow price of upper ramp up limit', NULL, NULL, 'ramping'),
245
+ ('UNMET_LOAD', 'mu_ramp_limit_down', 'Shadow Price Ramp Down', 'float', 'currency/MWh', '0', 'timeseries', FALSE, FALSE, 'Shadow price of lower ramp down limit', NULL, NULL, 'ramping');
246
246
 
247
247
  -- ============================================================================
248
248
  -- STORAGE_UNIT ATTRIBUTES
@@ -251,50 +251,50 @@ INSERT INTO attribute_validation_rules (component_type, attribute_name, display_
251
251
  -- STORAGE_UNIT attributes from storage_units.csv (PyPSA reference) - Updated to simplified groups
252
252
  INSERT INTO attribute_validation_rules (component_type, attribute_name, display_name, data_type, unit, default_value, allowed_storage_types, is_required, is_input, description, min_value, max_value, group_name) VALUES
253
253
  -- Input attributes for STORAGE_UNIT
254
- ('STORAGE_UNIT', 'control', 'Control Strategy', 'string', 'n/a', 'PQ', 'static', FALSE, TRUE, 'P,Q,V control strategy for PF, must be "PQ", "PV" or "Slack".', NULL, NULL, 'control'),
255
- ('STORAGE_UNIT', 'type', 'Storage Unit Type', 'string', 'n/a', 'n/a', 'static', FALSE, TRUE, 'Placeholder for storage unit type. Not yet implemented.', NULL, NULL, 'basic'),
256
- ('STORAGE_UNIT', 'p_nom', 'Nominal Power', 'float', 'MW', '0', 'static', FALSE, TRUE, 'Nominal power for limits in OPF.', 0, NULL, 'power'),
257
- ('STORAGE_UNIT', 'p_nom_mod', 'Nominal Power Module', 'float', 'MW', '0', 'static', FALSE, TRUE, 'Nominal power of the storage unit module.', 0, NULL, 'power'),
258
- ('STORAGE_UNIT', 'p_nom_extendable', 'Extendable Capacity', 'boolean', 'n/a', 'False', 'static', FALSE, TRUE, 'Switch to allow capacity p_nom to be extended in OPF.', NULL, NULL, 'power'),
259
- ('STORAGE_UNIT', 'p_nom_min', 'Min Nominal Power', 'float', 'MW', '0', 'static', FALSE, TRUE, 'If p_nom is extendable in OPF, set its minimum value.', 0, NULL, 'power'),
260
- ('STORAGE_UNIT', 'p_nom_max', 'Max Nominal Power', 'float', 'MW', 'inf', 'static', FALSE, TRUE, 'If p_nom is extendable in OPF, set its maximum value (e.g. limited by potential).', 0, NULL, 'power'),
261
- ('STORAGE_UNIT', 'p_min_pu', 'Min Capacity Factor', 'float', 'per unit', '-1', 'static_or_timeseries', FALSE, TRUE, 'The minimum output for each snapshot per unit of p_nom for the OPF (negative sign implies storing mode withdrawing power from bus).', -1, 1, 'power'),
262
- ('STORAGE_UNIT', 'p_max_pu', 'Max Capacity Factor', 'float', 'per unit', '1', 'static_or_timeseries', FALSE, TRUE, 'The maximum output for each snapshot per unit of p_nom for the OPF.', -1, 1, 'power'),
263
- ('STORAGE_UNIT', 'p_set', 'Active Power Setpoint', 'float', 'MW', '0', 'static_or_timeseries', FALSE, TRUE, 'active power set point (for PF)', NULL, NULL, 'power'),
264
- ('STORAGE_UNIT', 'q_set', 'Reactive Power Setpoint', 'float', 'MVar', '0', 'static_or_timeseries', FALSE, TRUE, 'reactive power set point (for PF)', NULL, NULL, 'power'),
265
- ('STORAGE_UNIT', 'sign', 'Power Sign', 'float', 'n/a', '1', 'static', FALSE, TRUE, 'power sign', NULL, NULL, 'power'),
266
- ('STORAGE_UNIT', 'carrier', 'Energy Carrier', 'string', 'n/a', 'n/a', 'static', FALSE, TRUE, 'Prime mover energy carrier (e.g. coal, gas, wind, solar); required for global constraints on primary energy in OPF', NULL, NULL, 'basic'),
267
- ('STORAGE_UNIT', 'spill_cost', 'Spill Cost', 'float', 'currency/MWh', '0', 'static_or_timeseries', FALSE, TRUE, 'Cost of spilling 1 MWh.', 0, NULL, 'economics'),
268
- ('STORAGE_UNIT', 'marginal_cost', 'Marginal Cost', 'float', 'currency/MWh', '0', 'static_or_timeseries', FALSE, TRUE, 'Marginal cost of production of 1 MWh.', 0, NULL, 'economics'),
269
- ('STORAGE_UNIT', 'marginal_cost_quadratic', 'Quadratic Marginal Cost', 'float', 'currency/MWh', '0', 'static_or_timeseries', FALSE, TRUE, 'Quadratic marginal cost of production (discharge) of 1 MWh.', 0, NULL, 'economics'),
270
- ('STORAGE_UNIT', 'marginal_cost_storage', 'Storage Marginal Cost', 'float', 'currency/MWh/h', '0', 'static_or_timeseries', FALSE, TRUE, 'Marginal cost of energy storage of 1 MWh for one hour.', 0, NULL, 'economics'),
271
- ('STORAGE_UNIT', 'capital_cost', 'Capital Cost', 'float', 'currency/MW', '0', 'static', FALSE, TRUE, 'Fixed period costs of extending p_nom by 1 MW, including periodized investment costs and periodic fixed O&M costs (e.g. annuitized investment costs).', 0, NULL, 'economics'),
272
- ('STORAGE_UNIT', 'active', 'Active', 'boolean', 'n/a', 'True', 'static', FALSE, TRUE, 'Whether to consider the component in basic functionality or not', NULL, NULL, 'basic'),
273
- ('STORAGE_UNIT', 'build_year', 'Build Year', 'int', 'year', '0', 'static', FALSE, TRUE, 'build year', 0, 3000, 'economics'),
274
- ('STORAGE_UNIT', 'lifetime', 'Lifetime', 'float', 'years', 'inf', 'static', FALSE, TRUE, 'lifetime', 0, NULL, 'economics'),
275
- ('STORAGE_UNIT', 'state_of_charge_initial', 'Initial State of Charge', 'float', 'MWh', '0', 'static', FALSE, TRUE, 'State of charge before the snapshots in the OPF.', 0, NULL, 'power'),
276
- ('STORAGE_UNIT', 'state_of_charge_initial_per_period', 'Initial SOC per Period', 'boolean', 'n/a', 'False', 'static', FALSE, TRUE, 'Switch: if True, then state of charge at the beginning of an investment period is set to state_of_charge_initial', NULL, NULL, 'power'),
277
- ('STORAGE_UNIT', 'state_of_charge_set', 'State of Charge Setpoint', 'float', 'MWh', '1', 'static_or_timeseries', FALSE, TRUE, 'State of charge set points for snapshots in the OPF.', NULL, NULL, 'power'),
278
- ('STORAGE_UNIT', 'cyclic_state_of_charge', 'Cyclic State of Charge', 'boolean', 'n/a', 'False', 'static', FALSE, TRUE, 'Switch: if True, then state_of_charge_initial is ignored and the initial state of charge is set to the final state of charge for the group of snapshots in the OPF (soc[-1] = soc[len(snapshots)-1]).', NULL, NULL, 'power'),
279
- ('STORAGE_UNIT', 'cyclic_state_of_charge_per_period', 'Cyclic SOC per Period', 'boolean', 'n/a', 'True', 'static', FALSE, TRUE, 'Switch: if True, then the cyclic constraints are applied to each period (first snapshot level if multiindexed) separately.', NULL, NULL, 'power'),
280
- ('STORAGE_UNIT', 'max_hours', 'Max Storage Hours', 'float', 'hours', '1', 'static', FALSE, TRUE, 'Maximum state of charge capacity in terms of hours at full output capacity p_nom', 0, NULL, 'power'),
281
- ('STORAGE_UNIT', 'efficiency_store', 'Storage Efficiency', 'float', 'per unit', '1', 'static_or_timeseries', FALSE, TRUE, 'Efficiency of storage on the way into the storage.', 0, 1, 'power'),
282
- ('STORAGE_UNIT', 'efficiency_dispatch', 'Dispatch Efficiency', 'float', 'per unit', '1', 'static_or_timeseries', FALSE, TRUE, 'Efficiency of storage on the way out of the storage.', 0, 1, 'power'),
283
- ('STORAGE_UNIT', 'standing_loss', 'Standing Loss', 'float', 'per unit', '0', 'static_or_timeseries', FALSE, TRUE, 'Losses per hour to state of charge.', 0, 1, 'power'),
284
- ('STORAGE_UNIT', '1low', 'Inflow', 'float', 'MW', '0', 'static_or_timeseries', FALSE, TRUE, '1low to the state of charge, e.g. due to river 1low in hydro reservoir.', NULL, NULL, 'power'),
254
+ ('STORAGE_UNIT', 'control', 'Control Strategy', 'string', 'n/a', 'PQ', 'static', FALSE, TRUE, 'Power flow control mode: "PQ" (fixed active and reactive power), "PV" (fixed active power and voltage magnitude), or "Slack" (balances system power, typically one per network).', NULL, NULL, 'electrical'),
255
+ ('STORAGE_UNIT', 'type', 'Type', 'string', 'n/a', 'n/a', 'static', FALSE, TRUE, 'Placeholder for storage unit type. Not yet implemented.', NULL, NULL, 'basic'),
256
+ ('STORAGE_UNIT', 'p_nom', 'Nominal Power', 'float', 'MW', '0', 'static', TRUE, TRUE, 'The maximum rated power capacity of the storage unit in MW. This sets the limit for both charging (negative power) and discharging (positive power) in all calculations.', 0, NULL, 'capacity'),
257
+ ('STORAGE_UNIT', 'p_nom_mod', 'Nominal Power Module', 'float', 'MW', '0', 'static', FALSE, TRUE, 'The unit size for capacity expansion. When extending the nominal power (p_nom), it can only be increased in multiples of this module size.', 0, NULL, 'capacity'),
258
+ ('STORAGE_UNIT', 'p_nom_extendable', 'Extendable Capacity', 'boolean', 'n/a', 'False', 'static', FALSE, TRUE, 'Switch to allow the nominal power (p_nom) to be extended in optimization.', NULL, NULL, 'capacity'),
259
+ ('STORAGE_UNIT', 'p_nom_min', 'Min Nominal Power', 'float', 'MW', '0', 'static', FALSE, TRUE, 'If the nominal power (p_nom) is extendable in optimization, set its minimum value.', 0, NULL, 'capacity'),
260
+ ('STORAGE_UNIT', 'p_nom_max', 'Max Nominal Power', 'float', 'MW', 'inf', 'static', FALSE, TRUE, 'If the nominal power (p_nom) is extendable in optimization, set its maximum value (e.g. limited by technical potential).', 0, NULL, 'capacity'),
261
+ ('STORAGE_UNIT', 'p_min_pu', 'Min Capacity Factor', 'float', 'per unit', '-1', 'static_or_timeseries', FALSE, TRUE, 'The minimum power flow per unit of the nominal power (p_nom). Negative values represent charging (withdrawing power from the bus), positive values represent discharging. Can be static or time-varying.', -1, 1, 'power_limits'),
262
+ ('STORAGE_UNIT', 'p_max_pu', 'Max Capacity Factor', 'float', 'per unit', '1', 'static_or_timeseries', FALSE, TRUE, 'The maximum power flow per unit of the nominal power (p_nom). Positive values represent discharging (injecting power into the bus), negative values represent charging. Can be static or time-varying.', -1, 1, 'power_limits'),
263
+ ('STORAGE_UNIT', 'p_set', 'Active Power Setpoint', 'float', 'MW', '0', 'static_or_timeseries', FALSE, TRUE, 'Fixed active power output that the storage unit must produce (positive for discharging, negative for charging). Used when the power output is predetermined rather than optimized.', NULL, NULL, 'power_limits'),
264
+ ('STORAGE_UNIT', 'q_set', 'Reactive Power Setpoint', 'float', 'MVar', '0', 'static_or_timeseries', FALSE, TRUE, 'Fixed reactive power output that the storage unit must produce. Used when the reactive power output is predetermined rather than optimized.', NULL, NULL, 'power_limits'),
265
+ ('STORAGE_UNIT', 'sign', 'Power Sign', 'float', 'n/a', '1', 'static', FALSE, TRUE, 'Power flow direction convention: 1 for generation/discharging (positive power flows into the network), -1 for consumption/charging (positive power flows out of the network).', NULL, NULL, 'power_limits'),
266
+ ('STORAGE_UNIT', 'carrier', 'Carrier', 'string', 'n/a', 'n/a', 'static', FALSE, TRUE, 'Carrier type for the storage unit (e.g. battery, hydro, hydrogen); required for global constraints on primary energy in optimization', NULL, NULL, 'basic'),
267
+ ('STORAGE_UNIT', 'spill_cost', 'Spill Cost', 'float', 'currency/MWh', '0', 'static_or_timeseries', FALSE, TRUE, 'The cost of spilling 1 MWh of energy that cannot be stored (e.g., water spillage from a hydro reservoir when the reservoir is full).', 0, NULL, 'costs'),
268
+ ('STORAGE_UNIT', 'marginal_cost', 'Marginal Cost', 'float', 'currency/MWh', '0', 'static_or_timeseries', FALSE, TRUE, 'The variable cost of discharging one additional MWh of electricity. Used by the optimizer to determine the economic dispatch order (lower cost storage units are dispatched first).', 0, NULL, 'costs'),
269
+ ('STORAGE_UNIT', 'marginal_cost_quadratic', 'Quadratic Marginal Cost', 'float', 'currency/MWh', '0', 'static_or_timeseries', FALSE, TRUE, 'Quadratic term for non-linear cost curves. When set, the total discharge cost includes a quadratic component that increases with the square of discharge power, modeling increasing marginal costs at higher discharge levels.', 0, NULL, 'costs'),
270
+ ('STORAGE_UNIT', 'marginal_cost_storage', 'Storage Marginal Cost', 'float', 'currency/MWh/h', '0', 'static_or_timeseries', FALSE, TRUE, 'The variable cost of storing 1 MWh of energy for one hour. This represents the opportunity cost or wear-and-tear cost associated with storing energy in the storage unit.', 0, NULL, 'costs'),
271
+ ('STORAGE_UNIT', 'capital_cost', 'Capital Cost', 'float', 'currency/MW', '0', 'static', FALSE, TRUE, 'The cost per MW of adding new storage capacity. Includes investment costs (spread over the planning period) and fixed operations & maintenance costs. Only relevant when extendable capacity (p_nom_extendable) is True.', 0, NULL, 'costs'),
272
+ ('STORAGE_UNIT', 'active', 'Active', 'boolean', 'n/a', 'True', 'static', FALSE, TRUE, 'Whether this storage unit is active and should be included in network calculations. Set to False to temporarily disable the storage unit without deleting it.', NULL, NULL, 'basic'),
273
+ ('STORAGE_UNIT', 'build_year', 'Build Year', 'int', 'year', '0', 'static', FALSE, TRUE, 'The year when the storage unit can be built or commissioned. Essential for multi-year capacity expansion planning models, which determine optimal investment timing and storage unit retirement schedules.', 0, 3000, 'capacity'),
274
+ ('STORAGE_UNIT', 'lifetime', 'Lifetime', 'float', 'years', 'inf', 'static', FALSE, TRUE, 'The operational lifetime of the storage unit in years. Essential for multi-year capacity expansion planning models, which use this to determine when storage units retire (build year (build_year) + lifetime). Set to "inf" for storage units that never retire.', 0, NULL, 'capacity'),
275
+ ('STORAGE_UNIT', 'state_of_charge_initial', 'Initial State of Charge', 'float', 'MWh', '0', 'static', FALSE, TRUE, 'The state of charge (energy stored) at the beginning of the optimization period, before the first snapshot. Ignored if cyclic state of charge (cyclic_state_of_charge) is True.', 0, NULL, 'energy'),
276
+ ('STORAGE_UNIT', 'state_of_charge_initial_per_period', 'Initial SOC per Period', 'boolean', 'n/a', 'False', 'static', FALSE, TRUE, 'If True, the initial state of charge (state_of_charge_initial) is applied at the beginning of each investment period separately, rather than only at the start of the entire optimization horizon.', NULL, NULL, 'energy'),
277
+ ('STORAGE_UNIT', 'state_of_charge_set', 'State of Charge Setpoint', 'float', 'MWh', '1', 'static_or_timeseries', FALSE, TRUE, 'Fixed state of charge values that the storage unit must maintain at specific snapshots. Used when the state of charge is predetermined rather than optimized. Can be static or time-varying.', NULL, NULL, 'energy'),
278
+ ('STORAGE_UNIT', 'cyclic_state_of_charge', 'Cyclic State of Charge', 'boolean', 'n/a', 'False', 'static', FALSE, TRUE, 'If True, the initial state of charge (state_of_charge_initial) is ignored and the storage unit must end with the same state of charge as it started (cyclic constraint). This ensures the storage unit returns to its initial state at the end of the optimization period.', NULL, NULL, 'energy'),
279
+ ('STORAGE_UNIT', 'cyclic_state_of_charge_per_period', 'Cyclic SOC per Period', 'boolean', 'n/a', 'True', 'static', FALSE, TRUE, 'If True, the cyclic state of charge constraint (cyclic_state_of_charge) is applied to each investment period separately, rather than only to the entire optimization horizon.', NULL, NULL, 'energy'),
280
+ ('STORAGE_UNIT', 'max_hours', 'Max Storage Hours', 'float', 'hours', '1', 'static', FALSE, TRUE, 'The maximum energy storage capacity expressed as the number of hours the storage unit can discharge at full nominal power (p_nom). The maximum state of charge in MWh equals max hours (max_hours) × nominal power (p_nom).', 0, NULL, 'energy'),
281
+ ('STORAGE_UNIT', 'efficiency_store', 'Storage Efficiency', 'float', 'per unit', '1', 'static_or_timeseries', FALSE, TRUE, 'The round-trip efficiency for charging (storing energy). A value of 1.0 means no losses, while lower values represent energy losses during charging. Can be time-varying to model temperature-dependent performance.', 0, 1, 'energy'),
282
+ ('STORAGE_UNIT', 'efficiency_dispatch', 'Dispatch Efficiency', 'float', 'per unit', '1', 'static_or_timeseries', FALSE, TRUE, 'The round-trip efficiency for discharging (releasing stored energy). A value of 1.0 means no losses, while lower values represent energy losses during discharging. Can be time-varying to model temperature-dependent performance.', 0, 1, 'energy'),
283
+ ('STORAGE_UNIT', 'standing_loss', 'Standing Loss', 'float', 'per unit', '0', 'static_or_timeseries', FALSE, TRUE, 'The self-discharge rate per hour, expressed as a fraction of the current state of charge. Represents energy losses that occur even when the storage unit is idle (e.g., battery self-discharge, reservoir evaporation). Can be time-varying.', 0, 1, 'energy'),
284
+ ('STORAGE_UNIT', 'inflow', 'Inflow', 'float', 'MW', '0', 'static_or_timeseries', FALSE, TRUE, 'Natural inflow of energy to the state of charge (e.g., river inflow to a hydro reservoir, solar charging for a battery). Positive values increase the stored energy without drawing power from the bus. Can be static or time-varying.', NULL, NULL, 'energy'),
285
285
  -- Output attributes for STORAGE_UNIT (PyPSA storage unit outputs)
286
- ('STORAGE_UNIT', 'p', 'Active Power', 'float', 'MW', '0', 'timeseries', FALSE, FALSE, 'active power at bus (positive if discharging)', NULL, NULL, 'power'),
287
- ('STORAGE_UNIT', 'q', 'Reactive Power', 'float', 'MVar', '0', 'timeseries', FALSE, FALSE, 'reactive power at bus', NULL, NULL, 'power'),
288
- ('STORAGE_UNIT', 'state_of_charge', 'State of Charge', 'float', 'MWh', '0', 'timeseries', FALSE, FALSE, 'State of charge of storage unit', 0, NULL, 'power'),
289
- ('STORAGE_UNIT', 'p_nom_opt', 'Optimised Nominal Power', 'float', 'MW', '0', 'static', FALSE, FALSE, 'Optimised nominal power.', 0, NULL, 'power'),
290
- ('STORAGE_UNIT', 'spill', 'Spill', 'float', 'MWh', '0', 'timeseries', FALSE, FALSE, 'Spillage of storage unit', 0, NULL, 'power'),
291
- ('STORAGE_UNIT', 'status', 'Status', 'float', 'n/a', '1', 'timeseries', FALSE, FALSE, 'Status (1 is on, 0 is off). Only outputted if committable is True.', NULL, NULL, 'control'),
292
- ('STORAGE_UNIT', 'mu_upper', 'Shadow Price Upper', 'float', 'currency/MWh', '0', 'timeseries', FALSE, FALSE, 'Shadow price of upper p_nom limit', NULL, NULL, 'economics'),
293
- ('STORAGE_UNIT', 'mu_lower', 'Shadow Price Lower', 'float', 'currency/MWh', '0', 'timeseries', FALSE, FALSE, 'Shadow price of lower p_nom limit', NULL, NULL, 'economics'),
294
- ('STORAGE_UNIT', 'p_dispatch', 'Active Power Dispatch', 'float', 'MW', '0', 'timeseries', FALSE, FALSE, 'active power dispatch at bus', NULL, NULL, 'power'),
295
- ('STORAGE_UNIT', 'p_store', 'Active Power Charging', 'float', 'MW', '0', 'timeseries', FALSE, FALSE, 'active power charging at bus', NULL, NULL, 'power'),
296
- ('STORAGE_UNIT', 'mu_state_of_charge_set', 'Shadow Price SOC Set', 'float', 'currency/MWh', '0', 'timeseries', FALSE, FALSE, 'Shadow price of fixed state of charge state_of_charge_set', NULL, NULL, 'economics'),
297
- ('STORAGE_UNIT', 'mu_energy_balance', 'Shadow Price Energy Balance', 'float', 'currency/MWh', '0', 'timeseries', FALSE, FALSE, 'Shadow price of storage consistency equations', NULL, NULL, 'economics');
286
+ ('STORAGE_UNIT', 'p', 'Active Power', 'float', 'MW', '0', 'timeseries', FALSE, FALSE, 'active power at bus (positive if discharging)', NULL, NULL, 'electrical'),
287
+ ('STORAGE_UNIT', 'q', 'Reactive Power', 'float', 'MVar', '0', 'timeseries', FALSE, FALSE, 'reactive power at bus', NULL, NULL, 'electrical'),
288
+ ('STORAGE_UNIT', 'state_of_charge', 'State of Charge', 'float', 'MWh', '0', 'timeseries', FALSE, FALSE, 'State of charge of storage unit', 0, NULL, 'energy'),
289
+ ('STORAGE_UNIT', 'p_nom_opt', 'Optimised Nominal Power', 'float', 'MW', '0', 'static', FALSE, FALSE, 'Optimised nominal power (p_nom) from capacity expansion optimization.', 0, NULL, 'capacity'),
290
+ ('STORAGE_UNIT', 'spill', 'Spill', 'float', 'MWh', '0', 'timeseries', FALSE, FALSE, 'Spillage of storage unit', 0, NULL, 'electrical'),
291
+ ('STORAGE_UNIT', 'status', 'Status', 'float', 'n/a', '1', 'timeseries', FALSE, FALSE, 'Status (1 is on, 0 is off). Only outputted if committable (committable) is True.', NULL, NULL, 'unit_commitment'),
292
+ ('STORAGE_UNIT', 'mu_upper', 'Shadow Price Upper', 'float', 'currency/MWh', '0', 'timeseries', FALSE, FALSE, 'Shadow price of upper nominal power (p_nom) limit', NULL, NULL, 'costs'),
293
+ ('STORAGE_UNIT', 'mu_lower', 'Shadow Price Lower', 'float', 'currency/MWh', '0', 'timeseries', FALSE, FALSE, 'Shadow price of lower nominal power (p_nom) limit', NULL, NULL, 'costs'),
294
+ ('STORAGE_UNIT', 'p_dispatch', 'Active Power Dispatch', 'float', 'MW', '0', 'timeseries', FALSE, FALSE, 'active power dispatch at bus', NULL, NULL, 'electrical'),
295
+ ('STORAGE_UNIT', 'p_store', 'Active Power Charging', 'float', 'MW', '0', 'timeseries', FALSE, FALSE, 'active power charging at bus', NULL, NULL, 'electrical'),
296
+ ('STORAGE_UNIT', 'mu_state_of_charge_set', 'Shadow Price SOC Set', 'float', 'currency/MWh', '0', 'timeseries', FALSE, FALSE, 'Shadow price of fixed state of charge setpoint (state_of_charge_set)', NULL, NULL, 'costs'),
297
+ ('STORAGE_UNIT', 'mu_energy_balance', 'Shadow Price Energy Balance', 'float', 'currency/MWh', '0', 'timeseries', FALSE, FALSE, 'Shadow price of storage consistency equations', NULL, NULL, 'costs');
298
298
 
299
299
  -- ============================================================================
300
300
  -- STORE ATTRIBUTES
@@ -303,37 +303,104 @@ INSERT INTO attribute_validation_rules (component_type, attribute_name, display_
303
303
  -- STORE attributes from stores.csv (PyPSA reference) - Updated to simplified groups
304
304
  INSERT INTO attribute_validation_rules (component_type, attribute_name, display_name, data_type, unit, default_value, allowed_storage_types, is_required, is_input, description, min_value, max_value, group_name) VALUES
305
305
  -- Input attributes for STORE
306
- ('STORE', 'type', 'Store Type', 'string', 'n/a', 'n/a', 'static', FALSE, TRUE, 'Placeholder for store type. Not yet implemented.', NULL, NULL, 'basic'),
307
- ('STORE', 'carrier', 'Energy Carrier', 'string', 'n/a', '', 'static', FALSE, TRUE, 'Energy carrier of the Store, e.g. "heat" or "gas".', NULL, NULL, 'basic'),
308
- ('STORE', 'e_nom', 'Nominal Energy Capacity', 'float', 'MWh', '0', 'static', FALSE, TRUE, 'Nominal energy capacity.', 0, NULL, 'power'),
309
- ('STORE', 'e_nom_mod', 'Nominal Energy Module', 'float', 'MWh', '0', 'static', FALSE, TRUE, 'Nominal energy capacity of the store module.', 0, NULL, 'power'),
310
- ('STORE', 'e_nom_extendable', 'Extendable Energy Capacity', 'boolean', 'n/a', 'False', 'static', FALSE, TRUE, 'Switch to allow capacity e_nom to be extended in OPF.', NULL, NULL, 'power'),
311
- ('STORE', 'e_nom_min', 'Min Energy Capacity', 'float', 'MWh', '0', 'static', FALSE, TRUE, 'If e_nom is extendable in OPF, set its minimum value.', 0, NULL, 'power'),
312
- ('STORE', 'e_nom_max', 'Max Energy Capacity', 'float', 'MWh', 'inf', 'static', FALSE, TRUE, 'If e_nom is extendable in OPF, set its maximum value (e.g. limited by technical potential).', 0, NULL, 'power'),
313
- ('STORE', 'e_min_pu', 'Min Energy Factor', 'float', 'per unit', '0', 'static_or_timeseries', FALSE, TRUE, 'Minimal value of e relative to e_nom for the OPF.', 0, 1, 'power'),
314
- ('STORE', 'e_max_pu', 'Max Energy Factor', 'float', 'per unit', '1', 'static_or_timeseries', FALSE, TRUE, 'Maximal value of e relative to e_nom for the OPF.', 0, 1, 'power'),
315
- ('STORE', 'e_initial', 'Initial Energy', 'float', 'MWh', '0', 'static', FALSE, TRUE, 'Energy before the snapshots in the OPF.', 0, NULL, 'power'),
316
- ('STORE', 'e_initial_per_period', 'Initial Energy per Period', 'boolean', 'n/a', 'False', 'static', FALSE, TRUE, 'Switch: if True, then at the beginning of each investment period e is set to e_initial', NULL, NULL, 'power'),
317
- ('STORE', 'e_cyclic', 'Cyclic Energy', 'boolean', 'n/a', 'False', 'static', FALSE, TRUE, 'Switch: if True, then e_initial is ignored and the initial energy is set to the final energy for the group of snapshots in the OPF.', NULL, NULL, 'power'),
318
- ('STORE', 'e_cyclic_per_period', 'Cyclic Energy per Period', 'boolean', 'n/a', 'True', 'static', FALSE, TRUE, 'Switch: if True, then the cyclic constraints are applied to each period (first snapshot level if multiindexed) separately.', NULL, NULL, 'power'),
319
- ('STORE', 'p_set', 'Active Power Setpoint', 'float', 'MW', '0', 'static_or_timeseries', FALSE, TRUE, 'active power set point (for PF)', NULL, NULL, 'power'),
320
- ('STORE', 'q_set', 'Reactive Power Setpoint', 'float', 'MVar', '0', 'static_or_timeseries', FALSE, TRUE, 'reactive power set point (for PF)', NULL, NULL, 'power'),
321
- ('STORE', 'sign', 'Power Sign', 'float', 'n/a', '1', 'static', FALSE, TRUE, 'power sign', NULL, NULL, 'power'),
322
- ('STORE', 'marginal_cost', 'Marginal Cost', 'float', 'currency/MWh', '0', 'static_or_timeseries', FALSE, TRUE, 'Marginal cost applied to both charging and discharging of 1 MWh.', 0, NULL, 'economics'),
323
- ('STORE', 'marginal_cost_quadratic', 'Quadratic Marginal Cost', 'float', 'currency/MWh', '0', 'static_or_timeseries', FALSE, TRUE, 'Quadratic marginal cost of applied to charging and discharging of 1 MWh.', 0, NULL, 'economics'),
324
- ('STORE', 'marginal_cost_storage', 'Storage Marginal Cost', 'float', 'currency/MWh/h', '0', 'static_or_timeseries', FALSE, TRUE, 'Marginal cost of energy storage of 1 MWh for one hour.', 0, NULL, 'economics'),
325
- ('STORE', 'capital_cost', 'Capital Cost', 'float', 'currency/MWh', '0', 'static', FALSE, TRUE, 'Fixed period costs of extending e_nom by 1 MWh, including periodized investment costs and periodic fixed O&M costs (e.g. annuitized investment costs).', 0, NULL, 'economics'),
326
- ('STORE', 'standing_loss', 'Standing Loss', 'float', 'per unit', '0', 'static_or_timeseries', FALSE, TRUE, 'Losses per hour to energy.', 0, 1, 'power'),
327
- ('STORE', 'active', 'Active', 'boolean', 'n/a', 'True', 'static', FALSE, TRUE, 'Whether to consider the component in basic functionality or not', NULL, NULL, 'basic'),
328
- ('STORE', 'build_year', 'Build Year', 'int', 'year', '0', 'static', FALSE, TRUE, 'build year', 0, 3000, 'economics'),
329
- ('STORE', 'lifetime', 'Lifetime', 'float', 'years', 'inf', 'static', FALSE, TRUE, 'lifetime', 0, NULL, 'economics'),
306
+ ('STORE', 'type', 'Type', 'string', 'n/a', 'n/a', 'static', FALSE, TRUE, 'Placeholder for store type. Not yet implemented.', NULL, NULL, 'basic'),
307
+ ('STORE', 'carrier', 'Carrier', 'string', 'n/a', '', 'static', FALSE, TRUE, 'Carrier type for the store (e.g. heat, gas, hydrogen). Used for categorization and energy balance constraints.', NULL, NULL, 'basic'),
308
+ ('STORE', 'e_nom', 'Nominal Energy Capacity', 'float', 'MWh', '0', 'static', TRUE, TRUE, 'The maximum energy storage capacity of the store in MWh. This sets the upper limit for the amount of energy that can be stored.', 0, NULL, 'capacity'),
309
+ ('STORE', 'e_nom_mod', 'Nominal Energy Module', 'float', 'MWh', '0', 'static', FALSE, TRUE, 'The unit size for capacity expansion. When extending the nominal energy capacity (e_nom), it can only be increased in multiples of this module size.', 0, NULL, 'capacity'),
310
+ ('STORE', 'e_nom_extendable', 'Extendable Energy Capacity', 'boolean', 'n/a', 'False', 'static', FALSE, TRUE, 'Switch to allow the nominal energy capacity (e_nom) to be extended in optimization.', NULL, NULL, 'capacity'),
311
+ ('STORE', 'e_nom_min', 'Min Energy Capacity', 'float', 'MWh', '0', 'static', FALSE, TRUE, 'If the nominal energy capacity (e_nom) is extendable in optimization, set its minimum value.', 0, NULL, 'capacity'),
312
+ ('STORE', 'e_nom_max', 'Max Energy Capacity', 'float', 'MWh', 'inf', 'static', FALSE, TRUE, 'If the nominal energy capacity (e_nom) is extendable in optimization, set its maximum value (e.g. limited by technical potential).', 0, NULL, 'capacity'),
313
+ ('STORE', 'e_min_pu', 'Min Energy Factor', 'float', 'per unit', '0', 'static_or_timeseries', FALSE, TRUE, 'The minimum stored energy per unit of the nominal energy capacity (e_nom). Can be static or time-varying.', 0, 1, 'energy'),
314
+ ('STORE', 'e_max_pu', 'Max Energy Factor', 'float', 'per unit', '1', 'static_or_timeseries', FALSE, TRUE, 'The maximum stored energy per unit of the nominal energy capacity (e_nom). Can be static or time-varying.', 0, 1, 'energy'),
315
+ ('STORE', 'e_initial', 'Initial Energy', 'float', 'MWh', '0', 'static', FALSE, TRUE, 'The energy stored at the beginning of the optimization period, before the first snapshot. Ignored if cyclic energy (e_cyclic) is True.', 0, NULL, 'energy'),
316
+ ('STORE', 'e_initial_per_period', 'Initial Energy per Period', 'boolean', 'n/a', 'False', 'static', FALSE, TRUE, 'If True, the initial energy (e_initial) is applied at the beginning of each investment period separately, rather than only at the start of the entire optimization horizon.', NULL, NULL, 'energy'),
317
+ ('STORE', 'e_cyclic', 'Cyclic Energy', 'boolean', 'n/a', 'False', 'static', FALSE, TRUE, 'If True, the initial energy (e_initial) is ignored and the store must end with the same energy as it started (cyclic constraint). This ensures the store returns to its initial state at the end of the optimization period.', NULL, NULL, 'energy'),
318
+ ('STORE', 'e_cyclic_per_period', 'Cyclic Energy per Period', 'boolean', 'n/a', 'True', 'static', FALSE, TRUE, 'If True, the cyclic energy constraint (e_cyclic) is applied to each investment period separately, rather than only to the entire optimization horizon.', NULL, NULL, 'energy'),
319
+ ('STORE', 'p_set', 'Active Power Setpoint', 'float', 'MW', '0', 'static_or_timeseries', FALSE, TRUE, 'Fixed active power flow that the store must maintain (positive for withdrawing energy from the bus, negative for injecting energy into the bus). Used when the power flow is predetermined rather than optimized.', NULL, NULL, 'power_limits'),
320
+ ('STORE', 'q_set', 'Reactive Power Setpoint', 'float', 'MVar', '0', 'static_or_timeseries', FALSE, TRUE, 'Fixed reactive power flow that the store must maintain. Used when the reactive power flow is predetermined rather than optimized.', NULL, NULL, 'power_limits'),
321
+ ('STORE', 'sign', 'Power Sign', 'float', 'n/a', '1', 'static', FALSE, TRUE, 'Power flow direction convention: 1 for generation/discharging (positive power flows into the network), -1 for consumption/charging (positive power flows out of the network).', NULL, NULL, 'power_limits'),
322
+ ('STORE', 'marginal_cost', 'Marginal Cost', 'float', 'currency/MWh', '0', 'static_or_timeseries', FALSE, TRUE, 'The variable cost applied to both charging and discharging 1 MWh of energy. Used by the optimizer to determine the economic dispatch order.', 0, NULL, 'costs'),
323
+ ('STORE', 'marginal_cost_quadratic', 'Quadratic Marginal Cost', 'float', 'currency/MWh', '0', 'static_or_timeseries', FALSE, TRUE, 'Quadratic term for non-linear cost curves. When set, the total cost includes a quadratic component that increases with the square of energy flow, modeling increasing marginal costs at higher flow levels.', 0, NULL, 'costs'),
324
+ ('STORE', 'marginal_cost_storage', 'Storage Marginal Cost', 'float', 'currency/MWh/h', '0', 'static_or_timeseries', FALSE, TRUE, 'The variable cost of storing 1 MWh of energy for one hour. This represents the opportunity cost or wear-and-tear cost associated with storing energy in the store.', 0, NULL, 'costs'),
325
+ ('STORE', 'capital_cost', 'Capital Cost', 'float', 'currency/MWh', '0', 'static', FALSE, TRUE, 'The cost per MWh of adding new storage capacity. Includes investment costs (spread over the planning period) and fixed operations & maintenance costs. Only relevant when extendable capacity (e_nom_extendable) is True.', 0, NULL, 'costs'),
326
+ ('STORE', 'standing_loss', 'Standing Loss', 'float', 'per unit', '0', 'static_or_timeseries', FALSE, TRUE, 'The self-discharge rate per hour, expressed as a fraction of the current stored energy. Represents energy losses that occur even when the store is idle (e.g., thermal losses, leakage). Can be time-varying.', 0, 1, 'energy'),
327
+ ('STORE', 'active', 'Active', 'boolean', 'n/a', 'True', 'static', FALSE, TRUE, 'Whether this store is active and should be included in network calculations. Set to False to temporarily disable the store without deleting it.', NULL, NULL, 'basic'),
328
+ ('STORE', 'build_year', 'Build Year', 'int', 'year', '0', 'static', FALSE, TRUE, 'The year when the store can be built or commissioned. Essential for multi-year capacity expansion planning models, which determine optimal investment timing and store retirement schedules.', 0, 3000, 'capacity'),
329
+ ('STORE', 'lifetime', 'Lifetime', 'float', 'years', 'inf', 'static', FALSE, TRUE, 'The operational lifetime of the store in years. Essential for multi-year capacity expansion planning models, which use this to determine when stores retire (build year (build_year) + lifetime). Set to "inf" for stores that never retire.', 0, NULL, 'capacity'),
330
330
  -- Output attributes for STORE (PyPSA store outputs)
331
- ('STORE', 'p', 'Active Power', 'float', 'MW', '0', 'timeseries', FALSE, FALSE, 'active power at bus (positive if withdrawing energy)', NULL, NULL, 'power'),
332
- ('STORE', 'q', 'Reactive Power', 'float', 'MVar', '0', 'timeseries', FALSE, FALSE, 'reactive power at bus', NULL, NULL, 'power'),
333
- ('STORE', 'e', 'Energy', 'float', 'MWh', '0', 'timeseries', FALSE, FALSE, 'Energy stored in store', 0, NULL, 'power'),
334
- ('STORE', 'e_nom_opt', 'Optimised Energy Capacity', 'float', 'MWh', '0', 'static', FALSE, FALSE, 'Optimised energy capacity.', 0, NULL, 'power'),
335
- ('STORE', 'mu_upper', 'Shadow Price Upper', 'float', 'currency/MWh', '0', 'timeseries', FALSE, FALSE, 'Shadow price of upper energy limit', NULL, NULL, 'economics'),
336
- ('STORE', 'mu_lower', 'Shadow Price Lower', 'float', 'currency/MWh', '0', 'timeseries', FALSE, FALSE, 'Shadow price of lower energy limit', NULL, NULL, 'economics');
331
+ ('STORE', 'p', 'Active Power', 'float', 'MW', '0', 'timeseries', FALSE, FALSE, 'active power at bus (positive if withdrawing energy)', NULL, NULL, 'electrical'),
332
+ ('STORE', 'q', 'Reactive Power', 'float', 'MVar', '0', 'timeseries', FALSE, FALSE, 'reactive power at bus', NULL, NULL, 'electrical'),
333
+ ('STORE', 'e', 'Energy', 'float', 'MWh', '0', 'timeseries', FALSE, FALSE, 'Energy stored in store', 0, NULL, 'electrical'),
334
+ ('STORE', 'e_nom_opt', 'Optimised Energy Capacity', 'float', 'MWh', '0', 'static', FALSE, FALSE, 'Optimised nominal energy capacity (e_nom) from capacity expansion optimization.', 0, NULL, 'capacity'),
335
+ ('STORE', 'mu_upper', 'Shadow Price Upper', 'float', 'currency/MWh', '0', 'timeseries', FALSE, FALSE, 'Shadow price of upper energy limit (e_max_pu × e_nom)', NULL, NULL, 'costs'),
336
+ ('STORE', 'mu_lower', 'Shadow Price Lower', 'float', 'currency/MWh', '0', 'timeseries', FALSE, FALSE, 'Shadow price of lower energy limit (e_min_pu × e_nom)', NULL, NULL, 'costs');
337
+
338
+ -- ============================================================================
339
+ -- TRANSFORMER ATTRIBUTES
340
+ -- ============================================================================
341
+
342
+ -- TRANSFORMER attributes from transformers.csv (PyPSA reference) - Updated to simplified groups
343
+ INSERT INTO attribute_validation_rules (component_type, attribute_name, display_name, data_type, unit, default_value, allowed_storage_types, is_required, is_input, description, min_value, max_value, group_name) VALUES
344
+ -- Input attributes for TRANSFORMER
345
+ ('TRANSFORMER', 'bus0', 'Origin Bus', 'string', 'n/a', 'n/a', 'static', TRUE, TRUE, 'Name of the origin bus (typically higher voltage) to which the transformer is attached.', NULL, NULL, 'basic'),
346
+ ('TRANSFORMER', 'bus1', 'Destination Bus', 'string', 'n/a', 'n/a', 'static', TRUE, TRUE, 'Name of the destination bus (typically lower voltage) to which the transformer is attached.', NULL, NULL, 'basic'),
347
+ ('TRANSFORMER', 'type', 'Type', 'string', 'n/a', 'n/a', 'static', FALSE, TRUE, 'Name of a predefined transformer standard type. If set, the transformer type impedance parameters are automatically calculated, overriding any manually set values for series reactance (x), series resistance (r), shunt susceptance (b), nominal apparent power (s_nom), tap ratio (tap_ratio), tap side (tap_side), and phase shift (phase_shift). Leave empty to manually specify impedance parameters.', NULL, NULL, 'basic'),
348
+ ('TRANSFORMER', 'model', 'Transformer Model', 'string', 'n/a', 't', 'static', TRUE, TRUE, 'Model used for admittance matrix: "t" or "pi". Defaults to "t" following physics and DIgSILENT PowerFactory conventions.', NULL, NULL, 'basic'),
349
+ ('TRANSFORMER', 'x', 'Series Reactance', 'float', 'per unit', '0', 'static', TRUE, TRUE, 'The series reactance in per unit (using nominal apparent power (s_nom) as base power). Must be non-zero for AC transformers in linear power flow. The series impedance is z = r + jx. Ignored if transformer type (type) is set.', NULL, NULL, 'electrical'),
350
+ ('TRANSFORMER', 'r', 'Series Resistance', 'float', 'per unit', '0', 'static', TRUE, TRUE, 'The series resistance in per unit (using nominal apparent power (s_nom) as base power). Must be non-zero for DC transformers in linear power flow. The series impedance is z = r + jx. Ignored if transformer type (type) is set.', NULL, NULL, 'electrical'),
351
+ ('TRANSFORMER', 'g', 'Shunt Conductance', 'float', 'per unit', '0', 'static', FALSE, TRUE, 'The shunt conductance in per unit (using nominal apparent power (s_nom) as base power). The shunt admittance is y = g + jb, where b is the shunt susceptance (b). Ignored if transformer type (type) is set.', NULL, NULL, 'electrical'),
352
+ ('TRANSFORMER', 'b', 'Shunt Susceptance', 'float', 'per unit', '0', 'static', FALSE, TRUE, 'The shunt susceptance in per unit (using nominal apparent power (s_nom) as base power). The shunt admittance is y = g + jb, where g is the shunt conductance (g). Ignored if transformer type (type) is set.', NULL, NULL, 'electrical'),
353
+ ('TRANSFORMER', 's_nom', 'Nominal Apparent Power', 'float', 'MVA', '0', 'static', FALSE, TRUE, 'The maximum apparent power capacity of the transformer in MVA. This sets the limit for power flow through the transformer in either direction. Ignored if extendable capacity (s_nom_extendable) is True.', 0, NULL, 'capacity'),
354
+ ('TRANSFORMER', 's_nom_mod', 'Nominal Apparent Power Module', 'float', 'MVA', '0', 'static', FALSE, TRUE, 'The unit size for capacity expansion. When extending the nominal apparent power (s_nom), it can only be increased in multiples of this module size. Introduces integer variables in optimization.', 0, NULL, 'capacity'),
355
+ ('TRANSFORMER', 's_nom_extendable', 'Extendable Capacity', 'boolean', 'n/a', 'False', 'static', FALSE, TRUE, 'Switch to allow the nominal apparent power (s_nom) to be extended in optimization.', NULL, NULL, 'capacity'),
356
+ ('TRANSFORMER', 's_nom_min', 'Min Nominal Apparent Power', 'float', 'MVA', '0', 'static', FALSE, TRUE, 'If the nominal apparent power (s_nom) is extendable in optimization, set its minimum value.', 0, NULL, 'capacity'),
357
+ ('TRANSFORMER', 's_nom_max', 'Max Nominal Apparent Power', 'float', 'MVA', 'inf', 'static', FALSE, TRUE, 'If the nominal apparent power (s_nom) is extendable in optimization, set its maximum value (e.g. limited by technical potential).', 0, NULL, 'capacity'),
358
+ ('TRANSFORMER', 's_nom_set', 'Nominal Apparent Power Setpoint', 'float', 'MVA', 'n/a', 'static', FALSE, TRUE, 'If the nominal apparent power (s_nom) is extendable in optimization, set the value of the optimized nominal apparent power (s_nom_opt).', 0, NULL, 'capacity'),
359
+ ('TRANSFORMER', 's_max_pu', 'Max Capacity Factor', 'float', 'per unit', '1', 'static_or_timeseries', FALSE, TRUE, 'The maximum allowed absolute flow per unit of the nominal apparent power (s_nom). Can be set less than 1 to account for security margins (e.g., n-1 contingency), or can be time-varying to represent weather-dependent dynamic rating.', 0, NULL, 'power_limits'),
360
+ ('TRANSFORMER', 'capital_cost', 'Capital Cost', 'float', 'currency/MVA', '0', 'static', FALSE, TRUE, 'The cost per MVA of adding new transformer capacity. Includes investment costs (spread over the planning period) and fixed operations & maintenance costs. Only relevant when extendable capacity (s_nom_extendable) is True.', 0, NULL, 'costs'),
361
+ ('TRANSFORMER', 'num_parallel', 'Number of Parallel Transformers', 'float', 'n/a', '1', 'static', FALSE, TRUE, 'The number of parallel transformers (can be fractional). When transformer type (type) is set, this is used to calculate the total impedance (more parallel transformers reduce effective impedance). If transformer type (type) is empty, this value is ignored.', 0, NULL, 'electrical'),
362
+ ('TRANSFORMER', 'tap_ratio', 'Tap Ratio', 'float', 'per unit', '1', 'static', FALSE, TRUE, 'Ratio of per unit voltages at each bus for tap changer. A value of 1.0 means no voltage transformation. Ignored if transformer type (type) is set.', NULL, NULL, 'electrical'),
363
+ ('TRANSFORMER', 'tap_side', 'Tap Side', 'int', 'n/a', '0', 'static', FALSE, TRUE, 'Defines if the tap changer is modeled at the primary side (bus0, usually high-voltage, value 0) or the secondary side (bus1, usually low-voltage, value 1). Must be 0 or 1. Ignored if transformer type (type) is set.', 0, 1, 'electrical'),
364
+ ('TRANSFORMER', 'tap_position', 'Tap Position', 'int', 'n/a', '0', 'static', FALSE, TRUE, 'If the transformer has a transformer type (type), determines the tap position relative to the neutral tap position.', NULL, NULL, 'electrical'),
365
+ ('TRANSFORMER', 'phase_shift', 'Phase Shift', 'float', 'Degrees', '0', 'static', FALSE, TRUE, 'Voltage phase angle shift in degrees. Used to model phase-shifting transformers. Ignored if transformer type (type) is set.', NULL, NULL, 'electrical'),
366
+ ('TRANSFORMER', 'active', 'Active', 'boolean', 'n/a', 'True', 'static', FALSE, TRUE, 'Whether this transformer is active and should be included in network calculations. Set to False to temporarily disable the transformer without deleting it.', NULL, NULL, 'basic'),
367
+ ('TRANSFORMER', 'build_year', 'Build Year', 'int', 'year', '0', 'static', FALSE, TRUE, 'The year when the transformer can be built or commissioned. Essential for multi-year capacity expansion planning models, which determine optimal investment timing and transformer retirement schedules.', 0, 3000, 'capacity'),
368
+ ('TRANSFORMER', 'lifetime', 'Lifetime', 'float', 'years', 'inf', 'static', FALSE, TRUE, 'The operational lifetime of the transformer in years. Essential for multi-year capacity expansion planning models, which use this to determine when transformers retire (build year (build_year) + lifetime). Set to "inf" for transformers that never retire.', 0, NULL, 'capacity'),
369
+ ('TRANSFORMER', 'v_ang_min', 'Min Voltage Angle Difference', 'float', 'Degrees', '-inf', 'static', FALSE, TRUE, 'Minimum voltage angle difference across the transformer in degrees. This is a placeholder attribute and is not currently used by any functions.', NULL, NULL, 'electrical'),
370
+ ('TRANSFORMER', 'v_ang_max', 'Max Voltage Angle Difference', 'float', 'Degrees', 'inf', 'static', FALSE, TRUE, 'Maximum voltage angle difference across the transformer in degrees. This is a placeholder attribute and is not currently used by any functions.', NULL, NULL, 'electrical'),
371
+ -- Output attributes for TRANSFORMER (PyPSA transformer outputs)
372
+ ('TRANSFORMER', 'sub_network', 'Sub Network', 'string', 'n/a', 'n/a', 'static', FALSE, FALSE, 'Name of connected sub-network to which transformer belongs, as calculated by network topology analysis. Do not set manually.', NULL, NULL, 'basic'),
373
+ ('TRANSFORMER', 'p0', 'Active Power Bus0', 'float', 'MW', '0', 'timeseries', FALSE, FALSE, 'Active power at bus0 (positive if branch is withdrawing power from bus0)', NULL, NULL, 'electrical'),
374
+ ('TRANSFORMER', 'q0', 'Reactive Power Bus0', 'float', 'MVar', '0', 'timeseries', FALSE, FALSE, 'Reactive power at bus0 (positive if branch is withdrawing power from bus0)', NULL, NULL, 'electrical'),
375
+ ('TRANSFORMER', 'p1', 'Active Power Bus1', 'float', 'MW', '0', 'timeseries', FALSE, FALSE, 'Active power at bus1 (positive if branch is withdrawing power from bus1)', NULL, NULL, 'electrical'),
376
+ ('TRANSFORMER', 'q1', 'Reactive Power Bus1', 'float', 'MVar', '0', 'timeseries', FALSE, FALSE, 'Reactive power at bus1 (positive if branch is withdrawing power from bus1)', NULL, NULL, 'electrical'),
377
+ ('TRANSFORMER', 'x_pu', 'Per Unit Series Reactance', 'float', 'per unit', '0', 'static', FALSE, FALSE, 'Per unit series reactance calculated from the series reactance (x) and the nominal voltage (v_nom) of the connected buses.', NULL, NULL, 'electrical'),
378
+ ('TRANSFORMER', 'r_pu', 'Per Unit Series Resistance', 'float', 'per unit', '0', 'static', FALSE, FALSE, 'Per unit series resistance calculated from the series resistance (r) and the nominal voltage (v_nom) of the connected buses.', NULL, NULL, 'electrical'),
379
+ ('TRANSFORMER', 'g_pu', 'Per Unit Shunt Conductance', 'float', 'per unit', '0', 'static', FALSE, FALSE, 'Per unit shunt conductance calculated from the shunt conductance (g) and the nominal voltage (v_nom) of the connected buses.', NULL, NULL, 'electrical'),
380
+ ('TRANSFORMER', 'b_pu', 'Per Unit Shunt Susceptance', 'float', 'per unit', '0', 'static', FALSE, FALSE, 'Per unit shunt susceptance calculated from the shunt susceptance (b) and the nominal voltage (v_nom) of the connected buses.', NULL, NULL, 'electrical'),
381
+ ('TRANSFORMER', 'x_pu_eff', 'Effective Per Unit Series Reactance', 'float', 'per unit', '0', 'static', FALSE, FALSE, 'Effective per unit series reactance for linear power flow, calculated from the series reactance (x), tap ratio (tap_ratio), and the nominal voltage (v_nom) of the connected buses.', NULL, NULL, 'electrical'),
382
+ ('TRANSFORMER', 'r_pu_eff', 'Effective Per Unit Series Resistance', 'float', 'per unit', '0', 'static', FALSE, FALSE, 'Effective per unit series resistance for linear power flow, calculated from the series resistance (r), tap ratio (tap_ratio), and the nominal voltage (v_nom) of the connected buses.', NULL, NULL, 'electrical'),
383
+ ('TRANSFORMER', 's_nom_opt', 'Optimised Nominal Apparent Power', 'float', 'MVA', '0', 'static', FALSE, FALSE, 'Optimised nominal apparent power (s_nom) from capacity expansion optimization.', 0, NULL, 'capacity'),
384
+ ('TRANSFORMER', 'mu_lower', 'Shadow Price Lower', 'float', 'currency/MVA', '0', 'timeseries', FALSE, FALSE, 'Shadow price of lower nominal apparent power (s_nom) limit. Always non-negative.', NULL, NULL, 'costs'),
385
+ ('TRANSFORMER', 'mu_upper', 'Shadow Price Upper', 'float', 'currency/MVA', '0', 'timeseries', FALSE, FALSE, 'Shadow price of upper nominal apparent power (s_nom) limit. Always non-negative.', NULL, NULL, 'costs');
386
+
387
+ -- ============================================================================
388
+ -- SHUNT_IMPEDANCE ATTRIBUTES
389
+ -- ============================================================================
390
+
391
+ -- SHUNT_IMPEDANCE attributes from shunt_impedances.csv (PyPSA reference) - Updated to simplified groups
392
+ INSERT INTO attribute_validation_rules (component_type, attribute_name, display_name, data_type, unit, default_value, allowed_storage_types, is_required, is_input, description, min_value, max_value, group_name) VALUES
393
+ -- Input attributes for SHUNT_IMPEDANCE
394
+ ('SHUNT_IMPEDANCE', 'bus', 'Bus', 'string', 'n/a', 'n/a', 'static', TRUE, TRUE, 'Name of the bus to which the shunt impedance is attached.', NULL, NULL, 'basic'),
395
+ ('SHUNT_IMPEDANCE', 'g', 'Shunt Conductance', 'float', 'Siemens', '0', 'static', FALSE, TRUE, 'The shunt conductance in Siemens. Positive values withdraw active power from the bus. The shunt admittance is y = g + jb, where b is the shunt susceptance (b).', NULL, NULL, 'electrical'),
396
+ ('SHUNT_IMPEDANCE', 'b', 'Shunt Susceptance', 'float', 'Siemens', '0', 'static', FALSE, TRUE, 'The shunt susceptance in Siemens. Positive values withdraw reactive power from the bus (inductive). The shunt admittance is y = g + jb, where g is the shunt conductance (g).', NULL, NULL, 'electrical'),
397
+ ('SHUNT_IMPEDANCE', 'sign', 'Power Sign', 'float', 'n/a', '-1', 'static', FALSE, TRUE, 'Power flow direction convention: -1 means positive conductance (g) withdraws active power (p) from the bus, 1 means positive conductance (g) injects active power (p) into the bus.', NULL, NULL, 'power_limits'),
398
+ ('SHUNT_IMPEDANCE', 'active', 'Active', 'boolean', 'n/a', 'True', 'static', FALSE, TRUE, 'Whether this shunt impedance is active and should be included in network calculations. Set to False to temporarily disable the shunt impedance without deleting it.', NULL, NULL, 'basic'),
399
+ -- Output attributes for SHUNT_IMPEDANCE (PyPSA shunt impedance outputs)
400
+ ('SHUNT_IMPEDANCE', 'p', 'Active Power', 'float', 'MW', '0', 'timeseries', FALSE, FALSE, 'Active power at bus (positive if net load)', NULL, NULL, 'electrical'),
401
+ ('SHUNT_IMPEDANCE', 'q', 'Reactive Power', 'float', 'MVar', '0', 'timeseries', FALSE, FALSE, 'Reactive power at bus (positive if net generation)', NULL, NULL, 'electrical'),
402
+ ('SHUNT_IMPEDANCE', 'g_pu', 'Per Unit Shunt Conductance', 'float', 'per unit', '0', 'static', FALSE, FALSE, 'Per unit shunt conductance calculated from the shunt conductance (g) and the nominal voltage (v_nom) of the connected bus.', NULL, NULL, 'electrical'),
403
+ ('SHUNT_IMPEDANCE', 'b_pu', 'Per Unit Shunt Susceptance', 'float', 'per unit', '0', 'static', FALSE, FALSE, 'Per unit shunt susceptance calculated from the shunt susceptance (b) and the nominal voltage (v_nom) of the connected bus.', NULL, NULL, 'electrical');
337
404
 
338
405
  -- ============================================================================
339
406
  -- CONSTRAINT ATTRIBUTES
@@ -362,7 +429,6 @@ BEGIN
362
429
  SELECT 1 FROM carriers
363
430
  WHERE id = NEW.carrier_id
364
431
  AND name IN ('AC', 'DC', 'heat', 'gas')
365
- AND network_id = NEW.network_id
366
432
  ) THEN
367
433
  RAISE(ABORT, 'Buses can only use AC, DC, heat, or gas carriers')
368
434
  END;
@@ -379,7 +445,6 @@ BEGIN
379
445
  SELECT 1 FROM carriers
380
446
  WHERE id = NEW.carrier_id
381
447
  AND name IN ('AC', 'DC', 'heat', 'gas')
382
- AND network_id = NEW.network_id
383
448
  ) THEN
384
449
  RAISE(ABORT, 'Buses can only use AC, DC, heat, or gas carriers')
385
450
  END;
@@ -396,7 +461,6 @@ BEGIN
396
461
  SELECT 1 FROM carriers
397
462
  WHERE id = NEW.carrier_id
398
463
  AND name = 'AC'
399
- AND network_id = NEW.network_id
400
464
  ) THEN
401
465
  RAISE(ABORT, 'Lines can only use AC carriers')
402
466
  END;
@@ -413,7 +477,6 @@ BEGIN
413
477
  SELECT 1 FROM carriers
414
478
  WHERE id = NEW.carrier_id
415
479
  AND name = 'AC'
416
- AND network_id = NEW.network_id
417
480
  ) THEN
418
481
  RAISE(ABORT, 'Lines can only use AC carriers')
419
482
  END;