Wire BPHX channel pressure drop on both sides with selectable correlations.
Some checks failed
CI / check (push) Has been cancelled
Some checks failed
CI / check (push) Has been cancelled
Replace isobaric 4-port closures with SimplifiedChannel (default) and Martin1996 DP models so z_dp and UI dp_correlation actually affect the Newton solve. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -163,6 +163,15 @@ impl HxSideConditions {
|
||||
}
|
||||
}
|
||||
|
||||
/// Live four-port edge indices: each triple is `(ṁ_idx, P_idx, h_idx)`.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub(crate) struct FourPortEdgeIndices {
|
||||
pub hot_in: (usize, usize, usize),
|
||||
pub hot_out: (usize, usize, usize),
|
||||
pub cold_in: (usize, usize, usize),
|
||||
pub cold_out: (usize, usize, usize),
|
||||
}
|
||||
|
||||
/// Generic heat exchanger component with 4 ports.
|
||||
///
|
||||
/// Uses the Strategy Pattern for heat transfer calculations via the
|
||||
@@ -516,7 +525,7 @@ impl<Model: HeatTransferModel + 'static> HeatExchanger<Model> {
|
||||
}
|
||||
|
||||
/// `true` when all 4 edges are wired (Modelica-style 4-port mode).
|
||||
fn edges_ready(&self) -> bool {
|
||||
pub(crate) fn edges_ready(&self) -> bool {
|
||||
self.hot_in_idx.is_some()
|
||||
&& self.hot_out_idx.is_some()
|
||||
&& self.cold_in_idx.is_some()
|
||||
@@ -525,6 +534,60 @@ impl<Model: HeatTransferModel + 'static> HeatExchanger<Model> {
|
||||
&& !self.cold_fluid_id_str.is_empty()
|
||||
}
|
||||
|
||||
/// Live four-port edge index triples `(ṁ, P, h)` when wired.
|
||||
pub(crate) fn four_port_edges(&self) -> Option<FourPortEdgeIndices> {
|
||||
if !self.edges_ready() {
|
||||
return None;
|
||||
}
|
||||
Some(FourPortEdgeIndices {
|
||||
hot_in: self.hot_in_idx?,
|
||||
hot_out: self.hot_out_idx?,
|
||||
cold_in: self.cold_in_idx?,
|
||||
cold_out: self.cold_out_idx?,
|
||||
})
|
||||
}
|
||||
|
||||
/// Thermal-model equation count (excludes the two pressure-closure rows).
|
||||
pub(crate) fn model_n_equations(&self) -> usize {
|
||||
self.model.n_equations()
|
||||
}
|
||||
|
||||
/// Calibration state indices (e.g. free `z_dp` actuator).
|
||||
pub(crate) fn calib_indices_ref(&self) -> &entropyk_core::CalibIndices {
|
||||
&self.calib_indices
|
||||
}
|
||||
|
||||
/// Hot-side fluid id used for live property queries.
|
||||
pub(crate) fn hot_fluid_id_str(&self) -> &str {
|
||||
&self.hot_fluid_id_str
|
||||
}
|
||||
|
||||
/// Cold-side fluid id used for live property queries.
|
||||
pub(crate) fn cold_fluid_id_str(&self) -> &str {
|
||||
&self.cold_fluid_id_str
|
||||
}
|
||||
|
||||
/// Inlet density [kg/m³] from the attached fluid backend at `(P, h)`.
|
||||
pub(crate) fn side_density(
|
||||
&self,
|
||||
side: &str,
|
||||
fluid_id: &str,
|
||||
p_pa: f64,
|
||||
h_jkg: f64,
|
||||
) -> Result<f64, ComponentError> {
|
||||
self.query_live_property(side, fluid_id, Property::Density, p_pa, h_jkg)
|
||||
.and_then(|rho| {
|
||||
if rho.is_finite() && rho > 1e-10 {
|
||||
Ok(rho)
|
||||
} else {
|
||||
Err(ComponentError::DomainViolation(DomainViolation {
|
||||
component: Some(self.name.clone()),
|
||||
detail: format!("{} {}-side density is invalid: {}", self.name, side, rho),
|
||||
}))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn live_state_required_error(&self) -> ComponentError {
|
||||
ComponentError::InvalidState(format!(
|
||||
"{} requires live four-port edge state (hot_inlet, hot_outlet, cold_inlet, cold_outlet); inlet-only boundary conditions cannot define outlet states",
|
||||
|
||||
Reference in New Issue
Block a user