use super::parameter_extraction::SimulationParameters;
use super::result_injection::{
ConvergenceInfo, SimulationProvenance, SimulationResult, StateVector,
};
use crate::error::{PhysicsError, PhysicsResult};
use async_trait::async_trait;
use chrono::Utc;
use std::collections::HashMap;
use uuid::Uuid;
#[async_trait]
pub trait PhysicsSimulation: Send + Sync {
fn simulation_type(&self) -> &str;
async fn run(&self, params: &SimulationParameters) -> PhysicsResult<SimulationResult>;
fn validate_results(&self, result: &SimulationResult) -> PhysicsResult<()>;
}
pub struct SimulationRunner;
impl SimulationRunner {
pub fn new() -> Self {
Self
}
}
impl Default for SimulationRunner {
fn default() -> Self {
Self::new()
}
}
pub struct MockThermalSimulation;
#[async_trait]
impl PhysicsSimulation for MockThermalSimulation {
fn simulation_type(&self) -> &str {
"thermal"
}
async fn run(&self, params: &SimulationParameters) -> PhysicsResult<SimulationResult> {
let mut trajectory = Vec::new();
for i in 0..params.time_steps {
let time = params.time_span.0
+ (params.time_span.1 - params.time_span.0) * (i as f64 / params.time_steps as f64);
let mut state = HashMap::new();
state.insert("temperature".to_string(), 20.0 + time * 0.1);
trajectory.push(StateVector { time, state });
}
Ok(SimulationResult {
entity_iri: params.entity_iri.clone(),
simulation_run_id: Uuid::new_v4().to_string(),
timestamp: Utc::now(),
state_trajectory: trajectory,
derived_quantities: HashMap::new(),
convergence_info: ConvergenceInfo {
converged: true,
iterations: params.time_steps,
final_residual: 1e-6,
},
provenance: SimulationProvenance {
software: "oxirs-physics".to_string(),
version: crate::VERSION.to_string(),
parameters_hash: "mock_hash".to_string(),
executed_at: Utc::now(),
execution_time_ms: 100,
},
})
}
fn validate_results(&self, result: &SimulationResult) -> PhysicsResult<()> {
if !result.convergence_info.converged {
return Err(PhysicsError::Simulation(
"Simulation did not converge".to_string(),
));
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn test_mock_thermal_simulation() {
let sim = MockThermalSimulation;
let params = SimulationParameters {
entity_iri: "urn:example:battery:001".to_string(),
simulation_type: "thermal".to_string(),
initial_conditions: HashMap::new(),
boundary_conditions: Vec::new(),
time_span: (0.0, 100.0),
time_steps: 10,
material_properties: HashMap::new(),
constraints: Vec::new(),
};
let result = sim.run(¶ms).await.expect("should succeed");
assert_eq!(result.state_trajectory.len(), 10);
assert!(result.convergence_info.converged);
assert!(sim.validate_results(&result).is_ok());
}
}