Capture uncommitted solver robustness work (regularization, domain errors, linear solver lifecycle, tube DP/MSH), web workbench updates, and synced BMAD skills across IDE agent folders before starting BPHX pressure-drop. Co-authored-by: Cursor <cursoragent@cursor.com>
26 KiB
Heat-Exchanger Architecture Audit (Phase A)
Date: 2026-07-16
Scope: Full Entropyk workspace, focused on the heat-exchanger family and the
FloodedEvaporator upgrade target.
Method: Code reading + live reproduction of cargo fmt/check/clippy/test on
C:\Users\serameza\impact\dev\Entropyk-main\entropyk. All claims cite file:line.
No code was modified during this audit.
Legend for evidence: [code] = confirmed by repository source; [build] = confirmed by running a command this session; [carrier] = confirmed by authorized Carrier source (none used in this audit — no Carrier data was provided); [assumption] = engineering assumption requiring validation.
1. Workspace and architecture inventory [code]
1.1 Workspace members (Cargo.toml)
12 workspace members: crates/{core, components, entropyk, fluids, solver, cli, vendors},
demo, bindings/{python, c, wasm}, tests/fluids. Version 0.1.0, edition 2021,
workspace deps thiserror, serde, serde_json.
1.2 Crate roles and dependencies (relevant subset)
| Crate | Role | CoolProp coupling |
|---|---|---|
entropyk-core |
Physical types, smoothing, calibration. Does NOT own the Component trait (see 1.4). |
none |
entropyk-fluids |
FluidBackend trait + backends (CoolProp, tabular, incompressible, damped, cached, dll, test). |
optional features coolprop, dll; default = [] |
entropyk-components |
Component trait + all thermodynamic components + HX family. |
depends on entropyk-fluids (default, no coolprop) |
entropyk-solver |
System (petgraph topology, stride-3 state [m,P,h] per edge), Newton/Picard/Fallback, ThermalCoupling. |
coolprop feature (default off) |
entropyk (facade) |
Re-export library. | forces entropyk-fluids/coolprop unconditionally (crates/entropyk/Cargo.toml:16) |
entropyk-cli |
CLI factory create_component, config IR v1/v2, subsystem templates. |
forces entropyk-fluids/coolprop unconditionally (crates/cli/Cargo.toml:23) |
entropyk-python |
PyO3 bindings. | optional; broken on Python 3.14 (see §4.4-B1) |
entropyk-vendors |
Compressor data (Bitzer/Copeland/Danfoss) + SWEP BPHX data. | none |
1.3 State vector and topology [code]
Systemholdspetgraph::Graph<Box<dyn Component>, FlowEdge, Directed>(crates/solver/src/system.rs:198); nodes = components, edges = flow connections.- State vector is stride-3:
[m₀,P₀,h₀, m₁,P₁,h₁, …]per edge (system.rs:192).FlowEdgecarriesstate_index_{m,p,h},source_port,target_port,mass_flow_branch_id(system.rs:134). - Series branches share one
state_index_mviapresolve_mass_flow_topologyusingComponent::flow_paths()(default empty). MAX_CIRCUIT_ID = 4→ at most 5 refrigerant circuits (IDs 0–4) (system.rs:30).- Cross-circuit edges are hard-rejected (
TopologyError::CrossCircuitConnection) — verified by test (crates/solver/tests/multi_circuit.rs:111).
1.4 Component trait — lives in components, not core [code]
Defined at crates/components/src/lib.rs:478. Required methods:
fn compute_residuals(&self, state: &StateSlice, residuals: &mut ResidualVector) -> Result<(), ComponentError>;
fn jacobian_entries(&self, state: &StateSlice, jacobian: &mut JacobianBuilder) -> Result<(), ComponentError>;
fn n_equations(&self) -> usize;
fn get_ports(&self) -> &[ConnectedPort];
Supporting types: type StateSlice = [f64]; (lib.rs:221),
type ResidualVector = Vec<f64>; (lib.rs:227),
JacobianBuilder = flat COO triplet accumulator add_entry(row,col,value)
(lib.rs:235,271) — not a blocked/sparse matrix. Relevant provided methods:
flow_paths(), set_port_context(&mut self, &[(m,p,h)]), set_system_context,
energy_transfers, measure_output, signature.
1.5 Strong physical types available [code]
In crates/core/src/types.rs (re-exported lib.rs:61): Pressure, Temperature,
Enthalpy (specific, J/kg — no separate SpecificEnthalpy), MassFlow
(with regularized() clamp at 1e-12, types.rs:334,382), Power, Concentration,
VolumeFlow, RelativeHumidity, VaporQuality, Entropy, ThermalConductance (W/K),
CircuitId(pub u16) (hashable).
Missing types needed by the mission (§6.1): Length, Mass, Area,
TemperatureDifference, ThermalConductivity, Volume. Geometry is currently raw f64
inside BPHX/FinCoil components. (TemperatureDelta exists only in
crates/fluids/src/types.rs:13, not in core.)
1.6 Smoothing / regularization toolkit already present [code]
crates/core/src/smoothing.rs: smoothstep/deriv (C¹), smootherstep (C²),
cubic_blend/quintic_blend, smooth_max/smooth_min (C^∞), smooth_abs/deriv,
smooth_clamp. All carry verified analytic derivatives. This is the foundation the
zero-flow regularization (mission §7.2) should reuse, not reimplement.
2. Heat-exchanger inventory [code]
crates/components/src/heat_exchanger/ — 23 files. Grouped below; line counts in
parentheses. Detailed per-file fields (purpose/API/ports/equations/jacobian/geometry/
zero-flow/multi-circuit/dp/tests/defects) were captured and are summarized; the most
decision-relevant items are inlined.
2.1 Framework / strategy layer
| File (lines) | Role | Key facts |
|---|---|---|
model.rs (206) |
Object-safe HeatTransferModel trait + FluidState. |
n_equations() per impl; UA is a single f64. Jacobian is the wrapper's job. |
eps_ntu.rs (349) |
ε-NTU model. | ExchangerType::ShellAndTube{passes}: passes is bound to _ and unused (eps_ntu.rs:168-174). The closed form used is actually the cross-flow both-unmixed formula, mislabelled. Zero-capacity guard: c_min<1e-10 → Q=0 (:204). |
lmtd.rs (403) |
LMTD model. | ShellAndTube1_2 correction factor hard-coded 0.9 (:53). |
exchanger.rs (1431) |
Generic 4-port HeatExchanger<M>. |
Jacobian is finite-difference by default (:816-865), re-evaluates backend property calls per column. Doc says 3 eqns, returns 2 (:73-79 vs :867). flow_paths=[(0,1),(2,3)] only. |
mod.rs (108) |
Barrel re-export. | — |
2.2 Refrigerant-side UA/ε-NTU components
| File (lines) | Geometry | Jacobian | DP | Zero-flow | Multi-circuit | Notable defects |
|---|---|---|---|---|---|---|
condenser.rs (2169) |
UA only | analytic (+ FD for dT_cond/dP, :1265) |
optional lumped quadratic_drop |
c_sec<=1e-10→ε=0 |
same-branch only | p_in>10_000 switch (×4); unwrap_or(inlet_p_idx) mass→pressure column fallback (:1057,1231); assert! in with_flooded_head_pressure (:572) |
evaporator.rs (1897) |
UA only | analytic (+ FD dT_evap/dP) |
optional quadratic_drop |
c_sec guard |
same-branch only | same p_in switch + unwrap_or(inlet_p_idx) (:851,1030); heavy duplication with condenser (SecondaryJacCtx) |
flooded_evaporator.rs (939) |
UA only | analytic + FD dT_sat/dP (:568-572) |
none | c_sec<=1e-10→ε=0 |
none | see §3 (target component) |
flooded_condenser.rs (704) |
UA only | delegates to inner (FD) | none | inner | none | n_equations=3 but only 2 non-trivial residuals (:247-266); interior mutability via &self (Cell, :45-46,269,280,283); no set_system_context override; ~20 undocumented public items |
2.3 Air-side / coil components
| File (lines) | Geometry | Notes |
|---|---|---|
condenser_coil.rs (278) |
inherits | Thin wrapper enforcing Air cold side; name() hard-coded. |
evaporator_coil.rs (292) |
inherits | Mirror of above (Air hot side). |
air_cooled_condenser.rs (302) |
approach-based | T_cond = OAT + approach (:78); UA unused in solver. |
fin_coil_condenser.rs (886) |
CoilGeometry (11 fields) |
Richest geometry model — Chang & Wang louvered-fin, fin efficiency, UA from geometry (:517-597); UA clamped [1e2,1e6] (:596); refrigerant resistance lumped ×0.92. |
mchx_condenser_coil.rs (498) |
variable UA | UA_eff=UA_nom·(ρ/ρ_ref)·fan_speed_ratio^n (:234); coil_index metadata only (no bank partition). |
2.4 Brazed-plate (BPHX) family — the pattern to reuse
| File (lines) | Role |
|---|---|
bphx_geometry.rs (504) |
Typed geometry: BphxGeometry (plates, dimensions, chevron, dh, area), mass_flux(m), n_channels=n_plates−1. |
correlation_registry.rs (1290) |
Evidence-aware registry (no formulas): CorrelationId, CorrelationMetadata{domain,evidence}, SelectionContext, assess_candidate→CandidateAssessment{InDomain/NearBoundary/Extrapolated}, select_correlation. Every correlation is EvidenceIncomplete (enforced by test :1267). |
bphx_correlation.rs (1597) |
Formula enum mirroring registry ids; HeatTransferCorrelation trait; CorrelationSelector::select_and_compute checked evaluation; Gnielinski with C¹ laminar→turbulent blend using entropyk_core::smoothing. |
bphx_exchanger.rs (846) |
UA/DP from geometry+correlation; interior mutability via &self (Cell fields :61-64,323-328); DP helper not wired into residual. |
bphx_evaporator.rs (865) / bphx_condenser.rs (912) |
DX variants; read outlet in compute_residuals(&self) writing Cell state; superheat/subcooling not enforced as residual equations. |
2.5 Other
| File (lines) | Role |
|---|---|
moving_boundary_hx.rs (851) |
Zone discretization (SH/TP/SC). Per-zone HTC hard-coded (5000/500/1500, :436-441); correlation_selector stored but unused (:97); Jacobian delegates to inner ignoring the UA scale it just computed (:219-225) — real correctness gap. |
two_phase_dp.rs (380) |
Friedel DP + lumped quadratic_drop (antisymmetric C¹). Fully analytic, well-tested. Rich Friedel model never wired into any residual — only quadratic_drop is. |
economizer.rs (280) |
Suction/liquid IHX, delegates to HeatExchanger<LmtdModel>, ON/OFF/BYPASS. |
3. FloodedEvaporator — current-state verification (every claim) [code]
Target file: crates/components/src/heat_exchanger/flooded_evaporator.rs.
| Mission claim (§2) | Verdict | Evidence |
|---|---|---|
Wraps HeatExchanger<EpsNtuModel> |
✅ | inner field; UA from EpsNtuModel fixed at new(ua) |
| Nominal constant UA | ✅ | self.ua() returns fixed value (:106,168-170,275) |
Q = ε·C_sec·(T_sec,in − T_sat) |
✅ | coupled_duty (:285-291); T_evap from evap_temperature(P) at quality 0.5 (:267) |
m_ref·(h_out−h_in) − Q = 0 |
✅ | residuals[1] (:488) |
| No refrigerant pressure drop | ✅ | residuals[0] = P_out − P_in (:486); no pressure_drop_coeff field |
| Optional outlet quality target | ✅ | quality_control_enabled adds r2 = q_actual − q_target (:445-449,490-496) |
| Secondary stored as boundary values, not live ports | ✅ | secondary_inlet_temp_k, secondary_capacity_rate are Option<f64> (:77-78); never edges |
| Zero secondary capacity → zero effectiveness | ✅ | effectiveness() returns 0 if c_sec<=1e-10 || ua<=0 (:276-280) |
Finite differences for dT_sat/dP |
✅ | central FD dp=p_in·1e-4+100 (:568-572) |
| No shell-and-tube geometry / tube count / passes / circuit partition | ✅ | struct carries only UA, fluid ids, indices, secondary scalars (:57-79) |
3.1 Defects in the current FloodedEvaporator
target_quality = 0.7hard-coded default (:112, doc:148) — the smell the mission §3 flags.- Quality clamped to
[0,1]incompute_quality(:375) and setters (:150,189) — hides subcooled/superheated extrapolation from the solver. p_in > 10_000.0magic switch (:471,541) — duplicated across condenser/evaporator/flooded.unwrap_or(inlet_p_idx)mass-flow → pressure column fallback (:478,548) — if no mass index resolves, the energy residual is written against the pressure column (mission §16.3).- Quality-control silent degradation:
residuals[2] = -target_qualitywhen backend cannot compute quality (:494,520,526) — hides config error. last_heat_transfer_w/last_outlet_qualityare dead state — declared but never written on the coupled path;heat_transfer()always returns the initial0.0.assert!(ua >= MIN_UA)innew(:105) — zero-panic policy violation (FloodedCondenser offerstry_new; this one does not).
4. Current-state verification (reproduction) [build]
Environment: Rust 1.95.0, cargo 1.95.0, Windows MSVC (VS 2022 BuildTools), CMake present, Python 3.14 on PATH. Commands run in the working repo on 2026-07-16.
4.1 Commands and exact results
| Command | Result | Exit |
|---|---|---|
cargo fmt --all -- --check |
PASS — no diffs | 0 |
cargo check --workspace --all-targets --all-features |
FAIL | 101 |
cargo check --workspace --all-targets --exclude entropyk-python (default feats) |
FAIL | 101 |
cargo clippy --workspace --all-targets --all-features -- -D warnings |
NOT RUN to completion — clippy was not installed (installed during audit); after install, fails on fluids clippy errors + coolprop/pyo3 blockers | — |
cargo test --workspace --all-features |
NOT RUN — blocked by build failures above | — |
cargo test --doc --workspace |
NOT RUN — blocked by build failures above | — |
Per-crate reproducible baseline (crates that do not force CoolProp):
| Crate | cargo test -p <crate> result |
|---|---|
entropyk-core |
PASS 160 + 38 = 198 tests |
entropyk-fluids (default, no coolprop) |
PASS 102 + 4 = 106 tests |
entropyk-components |
PASS 856 + 70 = 926 tests (18 ignored) |
entropyk-solver |
FAIL — convergence_criteria: test_newton_with_criteria_single_circuit panics at .expect("Solver should converge") (tests/convergence_criteria.rs:292); other suites pass |
entropyk-vendors |
PASS 66 + 4 = 70 tests |
4.2 Root causes of the workspace-wide failures (all pre-existing)
B1 — Python bindings (env). entropyk-python pins pyo3 = "0.23" (bindings/python/Cargo.toml:24), which resolves to 0.23.5 (max Python 3.13). The installed interpreter is Python 3.14, so pyo3-ffi build-script exits 1: configured Python interpreter version (3.14) is newer than PyO3's maximum supported version (3.13).
Fixes: install Python 3.13; or PYO3_USE_ABI3_FORWARD_COMPATIBILITY=1; or upgrade PyO3.
B2 — CoolProp from-source build (build). crates/entropyk and crates/cli force
entropyk-fluids/coolprop unconditionally (crates/entropyk/Cargo.toml:16,
crates/cli/Cargo.toml:23). entropyk-coolprop-sys/build.rs always recompiles CoolProp
from source via CMake because vendor/coolprop/CMakeLists.txt exists (build.rs:32),
and ignores the prebuilt static lib at
vendor/coolprop/install_root/static_library/Windows/64bit_MSVC_19.44.35227.0/CoolProp.lib.
The CMake generate_headers custom step fails: error MSB8066: la build personnalisée de '…generate_headers.rule' s'est arrêtée. Code 1 (MSBuild). The build appeared to work
once this session (cargo check -p entropyk-fluids --features coolprop finished in
30.5 s and 115 tests passed) only because cached artifacts from a prior session were
present; once that cache was invalidated the from-source header regeneration fails.
Consequence: a clean checkout (cargo clean && cargo build) does NOT build; the
facade, CLI, and any CoolProp code path are unbuildable once the cache is gone.
B3 — Clippy (lint). Two deny-by-default clippy errors in
crates/fluids/src/tabular/interpolate.rs:124 and :131
(unnecessary '>= y + 1') block clippy on every fluids-dependent crate.
B4 — Components http feature + integration test crate (code). Under --all-features:
entropyk-components http feature → E0308 at external_model.rs:675; tests/fluids
(fluids-integration-tests) → 89 errors (E0433) under its coolprop feature.
B5 — One red solver test (code). test_newton_with_criteria_single_circuit fails
(convergence expectation), independent of CoolProp.
None of B1–B5 was introduced by this audit. They confirm the warning in mission §4.4 that the "historical coherence report is stale". They must be resolved before the Phase B–F implementation can be validated workspace-wide.
5. Equation / unknown audit (per operating mode) [code]
5.1 FloodedEvaporator (single circuit, current)
Unknowns on its 2 refrigerant edges: inlet (m,P,h) + outlet (P,h) — outlet mass flow is
the same branch as inlet (series) so m_out = m_in. Effectively unknown: m_in, P_in, h_in,
P_out, h_out (5), with secondary T_sec,in and C_sec imposed as boundary scalars.
Equations: n_equations = 2 (+1 if quality_control) (:443-450):
- r0:
P_out − P_in(no DP) - r1:
m_ref·(h_out − h_in) − Q,Q = ε·C_sec·(T_sec,in − T_sat(P_in)) - r2 (optional):
q_actual − q_target
5.2 Mode-by-mode DoF assessment for the current model
| Mode | Behavior | Under/over-determined? |
|---|---|---|
| Both sides flowing | 2 eqns (or 3), 5 unknowns → completed by upstream/downstream component equations + boundary C_sec,T_sec |
Determined within a closed cycle |
C_sec = 0 (secondary zero) |
effectiveness→0, Q→0; r1 becomes m·(h_out−h_in)=0. No equation constrains h_out independently — outlet enthalpy floats unless an upstream/downstream component closes it |
At risk of underdetermination if nothing else fixes h_out |
| Quality control ON | r2 adds an h_out constraint via q_actual(h_out) = q_target |
Restores DoF |
| Component OFF / BYPASS | not implemented for FloodedEvaporator (no OperationalState handling visible) |
Gap |
| Flow reversal during Newton | m may go negative; model uses m directly in r1 (sign carried) but T_evap/effectiveness are flow-magnitude independent → finite, but no antisymmetric DP since DP is absent |
Finite but physically thin |
5.3 Multi-circuit modes — not representable today
The current FloodedEvaporator has exactly one inlet edge and one outlet edge. The solver
rejects cross-circuit edges, and the only inter-circuit heat mechanism is
ThermalCoupling (crates/solver/src/coupling.rs:52) which transfers duty via an external
Q unknown, never a shared fluid volume. Therefore none of these modes are representable:
- shared-vessel two refrigerant circuits + one water circuit (mission §5.1);
- one circuit ON while the other is OFF in the same vessel;
- independent refrigerant mass/energy per circuit with a common water energy balance.
The existing Drum (components/src/drum.rs) is a 4-port single-circuit separator
(n_equations 8 legacy / 4 edge-coupled, :333-338); it does not override
flow_paths/set_port_context and cannot model a shared multi-circuit vessel.
5.4 tests/multi_circuit.rs does NOT validate shared-vessel thermodynamics [code]
Read in full (233 lines). It uses a RefrigerantMock whose compute_residuals always
returns 0.0 (:23-26). Its 4 tests assert only: circuit counting, cross-circuit edge
rejection, max-5-circuits rejection, and one ThermalCoupling UA·ΔT arithmetic check
(coupling_residuals([(350,300)]) ≈ 50000 W). No real dual-circuit HX residuals, no shared
vessel, no converged coupled solve. Any claim of multi-circuit HX coverage from this file
is false (mission §16.13).
6. Cross-cutting defect catalogue [code]
| Pattern | Locations | Severity |
|---|---|---|
assert! in non-test constructors (zero-panic violation) |
lmtd.rs:101, eps_ntu.rs:88, flooded_evaporator.rs:105, flooded_condenser.rs:70, condenser.rs:572, bphx_condenser.rs:141, mchx_condenser_coil.rs:116-117 |
Medium |
Hard-coded target_quality=0.7 |
flooded_evaporator.rs:112 |
Low |
p_in > 10_000.0 magic mode switch |
condenser.rs:1050,1164,1224,1401; evaporator.rs:844,947,1023,1149; flooded_evaporator.rs:471,541 |
Medium |
m_idx = … .unwrap_or(inlet_p_idx) (mass→pressure column) |
condenser.rs:1057,1231; evaporator.rs:851,1030; flooded_evaporator.rs:478,548 |
High |
Quality clamped to [0,1] |
flooded_evaporator.rs:150,189,375; moving_boundary_hx.rs:474; two_phase_dp.rs:108,132,151 |
Low–Medium |
Interior mutability via &self in residual methods |
flooded_condenser.rs:45-46,269,280,283; bphx_exchanger.rs:61-64,323-328; bphx_evaporator.rs:94,348; bphx_condenser.rs:98-99 |
Medium |
n_equations vs actual residual mismatch |
flooded_condenser.rs:247-266; moving_boundary_hx.rs:176; exchanger.rs:73-79 vs :867 |
Medium |
| Jacobian ignores model state-dependence | moving_boundary_hx.rs:219-225 |
High (that component) |
passes unused in ShellAndTube ε-NTU |
eps_ntu.rs:168-174 |
Medium |
| Rich Friedel DP never wired into residuals | two_phase_dp.rs vs condenser.rs:668-676 |
Medium |
Duplicated SecondaryJacCtx/helpers |
condenser.rs ↔ evaporator.rs; compute_quality ×3 |
Medium |
ShellAndTube1_2 F=0.9 hard-coded |
lmtd.rs:53 |
Low |
UA clamping [1e2,1e6] |
fin_coil_condenser.rs:596 |
Low |
http feature E0308 |
external_model.rs:675 |
Medium (gatekeeps --all-features) |
7. Fluid backend — derivative capability (mission §9.2) [code]
The FluidBackend trait (crates/fluids/src/backend.rs:41) exposes point queries only:
property, full_state, bubble_point, dew_point, temperature_glide (= T_dew−T_bubble,
two point queries), saturation_pressure_t, saturation_enthalpy_t.
dT_sat/dP is NOT exposed by any backend. The CoolPropBackend
(crates/fluids/src/coolprop.rs:28) uses only the single-output PropsSI FFI shims
(props_si_pt/ph/ps/px/tq); it does not call CoolProp's AbstractState derivative API
(no first_partial_deriv). DampedBackend smooths property values near the critical
point but adds no derivative method.
Consequence: every analytic Jacobian needing dT_sat/dP must use a central
finite-difference fallback, exactly as FloodedEvaporator already does
(:568-572, 3 CoolProp calls per Jacobian eval). Phase B should: (a) add a thin, documented
backend method saturation_temperature_derivative_dp implemented as central FD over the
backend (single source of truth, cacheable), and (b) optionally wire CoolProp's analytic
derivative later. This satisfies mission §9.3 (explicit, documented fallback).
8. Bindings & examples coverage [code]
- Python:
FloodedEvaporatoris not exposed; pyo3 0.23 broken on Python 3.14 (B1). - C:
FloodedEvaporatornot exposed; C bindings are largelySimpleAdapterstubs (e.g.entropyk_compressor_createignores AHRI coeffs,bindings/c/src/components.rs:107-115). - WASM:
FloodedEvaporatornot exposed. - CLI factory (
crates/cli/src/run.rs:2432):FloodedEvaporatorarm exists (:2590) but reads onlyua,target_quality,refrigerant,secondary_fluid, secondary stream — no geometry, no circuit count, no shared-vessel config. Not wired into the factory at all:FloodedCondenser,Economizer,MchxCondenserCoil,ReversingValve,PumpController. - Examples (18):
FloodedEvaporatoris used in none.chiller_r134a_flooded_headpressure.jsonis misnamed (uses DXEvaporator+ a condenser parameter).chiller_r134a_dual_circuit_staging.jsonis two independent circuits with separate water loops — no shared vessel. - Vendor data: Copeland/Danfoss/Bitzer compressors + SWEP BPHX only. No Carrier data, no shell-and-tube / flooded-HX selection data.
9. Findings directly driving the implementation phases
- No shared-vessel / multi-circuit HX primitive exists — must be built (mission §6.4, Phase D).
Cross-circuit edges are rejected; only duty-transfer
ThermalCouplingexists. - Geometry domain types are missing from core (
Length,Mass,Area,TemperatureDifference,ThermalConductivity,Volume) — Phase B prerequisite. - The BPHX registry/geometry/correlation pattern is the reuse target, not a rewrite:
correlation_registry.rs+bphx_correlation.rs+bphx_geometry.rs+two_phase_dp.rsform a clean, evidence-aware, single-source-of-truth pattern to extend to shell-and-tube flooded boiling/condensation (mission §6.2). - Zero-flow regularization should build on
entropyk_core::smoothing(smooth_abs,cubic_blend,smooth_max) rather than hardif m<εbranches (mission §7.2). - Backend
dT_sat/dPis absent — add a documented central-FD method in Phase B (§7). - Baseline is red workspace-wide (B1–B5). These must be unblocked before Phase B–F can
be validated. Recommended pre-Phase-B fixes:
- B2 (highest leverage): make
coolprop-sysprefer the prebuiltinstall_rootlib, or fix thegenerate_headersstep, so the facade/CLI build reproducibly. - B3: fix the two clippy lints in
tabular/interpolate.rs. - B5: fix or
#[ignore]theconvergence_criteriared test with a tracked issue. - B1: standardize on Python 3.13 for the bindings (Phase F, but unblock early).
- B2 (highest leverage): make
ShellAndTubeε-NTUpassesis decorative — Phase B/C must implement a real P-NTU/multipass effectiveness or prevent its use for unsupported arrangements (mission §8.4).- Flooded evaporator outlet/control semantics (mission §3) are wrong by default
(
target_quality=0.7) — Phase C replaces with an explicitFloodedEvaporatorControlenum.
10. Open questions requiring Carrier/product input (not answered here)
No Carrier source documents were provided for this audit, so the following remain Unknown and must NOT be guessed (mission §1.4, §13):
- 61XWHVZE flooded-evaporator geometry (shell ID, tube count per pass, active length per refrigerant circuit, tube type/enhancement, water-box layout, refrigerants).
- 30XF-Z module/pass arrangement details.
- Actual water-path layout through the shared-vessel refrigerant partitions
(mission §6.4
SharedSecondaryLayout) — configurable until evidenced. - Validation datasets for any product.
These are captured in the companion montluel_machine_coverage.md with Unknown status.