11//! Code for updating the simulation state.
22use super :: optimisation:: Solution ;
3- use crate :: asset:: AssetPool ;
43use crate :: commodity:: CommodityID ;
54use crate :: model:: Model ;
65use crate :: region:: RegionID ;
76use crate :: time_slice:: { TimeSliceID , TimeSliceInfo } ;
87use log:: warn;
9- use std:: collections:: { BTreeMap , HashSet } ;
8+ use std:: collections:: { BTreeMap , HashMap , HashSet } ;
109
1110/// A map relating commodity ID + region + time slice to current price (endogenous)
1211#[ derive( Default ) ]
1312pub struct CommodityPrices ( BTreeMap < ( CommodityID , RegionID , TimeSliceID ) , f64 > ) ;
1413
1514impl CommodityPrices {
16- /// Calculate commodity prices based on the result of the dispatch optimisation.
17- ///
18- /// Missing prices will be calculated directly from the input data
19- pub fn from_model_and_solution ( model : & Model , solution : & Solution , assets : & AssetPool ) -> Self {
15+ /// Calculate commodity prices based on the result of the dispatch optimisation
16+ pub fn from_model_and_solution ( model : & Model , solution : & Solution ) -> Self {
2017 let mut prices = CommodityPrices :: default ( ) ;
21- let commodity_regions_updated = prices. add_from_solution ( solution, assets ) ;
18+ let commodity_regions_updated = prices. add_from_solution ( solution) ;
2219
2320 // Find commodity/region combinations not updated in last step
2421 let mut remaining_commodity_regions = HashSet :: new ( ) ;
@@ -44,27 +41,51 @@ impl CommodityPrices {
4441 /// # Arguments
4542 ///
4643 /// * `solution` - The solution to the dispatch optimisation
47- /// * `assets` - The asset pool
4844 ///
4945 /// # Returns
5046 ///
51- /// The set of commodities for which prices were added.
52- fn add_from_solution (
53- & mut self ,
54- _solution : & Solution ,
55- _assets : & AssetPool ,
56- ) -> HashSet < ( CommodityID , RegionID ) > {
57- // **TODO:** Calculate commodity prices here:
58- // https://github.com/EnergySystemsModellingLab/MUSE_2.0/issues/589
47+ /// The set of commodity/region pairs for which prices were added.
48+ fn add_from_solution ( & mut self , solution : & Solution ) -> HashSet < ( CommodityID , RegionID ) > {
49+ let mut commodity_regions_updated = HashSet :: new ( ) ;
50+
51+ // Calculate highest activity dual for each commodity/region/timeslice
52+ let mut highest_duals = HashMap :: new ( ) ;
53+ for ( asset, time_slice, dual) in solution. iter_activity_duals ( ) {
54+ // Iterate over all output flows
55+ for flow in asset. iter_flows ( ) . filter ( |flow| flow. coeff > 0.0 ) {
56+ // Update the highest dual for this commodity/timeslice
57+ highest_duals
58+ . entry ( (
59+ flow. commodity . id . clone ( ) ,
60+ asset. region_id . clone ( ) ,
61+ time_slice. clone ( ) ,
62+ ) )
63+ . and_modify ( |current_dual| {
64+ if dual > * current_dual {
65+ * current_dual = dual;
66+ }
67+ } )
68+ . or_insert ( dual) ;
69+ }
70+ }
71+
72+ // Add the highest activity dual for each commodity/region/timeslice to each commodity
73+ // balance dual
74+ for ( commodity_id, region_id, time_slice, dual) in solution. iter_commodity_balance_duals ( ) {
75+ let key = ( commodity_id. clone ( ) , region_id. clone ( ) , time_slice. clone ( ) ) ;
76+ let price = dual + highest_duals. get ( & key) . unwrap_or ( & 0.0 ) ;
77+ self . insert ( commodity_id, region_id, time_slice, price) ;
78+ commodity_regions_updated. insert ( ( commodity_id. clone ( ) , region_id. clone ( ) ) ) ;
79+ }
5980
60- HashSet :: new ( )
81+ commodity_regions_updated
6182 }
6283
6384 /// Add prices for any commodity not updated by the dispatch step.
6485 ///
6586 /// # Arguments
6687 ///
67- /// * `commodity_ids ` - IDs of commodities to update
88+ /// * `commodity_regions ` - Commodity/region pairs to update
6889 /// * `time_slice_info` - Information about time slices
6990 fn add_remaining < ' a , I > ( & mut self , commodity_regions : I , time_slice_info : & TimeSliceInfo )
7091 where
@@ -78,7 +99,7 @@ impl CommodityPrices {
7899 }
79100 }
80101
81- /// Insert a price for the given commodity, time slice and region
102+ /// Insert a price for the given commodity, region and time slice
82103 pub fn insert (
83104 & mut self ,
84105 commodity_id : & CommodityID ,
@@ -94,7 +115,7 @@ impl CommodityPrices {
94115 ///
95116 /// # Returns
96117 ///
97- /// An iterator of tuples containing commodity ID, time slice and price.
118+ /// An iterator of tuples containing commodity ID, region ID, time slice and price.
98119 pub fn iter ( & self ) -> impl Iterator < Item = ( & CommodityID , & RegionID , & TimeSliceID , f64 ) > {
99120 self . 0
100121 . iter ( )
0 commit comments