runmat_meshing_core/validation/
mod.rs1use crate::{
2 contracts::{artifact::ANALYSIS_MESH_SCHEMA_VERSION, AnalysisMeshArtifact},
3 quality::QualityThresholds,
4};
5
6mod components;
7use components::validate_volume_component_count;
8
9mod connectivity;
10pub use connectivity::{volume_component_count, volume_component_element_counts};
11
12mod coverage;
13use coverage::{
14 validate_boundary_area_coverage, validate_bounds_coverage, validate_coverage_samples,
15 validate_volume_coverage,
16};
17
18mod elements;
19use elements::validate_volume_elements;
20
21mod edges;
22use edges::validate_boundary_edges;
23
24mod faces;
25use faces::validate_boundary_faces;
26
27mod geometry;
28pub use geometry::mesh_contains_point;
29
30mod nodes;
31use nodes::validate_nodes;
32
33mod plc_input;
34use plc_input::validate_plc_input_evidence;
35
36mod quality;
37use quality::validate_quality;
38
39mod recovery;
40use recovery::{
41 validate_boundary_edge_recovery, validate_boundary_face_recovery,
42 validate_no_rolled_back_material_interface_partitions,
43 validate_no_unrecovered_tetrahedron_components, validate_no_unrepaired_exact_quality,
44 validate_recovery_evidence_consistency, validate_tetrahedron_recovery_complete,
45};
46
47mod regions;
48use regions::{validate_required_boundary_regions, validate_required_material_regions};
49
50mod source_provenance;
51use source_provenance::validate_boundary_source_provenance;
52
53mod types;
54pub use types::{
55 analysis_mesh_validation_error_code, AnalysisMeshValidationError, AnalysisMeshValidationOptions,
56};
57
58pub fn validate_analysis_mesh(
59 mesh: &AnalysisMeshArtifact,
60 thresholds: QualityThresholds,
61) -> Result<(), AnalysisMeshValidationError> {
62 validate_analysis_mesh_with_options(
63 mesh,
64 AnalysisMeshValidationOptions {
65 quality: thresholds,
66 ..AnalysisMeshValidationOptions::default()
67 },
68 )
69}
70
71pub fn validate_analysis_mesh_with_options(
72 mesh: &AnalysisMeshArtifact,
73 options: AnalysisMeshValidationOptions,
74) -> Result<(), AnalysisMeshValidationError> {
75 if mesh.schema_version != ANALYSIS_MESH_SCHEMA_VERSION {
76 return Err(AnalysisMeshValidationError::UnsupportedSchema {
77 schema_version: mesh.schema_version.clone(),
78 });
79 }
80 if mesh.nodes.is_empty() {
81 return Err(AnalysisMeshValidationError::EmptyNodes);
82 }
83 if mesh.volume_elements.is_empty() {
84 return Err(AnalysisMeshValidationError::EmptyVolumeElements);
85 }
86 if let Some(max_element_count) = options.max_volume_element_count {
87 if mesh.volume_elements.len() > max_element_count {
88 return Err(AnalysisMeshValidationError::ElementBudgetExceeded {
89 element_count: mesh.volume_elements.len(),
90 max_element_count,
91 });
92 }
93 }
94
95 let node_ids = validate_nodes(mesh)?;
96
97 let element_ids = validate_volume_elements(mesh, &node_ids)?;
98
99 let face_ids = validate_boundary_faces(mesh, &node_ids, &element_ids)?;
100
101 let recovered_boundary_edges = validate_boundary_edges(mesh, &node_ids, &face_ids)?;
102
103 validate_required_boundary_regions(mesh, &options.required_boundary_region_ids)?;
104 validate_required_material_regions(mesh, &options.required_material_region_ids)?;
105 validate_plc_input_evidence(mesh)?;
106 validate_boundary_source_provenance(mesh, options.require_boundary_source_edge_provenance)?;
107 validate_no_unrecovered_tetrahedron_components(
108 mesh,
109 options.require_no_unrecovered_tetrahedron_components,
110 )?;
111 validate_no_rolled_back_material_interface_partitions(mesh)?;
112 validate_recovery_evidence_consistency(mesh)?;
113 validate_tetrahedron_recovery_complete(mesh)?;
114 validate_no_unrepaired_exact_quality(mesh, options.require_no_unrepaired_exact_quality)?;
115 validate_volume_component_count(mesh, options.max_volume_component_count)?;
116 validate_coverage_samples(
117 mesh,
118 &options.coverage_sample_points_m,
119 options.min_coverage_sample_ratio,
120 )?;
121 validate_bounds_coverage(
122 mesh,
123 options.expected_bounds_m,
124 options.min_bounds_coverage_ratio,
125 )?;
126 validate_volume_coverage(
127 mesh,
128 options.expected_volume_m3,
129 options.min_volume_coverage_ratio,
130 )?;
131 validate_boundary_area_coverage(
132 mesh,
133 options.expected_boundary_area_m2,
134 options.min_boundary_area_ratio,
135 )?;
136 validate_boundary_face_recovery(mesh, options.min_boundary_face_recovery_ratio)?;
137 validate_boundary_edge_recovery(
138 mesh,
139 &recovered_boundary_edges,
140 options.min_boundary_edge_recovery_ratio,
141 )?;
142 validate_quality(mesh, options.quality)
143}
144
145#[cfg(test)]
146mod tests;