Snapshot WIP: solver HP epic progress, BPHX/HX physics, BMAD skill refresh.
Some checks failed
CI / check (push) Has been cancelled
Some checks failed
CI / check (push) Has been cancelled
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>
This commit is contained in:
4
crates/vendors/src/compressors/bitzer.rs
vendored
4
crates/vendors/src/compressors/bitzer.rs
vendored
@@ -325,9 +325,7 @@ mod tests {
|
||||
#[test]
|
||||
fn test_bitzer_get_compressor_4nfc_20y() {
|
||||
let backend = BitzerBackend::new().unwrap();
|
||||
let coeffs = backend
|
||||
.get_compressor_coefficients("4NFC-20Y")
|
||||
.unwrap();
|
||||
let coeffs = backend.get_compressor_coefficients("4NFC-20Y").unwrap();
|
||||
|
||||
assert_eq!(coeffs.model, "4NFC-20Y");
|
||||
assert_eq!(coeffs.manufacturer, "Bitzer");
|
||||
|
||||
29
crates/vendors/src/compressors/copeland.rs
vendored
29
crates/vendors/src/compressors/copeland.rs
vendored
@@ -7,9 +7,7 @@ use std::collections::HashMap;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::error::VendorError;
|
||||
use crate::vendor_api::{
|
||||
BphxParameters, CompressorCoefficients, UaCalcParams, VendorBackend,
|
||||
};
|
||||
use crate::vendor_api::{BphxParameters, CompressorCoefficients, UaCalcParams, VendorBackend};
|
||||
|
||||
/// Backend for Copeland (Emerson) scroll compressor data.
|
||||
///
|
||||
@@ -87,12 +85,11 @@ impl CopelandBackend {
|
||||
/// Load the compressor index and pre-cache all referenced models.
|
||||
fn load_index(&mut self) -> Result<(), VendorError> {
|
||||
let index_path = self.data_path.join("compressors").join("index.json");
|
||||
let index_content = std::fs::read_to_string(&index_path).map_err(|e| {
|
||||
VendorError::IoError {
|
||||
let index_content =
|
||||
std::fs::read_to_string(&index_path).map_err(|e| VendorError::IoError {
|
||||
path: index_path.display().to_string(),
|
||||
source: e,
|
||||
}
|
||||
})?;
|
||||
})?;
|
||||
|
||||
let models: Vec<String> = serde_json::from_str(&index_content)?;
|
||||
|
||||
@@ -103,7 +100,11 @@ impl CopelandBackend {
|
||||
self.sorted_models.push(model);
|
||||
}
|
||||
Err(e) => {
|
||||
log::warn!("[entropyk-vendors] Skipping Copeland model {}: {}", model, e);
|
||||
log::warn!(
|
||||
"[entropyk-vendors] Skipping Copeland model {}: {}",
|
||||
model,
|
||||
e
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -201,9 +202,7 @@ mod tests {
|
||||
#[test]
|
||||
fn test_copeland_get_compressor_zp54() {
|
||||
let backend = CopelandBackend::new().unwrap();
|
||||
let coeffs = backend
|
||||
.get_compressor_coefficients("ZP54KCE-TFD")
|
||||
.unwrap();
|
||||
let coeffs = backend.get_compressor_coefficients("ZP54KCE-TFD").unwrap();
|
||||
|
||||
assert_eq!(coeffs.model, "ZP54KCE-TFD");
|
||||
assert_eq!(coeffs.manufacturer, "Copeland");
|
||||
@@ -221,9 +220,7 @@ mod tests {
|
||||
#[test]
|
||||
fn test_copeland_get_compressor_zp49() {
|
||||
let backend = CopelandBackend::new().unwrap();
|
||||
let coeffs = backend
|
||||
.get_compressor_coefficients("ZP49KCE-TFD")
|
||||
.unwrap();
|
||||
let coeffs = backend.get_compressor_coefficients("ZP49KCE-TFD").unwrap();
|
||||
|
||||
assert_eq!(coeffs.model, "ZP49KCE-TFD");
|
||||
assert_eq!(coeffs.manufacturer, "Copeland");
|
||||
@@ -235,9 +232,7 @@ mod tests {
|
||||
#[test]
|
||||
fn test_copeland_validity_range() {
|
||||
let backend = CopelandBackend::new().unwrap();
|
||||
let coeffs = backend
|
||||
.get_compressor_coefficients("ZP54KCE-TFD")
|
||||
.unwrap();
|
||||
let coeffs = backend.get_compressor_coefficients("ZP54KCE-TFD").unwrap();
|
||||
|
||||
assert!((coeffs.validity.t_suction_min - (-10.0)).abs() < 1e-10);
|
||||
assert!((coeffs.validity.t_suction_max - 20.0).abs() < 1e-10);
|
||||
|
||||
30
crates/vendors/src/compressors/danfoss.rs
vendored
30
crates/vendors/src/compressors/danfoss.rs
vendored
@@ -7,9 +7,7 @@ use std::collections::HashMap;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::error::VendorError;
|
||||
use crate::vendor_api::{
|
||||
BphxParameters, CompressorCoefficients, UaCalcParams, VendorBackend,
|
||||
};
|
||||
use crate::vendor_api::{BphxParameters, CompressorCoefficients, UaCalcParams, VendorBackend};
|
||||
|
||||
/// Backend for Danfoss scroll compressor data.
|
||||
///
|
||||
@@ -87,12 +85,11 @@ impl DanfossBackend {
|
||||
/// Load the compressor index and pre-cache all referenced models.
|
||||
fn load_index(&mut self) -> Result<(), VendorError> {
|
||||
let index_path = self.data_path.join("compressors").join("index.json");
|
||||
let index_content = std::fs::read_to_string(&index_path).map_err(|e| {
|
||||
VendorError::IoError {
|
||||
let index_content =
|
||||
std::fs::read_to_string(&index_path).map_err(|e| VendorError::IoError {
|
||||
path: index_path.display().to_string(),
|
||||
source: e,
|
||||
}
|
||||
})?;
|
||||
})?;
|
||||
|
||||
let models: Vec<String> = serde_json::from_str(&index_content).map_err(|e| {
|
||||
VendorError::InvalidFormat(format!("Parse error in {}: {}", index_path.display(), e))
|
||||
@@ -205,9 +202,12 @@ mod tests {
|
||||
PathBuf::from("data")
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
let backend = DanfossBackend::from_path(base_path.join("danfoss"));
|
||||
assert!(backend.is_ok(), "DanfossBackend::from_path() should succeed");
|
||||
assert!(
|
||||
backend.is_ok(),
|
||||
"DanfossBackend::from_path() should succeed"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -229,9 +229,7 @@ mod tests {
|
||||
#[test]
|
||||
fn test_danfoss_get_compressor_sh140() {
|
||||
let backend = DanfossBackend::new().unwrap();
|
||||
let coeffs = backend
|
||||
.get_compressor_coefficients("SH140-4")
|
||||
.unwrap();
|
||||
let coeffs = backend.get_compressor_coefficients("SH140-4").unwrap();
|
||||
|
||||
assert_eq!(coeffs.model, "SH140-4");
|
||||
assert_eq!(coeffs.manufacturer, "Danfoss");
|
||||
@@ -253,9 +251,7 @@ mod tests {
|
||||
#[test]
|
||||
fn test_danfoss_get_compressor_sh090() {
|
||||
let backend = DanfossBackend::new().unwrap();
|
||||
let coeffs = backend
|
||||
.get_compressor_coefficients("SH090-4")
|
||||
.unwrap();
|
||||
let coeffs = backend.get_compressor_coefficients("SH090-4").unwrap();
|
||||
|
||||
assert_eq!(coeffs.model, "SH090-4");
|
||||
assert_eq!(coeffs.manufacturer, "Danfoss");
|
||||
@@ -269,9 +265,7 @@ mod tests {
|
||||
#[test]
|
||||
fn test_danfoss_validity_range() {
|
||||
let backend = DanfossBackend::new().unwrap();
|
||||
let coeffs = backend
|
||||
.get_compressor_coefficients("SH140-4")
|
||||
.unwrap();
|
||||
let coeffs = backend.get_compressor_coefficients("SH140-4").unwrap();
|
||||
|
||||
assert!((coeffs.validity.t_suction_min - (-15.0)).abs() < 1e-10);
|
||||
assert!((coeffs.validity.t_suction_max - 15.0).abs() < 1e-10);
|
||||
|
||||
2
crates/vendors/src/compressors/mod.rs
vendored
2
crates/vendors/src/compressors/mod.rs
vendored
@@ -6,6 +6,6 @@
|
||||
/// Copeland (Emerson) compressor data backend.
|
||||
pub mod copeland;
|
||||
|
||||
pub mod bitzer;
|
||||
/// Danfoss (11.14), Bitzer (11.15) compressor data backends.
|
||||
pub mod danfoss;
|
||||
pub mod bitzer;
|
||||
|
||||
16
crates/vendors/src/heat_exchangers/swep.rs
vendored
16
crates/vendors/src/heat_exchangers/swep.rs
vendored
@@ -7,9 +7,7 @@ use std::collections::HashMap;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::error::VendorError;
|
||||
use crate::vendor_api::{
|
||||
BphxParameters, CompressorCoefficients, UaCalcParams, VendorBackend,
|
||||
};
|
||||
use crate::vendor_api::{BphxParameters, CompressorCoefficients, UaCalcParams, VendorBackend};
|
||||
|
||||
/// Backend for SWEP brazed-plate heat exchanger data.
|
||||
///
|
||||
@@ -87,12 +85,11 @@ impl SwepBackend {
|
||||
/// Load the BPHX index and pre-cache all referenced models.
|
||||
fn load_index(&mut self) -> Result<(), VendorError> {
|
||||
let index_path = self.data_path.join("bphx").join("index.json");
|
||||
let index_content = std::fs::read_to_string(&index_path).map_err(|e| {
|
||||
VendorError::IoError {
|
||||
let index_content =
|
||||
std::fs::read_to_string(&index_path).map_err(|e| VendorError::IoError {
|
||||
path: index_path.display().to_string(),
|
||||
source: e,
|
||||
}
|
||||
})?;
|
||||
})?;
|
||||
|
||||
let models: Vec<String> = serde_json::from_str(&index_content)?;
|
||||
|
||||
@@ -114,10 +111,7 @@ impl SwepBackend {
|
||||
|
||||
/// Load a single BPHX model from its JSON file.
|
||||
fn load_model(&self, model: &str) -> Result<BphxParameters, VendorError> {
|
||||
let model_path = self
|
||||
.data_path
|
||||
.join("bphx")
|
||||
.join(format!("{}.json", model));
|
||||
let model_path = self.data_path.join("bphx").join(format!("{}.json", model));
|
||||
|
||||
let content = std::fs::read_to_string(&model_path).map_err(|e| VendorError::IoError {
|
||||
path: model_path.display().to_string(),
|
||||
|
||||
2
crates/vendors/src/lib.rs
vendored
2
crates/vendors/src/lib.rs
vendored
@@ -24,8 +24,8 @@ pub mod heat_exchangers;
|
||||
pub use compressors::bitzer::BitzerBackend;
|
||||
pub use compressors::copeland::CopelandBackend;
|
||||
pub use compressors::danfoss::DanfossBackend;
|
||||
pub use heat_exchangers::swep::SwepBackend;
|
||||
pub use error::VendorError;
|
||||
pub use heat_exchangers::swep::SwepBackend;
|
||||
pub use vendor_api::{
|
||||
BphxParameters, CompressorCoefficients, CompressorValidityRange, UaCalcParams, UaCurve,
|
||||
VendorBackend,
|
||||
|
||||
25
crates/vendors/src/vendor_api.rs
vendored
25
crates/vendors/src/vendor_api.rs
vendored
@@ -69,14 +69,14 @@ impl<'de> Deserialize<'de> for CompressorValidityRange {
|
||||
}
|
||||
|
||||
let inner = Inner::deserialize(deserializer)?;
|
||||
|
||||
|
||||
if inner.t_suction_min > inner.t_suction_max {
|
||||
return Err(serde::de::Error::custom(format!(
|
||||
"Invalid suction temperature range: min ({} °C) > max ({} °C)",
|
||||
inner.t_suction_min, inner.t_suction_max
|
||||
)));
|
||||
}
|
||||
|
||||
|
||||
if inner.t_discharge_min > inner.t_discharge_max {
|
||||
return Err(serde::de::Error::custom(format!(
|
||||
"Invalid discharge temperature range: min ({} °C) > max ({} °C)",
|
||||
@@ -141,14 +141,16 @@ impl<'de> Deserialize<'de> for UaCurve {
|
||||
}
|
||||
|
||||
let mut inner = Inner::deserialize(deserializer)?;
|
||||
|
||||
|
||||
// Sort points by mass_flow_ratio (x-axis) to ensure interpolation works correctly
|
||||
// even if the JSON is out of order. f64 sorting requires partial_cmp.
|
||||
inner.points.sort_by(|a, b| {
|
||||
a.0.partial_cmp(&b.0).unwrap_or(std::cmp::Ordering::Equal)
|
||||
});
|
||||
inner
|
||||
.points
|
||||
.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap_or(std::cmp::Ordering::Equal));
|
||||
|
||||
Ok(Self { points: inner.points })
|
||||
Ok(Self {
|
||||
points: inner.points,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -259,7 +261,9 @@ mod tests {
|
||||
model: "ZP54KCE-TFD".into(),
|
||||
manufacturer: "Copeland".into(),
|
||||
refrigerant: "R410A".into(),
|
||||
capacity_coeffs: [18000.0, 350.0, -120.0, 2.5, 1.8, -4.2, 0.05, 0.03, -0.02, 0.01],
|
||||
capacity_coeffs: [
|
||||
18000.0, 350.0, -120.0, 2.5, 1.8, -4.2, 0.05, 0.03, -0.02, 0.01,
|
||||
],
|
||||
power_coeffs: [4500.0, 95.0, 45.0, 0.8, 0.5, 1.2, 0.02, 0.01, 0.01, 0.005],
|
||||
mass_flow_coeffs: None,
|
||||
validity: CompressorValidityRange {
|
||||
@@ -402,7 +406,10 @@ mod tests {
|
||||
#[test]
|
||||
fn test_vendor_error_display_invalid_format() {
|
||||
let err = VendorError::InvalidFormat("missing capacity_coeffs".into());
|
||||
assert_eq!(err.to_string(), "Invalid data format: missing capacity_coeffs");
|
||||
assert_eq!(
|
||||
err.to_string(),
|
||||
"Invalid data format: missing capacity_coeffs"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user