Snapshot WIP: Probe calibration path, faer LU backend, and BPHX phase-change duty.
Some checks failed
CI / check (push) Has been cancelled
Some checks failed
CI / check (push) Has been cancelled
Checkpoint incomplete calibration work (cond SDT green, evap SST failing) plus related solver/UI changes so the next pass can fix and extend safely. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -115,10 +115,11 @@ pub use entropyk_components::{
|
||||
IncompressibleSplitter, IsenthalpicExpansionValve, IsentropicCompressor, JacobianBuilder,
|
||||
LmtdModel, MchxCondenserCoil, MockExternalModel, Node, NodeMeasurements, NodePhase,
|
||||
OperationalState, PerformanceCurves, PhaseRegion, Pipe, PipeGeometry, Polynomial1D,
|
||||
Polynomial2D, Pump, PumpCurves, RefrigerantSink, RefrigerantSource, RegistryError,
|
||||
ResidualVector, ScrewEconomizerCompressor, ScrewPerformanceCurves, ShellAndTubeHx,
|
||||
SstSdtCoefficients, StateHistory, StateManageable, StateTransitionError, SystemState,
|
||||
ThermalLoad, ThreadSafeExternalModel, UaMode, ValveCharacteristics, ValveFlowModel,
|
||||
Polynomial2D, Probe, ProbeMeasure, Pump, PumpCurves, RefrigerantSink, RefrigerantSource,
|
||||
RegistryError, ResidualVector, ScrewEconomizerCompressor, ScrewPerformanceCurves,
|
||||
ShellAndTubeHx, SstSdtCoefficients, StateHistory, StateManageable, StateTransitionError,
|
||||
SystemState, ThermalLoad, ThreadSafeExternalModel, UaMode, ValveCharacteristics,
|
||||
ValveFlowModel,
|
||||
};
|
||||
pub use entropyk_components::{ReversingMode, ReversingValve};
|
||||
|
||||
@@ -147,11 +148,11 @@ pub use entropyk_solver::{
|
||||
AddEdgeError, AntoineCoefficients, CircuitConvergence, CircuitId as SolverCircuitId,
|
||||
ComponentOutput, Constraint, ConstraintError, ConstraintId, ConvergedState,
|
||||
ConvergenceCriteria, ConvergenceReason, ConvergenceReport, ConvergenceStatus, CyclePerformance,
|
||||
DomainViolation, FallbackConfig, FallbackSolver, FlowEdge, HomotopyConfig, InitializerConfig,
|
||||
InitializerError, JacobianFreezingConfig, JacobianMatrix, LinearSolver, MacroComponent,
|
||||
MacroComponentSnapshot, NalgebraLuSolver, NewtonConfig, PicardConfig, PortMapping,
|
||||
SmartInitializer, SolveOutcome, Solver, SolverError, SolverStrategy, System, ThermalCoupling,
|
||||
TimeoutConfig, TopologyError,
|
||||
DomainViolation, FaerLuSolver, FallbackConfig, FallbackSolver, FlowEdge, HomotopyConfig,
|
||||
InitializerConfig, InitializerError, JacobianFreezingConfig, JacobianMatrix, LinearSolver,
|
||||
MacroComponent, MacroComponentSnapshot, NalgebraLuSolver, NewtonConfig, PicardConfig,
|
||||
PortMapping, SmartInitializer, SolveOutcome, Solver, SolverError, SolverStrategy, System,
|
||||
ThermalCoupling, TimeoutConfig, TopologyError,
|
||||
};
|
||||
|
||||
// =============================================================================
|
||||
|
||||
@@ -526,6 +526,42 @@ pub fn extract_solved_variables(system: &System, state: &[f64]) -> Vec<SolvedVar
|
||||
}
|
||||
}
|
||||
|
||||
// Calibration factors (z_ua, z_dp, z_flow, z_flow_eco, z_power, z_etav)
|
||||
// promoted to free unknowns via control loops. Each `Some(idx)` slot means
|
||||
// the solver computed a value for that factor at `state[idx]`. The generic
|
||||
// `actuator` slot (physical opening / fan speed) is already covered by the
|
||||
// bounded-variable path above, so we only surface the six named Z-factors.
|
||||
for (name, indices) in system.calib_indices_by_name() {
|
||||
for (factor, slot) in [
|
||||
("z_flow", indices.z_flow),
|
||||
("z_flow_eco", indices.z_flow_eco),
|
||||
("z_dp", indices.z_dp),
|
||||
("z_ua", indices.z_ua),
|
||||
("z_power", indices.z_power),
|
||||
("z_etav", indices.z_etav),
|
||||
] {
|
||||
if let Some(idx) = slot {
|
||||
if idx < state.len() {
|
||||
let id = format!("{}__{}", name, factor);
|
||||
// Skip if already emitted by the bounded-variable path.
|
||||
if out.iter().any(|v| v.id == id) {
|
||||
continue;
|
||||
}
|
||||
out.push(SolvedVariable {
|
||||
id,
|
||||
component: Some(name.clone()),
|
||||
variable: factor.to_string(),
|
||||
value: state[idx],
|
||||
// Calibration factors are bounded to [0.5, 2.0]
|
||||
// (see entropyk_core::CalibValidationError).
|
||||
min: 0.5,
|
||||
max: 2.0,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if skipped > 0 {
|
||||
tracing::debug!(
|
||||
skipped,
|
||||
@@ -547,9 +583,7 @@ pub fn extract_solved_variables(system: &System, state: &[f64]) -> Vec<SolvedVar
|
||||
/// user-facing `"opening"` label.
|
||||
fn derive_solved_variable_label(id: &str, component_id: Option<&str>) -> String {
|
||||
let stripped = match component_id {
|
||||
Some(c) => id
|
||||
.strip_prefix(&format!("{}__", c))
|
||||
.unwrap_or(id),
|
||||
Some(c) => id.strip_prefix(&format!("{}__", c)).unwrap_or(id),
|
||||
None => id.rfind("__").map(|i| &id[i + 2..]).unwrap_or(id),
|
||||
};
|
||||
match stripped {
|
||||
@@ -781,6 +815,9 @@ mod tests {
|
||||
// Component unknown → fall back to last "__"-separated segment.
|
||||
assert_eq!(derive_solved_variable_label("glob__z_dp", None), "z_dp");
|
||||
// No separator and no component → id itself.
|
||||
assert_eq!(derive_solved_variable_label("global_var", None), "global_var");
|
||||
assert_eq!(
|
||||
derive_solved_variable_label("global_var", None),
|
||||
"global_var"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user