From fba5e0498ce4a60adbbba1bd6123a0300bfd7836 Mon Sep 17 00:00:00 2001 From: Tom Bland Date: Wed, 16 Apr 2025 10:04:54 +0100 Subject: [PATCH 1/7] Tidy CommodityCostMap --- src/commodity.rs | 19 ++++++------------- src/input/commodity/cost.rs | 6 +++--- src/simulation/optimisation.rs | 14 +++++++++----- 3 files changed, 18 insertions(+), 21 deletions(-) diff --git a/src/commodity.rs b/src/commodity.rs index e61b41616..aea6342d4 100644 --- a/src/commodity.rs +++ b/src/commodity.rs @@ -69,22 +69,15 @@ impl CommodityCostMap { /// Insert a [`CommodityCost`] into the map pub fn insert( &mut self, - region_id: RegionID, - year: u32, - time_slice: TimeSliceID, + key: (RegionID, u32, TimeSliceID), value: CommodityCost, ) -> Option { - self.0.insert((region_id, year, time_slice), value) + self.0.insert(key, value) } /// Retrieve a [`CommodityCost`] from the map - pub fn get( - &self, - region_id: &RegionID, - year: u32, - time_slice: &TimeSliceID, - ) -> Option<&CommodityCost> { - self.0.get(&(region_id.clone(), year, time_slice.clone())) + pub fn get(&self, key: (RegionID, u32, TimeSliceID)) -> Option<&CommodityCost> { + self.0.get(&key) } } @@ -157,8 +150,8 @@ mod tests { }; let mut map = CommodityCostMap::new(); assert!(map - .insert("GBR".into(), 2010, ts.clone(), value.clone()) + .insert(("GBR".into(), 2010, ts.clone()), value.clone()) .is_none()); - assert_eq!(map.get(&"GBR".into(), 2010, &ts).unwrap(), &value); + assert_eq!(map.get(("GBR".into(), 2010, ts)).unwrap(), &value); } } diff --git a/src/input/commodity/cost.rs b/src/input/commodity/cost.rs index 5a7b9b261..a4ecb73ce 100644 --- a/src/input/commodity/cost.rs +++ b/src/input/commodity/cost.rs @@ -101,7 +101,7 @@ where }; ensure!( - map.insert(region_id.clone(), cost.year, time_slice.clone(), value) + map.insert((region_id.clone(), cost.year, time_slice.clone()), value) .is_none(), "Commodity cost entry covered by more than one time slice \ (region: {}, year: {}, time slice: {})", @@ -189,8 +189,8 @@ mod tests { value: cost2.value, }; let mut map = CommodityCostMap::new(); - map.insert("GBR".into(), cost1.year, time_slice.clone(), value1); - map.insert("FRA".into(), cost2.year, time_slice.clone(), value2); + map.insert(("GBR".into(), cost1.year, time_slice.clone()), value1); + map.insert(("FRA".into(), cost2.year, time_slice.clone()), value2); let expected = HashMap::from_iter([("commodity".into(), map)]); assert_eq!( read_commodity_costs_iter( diff --git a/src/simulation/optimisation.rs b/src/simulation/optimisation.rs index 0167c25a6..9f84bc00e 100644 --- a/src/simulation/optimisation.rs +++ b/src/simulation/optimisation.rs @@ -232,7 +232,11 @@ fn calculate_cost_coefficient( } // If there is a user-provided commodity cost for this combination of parameters, include it - if let Some(cost) = flow.commodity.costs.get(&asset.region_id, year, time_slice) { + if let Some(cost) = + flow.commodity + .costs + .get((asset.region_id.clone(), year, time_slice.clone())) + { let apply_cost = match cost.balance_type { BalanceType::Net => true, BalanceType::Consumption => flow.flow < 0.0, @@ -344,7 +348,7 @@ mod tests { value: 2.0, }; let mut costs = CommodityCostMap::new(); - costs.insert("GBR".into(), 2010, time_slice.clone(), cost); + costs.insert(("GBR".into(), 2010, time_slice.clone()), cost); check_coeff!(1.0, false, costs.clone(), 3.0); check_coeff!(-1.0, false, costs, -1.0); @@ -354,7 +358,7 @@ mod tests { value: 2.0, }; let mut costs = CommodityCostMap::new(); - costs.insert("GBR".into(), 2010, time_slice.clone(), cost); + costs.insert(("GBR".into(), 2010, time_slice.clone()), cost); check_coeff!(1.0, false, costs.clone(), 3.0); check_coeff!(-1.0, false, costs, -3.0); @@ -364,7 +368,7 @@ mod tests { value: 2.0, }; let mut costs = CommodityCostMap::new(); - costs.insert("GBR".into(), 2010, time_slice.clone(), cost); + costs.insert(("GBR".into(), 2010, time_slice.clone()), cost); check_coeff!(1.0, false, costs.clone(), 1.0); check_coeff!(-1.0, false, costs, -3.0); @@ -374,7 +378,7 @@ mod tests { value: 2.0, }; let mut costs = CommodityCostMap::new(); - costs.insert("GBR".into(), 2010, time_slice.clone(), cost); + costs.insert(("GBR".into(), 2010, time_slice.clone()), cost); check_coeff!(1.0, true, costs.clone(), 4.0); check_coeff!(-1.0, true, costs, -2.0); } From 476f0ec9caf02f6da97d7b2f411c3bf0f9161772 Mon Sep 17 00:00:00 2001 From: Tom Bland Date: Wed, 16 Apr 2025 10:21:26 +0100 Subject: [PATCH 2/7] Tidy DemandMap --- src/commodity.rs | 14 +++++++------- src/input/commodity/demand.rs | 4 +--- src/input/process.rs | 6 ++++-- src/simulation/optimisation/constraints.rs | 2 +- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/commodity.rs b/src/commodity.rs index aea6342d4..63615e532 100644 --- a/src/commodity.rs +++ b/src/commodity.rs @@ -108,16 +108,16 @@ impl DemandMap { } /// Retrieve the demand for the specified region, year and time slice - pub fn get(&self, region_id: &RegionID, year: u32, time_slice: &TimeSliceID) -> f64 { + pub fn get(&self, key: (RegionID, u32, TimeSliceID)) -> f64 { self.0 - .get(&(region_id.clone(), year, time_slice.clone())) + .get(&key) .copied() - .unwrap_or_else(|| panic!("Missing demand entry: {region_id}, {year}, {time_slice}")) + .unwrap_or_else(|| panic!("Missing demand entry")) } /// Insert a new demand entry for the specified region, year and time slice - pub fn insert(&mut self, region_id: RegionID, year: u32, time_slice: TimeSliceID, demand: f64) { - self.0.insert((region_id, year, time_slice), demand); + pub fn insert(&mut self, key: (RegionID, u32, TimeSliceID), demand: f64) { + self.0.insert(key, demand); } } @@ -133,9 +133,9 @@ mod tests { }; let value = 0.25; let mut map = DemandMap::new(); - map.insert("North".into(), 2020, time_slice.clone(), value); + map.insert(("North".into(), 2020, time_slice.clone()), value); - assert_eq!(map.get(&"North".into(), 2020, &time_slice), value) + assert_eq!(map.get(("North".into(), 2020, time_slice)), value) } #[test] diff --git a/src/input/commodity/demand.rs b/src/input/commodity/demand.rs index 6bd7c1cc7..da7f80bf6 100644 --- a/src/input/commodity/demand.rs +++ b/src/input/commodity/demand.rs @@ -193,9 +193,7 @@ fn compute_demand_maps( // Add a new demand entry map.insert( - region_id.clone(), - *year, - time_slice.clone(), + (region_id.clone(), *year, time_slice.clone()), annual_demand * demand_fraction, ); } diff --git a/src/input/process.rs b/src/input/process.rs index 96d8b097f..973059102 100644 --- a/src/input/process.rs +++ b/src/input/process.rs @@ -158,7 +158,9 @@ fn validate_svd_commodity( for region_id in params.region_ids.iter() { for year in params.milestone_years.iter().copied() { for time_slice in params.time_slice_info.iter_ids() { - let demand = commodity.demand.get(region_id, year, time_slice); + let demand = commodity + .demand + .get((region_id.clone(), year, time_slice.clone())); if demand > 0.0 { let mut has_producer = false; @@ -412,7 +414,7 @@ mod tests { for region in data.region_ids.iter() { for year in milestone_years { for time_slice in time_slice_info.iter_ids() { - demand_map.insert(region.clone(), year, time_slice.clone(), 0.5); + demand_map.insert((region.clone(), year, time_slice.clone()), 0.5); } } } diff --git a/src/simulation/optimisation/constraints.rs b/src/simulation/optimisation/constraints.rs index 0abe29e7e..cc1ef1f81 100644 --- a/src/simulation/optimisation/constraints.rs +++ b/src/simulation/optimisation/constraints.rs @@ -119,7 +119,7 @@ fn add_commodity_balance_constraints( CommodityType::ServiceDemand => { match ts_selection { TimeSliceSelection::Single(ref ts) => { - commodity.demand.get(region_id, year, ts) + commodity.demand.get((region_id.clone(), year, ts.clone())) } // We currently only support specifying demand at the time slice level: // https://github.com/EnergySystemsModellingLab/MUSE_2.0/issues/391 From d41c343327a70b553d700240f9b7d8af383149e9 Mon Sep 17 00:00:00 2001 From: Tom Bland Date: Wed, 16 Apr 2025 10:35:12 +0100 Subject: [PATCH 3/7] Assume CommodityCostMap completeness --- src/commodity.rs | 11 ++++++++--- src/simulation/optimisation.rs | 11 ++++++----- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/commodity.rs b/src/commodity.rs index 63615e532..8e9b498e6 100644 --- a/src/commodity.rs +++ b/src/commodity.rs @@ -66,6 +66,11 @@ impl CommodityCostMap { Self(HashMap::new()) } + /// Check if the map is empty + pub fn is_empty(&self) -> bool { + self.0.is_empty() + } + /// Insert a [`CommodityCost`] into the map pub fn insert( &mut self, @@ -76,8 +81,8 @@ impl CommodityCostMap { } /// Retrieve a [`CommodityCost`] from the map - pub fn get(&self, key: (RegionID, u32, TimeSliceID)) -> Option<&CommodityCost> { - self.0.get(&key) + pub fn get(&self, key: (RegionID, u32, TimeSliceID)) -> &CommodityCost { + self.0.get(&key).unwrap() } } @@ -152,6 +157,6 @@ mod tests { assert!(map .insert(("GBR".into(), 2010, ts.clone()), value.clone()) .is_none()); - assert_eq!(map.get(("GBR".into(), 2010, ts)).unwrap(), &value); + assert_eq!(map.get(("GBR".into(), 2010, ts)), &value); } } diff --git a/src/simulation/optimisation.rs b/src/simulation/optimisation.rs index 9f84bc00e..b64db821d 100644 --- a/src/simulation/optimisation.rs +++ b/src/simulation/optimisation.rs @@ -231,12 +231,13 @@ fn calculate_cost_coefficient( coeff += asset.process.parameter.variable_operating_cost } - // If there is a user-provided commodity cost for this combination of parameters, include it - if let Some(cost) = - flow.commodity + // If there is a user-provided cost for this commodity, include it + if !flow.commodity.costs.is_empty() { + let cost = flow + .commodity .costs - .get((asset.region_id.clone(), year, time_slice.clone())) - { + .get((asset.region_id.clone(), year, time_slice.clone())); + let apply_cost = match cost.balance_type { BalanceType::Net => true, BalanceType::Consumption => flow.flow < 0.0, From 4118428937e6a12899582f17c124cd16b49533d2 Mon Sep 17 00:00:00 2001 From: Tom Bland Date: Wed, 16 Apr 2025 10:43:05 +0100 Subject: [PATCH 4/7] Homogenize DemandMap and CommodityCostMap --- src/commodity.rs | 20 +++++++++++--------- src/input/process.rs | 2 +- src/simulation/optimisation/constraints.rs | 2 +- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/commodity.rs b/src/commodity.rs index 8e9b498e6..511bf0084 100644 --- a/src/commodity.rs +++ b/src/commodity.rs @@ -63,7 +63,7 @@ pub struct CommodityCostMap(HashMap<(RegionID, u32, TimeSliceID), CommodityCost> impl CommodityCostMap { /// Create a new, empty [`CommodityCostMap`] pub fn new() -> Self { - Self(HashMap::new()) + CommodityCostMap::default() } /// Check if the map is empty @@ -112,17 +112,19 @@ impl DemandMap { DemandMap::default() } + /// Check if the map is empty + pub fn is_empty(&self) -> bool { + self.0.is_empty() + } + /// Retrieve the demand for the specified region, year and time slice - pub fn get(&self, key: (RegionID, u32, TimeSliceID)) -> f64 { - self.0 - .get(&key) - .copied() - .unwrap_or_else(|| panic!("Missing demand entry")) + pub fn get(&self, key: (RegionID, u32, TimeSliceID)) -> &f64 { + self.0.get(&key).unwrap() } /// Insert a new demand entry for the specified region, year and time slice - pub fn insert(&mut self, key: (RegionID, u32, TimeSliceID), demand: f64) { - self.0.insert(key, demand); + pub fn insert(&mut self, key: (RegionID, u32, TimeSliceID), demand: f64) -> Option { + self.0.insert(key, demand) } } @@ -140,7 +142,7 @@ mod tests { let mut map = DemandMap::new(); map.insert(("North".into(), 2020, time_slice.clone()), value); - assert_eq!(map.get(("North".into(), 2020, time_slice)), value) + assert_eq!(map.get(("North".into(), 2020, time_slice)), &value) } #[test] diff --git a/src/input/process.rs b/src/input/process.rs index 973059102..f01257683 100644 --- a/src/input/process.rs +++ b/src/input/process.rs @@ -161,7 +161,7 @@ fn validate_svd_commodity( let demand = commodity .demand .get((region_id.clone(), year, time_slice.clone())); - if demand > 0.0 { + if *demand > 0.0 { let mut has_producer = false; // We must check for producers in every time slice, region, and year. diff --git a/src/simulation/optimisation/constraints.rs b/src/simulation/optimisation/constraints.rs index cc1ef1f81..b51df5b06 100644 --- a/src/simulation/optimisation/constraints.rs +++ b/src/simulation/optimisation/constraints.rs @@ -119,7 +119,7 @@ fn add_commodity_balance_constraints( CommodityType::ServiceDemand => { match ts_selection { TimeSliceSelection::Single(ref ts) => { - commodity.demand.get((region_id.clone(), year, ts.clone())) + *commodity.demand.get((region_id.clone(), year, ts.clone())) } // We currently only support specifying demand at the time slice level: // https://github.com/EnergySystemsModellingLab/MUSE_2.0/issues/391 From e379d73c5c905707dd7a318d7a024fba290e24e7 Mon Sep 17 00:00:00 2001 From: Tom Bland Date: Wed, 16 Apr 2025 10:59:10 +0100 Subject: [PATCH 5/7] Create and use macro --- src/commodity.rs | 71 +++------------------- src/input/process.rs | 2 +- src/lib.rs | 1 + src/map.rs | 31 ++++++++++ src/simulation/optimisation/constraints.rs | 2 +- 5 files changed, 44 insertions(+), 63 deletions(-) create mode 100644 src/map.rs diff --git a/src/commodity.rs b/src/commodity.rs index 511bf0084..2b327d2b7 100644 --- a/src/commodity.rs +++ b/src/commodity.rs @@ -1,5 +1,6 @@ #![allow(missing_docs)] use crate::id::{define_id_getter, define_id_type}; +use crate::map::define_map_type; use crate::region::RegionID; use crate::time_slice::{TimeSliceID, TimeSliceLevel}; use indexmap::IndexMap; @@ -15,6 +16,13 @@ define_id_type! {CommodityID} /// A map of [`Commodity`]s, keyed by commodity ID pub type CommodityMap = IndexMap>; +define_map_type!( + CommodityCostMap, + (RegionID, u32, TimeSliceID), + CommodityCost +); +define_map_type!(DemandMap, (RegionID, u32, TimeSliceID), f64); + /// A commodity within the simulation. Represents a substance (e.g. CO2) or form of energy (e.g. /// electricity) that can be produced and/or consumed by technologies in the model. #[derive(PartialEq, Debug, Deserialize)] @@ -56,36 +64,6 @@ pub struct CommodityCost { pub value: f64, } -/// A data structure for easy lookup of [`CommodityCost`]s -#[derive(PartialEq, Debug, Default, Clone)] -pub struct CommodityCostMap(HashMap<(RegionID, u32, TimeSliceID), CommodityCost>); - -impl CommodityCostMap { - /// Create a new, empty [`CommodityCostMap`] - pub fn new() -> Self { - CommodityCostMap::default() - } - - /// Check if the map is empty - pub fn is_empty(&self) -> bool { - self.0.is_empty() - } - - /// Insert a [`CommodityCost`] into the map - pub fn insert( - &mut self, - key: (RegionID, u32, TimeSliceID), - value: CommodityCost, - ) -> Option { - self.0.insert(key, value) - } - - /// Retrieve a [`CommodityCost`] from the map - pub fn get(&self, key: (RegionID, u32, TimeSliceID)) -> &CommodityCost { - self.0.get(&key).unwrap() - } -} - /// Commodity balance type #[derive(PartialEq, Debug, DeserializeLabeledStringEnum)] pub enum CommodityType { @@ -99,35 +77,6 @@ pub enum CommodityType { OutputCommodity, } -/// A map relating region, year and time slice to demand (in real units, not a fraction). -/// -/// This data type is exported as this is the way in we want to look up demand outside of this -/// module. -#[derive(PartialEq, Debug, Clone, Default)] -pub struct DemandMap(HashMap<(RegionID, u32, TimeSliceID), f64>); - -impl DemandMap { - /// Create a new, empty [`DemandMap`] - pub fn new() -> DemandMap { - DemandMap::default() - } - - /// Check if the map is empty - pub fn is_empty(&self) -> bool { - self.0.is_empty() - } - - /// Retrieve the demand for the specified region, year and time slice - pub fn get(&self, key: (RegionID, u32, TimeSliceID)) -> &f64 { - self.0.get(&key).unwrap() - } - - /// Insert a new demand entry for the specified region, year and time slice - pub fn insert(&mut self, key: (RegionID, u32, TimeSliceID), demand: f64) -> Option { - self.0.insert(key, demand) - } -} - #[cfg(test)] mod tests { use super::*; @@ -142,7 +91,7 @@ mod tests { let mut map = DemandMap::new(); map.insert(("North".into(), 2020, time_slice.clone()), value); - assert_eq!(map.get(("North".into(), 2020, time_slice)), &value) + assert_eq!(map.get(("North".into(), 2020, time_slice)), value) } #[test] @@ -159,6 +108,6 @@ mod tests { assert!(map .insert(("GBR".into(), 2010, ts.clone()), value.clone()) .is_none()); - assert_eq!(map.get(("GBR".into(), 2010, ts)), &value); + assert_eq!(map.get(("GBR".into(), 2010, ts)), value); } } diff --git a/src/input/process.rs b/src/input/process.rs index f01257683..973059102 100644 --- a/src/input/process.rs +++ b/src/input/process.rs @@ -161,7 +161,7 @@ fn validate_svd_commodity( let demand = commodity .demand .get((region_id.clone(), year, time_slice.clone())); - if *demand > 0.0 { + if demand > 0.0 { let mut has_producer = false; // We must check for producers in every time slice, region, and year. diff --git a/src/lib.rs b/src/lib.rs index 2290ab0d5..a6b218009 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,6 +7,7 @@ pub mod commodity; pub mod id; pub mod input; pub mod log; +pub mod map; pub mod model; pub mod output; pub mod process; diff --git a/src/map.rs b/src/map.rs new file mode 100644 index 000000000..a06500235 --- /dev/null +++ b/src/map.rs @@ -0,0 +1,31 @@ +//! This module defines a macro to create a map type with a specified key and value type. + +macro_rules! define_map_type { + ($name:ident, $key_type:ty, $value_type:ty) => { + #[derive(PartialEq, Debug, Clone, Default)] + pub struct $name(HashMap<$key_type, $value_type>); + + impl $name { + /// Create a new, empty map + pub fn new() -> Self { + Self::default() + } + + /// Check if the map is empty + pub fn is_empty(&self) -> bool { + self.0.is_empty() + } + + /// Insert a value into the map + pub fn insert(&mut self, key: $key_type, value: $value_type) -> Option<$value_type> { + self.0.insert(key, value) + } + + /// Retrieve a value from the map + pub fn get(&self, key: $key_type) -> $value_type { + self.0.get(&key).unwrap().clone() + } + } + }; +} +pub(crate) use define_map_type; diff --git a/src/simulation/optimisation/constraints.rs b/src/simulation/optimisation/constraints.rs index b51df5b06..cc1ef1f81 100644 --- a/src/simulation/optimisation/constraints.rs +++ b/src/simulation/optimisation/constraints.rs @@ -119,7 +119,7 @@ fn add_commodity_balance_constraints( CommodityType::ServiceDemand => { match ts_selection { TimeSliceSelection::Single(ref ts) => { - *commodity.demand.get((region_id.clone(), year, ts.clone())) + commodity.demand.get((region_id.clone(), year, ts.clone())) } // We currently only support specifying demand at the time slice level: // https://github.com/EnergySystemsModellingLab/MUSE_2.0/issues/391 From 10a6710de436d750d7475d29f75bd51b976264b5 Mon Sep 17 00:00:00 2001 From: Tom Bland Date: Wed, 16 Apr 2025 11:16:55 +0100 Subject: [PATCH 6/7] Add error message --- src/map.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/map.rs b/src/map.rs index a06500235..4b1b1d9df 100644 --- a/src/map.rs +++ b/src/map.rs @@ -22,8 +22,12 @@ macro_rules! define_map_type { } /// Retrieve a value from the map + /// Assumes the key exists in the map, otherwise will panic pub fn get(&self, key: $key_type) -> $value_type { - self.0.get(&key).unwrap().clone() + self.0 + .get(&key) + .unwrap_or_else(|| panic!("Key {:?} not found in the map", key)) + .clone() } } }; From bd530583aa00531fec706ff056bf4bc076c7a9dd Mon Sep 17 00:00:00 2001 From: Tom Bland Date: Wed, 16 Apr 2025 16:43:24 +0100 Subject: [PATCH 7/7] Using types for maps instead of structs --- src/commodity.rs | 19 ++++++------ src/input/process.rs | 5 ++-- src/lib.rs | 1 - src/map.rs | 35 ---------------------- src/simulation/optimisation.rs | 4 +-- src/simulation/optimisation/constraints.rs | 7 +++-- 6 files changed, 19 insertions(+), 52 deletions(-) delete mode 100644 src/map.rs diff --git a/src/commodity.rs b/src/commodity.rs index dec29a66c..c5b27b5f3 100644 --- a/src/commodity.rs +++ b/src/commodity.rs @@ -1,6 +1,5 @@ #![allow(missing_docs)] use crate::id::{define_id_getter, define_id_type}; -use crate::map::define_map_type; use crate::region::RegionID; use crate::time_slice::{TimeSliceID, TimeSliceLevel}; use indexmap::IndexMap; @@ -14,12 +13,11 @@ define_id_type! {CommodityID} /// A map of [`Commodity`]s, keyed by commodity ID pub type CommodityMap = IndexMap>; -define_map_type!( - CommodityCostMap, - (RegionID, u32, TimeSliceID), - CommodityCost -); -define_map_type!(DemandMap, (RegionID, u32, TimeSliceID), f64); +/// A map of [`CommodityCost`]s, keyed by region ID, year and time slice ID +pub type CommodityCostMap = HashMap<(RegionID, u32, TimeSliceID), CommodityCost>; + +/// A map of demand values, keyed by region ID, year and time slice ID +pub type DemandMap = HashMap<(RegionID, u32, TimeSliceID), f64>; /// A commodity within the simulation. Represents a substance (e.g. CO2) or form of energy (e.g. /// electricity) that can be produced and/or consumed by technologies in the model. @@ -89,7 +87,10 @@ mod tests { let mut map = DemandMap::new(); map.insert(("North".into(), 2020, time_slice.clone()), value); - assert_eq!(map.get(("North".into(), 2020, time_slice)), value) + assert_eq!( + map.get(&("North".into(), 2020, time_slice)).unwrap(), + &value + ) } #[test] @@ -106,6 +107,6 @@ mod tests { assert!(map .insert(("GBR".into(), 2010, ts.clone()), value.clone()) .is_none()); - assert_eq!(map.get(("GBR".into(), 2010, ts)), value); + assert_eq!(map.get(&("GBR".into(), 2010, ts)).unwrap(), &value); } } diff --git a/src/input/process.rs b/src/input/process.rs index 973059102..2bcfef061 100644 --- a/src/input/process.rs +++ b/src/input/process.rs @@ -160,8 +160,9 @@ fn validate_svd_commodity( for time_slice in params.time_slice_info.iter_ids() { let demand = commodity .demand - .get((region_id.clone(), year, time_slice.clone())); - if demand > 0.0 { + .get(&(region_id.clone(), year, time_slice.clone())) + .unwrap(); + if demand > &0.0 { let mut has_producer = false; // We must check for producers in every time slice, region, and year. diff --git a/src/lib.rs b/src/lib.rs index a6b218009..2290ab0d5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,7 +7,6 @@ pub mod commodity; pub mod id; pub mod input; pub mod log; -pub mod map; pub mod model; pub mod output; pub mod process; diff --git a/src/map.rs b/src/map.rs deleted file mode 100644 index 4b1b1d9df..000000000 --- a/src/map.rs +++ /dev/null @@ -1,35 +0,0 @@ -//! This module defines a macro to create a map type with a specified key and value type. - -macro_rules! define_map_type { - ($name:ident, $key_type:ty, $value_type:ty) => { - #[derive(PartialEq, Debug, Clone, Default)] - pub struct $name(HashMap<$key_type, $value_type>); - - impl $name { - /// Create a new, empty map - pub fn new() -> Self { - Self::default() - } - - /// Check if the map is empty - pub fn is_empty(&self) -> bool { - self.0.is_empty() - } - - /// Insert a value into the map - pub fn insert(&mut self, key: $key_type, value: $value_type) -> Option<$value_type> { - self.0.insert(key, value) - } - - /// Retrieve a value from the map - /// Assumes the key exists in the map, otherwise will panic - pub fn get(&self, key: $key_type) -> $value_type { - self.0 - .get(&key) - .unwrap_or_else(|| panic!("Key {:?} not found in the map", key)) - .clone() - } - } - }; -} -pub(crate) use define_map_type; diff --git a/src/simulation/optimisation.rs b/src/simulation/optimisation.rs index b64db821d..57c4c304d 100644 --- a/src/simulation/optimisation.rs +++ b/src/simulation/optimisation.rs @@ -236,8 +236,8 @@ fn calculate_cost_coefficient( let cost = flow .commodity .costs - .get((asset.region_id.clone(), year, time_slice.clone())); - + .get(&(asset.region_id.clone(), year, time_slice.clone())) + .unwrap(); let apply_cost = match cost.balance_type { BalanceType::Net => true, BalanceType::Consumption => flow.flow < 0.0, diff --git a/src/simulation/optimisation/constraints.rs b/src/simulation/optimisation/constraints.rs index cc1ef1f81..7b6580152 100644 --- a/src/simulation/optimisation/constraints.rs +++ b/src/simulation/optimisation/constraints.rs @@ -118,9 +118,10 @@ fn add_commodity_balance_constraints( CommodityType::SupplyEqualsDemand => 0.0, CommodityType::ServiceDemand => { match ts_selection { - TimeSliceSelection::Single(ref ts) => { - commodity.demand.get((region_id.clone(), year, ts.clone())) - } + TimeSliceSelection::Single(ref ts) => *commodity + .demand + .get(&(region_id.clone(), year, ts.clone())) + .unwrap(), // We currently only support specifying demand at the time slice level: // https://github.com/EnergySystemsModellingLab/MUSE_2.0/issues/391 _ => panic!(