pub mod ar_coefficients;
pub mod assembly;
pub mod correlation;
pub mod external;
pub mod inflow_history;
pub mod inflow_stats;
pub mod load_factors;
pub mod load_stats;
pub use ar_coefficients::{InflowArCoefficientRow, parse_inflow_ar_coefficients};
pub use assembly::{assemble_inflow_models, assemble_load_models};
pub use correlation::parse_correlation;
pub use external::{ExternalScenarioRow, parse_external_scenarios};
pub use inflow_history::{InflowHistoryRow, parse_inflow_history};
pub use inflow_stats::{InflowSeasonalStatsRow, parse_inflow_seasonal_stats};
pub use load_factors::{BlockFactor, LoadFactorEntry, parse_load_factors};
pub use load_stats::{LoadSeasonalStatsRow, parse_load_seasonal_stats};
use cobre_core::scenario::{CorrelationModel, InflowModel, LoadModel};
use crate::LoadError;
use crate::validation::structural::FileManifest;
use std::path::Path;
pub fn load_inflow_seasonal_stats(
path: Option<&Path>,
) -> Result<Vec<InflowSeasonalStatsRow>, LoadError> {
match path {
None => Ok(Vec::new()),
Some(p) => parse_inflow_seasonal_stats(p),
}
}
pub fn load_inflow_ar_coefficients(
path: Option<&Path>,
) -> Result<Vec<InflowArCoefficientRow>, LoadError> {
match path {
None => Ok(Vec::new()),
Some(p) => parse_inflow_ar_coefficients(p),
}
}
pub fn load_inflow_history(path: Option<&Path>) -> Result<Vec<InflowHistoryRow>, LoadError> {
match path {
None => Ok(Vec::new()),
Some(p) => parse_inflow_history(p),
}
}
pub fn load_load_seasonal_stats(
path: Option<&Path>,
) -> Result<Vec<LoadSeasonalStatsRow>, LoadError> {
match path {
None => Ok(Vec::new()),
Some(p) => parse_load_seasonal_stats(p),
}
}
pub fn load_load_factors(path: Option<&Path>) -> Result<Vec<LoadFactorEntry>, LoadError> {
match path {
None => Ok(Vec::new()),
Some(p) => parse_load_factors(p),
}
}
pub fn load_correlation(path: Option<&Path>) -> Result<CorrelationModel, LoadError> {
match path {
None => Ok(CorrelationModel::default()),
Some(p) => parse_correlation(p),
}
}
pub fn load_external_scenarios(path: Option<&Path>) -> Result<Vec<ExternalScenarioRow>, LoadError> {
match path {
None => Ok(Vec::new()),
Some(p) => parse_external_scenarios(p),
}
}
#[derive(Debug, Clone)]
pub struct ScenarioData {
pub inflow_models: Vec<InflowModel>,
pub load_models: Vec<LoadModel>,
pub correlation: CorrelationModel,
pub inflow_history: Vec<InflowHistoryRow>,
pub external_scenarios: Vec<ExternalScenarioRow>,
pub load_factors: Vec<LoadFactorEntry>,
}
pub fn load_scenarios(
case_root: &Path,
manifest: &FileManifest,
) -> Result<ScenarioData, LoadError> {
let stats_path = manifest
.scenarios_inflow_seasonal_stats_parquet
.then(|| case_root.join("scenarios/inflow_seasonal_stats.parquet"));
let coeff_path = manifest
.scenarios_inflow_ar_coefficients_parquet
.then(|| case_root.join("scenarios/inflow_ar_coefficients.parquet"));
let history_path = manifest
.scenarios_inflow_history_parquet
.then(|| case_root.join("scenarios/inflow_history.parquet"));
let load_stats_path = manifest
.scenarios_load_seasonal_stats_parquet
.then(|| case_root.join("scenarios/load_seasonal_stats.parquet"));
let load_factors_path = manifest
.scenarios_load_factors_json
.then(|| case_root.join("scenarios/load_factors.json"));
let correlation_path = manifest
.scenarios_correlation_json
.then(|| case_root.join("scenarios/correlation.json"));
let external_path = manifest
.scenarios_external_scenarios_parquet
.then(|| case_root.join("scenarios/external_scenarios.parquet"));
let raw_stats = load_inflow_seasonal_stats(stats_path.as_deref())?;
let raw_coefficients = load_inflow_ar_coefficients(coeff_path.as_deref())?;
let inflow_history = load_inflow_history(history_path.as_deref())?;
let raw_load_stats = load_load_seasonal_stats(load_stats_path.as_deref())?;
let load_factors = load_load_factors(load_factors_path.as_deref())?;
let correlation = load_correlation(correlation_path.as_deref())?;
let external_scenarios = load_external_scenarios(external_path.as_deref())?;
let inflow_models = assemble_inflow_models(raw_stats, raw_coefficients)?;
let load_models = assemble_load_models(raw_load_stats);
Ok(ScenarioData {
inflow_models,
load_models,
correlation,
inflow_history,
external_scenarios,
load_factors,
})
}
#[cfg(test)]
#[allow(
clippy::doc_markdown,
clippy::unwrap_used,
clippy::expect_used,
clippy::panic,
clippy::too_many_lines
)]
mod tests {
use super::*;
use crate::validation::structural::FileManifest;
use tempfile::TempDir;
#[test]
fn test_load_inflow_seasonal_stats_none_returns_empty() {
let result = load_inflow_seasonal_stats(None).unwrap();
assert!(result.is_empty());
}
#[test]
fn test_load_inflow_ar_coefficients_none_returns_empty() {
let result = load_inflow_ar_coefficients(None).unwrap();
assert!(result.is_empty());
}
#[test]
fn test_load_inflow_history_none_returns_empty() {
let result = load_inflow_history(None).unwrap();
assert!(result.is_empty());
}
#[test]
fn test_load_load_seasonal_stats_none_returns_empty() {
let result = load_load_seasonal_stats(None).unwrap();
assert!(result.is_empty());
}
#[test]
fn test_load_load_factors_none_returns_empty() {
let result = load_load_factors(None).unwrap();
assert!(result.is_empty());
}
#[test]
fn test_load_correlation_none_returns_default() {
let result = load_correlation(None).unwrap();
assert!(result.profiles.is_empty());
assert!(result.schedule.is_empty());
}
#[test]
fn test_load_external_scenarios_none_returns_empty() {
let result = load_external_scenarios(None).unwrap();
assert!(result.is_empty());
}
#[test]
fn test_load_scenarios_all_flags_false_returns_empty() {
let dir = TempDir::new().unwrap();
let manifest = FileManifest::default();
let data =
load_scenarios(dir.path(), &manifest).expect("empty manifest should always succeed");
assert!(
data.inflow_models.is_empty(),
"inflow_models should be empty when no scenario files present"
);
assert!(
data.load_models.is_empty(),
"load_models should be empty when no scenario files present"
);
assert!(
data.correlation.profiles.is_empty(),
"correlation.profiles should be empty (default) when correlation.json absent"
);
assert!(
data.correlation.schedule.is_empty(),
"correlation.schedule should be empty (default) when correlation.json absent"
);
assert!(
data.inflow_history.is_empty(),
"inflow_history should be empty when file absent"
);
assert!(
data.external_scenarios.is_empty(),
"external_scenarios should be empty when file absent"
);
assert!(
data.load_factors.is_empty(),
"load_factors should be empty when file absent"
);
}
}