feat(python): implement python bindings for all components and solvers

This commit is contained in:
Sepehr
2026-02-21 20:34:56 +01:00
parent 8ef8cd2eba
commit 4440132b0a
310 changed files with 11577 additions and 397 deletions

View File

@@ -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);