|
1 | 1 | //! Calculation for investment tools such as Levelised Cost of X (LCOX) and Net Present Value (NPV). |
2 | 2 | use super::DemandMap; |
3 | 3 | use crate::agent::ObjectiveType; |
4 | | -use crate::asset::AssetRef; |
| 4 | +use crate::asset::{Asset, AssetRef}; |
5 | 5 | use crate::commodity::Commodity; |
6 | 6 | use crate::finance::{lcox, profitability_index}; |
7 | 7 | use crate::model::Model; |
@@ -67,25 +67,28 @@ impl AppraisalOutput { |
67 | 67 | "Appraisal metrics must be equal" |
68 | 68 | ); |
69 | 69 |
|
70 | | - // Favour commissioned assets over non-commissioned |
71 | | - if self.asset.is_commissioned() && !other.asset.is_commissioned() { |
72 | | - return Ordering::Less; |
73 | | - } |
74 | | - if !self.asset.is_commissioned() && other.asset.is_commissioned() { |
75 | | - return Ordering::Greater; |
76 | | - } |
| 70 | + compare_asset_fallback(&self.asset, &other.asset) |
| 71 | + } |
| 72 | +} |
77 | 73 |
|
78 | | - // if both commissioned, favour newer ones |
79 | | - if self.asset.is_commissioned() && other.asset.is_commissioned() { |
80 | | - return self |
81 | | - .asset |
82 | | - .commission_year() |
83 | | - .cmp(&other.asset.commission_year()) |
84 | | - .reverse(); |
85 | | - } |
| 74 | +fn compare_asset_fallback(asset1: &Asset, asset2: &Asset) -> Ordering { |
| 75 | + // Favour commissioned assets over non-commissioned |
| 76 | + if asset1.is_commissioned() && !asset2.is_commissioned() { |
| 77 | + return Ordering::Less; |
| 78 | + } |
| 79 | + if !asset1.is_commissioned() && asset2.is_commissioned() { |
| 80 | + return Ordering::Greater; |
| 81 | + } |
86 | 82 |
|
87 | | - Ordering::Equal |
| 83 | + // if both commissioned, favour newer ones |
| 84 | + if asset1.is_commissioned() && asset2.is_commissioned() { |
| 85 | + return asset1 |
| 86 | + .commission_year() |
| 87 | + .cmp(&asset2.commission_year()) |
| 88 | + .reverse(); |
88 | 89 | } |
| 90 | + |
| 91 | + Ordering::Equal |
89 | 92 | } |
90 | 93 |
|
91 | 94 | /// Calculate LCOX for a hypothetical investment in the given asset. |
@@ -192,3 +195,44 @@ pub fn appraise_investment( |
192 | 195 | }; |
193 | 196 | appraisal_method(model, asset, max_capacity, commodity, coefficients, demand) |
194 | 197 | } |
| 198 | + |
| 199 | +#[cfg(test)] |
| 200 | +mod tests { |
| 201 | + use super::*; |
| 202 | + use crate::agent::AgentID; |
| 203 | + use crate::asset::Asset; |
| 204 | + use crate::fixture::{agent_id, process, region_id}; |
| 205 | + use crate::process::Process; |
| 206 | + use crate::region::RegionID; |
| 207 | + use crate::units::Capacity; |
| 208 | + use rstest::rstest; |
| 209 | + use std::rc::Rc; |
| 210 | + |
| 211 | + #[rstest] |
| 212 | + fn test_compare_assets_fallback(process: Process, region_id: RegionID, agent_id: AgentID) { |
| 213 | + let process = Rc::new(process); |
| 214 | + let capacity = Capacity(2.0); |
| 215 | + let asset1 = Asset::new_commissioned( |
| 216 | + agent_id.clone(), |
| 217 | + process.clone(), |
| 218 | + region_id.clone(), |
| 219 | + capacity, |
| 220 | + 2015, |
| 221 | + ) |
| 222 | + .unwrap(); |
| 223 | + let asset2 = |
| 224 | + Asset::new_candidate(process.clone(), region_id.clone(), capacity, 2015).unwrap(); |
| 225 | + let asset3 = |
| 226 | + Asset::new_commissioned(agent_id, process, region_id.clone(), capacity, 2010).unwrap(); |
| 227 | + |
| 228 | + assert!(compare_asset_fallback(&asset1, &asset1).is_eq()); |
| 229 | + assert!(compare_asset_fallback(&asset2, &asset2).is_eq()); |
| 230 | + assert!(compare_asset_fallback(&asset3, &asset3).is_eq()); |
| 231 | + assert!(compare_asset_fallback(&asset1, &asset2).is_lt()); |
| 232 | + assert!(compare_asset_fallback(&asset2, &asset1).is_gt()); |
| 233 | + assert!(compare_asset_fallback(&asset1, &asset3).is_lt()); |
| 234 | + assert!(compare_asset_fallback(&asset3, &asset1).is_gt()); |
| 235 | + assert!(compare_asset_fallback(&asset3, &asset2).is_lt()); |
| 236 | + assert!(compare_asset_fallback(&asset2, &asset3).is_gt()); |
| 237 | + } |
| 238 | +} |
0 commit comments