mesh-sieve 4.0.2

Modular, high-performance Rust library for mesh and data management, designed for scientific computing and PDE codes.
Documentation
use mesh_sieve::algs::transform::{CoordinateTransform, TransformHooks, transform_mesh};
use mesh_sieve::data::atlas::Atlas;
use mesh_sieve::data::coordinates::Coordinates;
use mesh_sieve::data::section::Section;
use mesh_sieve::data::storage::VecStorage;
use mesh_sieve::geometry::quality::cell_quality_from_section;
use mesh_sieve::io::MeshData;
use mesh_sieve::topology::cell_type::CellType;
use mesh_sieve::topology::point::PointId;
use mesh_sieve::topology::sieve::{MeshSieve, Sieve};
use std::collections::BTreeSet;

fn build_triangle_mesh() -> (
    MeshData<MeshSieve, f64, VecStorage<f64>, VecStorage<CellType>>,
    [PointId; 3],
) {
    let cell = PointId::new(10).unwrap();
    let v0 = PointId::new(1).unwrap();
    let v1 = PointId::new(2).unwrap();
    let v2 = PointId::new(3).unwrap();

    let mut sieve = MeshSieve::default();
    Sieve::add_arrow(&mut sieve, cell, v0, ());
    Sieve::add_arrow(&mut sieve, cell, v1, ());
    Sieve::add_arrow(&mut sieve, cell, v2, ());

    let mut coord_atlas = Atlas::default();
    coord_atlas.try_insert(v0, 2).unwrap();
    coord_atlas.try_insert(v1, 2).unwrap();
    coord_atlas.try_insert(v2, 2).unwrap();

    let mut coords = Coordinates::<f64, VecStorage<f64>>::try_new(2, 2, coord_atlas).unwrap();
    coords
        .try_restrict_mut(v0)
        .unwrap()
        .copy_from_slice(&[0.0, 0.0]);
    coords
        .try_restrict_mut(v1)
        .unwrap()
        .copy_from_slice(&[1.0, 0.0]);
    coords
        .try_restrict_mut(v2)
        .unwrap()
        .copy_from_slice(&[0.0, 1.0]);

    let mut cell_atlas = Atlas::default();
    cell_atlas.try_insert(cell, 1).unwrap();
    let mut cell_types = Section::<CellType, VecStorage<CellType>>::new(cell_atlas);
    cell_types
        .try_restrict_mut(cell)
        .unwrap()
        .copy_from_slice(&[CellType::Triangle]);

    let mut mesh = MeshData::new(sieve);
    mesh.coordinates = Some(coords);
    mesh.cell_types = Some(cell_types);

    (mesh, [v0, v1, v2])
}

#[test]
fn transform_mesh_displacement_updates_quality() {
    let (mut mesh, vertices) = build_triangle_mesh();
    let points_before: BTreeSet<_> = mesh.sieve.points().collect();
    let quality_before = cell_quality_from_section(
        CellType::Triangle,
        &vertices,
        mesh.coordinates.as_ref().unwrap(),
    )
    .unwrap();

    let atlas = mesh.coordinates.as_ref().unwrap().section().atlas().clone();
    let mut displacement = Section::<f64, VecStorage<f64>>::new(atlas);
    displacement
        .try_restrict_mut(vertices[0])
        .unwrap()
        .copy_from_slice(&[0.0, 0.0]);
    displacement
        .try_restrict_mut(vertices[1])
        .unwrap()
        .copy_from_slice(&[0.5, 0.0]);
    displacement
        .try_restrict_mut(vertices[2])
        .unwrap()
        .copy_from_slice(&[0.0, 0.25]);

    let mut quality_after = None;
    let hooks = TransformHooks {
        after_update: Some(&mut |mesh| {
            let coords = mesh.coordinates.as_ref().unwrap();
            quality_after = Some(cell_quality_from_section(
                CellType::Triangle,
                &vertices,
                coords,
            )?);
            Ok(())
        }),
    };

    transform_mesh(
        &mut mesh,
        CoordinateTransform::Displacement(&displacement),
        hooks,
    )
    .unwrap();

    let points_after: BTreeSet<_> = mesh.sieve.points().collect();
    assert_eq!(points_before, points_after);

    let coords = mesh.coordinates.as_ref().unwrap();
    assert_eq!(coords.try_restrict(vertices[1]).unwrap(), &[1.5, 0.0]);
    assert_eq!(coords.try_restrict(vertices[2]).unwrap(), &[0.0, 1.25]);

    let quality_after = quality_after.expect("hook should populate quality");
    assert_ne!(quality_before.aspect_ratio, quality_after.aspect_ratio);
    assert!(quality_after.jacobian_sign > 0.0);
}

#[test]
fn transform_mesh_function_applies_update() {
    let (mut mesh, vertices) = build_triangle_mesh();
    let mut translate = |_: PointId, coords: &mut [f64]| {
        coords[0] += 2.0;
        coords[1] -= 1.0;
        Ok(())
    };

    let hooks = TransformHooks { after_update: None };
    transform_mesh(
        &mut mesh,
        CoordinateTransform::Function(&mut translate),
        hooks,
    )
    .unwrap();

    let coords = mesh.coordinates.as_ref().unwrap();
    assert_eq!(coords.try_restrict(vertices[0]).unwrap(), &[2.0, -1.0]);
    assert_eq!(coords.try_restrict(vertices[1]).unwrap(), &[3.0, -1.0]);
    assert_eq!(coords.try_restrict(vertices[2]).unwrap(), &[2.0, 0.0]);
}