Skip to content

Commit c96d07f

Browse files
committed
More compare_asset_fallback to investment.rs
1 parent 3cd5896 commit c96d07f

File tree

2 files changed

+50
-63
lines changed

2 files changed

+50
-63
lines changed

src/simulation/investment.rs

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use anyhow::{Context, Result, bail, ensure};
1414
use indexmap::IndexMap;
1515
use itertools::{Itertools, chain};
1616
use log::debug;
17+
use std::cmp::Ordering;
1718
use std::collections::HashMap;
1819
use std::fmt::Display;
1920

@@ -721,7 +722,11 @@ fn select_best_assets(
721722
let assets_sorted_by_metric = outputs_for_opts
722723
.into_iter()
723724
.filter(|output| output.capacity > Capacity(0.0))
724-
.sorted_by(AppraisalOutput::compare_metric)
725+
.sorted_by(|output1, output2| match output1.compare_metric(output2) {
726+
// If equal, we fall back on comparing asset properties
727+
Ordering::Equal => compare_asset_fallback(&output1.asset, &output2.asset),
728+
cmp => cmp,
729+
})
725730
.collect_vec();
726731

727732
// Check if all options have zero capacity. If so, we cannot meet demand, so have to bail
@@ -787,6 +792,14 @@ fn is_any_remaining_demand(demand: &DemandMap) -> bool {
787792
demand.values().any(|flow| *flow > Flow(0.0))
788793
}
789794

795+
/// Compare assets, sorting commissioned before uncommissioned and newer before older.
796+
///
797+
/// Used as a fallback to sort assets when they have equal appraisal tool outputs.
798+
fn compare_asset_fallback(asset1: &Asset, asset2: &Asset) -> Ordering {
799+
(asset2.is_commissioned(), asset2.commission_year())
800+
.cmp(&(asset1.is_commissioned(), asset1.commission_year()))
801+
}
802+
790803
/// Update capacity of chosen asset, if needed, and update both asset options and chosen assets
791804
fn update_assets(
792805
mut best_asset: AssetRef,
@@ -833,14 +846,17 @@ fn update_assets(
833846
#[cfg(test)]
834847
mod tests {
835848
use super::*;
849+
use crate::agent::AgentID;
850+
use crate::asset::Asset;
836851
use crate::commodity::Commodity;
837852
use crate::fixture::{
838-
asset, process, process_activity_limits_map, process_flows_map, svd_commodity, time_slice,
839-
time_slice_info, time_slice_info2,
853+
agent_id, asset, process, process_activity_limits_map, process_flows_map, region_id,
854+
svd_commodity, time_slice, time_slice_info, time_slice_info2,
840855
};
841856
use crate::process::{ActivityLimits, FlowType, Process, ProcessFlow};
857+
use crate::region::RegionID;
842858
use crate::time_slice::{TimeSliceID, TimeSliceInfo};
843-
use crate::units::{Flow, FlowPerActivity, MoneyPerFlow};
859+
use crate::units::{Capacity, Flow, FlowPerActivity, MoneyPerFlow};
844860
use indexmap::indexmap;
845861
use rstest::rstest;
846862
use std::rc::Rc;
@@ -926,4 +942,32 @@ mod tests {
926942
// Maximum = 20.0
927943
assert_eq!(result, Capacity(20.0));
928944
}
945+
946+
#[rstest]
947+
fn test_compare_assets_fallback(process: Process, region_id: RegionID, agent_id: AgentID) {
948+
let process = Rc::new(process);
949+
let capacity = Capacity(2.0);
950+
let asset1 = Asset::new_commissioned(
951+
agent_id.clone(),
952+
process.clone(),
953+
region_id.clone(),
954+
capacity,
955+
2015,
956+
)
957+
.unwrap();
958+
let asset2 =
959+
Asset::new_candidate(process.clone(), region_id.clone(), capacity, 2015).unwrap();
960+
let asset3 =
961+
Asset::new_commissioned(agent_id, process, region_id.clone(), capacity, 2010).unwrap();
962+
963+
assert!(compare_asset_fallback(&asset1, &asset1).is_eq());
964+
assert!(compare_asset_fallback(&asset2, &asset2).is_eq());
965+
assert!(compare_asset_fallback(&asset3, &asset3).is_eq());
966+
assert!(compare_asset_fallback(&asset1, &asset2).is_lt());
967+
assert!(compare_asset_fallback(&asset2, &asset1).is_gt());
968+
assert!(compare_asset_fallback(&asset1, &asset3).is_lt());
969+
assert!(compare_asset_fallback(&asset3, &asset1).is_gt());
970+
assert!(compare_asset_fallback(&asset3, &asset2).is_lt());
971+
assert!(compare_asset_fallback(&asset2, &asset3).is_gt());
972+
}
929973
}

src/simulation/investment/appraisal.rs

Lines changed: 2 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! Calculation for investment tools such as Levelised Cost of X (LCOX) and Net Present Value (NPV).
22
use super::DemandMap;
33
use crate::agent::ObjectiveType;
4-
use crate::asset::{Asset, AssetRef};
4+
use crate::asset::AssetRef;
55
use crate::commodity::Commodity;
66
use crate::finance::{lcox, profitability_index};
77
use crate::model::Model;
@@ -54,27 +54,11 @@ impl AppraisalOutput {
5454
);
5555

5656
if approx_eq!(f64, self.metric, other.metric) {
57-
self.compare_with_equal_metrics(other)
57+
Ordering::Equal
5858
} else {
5959
self.metric.partial_cmp(&other.metric).unwrap()
6060
}
6161
}
62-
63-
/// Compare this appraisal to another when the metrics are known to be equal.
64-
pub fn compare_with_equal_metrics(&self, other: &Self) -> Ordering {
65-
assert!(
66-
approx_eq!(f64, self.metric, other.metric),
67-
"Appraisal metrics must be equal"
68-
);
69-
70-
compare_asset_fallback(&self.asset, &other.asset)
71-
}
72-
}
73-
74-
/// Sort commissioned assets first and newer before older
75-
fn compare_asset_fallback(asset1: &Asset, asset2: &Asset) -> Ordering {
76-
(asset2.is_commissioned(), asset2.commission_year())
77-
.cmp(&(asset1.is_commissioned(), asset1.commission_year()))
7862
}
7963

8064
/// Calculate LCOX for a hypothetical investment in the given asset.
@@ -181,44 +165,3 @@ pub fn appraise_investment(
181165
};
182166
appraisal_method(model, asset, max_capacity, commodity, coefficients, demand)
183167
}
184-
185-
#[cfg(test)]
186-
mod tests {
187-
use super::*;
188-
use crate::agent::AgentID;
189-
use crate::asset::Asset;
190-
use crate::fixture::{agent_id, process, region_id};
191-
use crate::process::Process;
192-
use crate::region::RegionID;
193-
use crate::units::Capacity;
194-
use rstest::rstest;
195-
use std::rc::Rc;
196-
197-
#[rstest]
198-
fn test_compare_assets_fallback(process: Process, region_id: RegionID, agent_id: AgentID) {
199-
let process = Rc::new(process);
200-
let capacity = Capacity(2.0);
201-
let asset1 = Asset::new_commissioned(
202-
agent_id.clone(),
203-
process.clone(),
204-
region_id.clone(),
205-
capacity,
206-
2015,
207-
)
208-
.unwrap();
209-
let asset2 =
210-
Asset::new_candidate(process.clone(), region_id.clone(), capacity, 2015).unwrap();
211-
let asset3 =
212-
Asset::new_commissioned(agent_id, process, region_id.clone(), capacity, 2010).unwrap();
213-
214-
assert!(compare_asset_fallback(&asset1, &asset1).is_eq());
215-
assert!(compare_asset_fallback(&asset2, &asset2).is_eq());
216-
assert!(compare_asset_fallback(&asset3, &asset3).is_eq());
217-
assert!(compare_asset_fallback(&asset1, &asset2).is_lt());
218-
assert!(compare_asset_fallback(&asset2, &asset1).is_gt());
219-
assert!(compare_asset_fallback(&asset1, &asset3).is_lt());
220-
assert!(compare_asset_fallback(&asset3, &asset1).is_gt());
221-
assert!(compare_asset_fallback(&asset3, &asset2).is_lt());
222-
assert!(compare_asset_fallback(&asset2, &asset3).is_gt());
223-
}
224-
}

0 commit comments

Comments
 (0)