runmat_analysis_core/
validate.rs1use runmat_geometry_core::UnitSystem;
2use thiserror::Error;
3
4use crate::problem::{
5 loads::LoadKind,
6 model::{AnalysisModel, ReferenceFrame},
7};
8
9#[derive(Debug, Clone, PartialEq, Eq, Error)]
10pub enum AnalysisValidationError {
11 #[error(
12 "ANALYSIS_VALIDATION_MISSING_MATERIALS: analysis model must include at least one material"
13 )]
14 MissingMaterials,
15 #[error("ANALYSIS_VALIDATION_MISSING_BCS: analysis model must include at least one boundary condition")]
16 MissingBoundaryConditions,
17 #[error("ANALYSIS_VALIDATION_MISSING_LOADS: analysis model must include at least one load")]
18 MissingLoads,
19 #[error(
20 "ANALYSIS_VALIDATION_INVALID_MOMENT: moment load {load_id} must have finite components"
21 )]
22 InvalidMomentVector { load_id: String },
23 #[error("ANALYSIS_VALIDATION_ZERO_MOMENT: moment load {load_id} must have nonzero magnitude")]
24 ZeroMomentVector { load_id: String },
25 #[error(
26 "ANALYSIS_VALIDATION_UNIT_MISMATCH: model units {model:?} do not match geometry units {geometry:?}"
27 )]
28 UnitMismatch {
29 model: UnitSystem,
30 geometry: UnitSystem,
31 },
32 #[error(
33 "ANALYSIS_VALIDATION_FRAME_MISMATCH: model frame {model:?} does not match geometry frame {geometry:?}"
34 )]
35 FrameMismatch {
36 model: ReferenceFrame,
37 geometry: ReferenceFrame,
38 },
39}
40
41pub fn validate_model(model: &AnalysisModel) -> Result<(), AnalysisValidationError> {
42 if model.materials.is_empty() {
43 return Err(AnalysisValidationError::MissingMaterials);
44 }
45 if model.boundary_conditions.is_empty() {
46 return Err(AnalysisValidationError::MissingBoundaryConditions);
47 }
48 if model.loads.is_empty() {
49 return Err(AnalysisValidationError::MissingLoads);
50 }
51 for load in &model.loads {
52 if let LoadKind::Moment { mx, my, mz } = load.kind {
53 if !mx.is_finite() || !my.is_finite() || !mz.is_finite() {
54 return Err(AnalysisValidationError::InvalidMomentVector {
55 load_id: load.load_id.clone(),
56 });
57 }
58 if mx == 0.0 && my == 0.0 && mz == 0.0 {
59 return Err(AnalysisValidationError::ZeroMomentVector {
60 load_id: load.load_id.clone(),
61 });
62 }
63 }
64 }
65 Ok(())
66}
67
68pub fn validate_model_against_geometry(
69 model: &AnalysisModel,
70 geometry_units: UnitSystem,
71 geometry_frame: &ReferenceFrame,
72) -> Result<(), AnalysisValidationError> {
73 validate_model(model)?;
74
75 if model.units != geometry_units {
76 return Err(AnalysisValidationError::UnitMismatch {
77 model: model.units,
78 geometry: geometry_units,
79 });
80 }
81 if &model.frame != geometry_frame {
82 return Err(AnalysisValidationError::FrameMismatch {
83 model: model.frame.clone(),
84 geometry: geometry_frame.clone(),
85 });
86 }
87 Ok(())
88}