11//! Code for adding constraints to the dispatch optimisation problem.
22use super :: VariableMap ;
33use crate :: asset:: { AssetPool , AssetRef } ;
4- use crate :: commodity:: CommodityID ;
4+ use crate :: commodity:: { CommodityID , CommodityType } ;
55use crate :: model:: Model ;
66use crate :: region:: RegionID ;
77use crate :: time_slice:: { TimeSliceID , TimeSliceInfo , TimeSliceSelection } ;
@@ -50,7 +50,6 @@ pub struct ConstraintKeys {
5050/// * `variables` - The variables in the problem
5151/// * `model` - The model
5252/// * `assets` - The asset pool
53- /// * `year` - Current milestone year
5453///
5554/// # Returns:
5655///
@@ -61,10 +60,9 @@ pub fn add_asset_constraints(
6160 variables : & VariableMap ,
6261 model : & Model ,
6362 assets : & AssetPool ,
64- year : u32 ,
6563) -> ConstraintKeys {
6664 let commodity_balance_keys =
67- add_commodity_balance_constraints ( problem, variables, model, assets, year ) ;
65+ add_commodity_balance_constraints ( problem, variables, model, assets) ;
6866
6967 let capacity_keys =
7068 add_asset_capacity_constraints ( problem, variables, assets, & model. time_slice_info ) ;
@@ -85,18 +83,44 @@ pub fn add_asset_constraints(
8583/// [1]: https://energysystemsmodellinglab.github.io/MUSE_2.0/dispatch_optimisation.html#commodity-balance-constraints
8684fn add_commodity_balance_constraints (
8785 problem : & mut Problem ,
88- _variables : & VariableMap ,
89- _model : & Model ,
90- _assets : & AssetPool ,
91- _year : u32 ,
86+ variables : & VariableMap ,
87+ model : & Model ,
88+ assets : & AssetPool ,
9289) -> CommodityBalanceKeys {
9390 // Row offset in problem. This line **must** come before we add more constraints.
9491 let offset = problem. num_rows ( ) ;
9592
96- let keys = Vec :: new ( ) ;
97-
98- // **TODO:** Add commodity balance constraints:
99- // https://github.com/EnergySystemsModellingLab/MUSE_2.0/issues/577
93+ let mut keys = Vec :: new ( ) ;
94+ let mut terms = Vec :: new ( ) ;
95+ for ( commodity_id, commodity) in model. commodities . iter ( ) {
96+ if commodity. kind != CommodityType :: SupplyEqualsDemand {
97+ continue ;
98+ }
99+
100+ for region_id in model. iter_regions ( ) {
101+ for ts_selection in model
102+ . time_slice_info
103+ . iter_selections_at_level ( commodity. time_slice_level )
104+ {
105+ for ( asset, flow) in assets. iter_for_region_and_commodity ( region_id, commodity_id) {
106+ // If the commodity has a time slice level of season/annual, the constraint will
107+ // cover multiple time slices
108+ for ( time_slice, _) in ts_selection. iter ( & model. time_slice_info ) {
109+ let var = variables. get ( asset, time_slice) ;
110+ terms. push ( ( var, flow. coeff ) ) ;
111+ }
112+ }
113+
114+ // Add constraint
115+ problem. add_row ( 0.0 ..=0.0 , terms. drain ( ..) ) ;
116+ keys. push ( (
117+ commodity_id. clone ( ) ,
118+ region_id. clone ( ) ,
119+ ts_selection. clone ( ) ,
120+ ) )
121+ }
122+ }
123+ }
100124
101125 CommodityBalanceKeys { offset, keys }
102126}
0 commit comments