Skip to content

Commit b6364c7

Browse files
committed
Apply suggestions from @alexdewar
1 parent 95f2083 commit b6364c7

3 files changed

Lines changed: 42 additions & 30 deletions

File tree

src/graph/validate.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,11 @@ fn prepare_commodities_graph_for_validation(
6868
filtered_graph
6969
}
7070

71-
/// Checks if a process can be active for a particular timeslice in a given year and region
71+
/// Checks if a process can be active for a particular time slice in a given year and region
7272
///
7373
/// It considers all commission years that can lead to a running process in the target region and
7474
/// year, accounting for the process lifetime, and then checks if, for any of those, the process
75-
/// is active in the required timeslice. In other words, this checks if there is the _possibility_
75+
/// is active in the required time slice. In other words, this checks if there is the _possibility_
7676
/// of having an active process, although there is no guarantee of that happening since it depends
7777
/// on the investment.
7878
fn can_be_active(

src/process.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,7 @@ impl ActivityLimits {
290290
let lower = *ts_limit.start();
291291
let mut upper = *ts_limit.end();
292292

293-
// If there's a seasonal/annual limit, we must cap the timeslice limit to ensure that it
293+
// If there's a seasonal/annual limit, we must cap the time slice limit to ensure that it
294294
// doesn't exceed the upper bound of the season/year
295295
if let Some(seasonal_limit) = self.seasonal_limits.get(&time_slice.season) {
296296
upper = upper.min(*seasonal_limit.end());
@@ -356,7 +356,7 @@ impl ActivityLimits {
356356

357357
/// Iterate over all limits
358358
///
359-
/// This first iterates over all individual timeslice limits, followed by seasonal limits (if
359+
/// This first iterates over all individual time slice limits, followed by seasonal limits (if
360360
/// any), and finally the annual limit (if any).
361361
pub fn iter_limits(
362362
&self,
@@ -1030,10 +1030,10 @@ mod tests {
10301030
fn new_with_full_availability(time_slice_info2: TimeSliceInfo) {
10311031
let limits = ActivityLimits::new_with_full_availability(&time_slice_info2);
10321032

1033-
// Each timeslice from the info should be present in the limits
1033+
// Each time slice from the info should be present in the limits
10341034
for (ts_id, ts_len) in time_slice_info2.iter() {
10351035
let l = limits.get_limit_for_time_slice(ts_id);
1036-
// Lower bound should be zero and upper bound equal to timeslice length
1036+
// Lower bound should be zero and upper bound equal to time slice length
10371037
assert_eq!(*l.start(), Dimensionless(0.0));
10381038
assert_eq!(*l.end(), Dimensionless(ts_len.value()));
10391039
}
@@ -1048,15 +1048,15 @@ mod tests {
10481048
fn new_from_limits_with_seasonal_limit_applied(time_slice_info2: TimeSliceInfo) {
10491049
let mut limits = HashMap::new();
10501050

1051-
// Set a seasonal upper limit that is stricter than the sum of timeslices
1051+
// Set a seasonal upper limit that is stricter than the sum of time slices
10521052
limits.insert(
10531053
TimeSliceSelection::Season("winter".into()),
10541054
Dimensionless(0.0)..=Dimensionless(0.01),
10551055
);
10561056

10571057
let result = ActivityLimits::new_from_limits(&limits, &time_slice_info2).unwrap();
10581058

1059-
// Each timeslice upper bound should be capped by the seasonal upper bound (0.01)
1059+
// Each time slice upper bound should be capped by the seasonal upper bound (0.01)
10601060
for (ts_id, _ts_len) in time_slice_info2.iter() {
10611061
let ts_limit = result.get_limit_for_time_slice(ts_id);
10621062
assert_eq!(*ts_limit.end(), Dimensionless(0.01));
@@ -1071,15 +1071,15 @@ mod tests {
10711071
fn new_from_limits_with_annual_limit_applied(time_slice_info2: TimeSliceInfo) {
10721072
let mut limits = HashMap::new();
10731073

1074-
// Set an annual upper limit that is stricter than the sum of timeslices
1074+
// Set an annual upper limit that is stricter than the sum of time slices
10751075
limits.insert(
10761076
TimeSliceSelection::Annual,
10771077
Dimensionless(0.0)..=Dimensionless(0.01),
10781078
);
10791079

10801080
let result = ActivityLimits::new_from_limits(&limits, &time_slice_info2).unwrap();
10811081

1082-
// Each timeslice upper bound should be capped by the annual upper bound (0.01)
1082+
// Each time slice upper bound should be capped by the annual upper bound (0.01)
10831083
for (ts_id, _ts_len) in time_slice_info2.iter() {
10841084
let ts_limit = result.get_limit_for_time_slice(ts_id);
10851085
assert_eq!(*ts_limit.end(), Dimensionless(0.01));
@@ -1098,7 +1098,7 @@ mod tests {
10981098
fn new_from_limits_missing_timeslices_error(time_slice_info2: TimeSliceInfo) {
10991099
let mut limits = HashMap::new();
11001100

1101-
// Add a single timeslice limit but do not provide limits for all timeslices
1101+
// Add a single time slice limit but do not provide limits for all time slices
11021102
let first_ts = time_slice_info2.iter().next().unwrap().0.clone();
11031103
limits.insert(
11041104
TimeSliceSelection::Single(first_ts),

src/simulation/prices.rs

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -508,7 +508,7 @@ fn add_marginal_cost_prices<'a, I, J>(
508508
year,
509509
commodities,
510510
&PricingStrategy::MarginalCost,
511-
None::<&HashMap<AssetRef, Activity>>,
511+
/*annual_activities=*/ None,
512512
)
513513
.collect();
514514
let priced_groups: HashSet<_> = group_prices.keys().cloned().collect();
@@ -567,10 +567,17 @@ where
567567
I: Iterator<Item = (&'a AssetRef, &'a TimeSliceID, Activity)>,
568568
{
569569
// Validate supported strategies, and require annual activities for FullCost pricing.
570-
assert!(matches!(
571-
(pricing_strategy, annual_activities),
572-
(PricingStrategy::MarginalCost, _) | (PricingStrategy::FullCost, Some(_))
573-
));
570+
match pricing_strategy {
571+
PricingStrategy::MarginalCost => assert!(
572+
annual_activities.is_none(),
573+
"Cannot provide annual_activities with marginal pricing strategy"
574+
),
575+
PricingStrategy::FullCost => assert!(
576+
annual_activities.is_some(),
577+
"annual_activities must be provided for full pricing strategy"
578+
),
579+
_ => panic!("Invalid pricing strategy"),
580+
}
574581

575582
// Accumulator map to collect costs from existing assets. For each (commodity, region,
576583
// ts selection), this maps each asset to a weighted average of the costs for that
@@ -583,16 +590,15 @@ where
583590
> = IndexMap::new();
584591

585592
// Cache of annual fixed costs per flow for each asset (only used for Full cost pricing)
586-
let mut annual_fixed_costs: HashMap<_, _> = HashMap::new();
593+
let mut annual_fixed_costs = HashMap::new();
587594

588595
// Iterate over existing assets and their activities
589596
for (asset, time_slice, activity) in activity_for_existing {
590597
let region_id = asset.region_id();
591598

592599
// When using full cost pricing, skip assets with zero activity across the year, since
593600
// we cannot calculate a fixed cost per flow.
594-
let annual_activity = matches!(pricing_strategy, PricingStrategy::FullCost)
595-
.then(|| annual_activities.unwrap()[asset]);
601+
let annual_activity = annual_activities.map(|activities| activities[asset]);
596602
if annual_activity.is_some_and(|annual_activity| annual_activity < Activity::EPSILON) {
597603
continue;
598604
}
@@ -654,7 +660,7 @@ where
654660
/// involves taking a weighted average across time slices for each asset according to potential
655661
/// activity (i.e. the upper activity limit), omitting prices in the extreme case of zero potential
656662
/// activity (Note: this should NOT happen as validation should ensure there is at least one
657-
/// candidate that can provide a price in each timeslice for which a price could be required).
663+
/// candidate that can provide a price in each time slice for which a price could be required).
658664
/// Costs for candidates are calculated assuming full utilisation.
659665
///
660666
/// # Arguments
@@ -692,10 +698,10 @@ where
692698
));
693699

694700
// Cache of annual fixed costs per flow for each asset (only used for Full cost pricing)
695-
let mut annual_fixed_costs: HashMap<_, _> = HashMap::new();
701+
let mut annual_fixed_costs = HashMap::new();
696702

697703
// Cache of annual activity limits for each asset (only used for Full cost pricing)
698-
let mut annual_activity_limits: HashMap<_, _> = HashMap::new();
704+
let mut annual_activity_limits = HashMap::new();
699705

700706
// Accumulator map to collect costs from candidate assets. Similar to existing_accum,
701707
// but costs are weighted according to activity limits (i.e. assuming full utilisation).
@@ -813,7 +819,7 @@ fn add_marginal_cost_average_prices<'a, I, J>(
813819
year,
814820
commodities,
815821
&PricingStrategy::MarginalCost,
816-
None::<&HashMap<AssetRef, Activity>>,
822+
/*annual_activities=*/ None,
817823
)
818824
.collect();
819825
let priced_groups: HashSet<_> = group_prices.keys().cloned().collect();
@@ -872,10 +878,17 @@ where
872878
I: Iterator<Item = (&'a AssetRef, &'a TimeSliceID, Activity)>,
873879
{
874880
// Validate supported strategies, and require annual activities for FullCost pricing.
875-
assert!(matches!(
876-
(pricing_strategy, annual_activities),
877-
(PricingStrategy::MarginalCost, _) | (PricingStrategy::FullCost, Some(_))
878-
));
881+
match pricing_strategy {
882+
PricingStrategy::MarginalCost => assert!(
883+
annual_activities.is_none(),
884+
"Cannot provide annual_activities with marginal pricing strategy"
885+
),
886+
PricingStrategy::FullCost => assert!(
887+
annual_activities.is_some(),
888+
"annual_activities must be provided for full pricing strategy"
889+
),
890+
_ => panic!("Invalid pricing strategy"),
891+
}
879892

880893
// Accumulator map to collect costs from existing assets. Collects a weighted average
881894
// for each (commodity, region, ts selection), across all contributing assets, weighted
@@ -888,16 +901,15 @@ where
888901
> = IndexMap::new();
889902

890903
// Cache of annual fixed costs per flow for each asset (only used for Full cost pricing)
891-
let mut annual_fixed_costs: HashMap<_, _> = HashMap::new();
904+
let mut annual_fixed_costs = HashMap::new();
892905

893906
// Iterate over existing assets and their activities
894907
for (asset, time_slice, activity) in activity_for_existing {
895908
let region_id = asset.region_id();
896909

897910
// When using full cost pricing, skip assets with zero annual activity, since we cannot
898911
// calculate a fixed cost per flow.
899-
let annual_activity = matches!(pricing_strategy, PricingStrategy::FullCost)
900-
.then(|| annual_activities.unwrap()[asset]);
912+
let annual_activity = annual_activities.map(|activities| activities[asset]);
901913
if annual_activity.is_some_and(|annual_activity| annual_activity < Activity::EPSILON) {
902914
continue;
903915
}

0 commit comments

Comments
 (0)