Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 2 additions & 9 deletions src/graph/validate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ fn prepare_commodities_graph_for_validation(
base_graph: &CommoditiesGraph,
processes: &ProcessMap,
commodities: &CommodityMap,
time_slice_info: &TimeSliceInfo,
region_id: &RegionID,
year: u32,
time_slice_selection: &TimeSliceSelection,
Expand All @@ -42,7 +41,7 @@ fn prepare_commodities_graph_for_validation(
let process = &processes[process_id];

// Check if the process has availability > 0 in any time slice in the selection
can_be_active(process, &key, time_slice_selection, time_slice_info)
can_be_active(process, &key, time_slice_selection)
});

// Add demand edges
Expand Down Expand Up @@ -80,7 +79,6 @@ fn can_be_active(
process: &Process,
target: &(RegionID, u32),
time_slice_selection: &TimeSliceSelection,
time_slice_info: &TimeSliceInfo,
) -> bool {
let (target_region, target_year) = target;

Expand All @@ -92,11 +90,7 @@ fn can_be_active(
let Some(limits_map) = process.activity_limits.get(target) else {
continue;
};
if limits_map
.get_limit(time_slice_selection, time_slice_info)
.end()
> &Dimensionless(0.0)
{
if limits_map.get_limit(time_slice_selection).end() > &Dimensionless(0.0) {
return true;
}
}
Expand Down Expand Up @@ -220,7 +214,6 @@ pub fn validate_commodity_graphs_for_model(
base_graph,
processes,
commodities,
time_slice_info,
region_id,
*year,
&ts_selection,
Expand Down
51 changes: 38 additions & 13 deletions src/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
use crate::commodity::{Commodity, CommodityID};
use crate::id::define_id_type;
use crate::region::RegionID;
use crate::time_slice::{Season, TimeSliceID, TimeSliceInfo, TimeSliceLevel, TimeSliceSelection};
use crate::time_slice::{Season, TimeSliceID, TimeSliceInfo, TimeSliceSelection};
use crate::units::{
ActivityPerCapacity, Dimensionless, FlowPerActivity, MoneyPerActivity, MoneyPerCapacity,
MoneyPerCapacityPerYear, MoneyPerFlow,
Expand Down Expand Up @@ -243,7 +243,7 @@ impl ActivityLimits {
/// Add an annual limit
fn add_annual_limit(&mut self, limit: RangeInclusive<Dimensionless>) -> Result<()> {
// Get current limit for the year
let current_limit = self.get_limit_for_year(&TimeSliceInfo::default());
let current_limit = self.get_limit_for_year();

// Ensure that the new limit overlaps with the current limit
// If not, it's impossible to satisfy both limits, so we must exit with an error
Expand All @@ -266,12 +266,11 @@ impl ActivityLimits {
pub fn get_limit(
&self,
time_slice_selection: &TimeSliceSelection,
time_slice_info: &TimeSliceInfo,
) -> RangeInclusive<Dimensionless> {
match time_slice_selection {
TimeSliceSelection::Single(ts_id) => self.get_limit_for_time_slice(ts_id),
TimeSliceSelection::Season(season) => self.get_limit_for_season(season),
TimeSliceSelection::Annual => self.get_limit_for_year(time_slice_info),
TimeSliceSelection::Annual => self.get_limit_for_year(),
}
}

Expand Down Expand Up @@ -325,14 +324,16 @@ impl ActivityLimits {
}

/// Get the limit for the entire year
fn get_limit_for_year(&self, time_slice_info: &TimeSliceInfo) -> RangeInclusive<Dimensionless> {
fn get_limit_for_year(&self) -> RangeInclusive<Dimensionless> {
// Get the sum of limits for all seasons
let mut total_lower = Dimensionless(0.0);
let mut total_upper = Dimensionless(0.0);
for ts_selection in time_slice_info.iter_selections_at_level(TimeSliceLevel::Season) {
let TimeSliceSelection::Season(season) = ts_selection else {
panic!("Expected season selection")
};
let seasons = self
.time_slice_limits
.keys()
.map(|ts_id| ts_id.season.clone())
.unique();
for season in seasons {
let season_limit = self.get_limit_for_season(&season);
total_lower += *season_limit.start();
total_upper += *season_limit.end();
Expand Down Expand Up @@ -990,7 +991,7 @@ mod tests {
}

// Annual limit should be 0..1
let annual_limit = limits.get_limit(&TimeSliceSelection::Annual, &time_slice_info2);
let annual_limit = limits.get_limit(&TimeSliceSelection::Annual);
assert_approx_eq!(Dimensionless, *annual_limit.start(), Dimensionless(0.0));
assert_approx_eq!(Dimensionless, *annual_limit.end(), Dimensionless(1.0));
}
Expand All @@ -1014,11 +1015,35 @@ mod tests {
}

// The seasonal limit should reflect the given bound
let season_limit = result.get_limit(
&TimeSliceSelection::Season("winter".into()),
&time_slice_info2,
let season_limit = result.get_limit(&TimeSliceSelection::Season("winter".into()));
assert_eq!(*season_limit.end(), Dimensionless(0.01));
}

#[rstest]
fn test_new_from_limits_with_annual_limit_applied(time_slice_info2: TimeSliceInfo) {
let mut limits = HashMap::new();

// Set an annual upper limit that is stricter than the sum of timeslices
limits.insert(
TimeSliceSelection::Annual,
Dimensionless(0.0)..=Dimensionless(0.01),
);

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

// Each timeslice upper bound should be capped by the annual upper bound (0.01)
for (ts_id, _ts_len) in time_slice_info2.iter() {
let ts_limit = result.get_limit_for_time_slice(&ts_id);
assert_eq!(*ts_limit.end(), Dimensionless(0.01));
}

// The seasonal limit should be capped by the annual upper bound (0.01)
let season_limit = result.get_limit(&TimeSliceSelection::Season("winter".into()));
assert_eq!(*season_limit.end(), Dimensionless(0.01));

// The annual limit should reflect the given bound
let annual_limit = result.get_limit(&TimeSliceSelection::Annual);
assert_eq!(*annual_limit.end(), Dimensionless(0.01));
}

#[rstest]
Expand Down
4 changes: 2 additions & 2 deletions tests/data/missing_commodity/assets.csv
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ asset_id,process_id,region_id,agent_id,commission_year,decommission_year,capacit
5,RELCHP,GBR,A0_RES,2020,2035,399.98
6,RBIOBL,GBR,A0_RES,2030,,355.83840587648046
7,BIOPLL,GBR,A0_BPL,2030,,427.00608705177655
8,BIOPRO,GBR,A0_BPD,2030,,108.68349219309701
8,BIOPRO,GBR,A0_BPD,2030,,448.35639140436535
9,RBIOBL,GBR,A0_RES,2040,,3655.8189696
10,BIOPLL,GBR,A0_BPL,2040,,2167.9571005431867
11,BIOPRO,GBR,A0_BPD,2040,,2616.027854781616
11,BIOPRO,GBR,A0_BPD,2040,,2276.354955570347
Loading