muse2/simulation/investment/appraisal/
coefficients.rs

1//! Calculation of cost coefficients for investment tools.
2use super::costs::{activity_cost, activity_surplus, annual_fixed_cost};
3use crate::asset::AssetRef;
4use crate::simulation::prices::ReducedCosts;
5use crate::time_slice::{TimeSliceID, TimeSliceInfo};
6use crate::units::{MoneyPerActivity, MoneyPerCapacity, MoneyPerFlow};
7use indexmap::IndexMap;
8
9/// Map storing coefficients for each variable
10pub struct CoefficientsMap {
11    /// Cost per unit of capacity
12    pub capacity_coefficient: MoneyPerCapacity,
13    /// Cost per unit of activity in each time slice
14    pub activity_coefficients: IndexMap<TimeSliceID, MoneyPerActivity>,
15    // Unmet demand coefficient
16    pub unmet_demand_coefficient: MoneyPerFlow,
17}
18
19/// Calculates the cost coefficients for LCOX.
20pub fn calculate_coefficients_for_lcox(
21    asset: &AssetRef,
22    time_slice_info: &TimeSliceInfo,
23    reduced_costs: &ReducedCosts,
24    value_of_lost_load: MoneyPerFlow,
25) -> CoefficientsMap {
26    // Capacity coefficient
27    let capacity_coefficient = annual_fixed_cost(asset);
28
29    // Activity coefficients
30    let mut activity_coefficients = IndexMap::new();
31    for time_slice in time_slice_info.iter_ids() {
32        let coefficient = activity_cost(asset, reduced_costs, time_slice.clone());
33        activity_coefficients.insert(time_slice.clone(), coefficient);
34    }
35
36    // Unmet demand coefficient
37    let unmet_demand_coefficient = value_of_lost_load;
38
39    CoefficientsMap {
40        capacity_coefficient,
41        activity_coefficients,
42        unmet_demand_coefficient,
43    }
44}
45
46/// Calculates the cost coefficients for NPV.
47pub fn calculate_coefficients_for_npv(
48    asset: &AssetRef,
49    time_slice_info: &TimeSliceInfo,
50    reduced_costs: &ReducedCosts,
51) -> CoefficientsMap {
52    // Capacity coefficient
53    let capacity_coefficient = -annual_fixed_cost(asset);
54
55    // Activity coefficients
56    let mut activity_coefficients = IndexMap::new();
57    for time_slice in time_slice_info.iter_ids() {
58        let coefficient = activity_surplus(asset, reduced_costs, time_slice.clone());
59        activity_coefficients.insert(time_slice.clone(), coefficient);
60    }
61
62    // Unmet demand coefficient (we don't apply a cost to unmet demand, so we set this to zero)
63    let unmet_demand_coefficient = MoneyPerFlow(0.0);
64
65    CoefficientsMap {
66        capacity_coefficient,
67        activity_coefficients,
68        unmet_demand_coefficient,
69    }
70}