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:
Sepehr
2026-04-25 15:01:09 +02:00
parent 891c4ba436
commit ab5dc7e568
3006 changed files with 279068 additions and 59151 deletions

View File

@@ -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);
}
}