use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct StressFieldVisualization {
pub values: Vec<f64>,
pub dimensions: [usize; 2],
pub origin: [f64; 2],
pub spacing: f64,
pub field_name: String,
pub min_value: f64,
pub max_value: f64,
pub unit: String,
}
impl StressFieldVisualization {
#[must_use]
pub fn from_values(
values: Vec<f64>,
dimensions: [usize; 2],
origin: [f64; 2],
spacing: f64,
field_name: &str,
unit: &str,
) -> Self {
let min_value = values.iter().cloned().fold(f64::MAX, f64::min);
let max_value = values.iter().cloned().fold(f64::MIN, f64::max);
Self {
values,
dimensions,
origin,
spacing,
field_name: field_name.to_string(),
min_value,
max_value,
unit: unit.to_string(),
}
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct DeformationVisualization {
pub positions: Vec<[f64; 3]>,
pub displacements: Vec<[f64; 3]>,
pub magnitudes: Vec<f64>,
pub max_displacement: f64,
pub display_scale: f64,
}
impl DeformationVisualization {
#[must_use]
pub fn new(positions: Vec<[f64; 3]>, displacements: Vec<[f64; 3]>, display_scale: f64) -> Self {
let magnitudes: Vec<f64> = displacements
.iter()
.map(|d| (d[0] * d[0] + d[1] * d[1] + d[2] * d[2]).sqrt())
.collect();
let max_displacement = magnitudes.iter().cloned().fold(0.0_f64, f64::max);
Self {
positions,
displacements,
magnitudes,
max_displacement,
display_scale,
}
}
#[must_use]
pub fn deformed_position(&self, i: usize) -> Option<[f64; 3]> {
let pos = self.positions.get(i)?;
let disp = self.displacements.get(i)?;
Some([
pos[0] + disp[0] * self.display_scale,
pos[1] + disp[1] * self.display_scale,
pos[2] + disp[2] * self.display_scale,
])
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct FractureVisualization {
pub crack_path: Vec<[f64; 2]>,
pub stress_intensity: Vec<f64>,
pub k_ic: f64,
pub crack_length: f64,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct FatigueDamageMap {
pub damage: Vec<f64>,
pub dimensions: [usize; 2],
pub spacing: f64,
pub cycles: u64,
pub max_damage: f64,
}
impl FatigueDamageMap {
#[must_use]
pub fn from_values(
damage: Vec<f64>,
dimensions: [usize; 2],
spacing: f64,
cycles: u64,
) -> Self {
let max_damage = damage.iter().cloned().fold(0.0_f64, f64::max);
Self {
damage,
dimensions,
spacing,
cycles,
max_damage,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn stress_field_basic() {
let values = vec![100.0, 200.0, 150.0, 300.0];
let field = StressFieldVisualization::from_values(
values,
[2, 2],
[0.0, 0.0],
1.0,
"von_mises",
"Pa",
);
assert_eq!(field.dimensions, [2, 2]);
assert!((field.min_value - 100.0).abs() < 0.01);
assert!((field.max_value - 300.0).abs() < 0.01);
}
#[test]
fn deformation_basic() {
let positions = vec![[0.0, 0.0, 0.0], [1.0, 0.0, 0.0]];
let displacements = vec![[0.0, 0.001, 0.0], [0.0, 0.002, 0.0]];
let viz = DeformationVisualization::new(positions, displacements, 100.0);
assert_eq!(viz.magnitudes.len(), 2);
assert!((viz.max_displacement - 0.002).abs() < 1e-6);
let def = viz.deformed_position(0).unwrap();
assert!((def[1] - 0.1).abs() < 1e-6); }
#[test]
fn deformation_out_of_bounds() {
let viz = DeformationVisualization::new(vec![], vec![], 1.0);
assert!(viz.deformed_position(0).is_none());
}
#[test]
fn fracture_serializes() {
let frac = FractureVisualization {
crack_path: vec![[0.0, 0.0], [0.01, 0.0], [0.02, 0.001]],
stress_intensity: vec![10e6, 15e6, 20e6],
k_ic: 30e6,
crack_length: 0.02,
};
let json = serde_json::to_string(&frac);
assert!(json.is_ok());
}
#[test]
fn fatigue_map_basic() {
let damage = vec![0.0, 0.1, 0.5, 0.9];
let map = FatigueDamageMap::from_values(damage, [2, 2], 0.01, 100_000);
assert_eq!(map.cycles, 100_000);
assert!((map.max_damage - 0.9).abs() < 0.01);
}
#[test]
fn fatigue_map_undamaged() {
let map = FatigueDamageMap::from_values(vec![0.0; 4], [2, 2], 1.0, 0);
assert_eq!(map.max_damage, 0.0);
}
#[test]
fn stress_field_serializes() {
let field = StressFieldVisualization::from_values(
vec![1.0, 2.0],
[2, 1],
[0.0, 0.0],
0.5,
"sigma_xx",
"MPa",
);
let json = serde_json::to_string(&field);
assert!(json.is_ok());
}
}