Files
rustytorch/demos/digital-twin-shared/src/ipc.rs
T
2026-03-04 00:08:42 +00:00

238 lines
6.8 KiB
Rust

//! IPC message types for Digital Twin demo.
use serde::{Deserialize, Serialize};
use crate::config::{InterventionType, ProbeConfig, SimulationConfig, TissueType};
/// Simulation progress update.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SimulationProgress {
/// Current simulation time in seconds
pub current_time: f32,
/// Total simulation duration in seconds
pub total_duration: f32,
/// Current iteration
pub iteration: u32,
/// Total iterations
pub total_iterations: u32,
/// Current maximum temperature in °C
pub max_temperature: f32,
/// Current damaged volume in mm³
pub damaged_volume: f32,
/// Residual (convergence metric)
pub residual: f32,
/// Solver status message
pub status: String,
}
impl Default for SimulationProgress {
fn default() -> Self {
Self {
current_time: 0.0,
total_duration: 0.0,
iteration: 0,
total_iterations: 0,
max_temperature: 37.0,
damaged_volume: 0.0,
residual: 0.0,
status: "Initializing".to_string(),
}
}
}
/// Simulation result.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SimulationResult {
/// Temperature field as flattened array [Z, Y, X]
pub temperature_field: Vec<f32>,
/// Damage field as flattened array [Z, Y, X]
pub damage_field: Vec<f32>,
/// Grid dimensions [x, y, z]
pub dimensions: [u32; 3],
/// Maximum temperature reached in °C
pub max_temperature: f32,
/// Total damaged volume in mm³
pub total_damaged_volume: f32,
/// Severe damage volume in mm³ (damage > 4.6)
pub severe_damage_volume: f32,
/// Simulation time in seconds
pub simulation_time: f32,
/// Number of iterations
pub iterations: u32,
/// Safety margin satisfied
pub safety_ok: bool,
}
/// What-if analysis result.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WhatIfResult {
/// Intervention type used
pub intervention_type: InterventionType,
/// Power setting in Watts
pub power: f32,
/// Duration in seconds
pub duration: f32,
/// Maximum temperature in °C
pub max_temperature: f32,
/// Total damaged volume in mm³
pub total_damaged_volume: f32,
/// Severe damage volume in mm³
pub severe_damage_volume: f32,
/// Moderate damage volume in mm³
pub moderate_damage_volume: f32,
/// Maximum boundary temperature in °C
pub max_boundary_temperature: f32,
/// Safety margin satisfied
pub safety_ok: bool,
/// Recommendation text
pub recommendation: String,
}
/// Geometry summary.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GeometrySummary {
/// Grid shape [x, y, z]
pub shape: [u32; 3],
/// Voxel spacing in mm [dx, dy, dz]
pub spacing: [f32; 3],
/// Physical dimensions in mm [x, y, z]
pub dimensions: [f32; 3],
/// Total number of voxels
pub total_voxels: u32,
/// Number of tissue voxels (non-air)
pub tissue_voxels: u32,
/// Total tissue volume in mm³
pub tissue_volume: f32,
/// Tissue type histogram
pub tissue_histogram: Vec<TissueCount>,
}
/// Tissue type count for histogram.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TissueCount {
/// Tissue type
pub tissue_type: TissueType,
/// Number of voxels
pub count: u32,
/// Percentage of total
pub percentage: f32,
}
/// Request to create a new digital twin.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CreateTwinRequest {
/// Simulation configuration
pub config: SimulationConfig,
/// Optional preset geometry (e.g., "`liver_tumor`", "kidney")
pub preset: Option<String>,
}
/// Request to run simulation.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RunSimulationRequest {
/// Probe configuration
pub probe: ProbeConfig,
/// Simulation duration override (uses config default if None)
pub duration: Option<f32>,
/// Run steady-state instead of transient
pub steady_state: bool,
}
/// Request for what-if analysis.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WhatIfRequest {
/// Probe configuration
pub probe: ProbeConfig,
/// Simulation duration
pub duration: f32,
}
/// Slice data for 2D visualization.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SliceData {
/// Slice orientation
pub orientation: SliceOrientation,
/// Slice index
pub index: u32,
/// Temperature values as flattened 2D array
pub temperature: Vec<f32>,
/// Damage values as flattened 2D array
pub damage: Vec<f32>,
/// Tissue labels as flattened 2D array
pub tissue: Vec<u8>,
/// Slice dimensions [width, height]
pub dimensions: [u32; 2],
}
/// Slice orientation.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
#[serde(rename_all = "snake_case")]
pub enum SliceOrientation {
/// XY plane (axial)
#[default]
Axial,
/// XZ plane (coronal)
Coronal,
/// YZ plane (sagittal)
Sagittal,
}
/// Demo state for UI synchronization.
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct DigitalTwinDemoState {
/// Whether twin is initialized
pub twin_initialized: bool,
/// Current configuration
pub config: Option<SimulationConfig>,
/// Current geometry summary
pub geometry_summary: Option<GeometrySummary>,
/// Whether simulation is running
pub is_simulating: bool,
/// Last simulation result
pub last_result: Option<SimulationResult>,
/// Last what-if result
pub last_what_if: Option<WhatIfResult>,
/// Current probe configuration
pub current_probe: Option<ProbeConfig>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_simulation_progress_default() {
let progress = SimulationProgress::default();
assert_eq!(progress.max_temperature, 37.0);
assert_eq!(progress.current_time, 0.0);
}
#[test]
fn test_demo_state_default() {
let state = DigitalTwinDemoState::default();
assert!(!state.twin_initialized);
assert!(!state.is_simulating);
}
#[test]
fn test_serialization() {
let result = WhatIfResult {
intervention_type: InterventionType::RadiofrequencyAblation,
power: 50.0,
duration: 60.0,
max_temperature: 85.0,
total_damaged_volume: 1500.0,
severe_damage_volume: 800.0,
moderate_damage_volume: 700.0,
max_boundary_temperature: 42.0,
safety_ok: true,
recommendation: "Proceed with treatment".to_string(),
};
let json = serde_json::to_string(&result).unwrap();
let deserialized: WhatIfResult = serde_json::from_str(&json).unwrap();
assert_eq!(deserialized.power, 50.0);
assert!(deserialized.safety_ok);
}
}