runmat-meshing-core 0.6.0

Deterministic meshing preparation contracts for RunMat
Documentation
use crate::{
    contracts::{artifact::ANALYSIS_MESH_SCHEMA_VERSION, AnalysisMeshArtifact},
    quality::QualityThresholds,
};

mod components;
use components::validate_volume_component_count;

mod connectivity;
pub use connectivity::{volume_component_count, volume_component_element_counts};

mod coverage;
use coverage::{
    validate_boundary_area_coverage, validate_bounds_coverage, validate_coverage_samples,
    validate_volume_coverage,
};

mod elements;
use elements::validate_volume_elements;

mod edges;
use edges::validate_boundary_edges;

mod faces;
use faces::validate_boundary_faces;

mod geometry;
pub use geometry::mesh_contains_point;

mod nodes;
use nodes::validate_nodes;

mod plc_input;
use plc_input::validate_plc_input_evidence;

mod quality;
use quality::validate_quality;

mod recovery;
use recovery::{
    validate_boundary_edge_recovery, validate_boundary_face_recovery,
    validate_no_rolled_back_material_interface_partitions,
    validate_no_unrecovered_tetrahedron_components, validate_no_unrepaired_exact_quality,
    validate_recovery_evidence_consistency, validate_tetrahedron_recovery_complete,
};

mod regions;
use regions::{validate_required_boundary_regions, validate_required_material_regions};

mod source_provenance;
use source_provenance::validate_boundary_source_provenance;

mod types;
pub use types::{
    analysis_mesh_validation_error_code, AnalysisMeshValidationError, AnalysisMeshValidationOptions,
};

pub fn validate_analysis_mesh(
    mesh: &AnalysisMeshArtifact,
    thresholds: QualityThresholds,
) -> Result<(), AnalysisMeshValidationError> {
    validate_analysis_mesh_with_options(
        mesh,
        AnalysisMeshValidationOptions {
            quality: thresholds,
            ..AnalysisMeshValidationOptions::default()
        },
    )
}

pub fn validate_analysis_mesh_with_options(
    mesh: &AnalysisMeshArtifact,
    options: AnalysisMeshValidationOptions,
) -> Result<(), AnalysisMeshValidationError> {
    if mesh.schema_version != ANALYSIS_MESH_SCHEMA_VERSION {
        return Err(AnalysisMeshValidationError::UnsupportedSchema {
            schema_version: mesh.schema_version.clone(),
        });
    }
    if mesh.nodes.is_empty() {
        return Err(AnalysisMeshValidationError::EmptyNodes);
    }
    if mesh.volume_elements.is_empty() {
        return Err(AnalysisMeshValidationError::EmptyVolumeElements);
    }
    if let Some(max_element_count) = options.max_volume_element_count {
        if mesh.volume_elements.len() > max_element_count {
            return Err(AnalysisMeshValidationError::ElementBudgetExceeded {
                element_count: mesh.volume_elements.len(),
                max_element_count,
            });
        }
    }

    let node_ids = validate_nodes(mesh)?;

    let element_ids = validate_volume_elements(mesh, &node_ids)?;

    let face_ids = validate_boundary_faces(mesh, &node_ids, &element_ids)?;

    let recovered_boundary_edges = validate_boundary_edges(mesh, &node_ids, &face_ids)?;

    validate_required_boundary_regions(mesh, &options.required_boundary_region_ids)?;
    validate_required_material_regions(mesh, &options.required_material_region_ids)?;
    validate_plc_input_evidence(mesh)?;
    validate_boundary_source_provenance(mesh, options.require_boundary_source_edge_provenance)?;
    validate_no_unrecovered_tetrahedron_components(
        mesh,
        options.require_no_unrecovered_tetrahedron_components,
    )?;
    validate_no_rolled_back_material_interface_partitions(mesh)?;
    validate_recovery_evidence_consistency(mesh)?;
    validate_tetrahedron_recovery_complete(mesh)?;
    validate_no_unrepaired_exact_quality(mesh, options.require_no_unrepaired_exact_quality)?;
    validate_volume_component_count(mesh, options.max_volume_component_count)?;
    validate_coverage_samples(
        mesh,
        &options.coverage_sample_points_m,
        options.min_coverage_sample_ratio,
    )?;
    validate_bounds_coverage(
        mesh,
        options.expected_bounds_m,
        options.min_bounds_coverage_ratio,
    )?;
    validate_volume_coverage(
        mesh,
        options.expected_volume_m3,
        options.min_volume_coverage_ratio,
    )?;
    validate_boundary_area_coverage(
        mesh,
        options.expected_boundary_area_m2,
        options.min_boundary_area_ratio,
    )?;
    validate_boundary_face_recovery(mesh, options.min_boundary_face_recovery_ratio)?;
    validate_boundary_edge_recovery(
        mesh,
        &recovered_boundary_edges,
        options.min_boundary_edge_recovery_ratio,
    )?;
    validate_quality(mesh, options.quality)
}

#[cfg(test)]
mod tests;