feat(python): implement python bindings for all components and solvers
This commit is contained in:
@@ -38,6 +38,7 @@ use crate::state_machine::{CircuitId, OperationalState, StateManageable};
|
||||
#[derive(Debug)]
|
||||
pub struct CondenserCoil {
|
||||
inner: Condenser,
|
||||
air_validated: std::sync::atomic::AtomicBool,
|
||||
}
|
||||
|
||||
impl CondenserCoil {
|
||||
@@ -49,6 +50,7 @@ impl CondenserCoil {
|
||||
pub fn new(ua: f64) -> Self {
|
||||
Self {
|
||||
inner: Condenser::new(ua),
|
||||
air_validated: std::sync::atomic::AtomicBool::new(false),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,6 +58,7 @@ impl CondenserCoil {
|
||||
pub fn with_saturation_temp(ua: f64, saturation_temp: f64) -> Self {
|
||||
Self {
|
||||
inner: Condenser::with_saturation_temp(ua, saturation_temp),
|
||||
air_validated: std::sync::atomic::AtomicBool::new(false),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,6 +89,17 @@ impl Component for CondenserCoil {
|
||||
state: &SystemState,
|
||||
residuals: &mut ResidualVector,
|
||||
) -> Result<(), ComponentError> {
|
||||
if !self.air_validated.load(std::sync::atomic::Ordering::Relaxed) {
|
||||
if let Some(fluid_id) = self.inner.cold_fluid_id() {
|
||||
if fluid_id.0.as_str() != "Air" {
|
||||
return Err(ComponentError::InvalidState(format!(
|
||||
"CondenserCoil requires Air on the cold side, found {}",
|
||||
fluid_id.0.as_str()
|
||||
)));
|
||||
}
|
||||
self.air_validated.store(true, std::sync::atomic::Ordering::Relaxed);
|
||||
}
|
||||
}
|
||||
self.inner.compute_residuals(state, residuals)
|
||||
}
|
||||
|
||||
@@ -104,6 +118,10 @@ impl Component for CondenserCoil {
|
||||
fn get_ports(&self) -> &[ConnectedPort] {
|
||||
self.inner.get_ports()
|
||||
}
|
||||
|
||||
fn set_calib_indices(&mut self, indices: entropyk_core::CalibIndices) {
|
||||
self.inner.set_calib_indices(indices);
|
||||
}
|
||||
}
|
||||
|
||||
impl StateManageable for CondenserCoil {
|
||||
@@ -161,6 +179,31 @@ mod tests {
|
||||
assert!(residuals.iter().all(|r| r.is_finite()), "residuals must be finite");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_condenser_coil_rejects_non_air() {
|
||||
use crate::heat_exchanger::HxSideConditions;
|
||||
use entropyk_core::{Temperature, Pressure, MassFlow};
|
||||
|
||||
let mut coil = CondenserCoil::new(10_000.0);
|
||||
coil.inner.set_cold_conditions(HxSideConditions::new(
|
||||
Temperature::from_celsius(20.0),
|
||||
Pressure::from_bar(1.0),
|
||||
MassFlow::from_kg_per_s(1.0),
|
||||
"Water",
|
||||
));
|
||||
|
||||
let state = vec![0.0; 10];
|
||||
let mut residuals = vec![0.0; 3];
|
||||
let result = coil.compute_residuals(&state, &mut residuals);
|
||||
|
||||
assert!(result.is_err());
|
||||
if let Err(ComponentError::InvalidState(msg)) = result {
|
||||
assert!(msg.contains("requires Air"));
|
||||
} else {
|
||||
panic!("Expected InvalidState error");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_condenser_coil_jacobian_entries() {
|
||||
let coil = CondenserCoil::new(10_000.0);
|
||||
|
||||
Reference in New Issue
Block a user