use crate::EntityId;
use chrono::NaiveDate;
#[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum AnticipatedConfig {
LeadStages(u32),
LeadTime(f64),
}
impl AnticipatedConfig {
#[must_use]
pub fn lead_stages(&self) -> Option<u32> {
match self {
Self::LeadStages(lead_stages) => Some(*lead_stages),
Self::LeadTime(_) => None,
}
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Thermal {
pub id: EntityId,
pub name: String,
pub operational_start_date: NaiveDate,
pub bus_id: EntityId,
pub entry_stage_id: Option<i32>,
pub exit_stage_id: Option<i32>,
pub cost_per_mwh: f64,
pub min_generation_mw: f64,
pub max_generation_mw: f64,
pub anticipated_config: Option<AnticipatedConfig>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_thermal_construction() {
let thermal = Thermal {
id: EntityId::from(1),
name: "Angra 1".to_string(),
operational_start_date: NaiveDate::from_ymd_opt(2024, 1, 1).unwrap(),
bus_id: EntityId::from(10),
entry_stage_id: None,
exit_stage_id: None,
cost_per_mwh: 50.0,
min_generation_mw: 0.0,
max_generation_mw: 657.0,
anticipated_config: None,
};
assert_eq!(thermal.id, EntityId::from(1));
assert_eq!(thermal.name, "Angra 1");
assert_eq!(thermal.bus_id, EntityId::from(10));
assert_eq!(thermal.entry_stage_id, None);
assert_eq!(thermal.exit_stage_id, None);
assert_eq!(thermal.cost_per_mwh, 50.0);
assert_eq!(thermal.min_generation_mw, 0.0);
assert_eq!(thermal.max_generation_mw, 657.0);
assert_eq!(thermal.anticipated_config, None);
}
#[test]
fn test_thermal_with_anticipated() {
let thermal = Thermal {
id: EntityId::from(2),
name: "Pecém I".to_string(),
operational_start_date: NaiveDate::from_ymd_opt(2024, 1, 1).unwrap(),
bus_id: EntityId::from(20),
entry_stage_id: Some(1),
exit_stage_id: Some(120),
cost_per_mwh: 120.0,
min_generation_mw: 100.0,
max_generation_mw: 360.0,
anticipated_config: Some(AnticipatedConfig::LeadStages(2)),
};
assert_eq!(
thermal.anticipated_config,
Some(AnticipatedConfig::LeadStages(2))
);
assert_eq!(thermal.entry_stage_id, Some(1));
assert_eq!(thermal.exit_stage_id, Some(120));
}
#[test]
fn test_anticipated_config_lead_stages_accessor_returns_stage_count() {
let config = AnticipatedConfig::LeadStages(5);
assert_eq!(config.lead_stages(), Some(5));
}
#[test]
fn test_anticipated_config_lead_stages_accessor_none_for_lead_time() {
let config = AnticipatedConfig::LeadTime(720.0);
assert_eq!(config.lead_stages(), None);
}
#[test]
fn test_anticipated_config_is_copy() {
let config = AnticipatedConfig::LeadStages(3);
let copied = config;
assert_eq!(config, copied);
}
#[test]
fn test_anticipated_config_partial_eq() {
assert_eq!(
AnticipatedConfig::LeadStages(2),
AnticipatedConfig::LeadStages(2)
);
assert_ne!(
AnticipatedConfig::LeadStages(2),
AnticipatedConfig::LeadStages(3)
);
assert_ne!(
AnticipatedConfig::LeadStages(2),
AnticipatedConfig::LeadTime(2.0)
);
assert_eq!(
AnticipatedConfig::LeadTime(720.0),
AnticipatedConfig::LeadTime(720.0)
);
}
#[cfg(feature = "serde")]
#[test]
fn test_thermal_serde_roundtrip() {
let thermal = Thermal {
id: EntityId::from(2),
name: "Pecém I".to_string(),
operational_start_date: NaiveDate::from_ymd_opt(2024, 1, 1).unwrap(),
bus_id: EntityId::from(20),
entry_stage_id: Some(1),
exit_stage_id: Some(120),
cost_per_mwh: 80.0,
min_generation_mw: 100.0,
max_generation_mw: 360.0,
anticipated_config: Some(AnticipatedConfig::LeadStages(2)),
};
let json = serde_json::to_string(&thermal).unwrap();
let deserialized: Thermal = serde_json::from_str(&json).unwrap();
assert_eq!(thermal, deserialized);
assert!(json.contains("\"anticipated_config\":{\"LeadStages\":2}"));
}
#[cfg(feature = "serde")]
#[test]
fn test_thermal_serde_roundtrip_lead_time() {
let thermal = Thermal {
id: EntityId::from(3),
name: "T_lead_time".to_string(),
operational_start_date: NaiveDate::from_ymd_opt(2024, 1, 1).unwrap(),
bus_id: EntityId::from(20),
entry_stage_id: None,
exit_stage_id: None,
cost_per_mwh: 80.0,
min_generation_mw: 100.0,
max_generation_mw: 360.0,
anticipated_config: Some(AnticipatedConfig::LeadTime(720.0)),
};
let json = serde_json::to_string(&thermal).unwrap();
let deserialized: Thermal = serde_json::from_str(&json).unwrap();
assert_eq!(thermal, deserialized);
}
}