runmat-meshing-core 0.6.0

Deterministic meshing preparation contracts for RunMat
Documentation
use crate::contracts::AnalysisMeshArtifact;

use super::AnalysisMeshValidationError;

const SOLID_BACKEND: &str = "solid";

pub(super) fn validate_plc_input_evidence(
    mesh: &AnalysisMeshArtifact,
) -> Result<(), AnalysisMeshValidationError> {
    if mesh.backend.backend != SOLID_BACKEND {
        return Ok(());
    }
    if mesh.backend.plc_input_node_count == 0 {
        return missing("missing_plc_nodes");
    }
    if mesh.backend.plc_input_facet_count == 0 {
        return missing("missing_plc_facets");
    }
    if mesh.backend.plc_input_protected_edge_count == 0 {
        return missing("missing_plc_protected_edges");
    }
    if mesh.backend.plc_input_boundary_component_count == 0 {
        return missing("missing_plc_boundary_components");
    }
    if mesh.backend.plc_input_boundary_component_count
        != mesh.backend.plc_input_outer_shell_count + mesh.backend.plc_input_nested_shell_count
    {
        return missing("inconsistent_plc_shell_component_count");
    }
    if mesh.backend.plc_input_boundary_component_count != 1
        && mesh.backend.tetrahedron_generation_family != "nested_tetrahedron_shell"
    {
        return missing("unsupported_plc_boundary_component_count");
    }
    if mesh.backend.plc_input_boundary_component_node_count == 0 {
        return missing("missing_plc_boundary_component_nodes");
    }
    if mesh.backend.plc_input_max_boundary_component_node_count == 0 {
        return missing("missing_plc_max_boundary_component_nodes");
    }
    if mesh.backend.plc_input_surface_boundary_node_count == 0 {
        return missing("missing_plc_surface_boundary_nodes");
    }
    if mesh.backend.plc_input_surface_boundary_node_count > mesh.backend.plc_input_node_count {
        return missing("inconsistent_plc_surface_boundary_nodes");
    }
    if mesh.backend.plc_input_surface_boundary_node_count
        > mesh.backend.plc_input_boundary_component_node_count
    {
        return missing("inconsistent_plc_surface_boundary_component_nodes");
    }
    if !mesh.backend.plc_input_shell_nesting_classified {
        return missing("unclassified_plc_shell_nesting");
    }
    if mesh.backend.plc_input_outer_shell_count != 1 {
        return missing("unsupported_plc_outer_shell_count");
    }
    if mesh.backend.plc_input_nested_shell_count > 0
        && mesh.backend.tetrahedron_generation_family != "nested_tetrahedron_shell"
    {
        return missing("unsupported_nested_plc_shell");
    }
    if mesh.backend.tetrahedron_generation_family == "nested_tetrahedron_shell"
        && (mesh.backend.plc_input_nested_shell_count == 0
            || mesh.backend.plc_input_max_shell_nesting_depth != 1)
    {
        return missing("inconsistent_nested_plc_shell_evidence");
    }
    validate_tetrahedron_generation_selection_evidence(mesh)?;
    if mesh.backend.tetrahedron_material_region_count == 0 {
        return missing("missing_tetrahedron_material_region_evidence");
    }
    if mesh.backend.tetrahedron_unclassified_material_element_count > 0 {
        return missing("unclassified_tetrahedron_material_ownership");
    }
    if mesh.backend.plc_input_material_region_count == 1
        && mesh.backend.tetrahedron_material_region_count != 1
    {
        return missing("inconsistent_single_material_region_ownership");
    }
    if mesh.backend.plc_input_material_region_count > 0
        && mesh.backend.plc_input_material_region_facet_count == 0
    {
        return missing("missing_plc_material_region_facet_evidence");
    }
    validate_plc_input_cad_curve_evidence(mesh)?;
    Ok(())
}

fn validate_tetrahedron_generation_selection_evidence(
    mesh: &AnalysisMeshArtifact,
) -> Result<(), AnalysisMeshValidationError> {
    let backend = &mesh.backend;
    if backend.tetrahedron_generation_family == "unknown" {
        return missing("missing_tetrahedron_generation_family");
    }
    if backend.tetrahedron_generation_attempted_family_count == 0 {
        return missing("missing_tetrahedron_generation_family_attempts");
    }
    if backend.tetrahedron_generation_selected_family_index == 0 {
        return missing("missing_tetrahedron_generation_selected_family");
    }
    if backend.tetrahedron_generation_selected_family_index
        > backend.tetrahedron_generation_attempted_family_count
    {
        return missing("inconsistent_tetrahedron_generation_selected_family_index");
    }
    if backend
        .tetrahedron_generation_rejected_family_count
        .checked_add(1)
        != Some(backend.tetrahedron_generation_attempted_family_count)
    {
        return missing("inconsistent_tetrahedron_generation_rejected_family_count");
    }
    if backend.tetrahedron_generation_interior_support_accepted_count
        > backend.tetrahedron_generation_interior_support_candidate_count
    {
        return missing("inconsistent_tetrahedron_generation_interior_support_count");
    }
    if backend.tetrahedron_generation_interior_support_accepted_count > 1 {
        return missing("unsupported_tetrahedron_generation_interior_support_count");
    }
    validate_nested_shell_generation_evidence(mesh)?;
    Ok(())
}

fn validate_nested_shell_generation_evidence(
    mesh: &AnalysisMeshArtifact,
) -> Result<(), AnalysisMeshValidationError> {
    let backend = &mesh.backend;
    let nested_generation_evidence_count = backend
        .tetrahedron_generation_nested_shell_outer_node_count
        + backend.tetrahedron_generation_nested_shell_inner_node_count
        + backend.tetrahedron_generation_nested_shell_generated_node_count
        + backend.tetrahedron_generation_nested_shell_refill_boundary_face_count
        + backend.tetrahedron_generation_nested_shell_boundary_centroid_refinement_attempt_count
        + backend.tetrahedron_generation_nested_shell_boundary_centroid_refinement_rejected_count
        + backend.tetrahedron_generation_nested_shell_boundary_exact_cover_refill_count
        + backend.tetrahedron_generation_nested_shell_boundary_centroid_refinement_refill_count
        + backend.tetrahedron_generation_nested_shell_barycentric_partition_refill_count
        + backend.tetrahedron_generation_nested_shell_outer_facet_count
        + backend.tetrahedron_generation_nested_shell_inner_facet_count;

    if backend.tetrahedron_generation_family != "nested_tetrahedron_shell" {
        if nested_generation_evidence_count > 0 {
            return missing("unexpected_nested_tetrahedron_shell_generation_evidence");
        }
        return Ok(());
    }

    if backend.tetrahedron_generation_nested_shell_outer_node_count == 0
        || backend.tetrahedron_generation_nested_shell_inner_node_count == 0
        || backend.tetrahedron_generation_nested_shell_outer_facet_count == 0
        || backend.tetrahedron_generation_nested_shell_inner_facet_count == 0
        || backend.tetrahedron_generation_nested_shell_refill_boundary_face_count == 0
    {
        return missing("missing_nested_tetrahedron_shell_generation_evidence");
    }

    let exact_cover_refill_count =
        backend.tetrahedron_generation_nested_shell_boundary_exact_cover_refill_count;
    let centroid_refill_count =
        backend.tetrahedron_generation_nested_shell_boundary_centroid_refinement_refill_count;
    let barycentric_refill_count =
        backend.tetrahedron_generation_nested_shell_barycentric_partition_refill_count;
    let strategy_count =
        exact_cover_refill_count + centroid_refill_count + barycentric_refill_count;
    if strategy_count != 1 {
        return missing("inconsistent_nested_tetrahedron_shell_refill_strategy_count");
    }

    let refinement_attempt_count =
        backend.tetrahedron_generation_nested_shell_boundary_centroid_refinement_attempt_count;
    let refinement_rejected_count =
        backend.tetrahedron_generation_nested_shell_boundary_centroid_refinement_rejected_count;
    if refinement_rejected_count > refinement_attempt_count {
        return missing("inconsistent_nested_tetrahedron_shell_refinement_rejection_count");
    }
    if centroid_refill_count > refinement_attempt_count {
        return missing("inconsistent_nested_tetrahedron_shell_refinement_refill_count");
    }
    if refinement_attempt_count != refinement_rejected_count + centroid_refill_count {
        return missing("inconsistent_nested_tetrahedron_shell_refinement_attempt_count");
    }
    if exact_cover_refill_count > refinement_rejected_count {
        return missing("inconsistent_nested_tetrahedron_shell_exact_cover_refill_count");
    }

    Ok(())
}

fn validate_plc_input_cad_curve_evidence(
    mesh: &AnalysisMeshArtifact,
) -> Result<(), AnalysisMeshValidationError> {
    let backend = &mesh.backend;
    let source_edge_count = backend.plc_input_cad_curve_boundary_source_edge_count;
    let boundary_segment_count = backend.plc_input_cad_curve_boundary_segment_count;
    let imported_edge_count = backend.plc_input_cad_curve_imported_edge_count;
    let evaluator_edge_count = backend.plc_input_cad_curve_evaluator_edge_count;
    let evaluator_sample_count = backend.plc_input_cad_curve_evaluator_sample_count;
    let live_query_edge_count = backend.plc_input_cad_curve_live_query_edge_count;
    let live_query_sample_count = backend.plc_input_cad_curve_live_query_sample_count;
    let rejected_sample_count = backend.plc_input_cad_curve_rejected_evaluator_sample_count;
    let curvature_sized_edge_count = backend.plc_input_cad_curve_curvature_sized_edge_count;
    let curvature_sample_count = backend.plc_input_cad_curve_curvature_sample_count;

    if source_edge_count == 0 {
        let any_cad_curve_evidence = boundary_segment_count
            + imported_edge_count
            + evaluator_edge_count
            + evaluator_sample_count
            + live_query_edge_count
            + live_query_sample_count
            + rejected_sample_count
            + curvature_sized_edge_count
            + curvature_sample_count;
        if any_cad_curve_evidence > 0 {
            return missing("missing_plc_cad_curve_boundary_source_edges");
        }
        return Ok(());
    }

    if source_edge_count > backend.plc_input_protected_edge_count {
        return missing("inconsistent_plc_cad_curve_source_edge_count");
    }
    if boundary_segment_count < source_edge_count {
        return missing("inconsistent_plc_cad_curve_boundary_segment_count");
    }
    if imported_edge_count > source_edge_count {
        return missing("inconsistent_plc_cad_curve_imported_edge_count");
    }
    if evaluator_edge_count > source_edge_count {
        return missing("inconsistent_plc_cad_curve_evaluator_edge_count");
    }
    if live_query_edge_count > evaluator_edge_count {
        return missing("inconsistent_plc_cad_curve_live_query_edge_count");
    }
    if curvature_sized_edge_count > source_edge_count {
        return missing("inconsistent_plc_cad_curve_curvature_sized_edge_count");
    }
    if evaluator_sample_count > 0 && imported_edge_count + evaluator_edge_count == 0 {
        return missing("missing_plc_cad_curve_sample_edge_evidence");
    }
    if live_query_sample_count > 0 && live_query_edge_count == 0 {
        return missing("missing_plc_cad_curve_live_query_edge_evidence");
    }
    if rejected_sample_count > 0 && imported_edge_count + evaluator_edge_count == 0 {
        return missing("missing_plc_cad_curve_rejected_sample_edge_evidence");
    }
    if curvature_sample_count > 0 && source_edge_count == 0 {
        return missing("missing_plc_cad_curve_curvature_source_edge_evidence");
    }

    Ok(())
}

fn missing<T>(reason: &str) -> Result<T, AnalysisMeshValidationError> {
    Err(AnalysisMeshValidationError::MissingPlcInputEvidence {
        reason: reason.to_string(),
    })
}