chore: sync project state and current artifacts
This commit is contained in:
@@ -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> {
|
||||
|
||||
Reference in New Issue
Block a user