use crate::agent::Asset;
use crate::input::*;
use crate::process::Process;
use anyhow::{ensure, Context, Result};
use itertools::Itertools;
use serde::Deserialize;
use std::collections::{HashMap, HashSet};
use std::path::Path;
use std::rc::Rc;
const ASSETS_FILE_NAME: &str = "assets.csv";
#[derive(Deserialize, PartialEq)]
struct AssetRaw {
process_id: String,
region_id: String,
agent_id: String,
capacity: f64,
commission_year: u32,
}
pub fn read_assets(
model_dir: &Path,
agent_ids: &HashSet<Rc<str>>,
processes: &HashMap<Rc<str>, Rc<Process>>,
region_ids: &HashSet<Rc<str>>,
) -> Result<Vec<Asset>> {
let file_path = model_dir.join(ASSETS_FILE_NAME);
let assets_csv = read_csv(&file_path)?;
read_assets_from_iter(assets_csv, agent_ids, processes, region_ids)
.with_context(|| input_err_msg(&file_path))
}
fn read_assets_from_iter<I>(
iter: I,
agent_ids: &HashSet<Rc<str>>,
processes: &HashMap<Rc<str>, Rc<Process>>,
region_ids: &HashSet<Rc<str>>,
) -> Result<Vec<Asset>>
where
I: Iterator<Item = AssetRaw>,
{
let mut id = 0u32;
iter.map(|asset| -> Result<_> {
let agent_id = agent_ids.get_id(&asset.agent_id)?;
let process = processes
.get(asset.process_id.as_str())
.with_context(|| format!("Invalid process ID: {}", &asset.process_id))?;
let region_id = region_ids.get_id(&asset.region_id)?;
ensure!(
process.regions.contains(®ion_id),
"Region {} is not one of the regions in which process {} operates",
region_id,
process.id
);
let asset = Asset {
id,
agent_id,
process: Rc::clone(process),
region_id,
capacity: asset.capacity,
commission_year: asset.commission_year,
};
id += 1;
Ok(asset)
})
.try_collect()
}
#[cfg(test)]
mod tests {
use super::*;
use crate::process::{ProcessCapacityMap, ProcessParameter};
use crate::region::RegionSelection;
use itertools::assert_equal;
use std::iter;
#[test]
fn test_read_assets_from_iter() {
let process_param = ProcessParameter {
process_id: "process1".into(),
years: 2010..=2020,
capital_cost: 5.0,
fixed_operating_cost: 2.0,
variable_operating_cost: 1.0,
lifetime: 5,
discount_rate: 0.9,
cap2act: 1.0,
};
let process = Rc::new(Process {
id: "process1".into(),
description: "Description".into(),
capacity_fractions: ProcessCapacityMap::new(),
flows: vec![],
parameter: process_param.clone(),
regions: RegionSelection::All,
});
let processes = [(Rc::clone(&process.id), Rc::clone(&process))]
.into_iter()
.collect();
let agent_ids = ["agent1".into()].into_iter().collect();
let region_ids = ["GBR".into(), "USA".into()].into_iter().collect();
let asset_in = AssetRaw {
agent_id: "agent1".into(),
process_id: "process1".into(),
region_id: "GBR".into(),
capacity: 1.0,
commission_year: 2010,
};
let asset_out = Asset {
id: 0,
agent_id: "agent1".into(),
process: Rc::clone(&process),
region_id: "GBR".into(),
capacity: 1.0,
commission_year: 2010,
};
assert_equal(
read_assets_from_iter([asset_in].into_iter(), &agent_ids, &processes, ®ion_ids)
.unwrap(),
iter::once(asset_out),
);
let asset_in = AssetRaw {
agent_id: "agent1".into(),
process_id: "process2".into(),
region_id: "GBR".into(),
capacity: 1.0,
commission_year: 2010,
};
assert!(
read_assets_from_iter([asset_in].into_iter(), &agent_ids, &processes, ®ion_ids)
.is_err()
);
let asset_in = AssetRaw {
agent_id: "agent2".into(),
process_id: "process1".into(),
region_id: "GBR".into(),
capacity: 1.0,
commission_year: 2010,
};
assert!(
read_assets_from_iter([asset_in].into_iter(), &agent_ids, &processes, ®ion_ids)
.is_err()
);
let asset_in = AssetRaw {
agent_id: "agent1".into(),
process_id: "process1".into(),
region_id: "FRA".into(),
capacity: 1.0,
commission_year: 2010,
};
assert!(
read_assets_from_iter([asset_in].into_iter(), &agent_ids, &processes, ®ion_ids)
.is_err()
);
let process = Rc::new(Process {
id: "process1".into(),
description: "Description".into(),
capacity_fractions: ProcessCapacityMap::new(),
flows: vec![],
parameter: process_param,
regions: RegionSelection::Some(["GBR".into()].into_iter().collect()),
});
let asset_in = AssetRaw {
agent_id: "agent1".into(),
process_id: "process1".into(),
region_id: "USA".into(), capacity: 1.0,
commission_year: 2010,
};
let processes = [(Rc::clone(&process.id), Rc::clone(&process))]
.into_iter()
.collect();
assert!(
read_assets_from_iter([asset_in].into_iter(), &agent_ids, &processes, ®ion_ids)
.is_err()
);
}
}