chore: sync project state and current artifacts

This commit is contained in:
Sepehr
2026-02-22 23:27:31 +01:00
parent 1b6415776e
commit dd77089b22
232 changed files with 37056 additions and 4296 deletions

View File

@@ -23,7 +23,7 @@ use crate::port::{Connected, Disconnected, FluidId, Port};
use crate::state_machine::StateManageable;
use crate::{
CircuitId, Component, ComponentError, ConnectedPort, JacobianBuilder, OperationalState,
ResidualVector, SystemState,
ResidualVector, StateSlice,
};
use entropyk_core::{MassFlow, Power};
use serde::{Deserialize, Serialize};
@@ -257,13 +257,13 @@ impl Fan<Connected> {
return 0.0;
}
// Handle negative flow gracefully by using a linear extrapolation from Q=0
// Handle negative flow gracefully by using a linear extrapolation from Q=0
// to prevent polynomial extrapolation issues with quadratic/cubic terms
if flow_m3_per_s < 0.0 {
let p0 = self.curves.static_pressure_at_flow(0.0);
let p_eps = self.curves.static_pressure_at_flow(1e-6);
let dp_dq = (p_eps - p0) / 1e-6;
let pressure = p0 + dp_dq * flow_m3_per_s;
return AffinityLaws::scale_head(pressure, self.speed_ratio);
}
@@ -376,7 +376,7 @@ impl Fan<Connected> {
impl Component for Fan<Connected> {
fn compute_residuals(
&self,
state: &SystemState,
state: &StateSlice,
residuals: &mut ResidualVector,
) -> Result<(), ComponentError> {
if residuals.len() != self.n_equations() {
@@ -432,7 +432,7 @@ impl Component for Fan<Connected> {
fn jacobian_entries(
&self,
state: &SystemState,
state: &StateSlice,
jacobian: &mut JacobianBuilder,
) -> Result<(), ComponentError> {
if state.len() < 2 {
@@ -474,6 +474,60 @@ impl Component for Fan<Connected> {
fn get_ports(&self) -> &[ConnectedPort] {
&[]
}
fn port_mass_flows(
&self,
state: &StateSlice,
) -> Result<Vec<entropyk_core::MassFlow>, ComponentError> {
if state.len() < 1 {
return Err(ComponentError::InvalidStateDimensions {
expected: 1,
actual: state.len(),
});
}
// Fan has inlet and outlet with same mass flow (air is incompressible for HVAC applications)
let m = entropyk_core::MassFlow::from_kg_per_s(state[0]);
// Inlet (positive = entering), Outlet (negative = leaving)
Ok(vec![
m,
entropyk_core::MassFlow::from_kg_per_s(-m.to_kg_per_s()),
])
}
fn port_enthalpies(
&self,
_state: &StateSlice,
) -> Result<Vec<entropyk_core::Enthalpy>, ComponentError> {
// Fan uses internally simulated enthalpies
Ok(vec![
self.port_inlet.enthalpy(),
self.port_outlet.enthalpy(),
])
}
fn energy_transfers(
&self,
state: &StateSlice,
) -> Option<(entropyk_core::Power, entropyk_core::Power)> {
match self.operational_state {
OperationalState::Off | OperationalState::Bypass => Some((
entropyk_core::Power::from_watts(0.0),
entropyk_core::Power::from_watts(0.0),
)),
OperationalState::On => {
if state.is_empty() {
return None;
}
let mass_flow_kg_s = state[0];
let flow_m3_s = mass_flow_kg_s / self.air_density_kg_per_m3;
let power_calc = self.fan_power(flow_m3_s).to_watts();
Some((
entropyk_core::Power::from_watts(0.0),
entropyk_core::Power::from_watts(-power_calc),
))
}
}
}
}
impl StateManageable for Fan<Connected> {