diff --git a/data_files/temoa_schema_v4.sql b/data_files/temoa_schema_v4.sql index 8efedde6..2019e7f0 100644 --- a/data_files/temoa_schema_v4.sql +++ b/data_files/temoa_schema_v4.sql @@ -708,7 +708,7 @@ CREATE TABLE IF NOT EXISTS output_curtailment period INTEGER REFERENCES time_period (period), season TEXT - REFERENCES time_period (period), + REFERENCES season_label (season), tod TEXT REFERENCES time_of_day (tod), input_comm TEXT diff --git a/temoa/components/costs.py b/temoa/components/costs.py index a4647e64..cd22729c 100644 --- a/temoa/components/costs.py +++ b/temoa/components/costs.py @@ -113,13 +113,14 @@ def cost_variable_indices(model: TemoaModel) -> set[tuple[Region, Period, Techno def lifetime_loan_process_indices(model: TemoaModel) -> set[tuple[Region, Technology, Vintage]]: """ - Based on the efficiency parameter's indices and time_future parameter, this - function returns the set of process indices that may be specified in the - cost_invest parameter. - """ - min_period = min(model.vintage_optimize) + Based on the efficiency parameter's indices, this function returns the set of + process indices that may be specified in the loan_lifetime_process parameter. - indices = {(r, t, v) for r, i, t, v, o in model.efficiency.sparse_iterkeys() if v >= min_period} + Note: We include all efficiency vintages (not just >= min optimization period) + because in myopic mode, previously optimized vintages remain active in later + windows and their data must be accepted by the param's index set. + """ + indices = {(r, t, v) for r, i, t, v, o in model.efficiency.sparse_iterkeys()} return indices diff --git a/temoa/components/limits.py b/temoa/components/limits.py index baa4b042..3f55985a 100644 --- a/temoa/components/limits.py +++ b/temoa/components/limits.py @@ -1361,6 +1361,8 @@ def limit_new_capacity_constraint( cap_lim = value(model.limit_new_capacity[r, p, t, op]) new_cap = quicksum(model.v_new_capacity[_r, _t, p] for _t in techs for _r in regions) expr = operator_expression(new_cap, Operator(op), cap_lim) + if isinstance(expr, bool): + return Constraint.Skip return expr @@ -1383,9 +1385,14 @@ def limit_capacity_constraint( techs = technology.gather_group_techs(model, t) cap_lim = value(model.limit_capacity[r, p, t, op]) capacity = quicksum( - model.v_capacity_available_by_period_and_tech[_r, p, _t] for _t in techs for _r in regions + model.v_capacity_available_by_period_and_tech[_r, p, _t] + for _t in techs + for _r in regions + if (_r, p, _t) in model.v_capacity_available_by_period_and_tech ) expr = operator_expression(capacity, Operator(op), cap_lim) + if isinstance(expr, bool): + return Constraint.Skip return expr diff --git a/temoa/components/operations.py b/temoa/components/operations.py index ee11f26c..bcfe0356 100644 --- a/temoa/components/operations.py +++ b/temoa/components/operations.py @@ -74,7 +74,9 @@ def ramp_down_day_constraint_indices( def ramp_up_season_constraint_indices( model: TemoaModel, ) -> set[tuple[Region, Period, Season, Season, Technology, Vintage]]: - if model.time_sequencing.first() == 'consecutive_days': + # Season-to-season ramp constraints require full inter-season ordering; + # skip for consecutive_days (no season links) and seasonal_timeslices (no TOD ordering). + if model.time_sequencing.first() in ('consecutive_days', 'seasonal_timeslices'): return set() # s, s_next indexing ensures we dont build redundant constraints @@ -94,7 +96,9 @@ def ramp_up_season_constraint_indices( def ramp_down_season_constraint_indices( model: TemoaModel, ) -> set[tuple[Region, Period, Season, Season, Technology, Vintage]]: - if model.time_sequencing.first() == 'consecutive_days': + # Season-to-season ramp constraints require full inter-season ordering; + # skip for consecutive_days (no season links) and seasonal_timeslices (no TOD ordering). + if model.time_sequencing.first() in ('consecutive_days', 'seasonal_timeslices'): return set() # s, s_next indexing ensures we dont build redundant constraints diff --git a/tests/legacy_test_values.py b/tests/legacy_test_values.py index 2223cdb7..aacfd3d5 100644 --- a/tests/legacy_test_values.py +++ b/tests/legacy_test_values.py @@ -71,7 +71,8 @@ class ExpectedVals(Enum): # increased 2025/08/19 after making annual demands optional # increased by 2 after tying v_storage_level[d_last] to v_storage_init # reduced by 10 after dropping DAC for single-tech demands - ExpectedVals.CONSTR_COUNT: 232, + # reduced by 8 after disabling season ramp for seasonal_timeslices + ExpectedVals.CONSTR_COUNT: 224, # reduced 2025/07/25 by 18 after annualising demands # increased 2025/08/19 after making annual demands optional # increased by 2 after adding v_storage_init variable diff --git a/tests/testing_data/mediumville_sets.json b/tests/testing_data/mediumville_sets.json index 2c07b6ba..5c406fed 100644 --- a/tests/testing_data/mediumville_sets.json +++ b/tests/testing_data/mediumville_sets.json @@ -3788,40 +3788,7 @@ 2025 ] ], - "ramp_down_season_constraint_rpsstv": [ - [ - "A", - 2025, - "s1", - "s2", - "EH", - 2025 - ], - [ - "A", - 2025, - "s2", - "s1", - "EH", - 2025 - ], - [ - "B", - 2025, - "s1", - "s2", - "EH", - 2025 - ], - [ - "B", - 2025, - "s2", - "s1", - "EH", - 2025 - ] - ], + "ramp_down_season_constraint_rpsstv": [], "ramp_up_day_constraint_rpsdtv": [ [ "B", @@ -3888,40 +3855,7 @@ 2025 ] ], - "ramp_up_season_constraint_rpsstv": [ - [ - "A", - 2025, - "s1", - "s2", - "EH", - 2025 - ], - [ - "A", - 2025, - "s2", - "s1", - "EH", - 2025 - ], - [ - "B", - 2025, - "s1", - "s2", - "EH", - 2025 - ], - [ - "B", - 2025, - "s2", - "s1", - "EH", - 2025 - ] - ], + "ramp_up_season_constraint_rpsstv": [], "regional_exchange_capacity_constraint_rrptv": [ [ "B", diff --git a/tests/testing_data/test_system_sets.json b/tests/testing_data/test_system_sets.json index df2014de..17bb457e 100644 --- a/tests/testing_data/test_system_sets.json +++ b/tests/testing_data/test_system_sets.json @@ -42293,6 +42293,26 @@ "R1", "S_OILREF", 2020 + ], + [ + "R1", + "E_NUCLEAR", + 2015 + ], + [ + "R2", + "E_NUCLEAR", + 2015 + ], + [ + "R1-R2", + "E_TRANS", + 2015 + ], + [ + "R2-R1", + "E_TRANS", + 2015 ] ], "new_capacity_var_rtv": [ diff --git a/tests/testing_data/utopia_sets.json b/tests/testing_data/utopia_sets.json index 8be5f4a3..77181f16 100644 --- a/tests/testing_data/utopia_sets.json +++ b/tests/testing_data/utopia_sets.json @@ -23130,6 +23130,81 @@ "utopia", "RL1", 2000 + ], + [ + "utopia", + "E01", + 1960 + ], + [ + "utopia", + "E01", + 1970 + ], + [ + "utopia", + "E01", + 1980 + ], + [ + "utopia", + "E70", + 1960 + ], + [ + "utopia", + "E70", + 1970 + ], + [ + "utopia", + "E70", + 1980 + ], + [ + "utopia", + "RHO", + 1970 + ], + [ + "utopia", + "RHO", + 1980 + ], + [ + "utopia", + "TXG", + 1970 + ], + [ + "utopia", + "TXG", + 1980 + ], + [ + "utopia", + "TXD", + 1970 + ], + [ + "utopia", + "TXD", + 1980 + ], + [ + "utopia", + "E31", + 1980 + ], + [ + "utopia", + "E51", + 1980 + ], + [ + "utopia", + "RL1", + 1980 ] ], "new_capacity_var_rtv": [