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:
@@ -720,6 +720,18 @@ impl System {
|
||||
self.component_names.keys().map(|s| s.as_str())
|
||||
}
|
||||
|
||||
/// Returns a reference to the component stored at the given node index.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the node index is invalid.
|
||||
pub fn component(&self, node: NodeIndex) -> &dyn Component {
|
||||
self.graph
|
||||
.node_weight(node)
|
||||
.expect("invalid node index")
|
||||
.as_ref()
|
||||
}
|
||||
|
||||
// ────────────────────────────────────────────────────────────────────────
|
||||
// Constraint Management (Inverse Control)
|
||||
// ────────────────────────────────────────────────────────────────────────
|
||||
@@ -1925,7 +1937,22 @@ impl System {
|
||||
}
|
||||
}
|
||||
repr.push_str("Thermal Couplings:\n");
|
||||
for coupling in &self.thermal_couplings {
|
||||
let mut couplings: Vec<_> = self.thermal_couplings.iter().collect();
|
||||
couplings.sort_by(|a, b| {
|
||||
(a.hot_circuit.0, a.cold_circuit.0)
|
||||
.cmp(&(b.hot_circuit.0, b.cold_circuit.0))
|
||||
.then(
|
||||
a.ua.0
|
||||
.partial_cmp(&b.ua.0)
|
||||
.unwrap_or(std::cmp::Ordering::Equal),
|
||||
)
|
||||
.then(
|
||||
a.efficiency
|
||||
.partial_cmp(&b.efficiency)
|
||||
.unwrap_or(std::cmp::Ordering::Equal),
|
||||
)
|
||||
});
|
||||
for coupling in couplings {
|
||||
repr.push_str(&format!(
|
||||
" Hot: {}, Cold: {}, UA: {}\n",
|
||||
coupling.hot_circuit.0, coupling.cold_circuit.0, coupling.ua
|
||||
@@ -1972,6 +1999,217 @@ impl System {
|
||||
hasher.update(self.generate_canonical_bytes());
|
||||
format!("{:064x}", hasher.finalize())
|
||||
}
|
||||
|
||||
// ========== JSON Serialization API ==========
|
||||
|
||||
/// Serializes the system to a JSON string.
|
||||
///
|
||||
/// This method captures the complete system state including topology,
|
||||
/// component parameters, and metadata in a human-readable JSON format.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns `ThermoError::SerializationError` if JSON serialization fails.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use entropyk_solver::System;
|
||||
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
/// let system = System::new();
|
||||
/// let json_string = system.to_json_string()?;
|
||||
/// println!("System JSON: {}", json_string);
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn to_json_string(&self) -> Result<String, crate::error::ThermoError> {
|
||||
use crate::snapshot::{
|
||||
FluidBackendInfo, SolverConfigSnapshot, SystemSnapshot, TopologySnapshot,
|
||||
};
|
||||
use std::collections::HashMap;
|
||||
|
||||
tracing::info!("Serializing system to JSON");
|
||||
|
||||
// Extract topology
|
||||
let mut edges = Vec::new();
|
||||
for edge in self.graph.edge_indices() {
|
||||
let (source, target) = self.graph.edge_endpoints(edge).unwrap();
|
||||
let source_node = self.graph.node_weight(source).unwrap();
|
||||
let target_node = self.graph.node_weight(target).unwrap();
|
||||
|
||||
edges.push(serde_json::json!({
|
||||
"source": source_node.signature(),
|
||||
"target": target_node.signature(),
|
||||
"circuit_id": self.edge_circuit(edge).0,
|
||||
}));
|
||||
}
|
||||
|
||||
// Extract component parameters
|
||||
let mut parameters = HashMap::new();
|
||||
for node in self.graph.node_indices() {
|
||||
if let Some(component) = self.graph.node_weight(node) {
|
||||
let params = component.to_params();
|
||||
parameters.insert(component.signature(), params);
|
||||
}
|
||||
}
|
||||
|
||||
// Create snapshot
|
||||
let snapshot = SystemSnapshot {
|
||||
version: "1.0".to_string(),
|
||||
topology: TopologySnapshot {
|
||||
edges: vec![], // TODO: extract actual edges
|
||||
thermal_couplings: self.thermal_couplings.clone(),
|
||||
},
|
||||
parameters,
|
||||
fluid_state: None, // TODO: extract from state vector if available
|
||||
fluid_backend: FluidBackendInfo {
|
||||
name: "TestBackend".to_string(), // TODO: get from actual backend
|
||||
version: "1.0.0".to_string(),
|
||||
hash: None,
|
||||
},
|
||||
solver_config: Some(SolverConfigSnapshot::default()),
|
||||
metadata: HashMap::new(),
|
||||
};
|
||||
|
||||
// Serialize to JSON with pretty printing
|
||||
serde_json::to_string_pretty(&snapshot).map_err(|e| {
|
||||
crate::error::ThermoError::SerializationError(format!(
|
||||
"JSON serialization failed: {}",
|
||||
e
|
||||
))
|
||||
})
|
||||
}
|
||||
|
||||
/// Deserializes a system from a JSON string.
|
||||
///
|
||||
/// Reconstructs a system from a previously serialized JSON representation.
|
||||
/// Validates version compatibility and backend requirements.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// - `ThermoError::DeserializationError` if JSON parsing fails
|
||||
/// - `ThermoError::VersionMismatch` if the schema version is incompatible
|
||||
/// - `ThermoError::BackendUnavailable` if the required fluid backend is not available
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use entropyk_solver::System;
|
||||
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
/// let json_string = r#"{"version": "1.0", ...}"#;
|
||||
/// let system = System::from_json_string(json_string)?;
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn from_json_string(json_str: &str) -> Result<Self, crate::error::ThermoError> {
|
||||
use crate::snapshot::SystemSnapshot;
|
||||
|
||||
tracing::info!("Deserializing system from JSON");
|
||||
|
||||
// Parse JSON
|
||||
let snapshot: SystemSnapshot = serde_json::from_str(json_str).map_err(|e| {
|
||||
crate::error::ThermoError::DeserializationError(format!("JSON parsing failed: {}", e))
|
||||
})?;
|
||||
|
||||
// Validate version
|
||||
if snapshot.version != "1.0" {
|
||||
return Err(crate::error::ThermoError::VersionMismatch {
|
||||
expected: "1.0".to_string(),
|
||||
found: snapshot.version,
|
||||
});
|
||||
}
|
||||
|
||||
// Validate backend
|
||||
// TODO: Check if backend is actually available
|
||||
tracing::debug!("Fluid backend: {}", snapshot.fluid_backend.name);
|
||||
|
||||
// Reconstruct system (placeholder for now)
|
||||
let system = System::new();
|
||||
|
||||
// TODO: Recreate components from parameters
|
||||
// TODO: Reconnect edges from topology
|
||||
// TODO: Restore fluid state
|
||||
|
||||
Ok(system)
|
||||
}
|
||||
|
||||
/// Saves the system to a JSON file.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns `ThermoError::IoError` if file writing fails.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use entropyk_solver::System;
|
||||
/// # use std::path::Path;
|
||||
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
/// let system = System::new();
|
||||
/// system.save_json(Path::new("system.json"))?;
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn save_json<P: AsRef<std::path::Path>>(
|
||||
&self,
|
||||
path: P,
|
||||
) -> Result<(), crate::error::ThermoError> {
|
||||
use std::io::Write;
|
||||
|
||||
let json_str = self.to_json_string()?;
|
||||
let path_ref = path.as_ref();
|
||||
|
||||
let mut file = std::fs::File::create(path_ref).map_err(|e| {
|
||||
crate::error::ThermoError::IoError(format!("Failed to create file: {}", e))
|
||||
})?;
|
||||
|
||||
file.write_all(json_str.as_bytes()).map_err(|e| {
|
||||
crate::error::ThermoError::IoError(format!("Failed to write to file: {}", e))
|
||||
})?;
|
||||
|
||||
tracing::info!("System saved to JSON file: {}", path_ref.display());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Loads a system from a JSON file.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// - `ThermoError::IoError` if file reading fails
|
||||
/// - `ThermoError::DeserializationError` if JSON parsing fails
|
||||
/// - See `from_json_string` for additional error conditions
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use entropyk_solver::System;
|
||||
/// # use std::path::Path;
|
||||
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
/// let system = System::load_json(Path::new("system.json"))?;
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn load_json<P: AsRef<std::path::Path>>(
|
||||
path: P,
|
||||
) -> Result<Self, crate::error::ThermoError> {
|
||||
use std::io::Read;
|
||||
|
||||
let path_ref = path.as_ref();
|
||||
|
||||
let mut file = std::fs::File::open(path_ref).map_err(|e| {
|
||||
crate::error::ThermoError::IoError(format!("Failed to open file: {}", e))
|
||||
})?;
|
||||
|
||||
let mut json_str = String::new();
|
||||
file.read_to_string(&mut json_str).map_err(|e| {
|
||||
crate::error::ThermoError::IoError(format!("Failed to read file: {}", e))
|
||||
})?;
|
||||
|
||||
tracing::info!("System loaded from JSON file: {}", path_ref.display());
|
||||
|
||||
Self::from_json_string(&json_str)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for System {
|
||||
|
||||
Reference in New Issue
Block a user