Skip to content

Commit ff15327

Browse files
authored
Merge pull request #1091 from EnergySystemsModellingLab/add-appraisal-output-tests
add tests for checking appraisal outputs are ordered by investment priority correctly
2 parents 2ab3ed7 + 5897b60 commit ff15327

File tree

3 files changed

+437
-65
lines changed

3 files changed

+437
-65
lines changed

src/simulation/investment.rs

Lines changed: 9 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,14 @@ use anyhow::{Context, Result, ensure};
1313
use indexmap::IndexMap;
1414
use itertools::{Itertools, chain};
1515
use log::debug;
16-
use std::cmp::Ordering;
1716
use std::collections::{HashMap, HashSet};
1817
use std::fmt::Display;
1918

2019
pub mod appraisal;
2120
use appraisal::coefficients::calculate_coefficients_for_assets;
22-
use appraisal::{AppraisalOutput, appraise_investment};
21+
use appraisal::{
22+
AppraisalOutput, appraise_investment, sort_appraisal_outputs_by_investment_priority,
23+
};
2324

2425
/// A map of demand across time slices for a specific market
2526
type DemandMap = IndexMap<TimeSliceID, Flow>;
@@ -745,16 +746,7 @@ fn select_best_assets(
745746
&outputs_for_opts,
746747
)?;
747748

748-
// Sort assets by appraisal metric
749-
let assets_sorted_by_metric = outputs_for_opts
750-
.into_iter()
751-
.filter(|output| output.capacity.total_capacity() > Capacity(0.0))
752-
.sorted_by(|output1, output2| match output1.compare_metric(output2) {
753-
// If equal, we fall back on comparing asset properties
754-
Ordering::Equal => compare_asset_fallback(&output1.asset, &output2.asset),
755-
cmp => cmp,
756-
})
757-
.collect_vec();
749+
sort_appraisal_outputs_by_investment_priority(&mut outputs_for_opts);
758750

759751
// Check if all options have zero capacity. If so, we cannot meet demand, so have to bail
760752
// out.
@@ -765,20 +757,15 @@ fn select_best_assets(
765757
// - known issue with the NPV objective
766758
// (see https://github.com/EnergySystemsModellingLab/MUSE2/issues/716).
767759
ensure!(
768-
!assets_sorted_by_metric.is_empty(),
760+
!outputs_for_opts.is_empty(),
769761
"No feasible investment options for commodity '{}' after appraisal",
770762
&commodity.id
771763
);
772764

773765
// Warn if there are multiple equally good assets
774-
warn_on_equal_appraisal_outputs(
775-
&assets_sorted_by_metric,
776-
&agent.id,
777-
&commodity.id,
778-
region_id,
779-
);
766+
warn_on_equal_appraisal_outputs(&outputs_for_opts, &agent.id, &commodity.id, region_id);
780767

781-
let best_output = assets_sorted_by_metric.into_iter().next().unwrap();
768+
let best_output = outputs_for_opts.into_iter().next().unwrap();
782769

783770
// Log the selected asset
784771
debug!(
@@ -819,16 +806,6 @@ fn is_any_remaining_demand(demand: &DemandMap) -> bool {
819806
demand.values().any(|flow| *flow > Flow(0.0))
820807
}
821808

822-
/// Compare assets as a fallback if metrics are equal.
823-
///
824-
/// Commissioned assets are ordered before uncommissioned and newer before older.
825-
///
826-
/// Used as a fallback to sort assets when they have equal appraisal tool outputs.
827-
fn compare_asset_fallback(asset1: &Asset, asset2: &Asset) -> Ordering {
828-
(asset2.is_commissioned(), asset2.commission_year())
829-
.cmp(&(asset1.is_commissioned(), asset1.commission_year()))
830-
}
831-
832809
/// Update capacity of chosen asset, if needed, and update both asset options and chosen assets
833810
fn update_assets(
834811
mut best_asset: AssetRef,
@@ -875,15 +852,12 @@ fn update_assets(
875852
#[cfg(test)]
876853
mod tests {
877854
use super::*;
878-
use crate::agent::AgentID;
879-
use crate::asset::Asset;
880855
use crate::commodity::Commodity;
881856
use crate::fixture::{
882-
agent_id, asset, process, process_activity_limits_map, process_flows_map, region_id,
883-
svd_commodity, time_slice, time_slice_info, time_slice_info2,
857+
asset, process, process_activity_limits_map, process_flows_map, svd_commodity, time_slice,
858+
time_slice_info, time_slice_info2,
884859
};
885860
use crate::process::{ActivityLimits, FlowType, Process, ProcessFlow};
886-
use crate::region::RegionID;
887861
use crate::time_slice::{TimeSliceID, TimeSliceInfo};
888862
use crate::units::{Capacity, Flow, FlowPerActivity, MoneyPerFlow};
889863
use indexmap::indexmap;
@@ -971,32 +945,4 @@ mod tests {
971945
// Maximum = 20.0
972946
assert_eq!(result, Capacity(20.0));
973947
}
974-
975-
#[rstest]
976-
fn compare_assets_fallback(process: Process, region_id: RegionID, agent_id: AgentID) {
977-
let process = Rc::new(process);
978-
let capacity = Capacity(2.0);
979-
let asset1 = Asset::new_commissioned(
980-
agent_id.clone(),
981-
process.clone(),
982-
region_id.clone(),
983-
capacity,
984-
2015,
985-
)
986-
.unwrap();
987-
let asset2 =
988-
Asset::new_candidate(process.clone(), region_id.clone(), capacity, 2015).unwrap();
989-
let asset3 =
990-
Asset::new_commissioned(agent_id, process, region_id.clone(), capacity, 2010).unwrap();
991-
992-
assert!(compare_asset_fallback(&asset1, &asset1).is_eq());
993-
assert!(compare_asset_fallback(&asset2, &asset2).is_eq());
994-
assert!(compare_asset_fallback(&asset3, &asset3).is_eq());
995-
assert!(compare_asset_fallback(&asset1, &asset2).is_lt());
996-
assert!(compare_asset_fallback(&asset2, &asset1).is_gt());
997-
assert!(compare_asset_fallback(&asset1, &asset3).is_lt());
998-
assert!(compare_asset_fallback(&asset3, &asset1).is_gt());
999-
assert!(compare_asset_fallback(&asset3, &asset2).is_lt());
1000-
assert!(compare_asset_fallback(&asset2, &asset3).is_gt());
1001-
}
1002948
}

0 commit comments

Comments
 (0)