Skip to content

Commit c66970a

Browse files
committed
Address copilot suggestions
1 parent 7f27c71 commit c66970a

1 file changed

Lines changed: 24 additions & 7 deletions

File tree

src/simulation/prices.rs

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -556,7 +556,7 @@ where
556556
assert!(matches!(
557557
(pricing_strategy, annual_activities),
558558
(PricingStrategy::MarginalCost, _) | (PricingStrategy::FullCost, Some(_))
559-
),);
559+
));
560560

561561
// Accumulator map to collect costs from existing assets. For each (commodity, region,
562562
// ts selection), this maps each asset to a weighted average of the costs for that
@@ -653,7 +653,7 @@ where
653653
/// * `markets_to_price` - Set of (commodity, region) pairs to attempt to price
654654
/// * `existing_prices` - Current commodity prices (used to calculate marginal costs)
655655
/// * `priced_groups` - Set of (commodity, region, time slice selection) groups that have already
656-
/// been prices using existing assets, so should be skipped when looking at candidates
656+
/// been priced using existing assets, so should be skipped when looking at candidates
657657
/// * `year` - Year for which prices are being calculated
658658
/// * `commodities` - Commodity map
659659
/// * `pricing_strategy` - Pricing strategy, either `MarginalCost` or `FullCost`
@@ -684,6 +684,9 @@ where
684684
// Cache of annual fixed costs per flow for each asset (only used for Full cost pricing)
685685
let mut annual_fixed_costs: HashMap<_, _> = HashMap::new();
686686

687+
// Cache of annual activity limits for each asset (only used for Full cost pricing)
688+
let mut annual_activity_limits: HashMap<_, _> = HashMap::new();
689+
687690
// Accumulator map to collect costs from candidate assets. Similar to existing_accum,
688691
// but costs are weighted according to activity limits (i.e. assuming full utilisation).
689692
let mut cand_accum: IndexMap<
@@ -695,6 +698,22 @@ where
695698
for (asset, time_slice) in activity_keys_for_candidates {
696699
let region_id = asset.region_id();
697700

701+
// When using full cost pricing, skip assets with a zero upper limit on annual activity,
702+
// since we cannot calculate a fixed cost per flow.
703+
let annual_activity_limit =
704+
matches!(pricing_strategy, PricingStrategy::FullCost).then(|| {
705+
*annual_activity_limits
706+
.entry(asset.clone())
707+
.or_insert_with(|| {
708+
*asset
709+
.get_activity_limits_for_selection(&TimeSliceSelection::Annual)
710+
.end()
711+
})
712+
});
713+
if annual_activity_limit.is_some_and(|limit| limit < Activity::EPSILON) {
714+
continue;
715+
}
716+
698717
// Get activity limits: used to weight marginal costs for seasonal/annual commodities
699718
let activity_limit = *asset
700719
.get_activity_limits_for_selection(&TimeSliceSelection::Single(time_slice.clone()))
@@ -724,13 +743,11 @@ where
724743
// Calculate total cost (marginal + fixed if applicable)
725744
let total_cost = match pricing_strategy {
726745
PricingStrategy::FullCost => {
746+
// Get fixed costs assuming full utilisation (i.e. using the activity limit)
747+
// Input-stage validation should ensure that this limit is never zero
727748
let annual_fixed_costs_per_flow =
728749
annual_fixed_costs.entry(asset.clone()).or_insert_with(|| {
729-
asset.get_annual_fixed_costs_per_flow(
730-
*asset
731-
.get_activity_limits_for_selection(&TimeSliceSelection::Annual)
732-
.end(),
733-
)
750+
asset.get_annual_fixed_costs_per_flow(annual_activity_limit.unwrap())
734751
});
735752
marginal_cost + *annual_fixed_costs_per_flow
736753
}

0 commit comments

Comments
 (0)