Skip to content

Commit d40d69c

Browse files
committed
Use fixed opex in full cost calculation
1 parent e05d55e commit d40d69c

2 files changed

Lines changed: 29 additions & 27 deletions

File tree

src/asset.rs

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use crate::simulation::CommodityPrices;
1010
use crate::time_slice::{TimeSliceID, TimeSliceSelection};
1111
use crate::units::{
1212
Activity, ActivityPerCapacity, Capacity, Dimensionless, FlowPerActivity, MoneyPerActivity,
13-
MoneyPerCapacity, MoneyPerFlow,
13+
MoneyPerCapacity, MoneyPerFlow, Year,
1414
};
1515
use anyhow::{Context, Result, ensure};
1616
use indexmap::IndexMap;
@@ -756,33 +756,35 @@ impl Asset {
756756
annual_capital_cost(capital_cost, lifetime, discount_rate)
757757
}
758758

759-
/// Get the annual capital cost per unit of activity for this asset
759+
/// Get the annual fixed costs (AFC) per unit of activity for this asset
760760
///
761-
/// Total capital costs (cost per capacity * capacity) are shared equally over the year in
762-
/// accordance with the annual activity.
763-
pub fn get_annual_capital_cost_per_activity(
761+
/// Total capital costs and fixed opex are shared equally over the year in accordance with the
762+
/// annual activity.
763+
pub fn get_annual_fixed_costs_per_activity(
764764
&self,
765765
annual_activity: Activity,
766766
) -> MoneyPerActivity {
767767
let annual_capital_cost_per_capacity = self.get_annual_capital_cost_per_capacity();
768-
let total_annual_capital_cost = annual_capital_cost_per_capacity * self.total_capacity();
768+
let annual_fixed_opex = self.process_parameter.fixed_operating_cost * Year(1.0);
769+
let total_annual_fixed_costs =
770+
(annual_capital_cost_per_capacity + annual_fixed_opex) * self.total_capacity();
769771
assert!(
770772
annual_activity > Activity::EPSILON,
771-
"Cannot calculate annual capital cost per activity for an asset with zero annual activity"
773+
"Cannot calculate annual fixed costs per activity for an asset with zero annual activity"
772774
);
773-
total_annual_capital_cost / annual_activity
775+
total_annual_fixed_costs / annual_activity
774776
}
775777

776-
/// Get the annual capital cost per unit of output flow for this asset
778+
/// Get the annual fixed costs (AFC) per unit of output flow for this asset
777779
///
778-
/// Total capital costs (cost per capacity * capacity) are shared equally across all output
779-
/// flows in accordance with the annual activity and total output per unit of activity.
780-
pub fn get_annual_capital_cost_per_flow(&self, annual_activity: Activity) -> MoneyPerFlow {
781-
let annual_capital_cost_per_activity =
782-
self.get_annual_capital_cost_per_activity(annual_activity);
780+
/// Total capital costs and fixed opex are shared equally across all output flows in accordance
781+
/// with the annual activity and total output per unit of activity.
782+
pub fn get_annual_fixed_costs_per_flow(&self, annual_activity: Activity) -> MoneyPerFlow {
783+
let annual_fixed_costs_per_activity =
784+
self.get_annual_fixed_costs_per_activity(annual_activity);
783785
let total_output_per_activity = self.get_total_output_per_activity();
784786
assert!(total_output_per_activity > FlowPerActivity::EPSILON); // input checks should guarantee this
785-
annual_capital_cost_per_activity / total_output_per_activity
787+
annual_fixed_costs_per_activity / total_output_per_activity
786788
}
787789

788790
/// Maximum activity for this asset

src/simulation/prices.rs

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ pub fn calculate_prices(model: &Model, solution: &Solution, year: u32) -> Result
6262
ensure!(
6363
!matches!(investment_set, InvestmentSet::Cycle(_)),
6464
"Cannot calculate prices using the `marginal` and `full` pricing strategies \
65-
for Cycle investment sets."
65+
for markets with cyclical commodity dependencies."
6666
);
6767
}
6868

@@ -551,7 +551,7 @@ where
551551
// Start by looking at existing assets
552552
// Calculate highest full cost for each commodity/region/time slice
553553
// Keep track of keys with prices - missing keys will be handled by candidates later
554-
let mut annual_capital_costs_cache = HashMap::new();
554+
let mut annual_fixed_costs_cache = HashMap::new();
555555
let mut priced_by_existing = HashSet::new();
556556
for (asset, time_slice) in activity_keys_for_existing {
557557
let annual_activity = annual_activities[asset];
@@ -571,10 +571,10 @@ where
571571
continue;
572572
}
573573

574-
// Calculate/cache annual capital cost for this asset
575-
let annual_capital_cost_per_flow = *annual_capital_costs_cache
574+
// Calculate/cache annual fixed costs for this asset
575+
let annual_fixed_costs_per_flow = *annual_fixed_costs_cache
576576
.entry(asset.clone())
577-
.or_insert_with(|| asset.get_annual_capital_cost_per_flow(annual_activity));
577+
.or_insert_with(|| asset.get_annual_fixed_costs_per_flow(annual_activity));
578578

579579
// Iterate over all the SED/SVD marginal costs for commodities we need prices for
580580
for (commodity_id, marginal_cost) in asset.iter_marginal_costs_with_filter(
@@ -583,8 +583,8 @@ where
583583
time_slice,
584584
|cid: &CommodityID| markets_to_price.contains(&(cid.clone(), region_id.clone())),
585585
) {
586-
// Add capital cost per flow to marginal cost to get full cost
587-
let marginal_cost = marginal_cost + annual_capital_cost_per_flow;
586+
// Add annual fixed costs per flow to marginal cost to get full cost
587+
let marginal_cost = marginal_cost + annual_fixed_costs_per_flow;
588588

589589
// Update the highest cost for this commodity/region/time slice
590590
let key = (commodity_id.clone(), region_id.clone(), time_slice.clone());
@@ -619,12 +619,12 @@ where
619619
continue;
620620
}
621621

622-
// Calculate/cache annual capital cost per flow for this asset assuming full dispatch
622+
// Calculate/cache annual fixed cost per flow for this asset assuming full dispatch
623623
// (bound by the activity limits of the asset)
624-
let annual_capital_cost_per_flow = *annual_capital_costs_cache
624+
let annual_fixed_costs_per_flow = *annual_fixed_costs_cache
625625
.entry(asset.clone())
626626
.or_insert_with(|| {
627-
asset.get_annual_capital_cost_per_flow(
627+
asset.get_annual_fixed_costs_per_flow(
628628
*asset
629629
.get_activity_limits_for_selection(&TimeSliceSelection::Annual)
630630
.end(),
@@ -638,8 +638,8 @@ where
638638
time_slice,
639639
|cid: &CommodityID| should_process(cid),
640640
) {
641-
// Add capital cost per flow to marginal cost to get full cost
642-
let full_cost = marginal_cost + annual_capital_cost_per_flow;
641+
// Add annual fixed costs per flow to marginal cost to get full cost
642+
let full_cost = marginal_cost + annual_fixed_costs_per_flow;
643643

644644
// Update the _lowest_ cost for this commodity/region/time slice
645645
let key = (commodity_id.clone(), region_id.clone(), time_slice.clone());

0 commit comments

Comments
 (0)