muse2/simulation/
prices.rs1use super::optimisation::Solution;
3use crate::commodity::CommodityID;
4use crate::model::Model;
5use crate::region::RegionID;
6use crate::time_slice::TimeSliceID;
7use crate::units::MoneyPerFlow;
8use itertools::iproduct;
9use std::collections::{BTreeMap, HashMap};
10
11#[derive(Default)]
13pub struct CommodityPrices(BTreeMap<(CommodityID, RegionID, TimeSliceID), MoneyPerFlow>);
14
15impl CommodityPrices {
16 pub fn calculate(model: &Model, solution: &Solution, year: u32) -> Self {
22 let mut prices = CommodityPrices::default();
23 prices.add_from_duals(solution);
24 prices.add_from_levies(model, year);
25
26 prices
27 }
28
29 fn add_from_duals(&mut self, solution: &Solution) {
38 let mut highest_duals = HashMap::new();
40 for (asset, time_slice, dual) in solution.iter_activity_duals() {
41 for flow in asset.iter_flows().filter(|flow| flow.is_output()) {
43 highest_duals
45 .entry((
46 flow.commodity.id.clone(),
47 asset.region_id.clone(),
48 time_slice.clone(),
49 ))
50 .and_modify(|current_dual| {
51 if dual > *current_dual {
52 *current_dual = dual;
53 }
54 })
55 .or_insert(dual);
56 }
57 }
58
59 for (commodity_id, region_id, time_slice, dual) in solution.iter_commodity_balance_duals() {
62 let key = (commodity_id.clone(), region_id.clone(), time_slice.clone());
63 let price = dual + highest_duals.get(&key).unwrap_or(&0.0);
64 self.0.insert(key, MoneyPerFlow(price));
65 }
66 }
67
68 fn add_from_levies(&mut self, model: &Model, year: u32) {
78 for (region_id, time_slice) in
79 iproduct!(model.iter_regions(), model.time_slice_info.iter_ids())
80 {
81 let levy_key = (region_id.clone(), year, time_slice.clone());
82 for commodity in model.commodities.values() {
83 if let Some(levy) = commodity.levies.get(&levy_key) {
84 let key = (commodity.id.clone(), region_id.clone(), time_slice.clone());
85 self.0
86 .entry(key)
87 .and_modify(|price| *price = price.max(levy.value))
88 .or_insert(levy.value);
89 }
90 }
91 }
92 }
93
94 pub fn insert(
96 &mut self,
97 commodity_id: &CommodityID,
98 region_id: &RegionID,
99 time_slice: &TimeSliceID,
100 price: MoneyPerFlow,
101 ) {
102 let key = (commodity_id.clone(), region_id.clone(), time_slice.clone());
103 self.0.insert(key, price);
104 }
105
106 pub fn iter(
112 &self,
113 ) -> impl Iterator<Item = (&CommodityID, &RegionID, &TimeSliceID, MoneyPerFlow)> {
114 self.0
115 .iter()
116 .map(|((commodity_id, region_id, ts), price)| (commodity_id, region_id, ts, *price))
117 }
118}