chore: remove BMAD framework files and IDE configuration artifacts
Clean up unused BMAD workflow, agent, and command files across all IDE configurations (.agent, .clinerules, .cursor, .gemini, .github, .kilocode, .opencode) and internal module files (_bmad/bmb, _bmad/bmm). Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -90,7 +90,6 @@ impl MovingBoundaryCache {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// MovingBoundaryHX - Zone discretization heat exchanger component
|
||||
pub struct MovingBoundaryHX {
|
||||
inner: HeatExchanger<EpsNtuModel>,
|
||||
@@ -119,7 +118,7 @@ impl MovingBoundaryHX {
|
||||
pub fn new() -> Self {
|
||||
let geometry = BphxGeometry::from_dh_area(0.003, 0.5, 20);
|
||||
let model = EpsNtuModel::counter_flow(1000.0);
|
||||
|
||||
|
||||
Self {
|
||||
inner: HeatExchanger::new(model, "MovingBoundaryHX"),
|
||||
geometry,
|
||||
@@ -181,22 +180,36 @@ impl Component for MovingBoundaryHX {
|
||||
state: &StateSlice,
|
||||
residuals: &mut ResidualVector,
|
||||
) -> Result<(), ComponentError> {
|
||||
let (p, m_refrig, t_sec_in, t_sec_out) = if let (Some(hot), Some(cold)) = (self.inner.hot_conditions(), self.inner.cold_conditions()) {
|
||||
(hot.pressure_pa(), hot.mass_flow_kg_s(), cold.temperature_k(), cold.temperature_k() + 5.0)
|
||||
let (p, m_refrig, t_sec_in, t_sec_out) = if let (Some(hot), Some(cold)) =
|
||||
(self.inner.hot_conditions(), self.inner.cold_conditions())
|
||||
{
|
||||
(
|
||||
hot.pressure_pa(),
|
||||
hot.mass_flow_kg_s(),
|
||||
cold.temperature_k(),
|
||||
cold.temperature_k() + 5.0,
|
||||
)
|
||||
} else {
|
||||
(500_000.0, 0.1, 300.0, 320.0)
|
||||
};
|
||||
|
||||
// Extract enthalpies exactly as HeatExchanger does:
|
||||
let enthalpies = self.port_enthalpies(state)?;
|
||||
let h_in = enthalpies.get(0).map(|h| h.to_joules_per_kg()).unwrap_or(400_000.0);
|
||||
let h_out = enthalpies.get(1).map(|h| h.to_joules_per_kg()).unwrap_or(200_000.0);
|
||||
let h_in = enthalpies
|
||||
.get(0)
|
||||
.map(|h| h.to_joules_per_kg())
|
||||
.unwrap_or(400_000.0);
|
||||
let h_out = enthalpies
|
||||
.get(1)
|
||||
.map(|h| h.to_joules_per_kg())
|
||||
.unwrap_or(200_000.0);
|
||||
|
||||
let mut cache = self.cache.borrow_mut();
|
||||
let use_cache = cache.is_valid_for(p, m_refrig);
|
||||
|
||||
if !use_cache {
|
||||
let (disc, h_sat_l, h_sat_v) = self.identify_zones(h_in, h_out, p, t_sec_in, t_sec_out)?;
|
||||
let (disc, h_sat_l, h_sat_v) =
|
||||
self.identify_zones(h_in, h_out, p, t_sec_in, t_sec_out)?;
|
||||
cache.valid = true;
|
||||
cache.p_ref = p;
|
||||
cache.m_ref = m_refrig;
|
||||
@@ -207,9 +220,14 @@ impl Component for MovingBoundaryHX {
|
||||
|
||||
let total_ua = cache.discretization.total_ua;
|
||||
let base_ua = self.inner.ua_nominal();
|
||||
let custom_ua_scale = if base_ua > 0.0 { total_ua / base_ua } else { 1.0 };
|
||||
let custom_ua_scale = if base_ua > 0.0 {
|
||||
total_ua / base_ua
|
||||
} else {
|
||||
1.0
|
||||
};
|
||||
|
||||
self.inner.compute_residuals_with_ua_scale(state, residuals, custom_ua_scale)
|
||||
self.inner
|
||||
.compute_residuals_with_ua_scale(state, residuals, custom_ua_scale)
|
||||
}
|
||||
|
||||
fn jacobian_entries(
|
||||
@@ -264,7 +282,6 @@ impl StateManageable for MovingBoundaryHX {
|
||||
}
|
||||
|
||||
impl MovingBoundaryHX {
|
||||
|
||||
/// Identifies the phase zones along the heat exchanger and calculates boundaries.
|
||||
pub fn identify_zones(
|
||||
&self,
|
||||
@@ -296,10 +313,10 @@ impl MovingBoundaryHX {
|
||||
.map_err(|e| ComponentError::CalculationFailed(format!("h_sat_v failed: {}", e)))?;
|
||||
|
||||
let mut boundaries = Vec::new();
|
||||
|
||||
|
||||
// Calculate transition positions and types
|
||||
let is_condensing = h_refrig_in > h_refrig_out;
|
||||
|
||||
|
||||
// Add inlet boundary
|
||||
let inlet_type = if h_refrig_in > h_sat_v + 1e-3 {
|
||||
ZoneType::Superheated
|
||||
@@ -308,7 +325,15 @@ impl MovingBoundaryHX {
|
||||
} else {
|
||||
ZoneType::TwoPhase
|
||||
};
|
||||
boundaries.push(self.create_boundary(0.0, h_refrig_in, p_refrig, inlet_type, t_secondary_in, h_sat_l, h_sat_v)?);
|
||||
boundaries.push(self.create_boundary(
|
||||
0.0,
|
||||
h_refrig_in,
|
||||
p_refrig,
|
||||
inlet_type,
|
||||
t_secondary_in,
|
||||
h_sat_l,
|
||||
h_sat_v,
|
||||
)?);
|
||||
|
||||
let (h_min, h_max) = if is_condensing {
|
||||
(h_refrig_out, h_refrig_in)
|
||||
@@ -320,16 +345,28 @@ impl MovingBoundaryHX {
|
||||
let pos = (h_sat_l - h_refrig_in) / (h_refrig_out - h_refrig_in);
|
||||
let t_sec = t_secondary_in + pos * (t_secondary_out - t_secondary_in);
|
||||
// After sat_l, type is SC (if condensing) or TP (if evaporating)
|
||||
let post_type = if is_condensing { ZoneType::Subcooled } else { ZoneType::TwoPhase };
|
||||
boundaries.push(self.create_boundary(pos, h_sat_l, p_refrig, post_type, t_sec, h_sat_l, h_sat_v)?);
|
||||
let post_type = if is_condensing {
|
||||
ZoneType::Subcooled
|
||||
} else {
|
||||
ZoneType::TwoPhase
|
||||
};
|
||||
boundaries.push(
|
||||
self.create_boundary(pos, h_sat_l, p_refrig, post_type, t_sec, h_sat_l, h_sat_v)?,
|
||||
);
|
||||
}
|
||||
|
||||
if h_min < h_sat_v && h_max > h_sat_v {
|
||||
let pos = (h_sat_v - h_refrig_in) / (h_refrig_out - h_refrig_in);
|
||||
let t_sec = t_secondary_in + pos * (t_secondary_out - t_secondary_in);
|
||||
// After sat_v, type is TP (if condensing) or SH (if evaporating)
|
||||
let post_type = if is_condensing { ZoneType::TwoPhase } else { ZoneType::Superheated };
|
||||
boundaries.push(self.create_boundary(pos, h_sat_v, p_refrig, post_type, t_sec, h_sat_l, h_sat_v)?);
|
||||
let post_type = if is_condensing {
|
||||
ZoneType::TwoPhase
|
||||
} else {
|
||||
ZoneType::Superheated
|
||||
};
|
||||
boundaries.push(
|
||||
self.create_boundary(pos, h_sat_v, p_refrig, post_type, t_sec, h_sat_l, h_sat_v)?,
|
||||
);
|
||||
}
|
||||
|
||||
// Add outlet boundary
|
||||
@@ -340,7 +377,15 @@ impl MovingBoundaryHX {
|
||||
} else {
|
||||
ZoneType::TwoPhase
|
||||
};
|
||||
boundaries.push(self.create_boundary(1.0, h_refrig_out, p_refrig, outlet_type, t_secondary_out, h_sat_l, h_sat_v)?);
|
||||
boundaries.push(self.create_boundary(
|
||||
1.0,
|
||||
h_refrig_out,
|
||||
p_refrig,
|
||||
outlet_type,
|
||||
t_secondary_out,
|
||||
h_sat_l,
|
||||
h_sat_v,
|
||||
)?);
|
||||
|
||||
// Sort boundaries by position
|
||||
boundaries.sort_by(|a, b| a.position.partial_cmp(&b.position).unwrap());
|
||||
@@ -355,19 +400,19 @@ impl MovingBoundaryHX {
|
||||
|
||||
let (pinch_temp, pinch_pos) = self.calculate_pinch(&boundaries);
|
||||
|
||||
Ok((ZoneDiscretization {
|
||||
boundaries,
|
||||
total_ua,
|
||||
pinch_temp,
|
||||
pinch_position: pinch_pos,
|
||||
}, h_sat_l, h_sat_v))
|
||||
Ok((
|
||||
ZoneDiscretization {
|
||||
boundaries,
|
||||
total_ua,
|
||||
pinch_temp,
|
||||
pinch_position: pinch_pos,
|
||||
},
|
||||
h_sat_l,
|
||||
h_sat_v,
|
||||
))
|
||||
}
|
||||
|
||||
fn compute_zone_ua(
|
||||
&self,
|
||||
b1: &ZoneBoundary,
|
||||
b2: &ZoneBoundary,
|
||||
) -> Result<f64, ComponentError> {
|
||||
fn compute_zone_ua(&self, b1: &ZoneBoundary, b2: &ZoneBoundary) -> Result<f64, ComponentError> {
|
||||
let area_zone = self.geometry.area * (b2.position - b1.position);
|
||||
if area_zone <= 1e-10 {
|
||||
return Ok(0.0);
|
||||
@@ -377,14 +422,14 @@ impl MovingBoundaryHX {
|
||||
// we use a simplified approximation based on zone type.
|
||||
// A true implementation would query self.correlation_selector
|
||||
let h_refrig = match b1.zone_type {
|
||||
ZoneType::TwoPhase => 5000.0, // Boiling or condensation
|
||||
ZoneType::TwoPhase => 5000.0, // Boiling or condensation
|
||||
ZoneType::Superheated => 500.0, // Vapor
|
||||
ZoneType::Subcooled => 1500.0, // Liquid
|
||||
ZoneType::Subcooled => 1500.0, // Liquid
|
||||
};
|
||||
let h_secondary = 5000.0; // Generally high for water/glycol
|
||||
|
||||
|
||||
let u_overall = 1.0 / (1.0 / h_refrig + 1.0 / h_secondary);
|
||||
|
||||
|
||||
Ok(u_overall * area_zone)
|
||||
}
|
||||
|
||||
@@ -413,7 +458,6 @@ impl MovingBoundaryHX {
|
||||
h_sat_l: f64,
|
||||
h_sat_v: f64,
|
||||
) -> Result<ZoneBoundary, ComponentError> {
|
||||
|
||||
let quality = if h_sat_v > h_sat_l {
|
||||
((h - h_sat_l) / (h_sat_v - h_sat_l)).clamp(0.0, 1.0)
|
||||
} else {
|
||||
@@ -422,14 +466,16 @@ impl MovingBoundaryHX {
|
||||
|
||||
let t_refrig = if let Some(backend) = &self.fluid_backend {
|
||||
let fluid = entropyk_fluids::FluidId::new(&self.refrigerant_id);
|
||||
backend.property(
|
||||
fluid,
|
||||
entropyk_fluids::Property::Temperature,
|
||||
entropyk_fluids::FluidState::from_ph(
|
||||
entropyk_core::Pressure::from_pascals(p),
|
||||
entropyk_core::Enthalpy::from_joules_per_kg(h),
|
||||
backend
|
||||
.property(
|
||||
fluid,
|
||||
entropyk_fluids::Property::Temperature,
|
||||
entropyk_fluids::FluidState::from_ph(
|
||||
entropyk_core::Pressure::from_pascals(p),
|
||||
entropyk_core::Enthalpy::from_joules_per_kg(h),
|
||||
),
|
||||
)
|
||||
).map_err(|e| ComponentError::CalculationFailed(format!("T_refrig failed: {}", e)))?
|
||||
.map_err(|e| ComponentError::CalculationFailed(format!("T_refrig failed: {}", e)))?
|
||||
} else {
|
||||
300.0
|
||||
};
|
||||
@@ -445,7 +491,6 @@ impl MovingBoundaryHX {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@@ -489,8 +534,10 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_identify_zones_basic() {
|
||||
use entropyk_fluids::{CriticalPoint, FluidError, FluidId, FluidResult, Phase, ThermoState};
|
||||
use entropyk_core::Pressure;
|
||||
use entropyk_fluids::{
|
||||
CriticalPoint, FluidError, FluidId, FluidResult, Phase, ThermoState,
|
||||
};
|
||||
|
||||
struct MockBackend {
|
||||
h_sat_l: f64,
|
||||
@@ -518,7 +565,9 @@ mod tests {
|
||||
_ => Ok(self.h_sat_v),
|
||||
}
|
||||
}
|
||||
_ => Err(FluidError::UnsupportedProperty { property: format!("{:?}", property) }),
|
||||
_ => Err(FluidError::UnsupportedProperty {
|
||||
property: format!("{:?}", property),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -526,12 +575,29 @@ mod tests {
|
||||
Err(FluidError::NoCriticalPoint { fluid: fluid.0 })
|
||||
}
|
||||
|
||||
fn is_fluid_available(&self, _fluid: &FluidId) -> bool { true }
|
||||
fn phase(&self, _fluid: FluidId, _state: entropyk_fluids::FluidState) -> FluidResult<Phase> { Ok(Phase::Unknown) }
|
||||
fn full_state(&self, _fluid: FluidId, _p: Pressure, _h: Enthalpy) -> FluidResult<ThermoState> {
|
||||
Err(FluidError::UnsupportedProperty { property: "full_state".to_string() })
|
||||
fn is_fluid_available(&self, _fluid: &FluidId) -> bool {
|
||||
true
|
||||
}
|
||||
fn phase(
|
||||
&self,
|
||||
_fluid: FluidId,
|
||||
_state: entropyk_fluids::FluidState,
|
||||
) -> FluidResult<Phase> {
|
||||
Ok(Phase::Unknown)
|
||||
}
|
||||
fn full_state(
|
||||
&self,
|
||||
_fluid: FluidId,
|
||||
_p: Pressure,
|
||||
_h: Enthalpy,
|
||||
) -> FluidResult<ThermoState> {
|
||||
Err(FluidError::UnsupportedProperty {
|
||||
property: "full_state".to_string(),
|
||||
})
|
||||
}
|
||||
fn list_fluids(&self) -> Vec<FluidId> {
|
||||
vec![]
|
||||
}
|
||||
fn list_fluids(&self) -> Vec<FluidId> { vec![] }
|
||||
}
|
||||
|
||||
let backend = MockBackend {
|
||||
@@ -548,16 +614,16 @@ mod tests {
|
||||
let result = hx.identify_zones(450_000.0, 150_000.0, 500_000.0, 300.0, 320.0);
|
||||
assert!(result.is_ok());
|
||||
let (disc, h_sat_l_res, h_sat_v_res) = result.unwrap();
|
||||
|
||||
|
||||
assert_eq!(h_sat_l_res, 200_000.0);
|
||||
assert_eq!(h_sat_v_res, 400_000.0);
|
||||
|
||||
|
||||
// Should have 4 boundaries: inlet(SH), sat_v(SH/TP), sat_l(TP/SC), outlet(SC)
|
||||
assert_eq!(disc.boundaries.len(), 4);
|
||||
assert_eq!(disc.boundaries[0].zone_type, ZoneType::Superheated);
|
||||
assert_eq!(disc.boundaries[1].zone_type, ZoneType::TwoPhase);
|
||||
assert_eq!(disc.boundaries[2].zone_type, ZoneType::Subcooled);
|
||||
assert_eq!(disc.boundaries[3].zone_type, ZoneType::Subcooled);
|
||||
assert_eq!(disc.boundaries[3].zone_type, ZoneType::Subcooled);
|
||||
|
||||
// Total UA should be positive
|
||||
assert!(disc.total_ua > 0.0);
|
||||
@@ -576,10 +642,10 @@ mod tests {
|
||||
|
||||
// Identical
|
||||
assert!(cache.is_valid_for(100_000.0, 1.0));
|
||||
|
||||
|
||||
// P < 5% deviation (104,000 is 4%)
|
||||
assert!(cache.is_valid_for(104_000.0, 1.0));
|
||||
|
||||
|
||||
// P > 5% deviation (106,000 is 6%)
|
||||
assert!(!cache.is_valid_for(106_000.0, 1.0));
|
||||
|
||||
@@ -597,8 +663,10 @@ mod tests {
|
||||
#[test]
|
||||
fn test_compute_residuals_uses_cache() {
|
||||
use crate::{Component, ResidualVector};
|
||||
use entropyk_fluids::{CriticalPoint, FluidError, FluidId, FluidResult, Phase, ThermoState};
|
||||
use entropyk_core::Pressure;
|
||||
use entropyk_fluids::{
|
||||
CriticalPoint, FluidError, FluidId, FluidResult, Phase, ThermoState,
|
||||
};
|
||||
|
||||
struct TrackingMockBackend {
|
||||
pub calls: std::sync::atomic::AtomicUsize,
|
||||
@@ -615,14 +683,33 @@ mod tests {
|
||||
Ok(100.0)
|
||||
}
|
||||
fn critical_point(&self, _fluid: FluidId) -> FluidResult<CriticalPoint> {
|
||||
Err(FluidError::NoCriticalPoint { fluid: "".to_string() })
|
||||
Err(FluidError::NoCriticalPoint {
|
||||
fluid: "".to_string(),
|
||||
})
|
||||
}
|
||||
fn is_fluid_available(&self, _fluid: &FluidId) -> bool { true }
|
||||
fn phase(&self, _fluid: FluidId, _state: entropyk_fluids::FluidState) -> FluidResult<Phase> { Ok(Phase::Unknown) }
|
||||
fn full_state(&self, _fluid: FluidId, _p: Pressure, _h: Enthalpy) -> FluidResult<ThermoState> {
|
||||
Err(FluidError::UnsupportedProperty { property: "full_state".to_string() })
|
||||
fn is_fluid_available(&self, _fluid: &FluidId) -> bool {
|
||||
true
|
||||
}
|
||||
fn phase(
|
||||
&self,
|
||||
_fluid: FluidId,
|
||||
_state: entropyk_fluids::FluidState,
|
||||
) -> FluidResult<Phase> {
|
||||
Ok(Phase::Unknown)
|
||||
}
|
||||
fn full_state(
|
||||
&self,
|
||||
_fluid: FluidId,
|
||||
_p: Pressure,
|
||||
_h: Enthalpy,
|
||||
) -> FluidResult<ThermoState> {
|
||||
Err(FluidError::UnsupportedProperty {
|
||||
property: "full_state".to_string(),
|
||||
})
|
||||
}
|
||||
fn list_fluids(&self) -> Vec<FluidId> {
|
||||
vec![]
|
||||
}
|
||||
fn list_fluids(&self) -> Vec<FluidId> { vec![] }
|
||||
}
|
||||
|
||||
let backend = Arc::new(TrackingMockBackend {
|
||||
@@ -632,7 +719,7 @@ mod tests {
|
||||
let hx = MovingBoundaryHX::new()
|
||||
.with_refrigerant("R410A")
|
||||
.with_fluid_backend(backend.clone());
|
||||
|
||||
|
||||
let state = vec![500_000.0, 400_000.0];
|
||||
let mut residuals = vec![0.0; 3];
|
||||
|
||||
@@ -650,8 +737,10 @@ mod tests {
|
||||
#[test]
|
||||
fn test_performance_speedup() {
|
||||
use crate::{Component, ResidualVector};
|
||||
use entropyk_fluids::{CriticalPoint, FluidError, FluidId, FluidResult, Phase, ThermoState};
|
||||
use entropyk_core::Pressure;
|
||||
use entropyk_fluids::{
|
||||
CriticalPoint, FluidError, FluidId, FluidResult, Phase, ThermoState,
|
||||
};
|
||||
use std::time::Instant;
|
||||
|
||||
struct SlowMockBackend;
|
||||
@@ -668,14 +757,33 @@ mod tests {
|
||||
Ok(100.0)
|
||||
}
|
||||
fn critical_point(&self, _fluid: FluidId) -> FluidResult<CriticalPoint> {
|
||||
Err(FluidError::NoCriticalPoint { fluid: "".to_string() })
|
||||
Err(FluidError::NoCriticalPoint {
|
||||
fluid: "".to_string(),
|
||||
})
|
||||
}
|
||||
fn is_fluid_available(&self, _fluid: &FluidId) -> bool { true }
|
||||
fn phase(&self, _fluid: FluidId, _state: entropyk_fluids::FluidState) -> FluidResult<Phase> { Ok(Phase::Unknown) }
|
||||
fn full_state(&self, _fluid: FluidId, _p: Pressure, _h: Enthalpy) -> FluidResult<ThermoState> {
|
||||
Err(FluidError::UnsupportedProperty { property: "full_state".to_string() })
|
||||
fn is_fluid_available(&self, _fluid: &FluidId) -> bool {
|
||||
true
|
||||
}
|
||||
fn phase(
|
||||
&self,
|
||||
_fluid: FluidId,
|
||||
_state: entropyk_fluids::FluidState,
|
||||
) -> FluidResult<Phase> {
|
||||
Ok(Phase::Unknown)
|
||||
}
|
||||
fn full_state(
|
||||
&self,
|
||||
_fluid: FluidId,
|
||||
_p: Pressure,
|
||||
_h: Enthalpy,
|
||||
) -> FluidResult<ThermoState> {
|
||||
Err(FluidError::UnsupportedProperty {
|
||||
property: "full_state".to_string(),
|
||||
})
|
||||
}
|
||||
fn list_fluids(&self) -> Vec<FluidId> {
|
||||
vec![]
|
||||
}
|
||||
fn list_fluids(&self) -> Vec<FluidId> { vec![] }
|
||||
}
|
||||
|
||||
let backend = Arc::new(SlowMockBackend);
|
||||
@@ -683,7 +791,7 @@ mod tests {
|
||||
let hx = MovingBoundaryHX::new()
|
||||
.with_refrigerant("R410A")
|
||||
.with_fluid_backend(backend.clone());
|
||||
|
||||
|
||||
let state = vec![500_000.0, 400_000.0];
|
||||
let mut residuals = vec![0.0; 3];
|
||||
|
||||
@@ -699,10 +807,10 @@ mod tests {
|
||||
|
||||
println!("Uncached duration: {:?}", duration_uncached);
|
||||
println!("Cached duration: {:?}", duration_cached);
|
||||
|
||||
|
||||
let speedup = duration_uncached.as_secs_f64() / duration_cached.as_secs_f64().max(1e-9);
|
||||
println!("Speedup multiplier: {:.1}x", speedup);
|
||||
|
||||
|
||||
assert!(duration_cached < duration_uncached);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user