From bb2ef3c89c7e47eb336bc65c29e820d0be1f28be Mon Sep 17 00:00:00 2001 From: Ana Mileva <anamileva@users.noreply.github.com> Date: Sun, 5 Jan 2025 13:46:36 -0800 Subject: [PATCH] Optionally allow slack flows in first timepoint of linear horizons (#1196) This can help avoid infeasibilities in the first timepoint of linear horizons when flows have not yet reached a particular node, making it impossible to meet a minimum flow constraint. This problem could arise in later timepoints too; slack is currently only allowed in the first timepoint of the horizon (if enabled by the user). --- .../1_base_water_system_params.csv | 4 +- db/db_schema.sql | 30 ++--- .../inputs/water_system_params.tab | 4 +- .../inputs/water_system_params.tab | 4 +- gridpath/auxiliary/module_list.py | 4 +- gridpath/objective/system/water/__init__.py | 0 ..._flow_constraint_slack_use_tuning_costs.py | 71 +++++++++++ gridpath/system/water/water_flows.py | 90 +++++++++----- gridpath/system/water/water_node_balance.py | 27 ----- gridpath/system/water/water_system_params.py | 20 +++- ..._flow_constraint_slack_use_tuning_costs.py | 110 ++++++++++++++++++ .../system/water/test_water_system_params.py | 14 +++ .../test_data/inputs/water_system_params.tab | 4 +- .../202001/2/inputs/water_system_params.tab | 4 +- 14 files changed, 305 insertions(+), 81 deletions(-) create mode 100644 gridpath/objective/system/water/__init__.py create mode 100644 gridpath/objective/system/water/aggregate_flow_constraint_slack_use_tuning_costs.py create mode 100644 tests/objective/system/water/test_aggregate_flow_constraint_slack_use_tuning_costs.py diff --git a/db/csvs_test_examples/water/water_system_params/1_base_water_system_params.csv b/db/csvs_test_examples/water/water_system_params/1_base_water_system_params.csv index 2570accee..e75469e1a 100644 --- a/db/csvs_test_examples/water/water_system_params/1_base_water_system_params.csv +++ b/db/csvs_test_examples/water/water_system_params/1_base_water_system_params.csv @@ -1,2 +1,2 @@ -water_system_balancing_type,theoretical_power_coefficient -day,84.7 \ No newline at end of file +water_system_balancing_type,theoretical_power_coefficient,allow_lin_hrz_first_tmp_flow_slack,allow_lin_hrz_first_tmp_flow_slack_tuning_cost +day,84.7,0,0 \ No newline at end of file diff --git a/db/db_schema.sql b/db/db_schema.sql index 4b1a6a781..b62f0c174 100644 --- a/db/db_schema.sql +++ b/db/db_schema.sql @@ -1057,9 +1057,11 @@ CREATE TABLE subscenarios_system_water_system_params DROP TABLE IF EXISTS inputs_system_water_system_params; CREATE TABLE inputs_system_water_system_params ( - water_system_params_scenario_id INTEGER PRIMARY KEY, - water_system_balancing_type TEXT, - theoretical_power_coefficient FLOAT, + water_system_params_scenario_id INTEGER PRIMARY KEY, + water_system_balancing_type TEXT, + theoretical_power_coefficient FLOAT, + allow_lin_hrz_first_tmp_flow_slack FLOAT, + allow_lin_hrz_first_tmp_flow_slack_tuning_cost FLOAT, FOREIGN KEY (water_system_params_scenario_id) REFERENCES subscenarios_system_water_system_params (water_system_params_scenario_id) ); @@ -6856,16 +6858,17 @@ DROP TABLE IF EXISTS results_system_ra; DROP TABLE IF EXISTS results_system_water_link_timepoint; CREATE TABLE results_system_water_link_timepoint ( - scenario_id INTEGER, - weather_iteration INTEGER, - hydro_iteration INTEGER, - availability_iteration INTEGER, - subproblem_id INTEGER, - stage_id INTEGER, - water_link VARCHAR(32), - departure_timepoint INTEGER, - arrival_timepoint INTEGER, - water_flow_vol_per_sec FLOAT, + scenario_id INTEGER, + weather_iteration INTEGER, + hydro_iteration INTEGER, + availability_iteration INTEGER, + subproblem_id INTEGER, + stage_id INTEGER, + water_link VARCHAR(32), + departure_timepoint INTEGER, + arrival_timepoint INTEGER, + water_flow_vol_per_sec FLOAT, + water_flow_slack_used_vol_per_sec FLOAT, PRIMARY KEY (scenario_id, weather_iteration, hydro_iteration, availability_iteration, subproblem_id, stage_id, water_link, departure_timepoint) @@ -6973,6 +6976,7 @@ CREATE TABLE results_system_costs Total_Carbon_Credit_Costs FLOAT, Total_Peak_Deviation_Monthly_Demand_Charge_Cost FLOAT, Total_Policy_Target_Balance_Penalty_Costs FLOAT, + Total_Flow_Constraint_Slack_Tuning_Cost FLOAT, PRIMARY KEY (scenario_id, weather_iteration, hydro_iteration, availability_iteration, subproblem_id, stage_id) ); diff --git a/examples/hydro_system_exog_elev/hydro_iteration_1/inputs/water_system_params.tab b/examples/hydro_system_exog_elev/hydro_iteration_1/inputs/water_system_params.tab index 20d51e51c..22ca2c5d8 100644 --- a/examples/hydro_system_exog_elev/hydro_iteration_1/inputs/water_system_params.tab +++ b/examples/hydro_system_exog_elev/hydro_iteration_1/inputs/water_system_params.tab @@ -1,2 +1,2 @@ -water_system_balancing_type theoretical_power_coefficient -day 84.7 +water_system_balancing_type theoretical_power_coefficient allow_lin_hrz_first_tmp_flow_slack allow_lin_hrz_first_tmp_flow_slack_tuning_cost +day 84.7 0.0 0.0 diff --git a/examples/hydro_system_exog_elev_w_travel_time/hydro_iteration_1/inputs/water_system_params.tab b/examples/hydro_system_exog_elev_w_travel_time/hydro_iteration_1/inputs/water_system_params.tab index 20d51e51c..22ca2c5d8 100644 --- a/examples/hydro_system_exog_elev_w_travel_time/hydro_iteration_1/inputs/water_system_params.tab +++ b/examples/hydro_system_exog_elev_w_travel_time/hydro_iteration_1/inputs/water_system_params.tab @@ -1,2 +1,2 @@ -water_system_balancing_type theoretical_power_coefficient -day 84.7 +water_system_balancing_type theoretical_power_coefficient allow_lin_hrz_first_tmp_flow_slack allow_lin_hrz_first_tmp_flow_slack_tuning_cost +day 84.7 0.0 0.0 diff --git a/gridpath/auxiliary/module_list.py b/gridpath/auxiliary/module_list.py index cc3cddeb0..db0938688 100644 --- a/gridpath/auxiliary/module_list.py +++ b/gridpath/auxiliary/module_list.py @@ -89,8 +89,8 @@ def all_modules_list(): "system.reliability.local_capacity.local_capacity_requirement", "system.markets.prices", "system.water.water_system_params", - "system.water.water_flows", "system.water.water_nodes", + "system.water.water_flows", "system.water.reservoirs", "system.water.water_node_balance", "system.water.powerhouses", @@ -266,6 +266,7 @@ def all_modules_list(): "objective.system.reliability.local_capacity" ".aggregate_local_capacity_violation_penalties", "objective.system.aggregate_market_revenue_and_costs", + "objective.system.water.aggregate_flow_constraint_slack_use_tuning_costs", "objective.max_npv", ] return all_modules @@ -491,6 +492,7 @@ def optional_modules_list(): "system.water.water_node_balance", "system.water.water_flows", "system.water.powerhouses", + "objective.system.water.aggregate_flow_constraint_slack_use_tuning_costs", ], "tuning": [ "project.operations.tuning_costs", diff --git a/gridpath/objective/system/water/__init__.py b/gridpath/objective/system/water/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/gridpath/objective/system/water/aggregate_flow_constraint_slack_use_tuning_costs.py b/gridpath/objective/system/water/aggregate_flow_constraint_slack_use_tuning_costs.py new file mode 100644 index 000000000..f8b4319a9 --- /dev/null +++ b/gridpath/objective/system/water/aggregate_flow_constraint_slack_use_tuning_costs.py @@ -0,0 +1,71 @@ +# Copyright 2016-2024 Blue Marble Analytics LLC. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +from pyomo.environ import Param, Expression + +from gridpath.auxiliary.dynamic_components import cost_components + + +def add_model_components( + m, + d, + scenario_directory, + weather_iteration, + hydro_iteration, + availability_iteration, + subproblem, + stage, +): + """ + + :param m: + :param d: + :return: + """ + + def total_flow_constraint_slack_tuning_cost_rule(mod): + """ + Ramp tuning costs for all projects + :param mod: + :return: + """ + return sum( + mod.Water_Link_Flow_Rate_Vol_per_Sec_LinHrzFirstTmpSlack[wl, tmp] + * mod.allow_lin_hrz_first_tmp_flow_slack_tuning_cost + * mod.hrs_in_tmp[tmp] + * mod.tmp_weight[tmp] + * mod.number_years_represented[mod.period[tmp]] + * mod.discount_factor[mod.period[tmp]] + for wl in mod.WATER_LINKS + for tmp in mod.TMPS + ) + + m.Total_Flow_Constraint_Slack_Tuning_Cost = Expression( + rule=total_flow_constraint_slack_tuning_cost_rule + ) + + record_dynamic_components(dynamic_components=d) + + +def record_dynamic_components(dynamic_components): + """ + :param dynamic_components: + + Add tuning costs to cost components + """ + + getattr(dynamic_components, cost_components).append( + "Total_Flow_Constraint_Slack_Tuning_Cost" + ) diff --git a/gridpath/system/water/water_flows.py b/gridpath/system/water/water_flows.py index a91dbb2e3..ca28de7aa 100644 --- a/gridpath/system/water/water_flows.py +++ b/gridpath/system/water/water_flows.py @@ -34,6 +34,7 @@ from gridpath.project.common_functions import ( check_if_boundary_type_and_last_timepoint, check_boundary_type, + check_if_boundary_type_and_first_timepoint, ) @@ -69,7 +70,7 @@ def water_link_departure_arrival_tmp_init(mod): for departure_tmp in mod.TMPS: arrival_tmp = determine_arrival_timepoint( mod=mod, - tmp=departure_tmp, + dep_tmp=departure_tmp, travel_time_hours=mod.water_link_flow_transport_time_hours[wl], ) if arrival_tmp is not None: @@ -89,10 +90,15 @@ def water_link_departure_arrival_tmp_init(mod): m.WATER_LINK_DEPARTURE_ARRIVAL_TMPS, within=NonNegativeReals ) + m.Water_Link_Flow_Rate_Vol_per_Sec_LinHrzFirstTmpSlack = Var( + m.WATER_LINKS, m.TMPS, within=NonNegativeReals, initialize=0 + ) + # ### Constraints ### # def min_flow_rule(mod, wl, dep_tmp, arr_tmp): return ( mod.Water_Link_Flow_Rate_Vol_per_Sec[wl, dep_tmp, arr_tmp] + + mod.Water_Link_Flow_Rate_Vol_per_Sec_LinHrzFirstTmpSlack[wl, dep_tmp] >= mod.min_flow_vol_per_second[wl, dep_tmp] ) @@ -100,6 +106,32 @@ def min_flow_rule(mod, wl, dep_tmp, arr_tmp): m.WATER_LINK_DEPARTURE_ARRIVAL_TMPS, rule=min_flow_rule ) + def min_flow_slack_rule(mod, wl, tmp): + if mod.allow_lin_hrz_first_tmp_flow_slack: + if check_if_boundary_type_and_first_timepoint( + mod=mod, + tmp=tmp, + boundary_type="linear", + balancing_type=mod.water_system_balancing_type, + ): + return ( + mod.Water_Link_Flow_Rate_Vol_per_Sec_LinHrzFirstTmpSlack[wl, tmp] + <= mod.min_flow_vol_per_second[wl, tmp] + ) + else: + return ( + mod.Water_Link_Flow_Rate_Vol_per_Sec_LinHrzFirstTmpSlack[wl, tmp] + == 0 + ) + else: + return ( + mod.Water_Link_Flow_Rate_Vol_per_Sec_LinHrzFirstTmpSlack[wl, tmp] == 0 + ) + + m.MinFlowSlackConstraint = Constraint( + m.WATER_LINKS, m.TMPS, rule=min_flow_slack_rule + ) + def max_flow_rule(mod, wl, dep_tmp, arr_tmp): return ( mod.Water_Link_Flow_Rate_Vol_per_Sec[wl, dep_tmp, arr_tmp] @@ -111,35 +143,34 @@ def max_flow_rule(mod, wl, dep_tmp, arr_tmp): ) -def determine_arrival_timepoint(mod, tmp, travel_time_hours): +def determine_arrival_timepoint(mod, dep_tmp, travel_time_hours): + # If travel time is less than the hours in the departure timepoint, we stay + # in the same timepoint + if travel_time_hours < mod.hrs_in_tmp[dep_tmp]: + arr_tmp = dep_tmp # If this is the last timepoint of a linear horizon, there are no - # timepoints to check - # TODO: check if this makes sense - if check_if_boundary_type_and_last_timepoint( + # timepoints to check and we'll return 'tmp_outside_horizon' + elif check_if_boundary_type_and_last_timepoint( mod=mod, - tmp=tmp, + tmp=dep_tmp, balancing_type=mod.water_system_balancing_type, boundary_type="linear", ): - tmp_to_check = "tmp_outside_horizon" + arr_tmp = "tmp_outside_horizon" elif check_if_boundary_type_and_last_timepoint( mod=mod, - tmp=tmp, + tmp=dep_tmp, balancing_type=mod.water_system_balancing_type, boundary_type="linked", ): # TODO: add linked - tmp_to_check = None - # If travel time is less than the hours in the starting timepoint, we stay - # in the same timepoint - elif travel_time_hours < mod.hrs_in_tmp[tmp]: - tmp_to_check = tmp + arr_tmp = None else: # Otherwise, we check the following timepoints # First we'll check the next timepoint of the starting timepoint and # start with the duration of the starting timepoint - tmp_to_check = mod.next_tmp[tmp, mod.water_system_balancing_type] - hours_from_departure_tmp = mod.hrs_in_tmp[tmp] + arr_tmp = mod.next_tmp[dep_tmp, mod.water_system_balancing_type] + hours_from_departure_tmp = mod.hrs_in_tmp[dep_tmp] while hours_from_departure_tmp < travel_time_hours: # If we haven't exceeded the travel time yet, we move on to the next tmp # In a 'linear' horizon setting, once we reach the last @@ -147,24 +178,26 @@ def determine_arrival_timepoint(mod, tmp, travel_time_hours): # "tmp_outside_horizon" and break out of the loop if check_if_boundary_type_and_last_timepoint( mod=mod, - tmp=tmp_to_check, + tmp=arr_tmp, balancing_type=mod.water_system_balancing_type, boundary_type="linear", ): - tmp_to_check = "tmp_outside_horizon" + arr_tmp = "tmp_outside_horizon" break - # In a 'circular' horizon setting, once we reach timepoint *t*, - # we break out of the loop since there are no more timepoints to - # consider (we have already checked all horizon timepoints) + # In a 'circular' horizon setting, once we loop back to the + # departure timepoint again, we break out of the loop since there + # are no more timepoints to consider (we have already checked all + # horizon timepoints) elif ( check_boundary_type( mod=mod, - tmp=tmp, + tmp=dep_tmp, balancing_type=mod.water_system_balancing_type, boundary_type="circular", ) - and tmp_to_check == tmp + and arr_tmp == dep_tmp ): + arr_tmp = "tmp_outside_horizon" break # TODO: only allow the first horizon of a subproblem to have # linked timepoints @@ -173,21 +206,20 @@ def determine_arrival_timepoint(mod, tmp, travel_time_hours): # timepoints until we reach the target min time elif check_if_boundary_type_and_last_timepoint( mod=mod, - tmp=tmp_to_check, + tmp=arr_tmp, balancing_type=mod.water_system_balancing_type, boundary_type="linked", ): # TODO: add linked + arr_tmp = None break # Otherwise, we move on to the next timepoint and will add that # timepoint's duration to hours_from_departure_tmp else: - hours_from_departure_tmp += mod.hrs_in_tmp[tmp_to_check] - tmp_to_check = mod.next_tmp[ - tmp_to_check, mod.water_system_balancing_type - ] + hours_from_departure_tmp += mod.hrs_in_tmp[arr_tmp] + arr_tmp = mod.next_tmp[arr_tmp, mod.water_system_balancing_type] - return tmp_to_check + return arr_tmp def load_model_data( @@ -384,6 +416,7 @@ def export_results( """ results_columns = [ "water_flow_vol_per_sec", + "water_flow_slack_used_vol_per_sec", ] data = [ [ @@ -391,6 +424,7 @@ def export_results( dep_tmp, arr_tmp, value(m.Water_Link_Flow_Rate_Vol_per_Sec[wl, dep_tmp, arr_tmp]), + value(m.Water_Link_Flow_Rate_Vol_per_Sec_LinHrzFirstTmpSlack[wl, dep_tmp]), ] for (wl, dep_tmp, arr_tmp) in m.WATER_LINK_DEPARTURE_ARRIVAL_TMPS ] diff --git a/gridpath/system/water/water_node_balance.py b/gridpath/system/water/water_node_balance.py index 4c7add728..1ae5b22c4 100644 --- a/gridpath/system/water/water_node_balance.py +++ b/gridpath/system/water/water_node_balance.py @@ -210,33 +210,6 @@ def enforce_mass_balance_outflow_rule(mod, wn, tmp): ) -def load_model_data( - m, - d, - data_portal, - scenario_directory, - weather_iteration, - hydro_iteration, - availability_iteration, - subproblem, - stage, -): - - data_portal.load( - filename=os.path.join( - scenario_directory, - weather_iteration, - hydro_iteration, - availability_iteration, - subproblem, - stage, - "inputs", - "water_inflows.tab", - ), - param=m.exogenous_water_inflow_rate_vol_per_sec, - ) - - def validate_inputs( scenario_id, subscenarios, diff --git a/gridpath/system/water/water_system_params.py b/gridpath/system/water/water_system_params.py index f3c35d5f8..de436565d 100644 --- a/gridpath/system/water/water_system_params.py +++ b/gridpath/system/water/water_system_params.py @@ -48,6 +48,13 @@ def add_model_components( # m vs ft; user must ensure consistent units m.theoretical_power_coefficient = Param(within=NonNegativeReals) + # To avoid infeasibilities, slack can be allowed for some flow constraints + # See water_flows module + m.allow_lin_hrz_first_tmp_flow_slack = Param(within=NonNegativeReals, default=0) + m.allow_lin_hrz_first_tmp_flow_slack_tuning_cost = Param( + within=NonNegativeReals, default=0 + ) + def load_model_data( m, @@ -72,7 +79,12 @@ def load_model_data( "inputs", "water_system_params.tab", ), - param=(m.water_system_balancing_type, m.theoretical_power_coefficient), + param=( + m.water_system_balancing_type, + m.theoretical_power_coefficient, + m.allow_lin_hrz_first_tmp_flow_slack, + m.allow_lin_hrz_first_tmp_flow_slack_tuning_cost, + ), ) @@ -96,7 +108,9 @@ def get_inputs_from_database( c = conn.cursor() water_system_params = c.execute( - f"""SELECT water_system_balancing_type, theoretical_power_coefficient + f"""SELECT water_system_balancing_type, theoretical_power_coefficient, + allow_lin_hrz_first_tmp_flow_slack, + allow_lin_hrz_first_tmp_flow_slack_tuning_cost FROM inputs_system_water_system_params WHERE water_system_params_scenario_id = {subscenarios.WATER_SYSTEM_PARAMS_SCENARIO_ID} @@ -194,6 +208,8 @@ def write_model_inputs( [ "water_system_balancing_type", "theoretical_power_coefficient", + "allow_lin_hrz_first_tmp_flow_slack", + "allow_lin_hrz_first_tmp_flow_slack_tuning_cost", ] ) diff --git a/tests/objective/system/water/test_aggregate_flow_constraint_slack_use_tuning_costs.py b/tests/objective/system/water/test_aggregate_flow_constraint_slack_use_tuning_costs.py new file mode 100644 index 000000000..c62cdd28c --- /dev/null +++ b/tests/objective/system/water/test_aggregate_flow_constraint_slack_use_tuning_costs.py @@ -0,0 +1,110 @@ +# Copyright 2016-2024 Blue Marble Analytics LLC. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from importlib import import_module +import os.path +import pandas as pd +import sys +import unittest + +from tests.common_functions import create_abstract_model, add_components_and_load_data + +TEST_DATA_DIRECTORY = os.path.join( + os.path.dirname(__file__), "..", "..", "..", "test_data" +) + +# Import prerequisite modules +PREREQUISITE_MODULE_NAMES = [ + "temporal.operations.timepoints", + "temporal.investment.periods", + "temporal.operations.horizons", + "geography.water_network", + "system.water.water_system_params", + "system.water.water_flows", +] +NAME_OF_MODULE_BEING_TESTED = ( + "objective.system.water.aggregate_flow_constraint_slack_use_tuning_costs" +) +IMPORTED_PREREQ_MODULES = list() +for mdl in PREREQUISITE_MODULE_NAMES: + try: + imported_module = import_module("." + str(mdl), package="gridpath") + IMPORTED_PREREQ_MODULES.append(imported_module) + except ImportError: + print("ERROR! Module " + str(mdl) + " not found.") + sys.exit(1) +# Import the module we'll test +try: + MODULE_BEING_TESTED = import_module( + "." + NAME_OF_MODULE_BEING_TESTED, package="gridpath" + ) +except ImportError: + print("ERROR! Couldn't import module " + NAME_OF_MODULE_BEING_TESTED + " to test.") + + +class TestFlowSlackTuningCostsAgg(unittest.TestCase): + """ """ + + def test_add_model_components(self): + """ + Test that there are no errors when adding model components + :return: + """ + create_abstract_model( + prereq_modules=IMPORTED_PREREQ_MODULES, + module_to_test=MODULE_BEING_TESTED, + test_data_dir=TEST_DATA_DIRECTORY, + weather_iteration="", + hydro_iteration="", + availability_iteration="", + subproblem="", + stage="", + ) + + def test_load_model_data(self): + """ + Test that data are loaded with no errors + :return: + """ + add_components_and_load_data( + prereq_modules=IMPORTED_PREREQ_MODULES, + module_to_test=MODULE_BEING_TESTED, + test_data_dir=TEST_DATA_DIRECTORY, + weather_iteration="", + hydro_iteration="", + availability_iteration="", + subproblem="", + stage="", + ) + + def test_data_loaded_correctly(self): + """ + Test that the data loaded are as expected + :return: + """ + m, data = add_components_and_load_data( + prereq_modules=IMPORTED_PREREQ_MODULES, + module_to_test=MODULE_BEING_TESTED, + test_data_dir=TEST_DATA_DIRECTORY, + weather_iteration="", + hydro_iteration="", + availability_iteration="", + subproblem="", + stage="", + ) + instance = m.create_instance(data) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/system/water/test_water_system_params.py b/tests/system/water/test_water_system_params.py index aa6050400..bbfaa0765 100644 --- a/tests/system/water/test_water_system_params.py +++ b/tests/system/water/test_water_system_params.py @@ -111,3 +111,17 @@ def test_data_loaded_correctly(self): actual_coeff = instance.theoretical_power_coefficient.value self.assertEqual(expected_coeff, actual_coeff) + + # Param: allow_lin_hrz_first_tmp_flow_slack + expect_slack = 0 + actual_slack = instance.allow_lin_hrz_first_tmp_flow_slack.value + + self.assertEqual(expect_slack, actual_slack) + + # Param: allow_lin_hrz_first_tmp_flow_slack_tuning_cost + expect_slack_tuning_cost = 0 + actual_slack_tuning_cost = ( + instance.allow_lin_hrz_first_tmp_flow_slack_tuning_cost.value + ) + + self.assertEqual(expect_slack_tuning_cost, actual_slack_tuning_cost) diff --git a/tests/test_data/inputs/water_system_params.tab b/tests/test_data/inputs/water_system_params.tab index 9947468c3..578e18ada 100644 --- a/tests/test_data/inputs/water_system_params.tab +++ b/tests/test_data/inputs/water_system_params.tab @@ -1,2 +1,2 @@ -water_system_balancing_type theoretical_power_coefficient -day 0.0847 \ No newline at end of file +water_system_balancing_type theoretical_power_coefficient allow_lin_hrz_first_tmp_flow_slack allow_lin_hrz_first_tmp_flow_slack_tuning_cost +day 0.0847 0 0 \ No newline at end of file diff --git a/tests/test_data/subproblems/202001/2/inputs/water_system_params.tab b/tests/test_data/subproblems/202001/2/inputs/water_system_params.tab index 9947468c3..578e18ada 100644 --- a/tests/test_data/subproblems/202001/2/inputs/water_system_params.tab +++ b/tests/test_data/subproblems/202001/2/inputs/water_system_params.tab @@ -1,2 +1,2 @@ -water_system_balancing_type theoretical_power_coefficient -day 0.0847 \ No newline at end of file +water_system_balancing_type theoretical_power_coefficient allow_lin_hrz_first_tmp_flow_slack allow_lin_hrz_first_tmp_flow_slack_tuning_cost +day 0.0847 0 0 \ No newline at end of file