conspire 0.6.0

The Rust interface to conspire.
Documentation
macro_rules! test_thermal {
    ($element: ident) => {
        mod thermal_block {
            use super::{
                D, G, M, N, P, get_connectivity, get_reference_coordinates_block, $element,
            };
            use crate::{
                EPSILON,
                constitutive::thermal::conduction::Fourier,
                fem::block::{
                    Block, FiniteElementBlockError,
                    thermal::{
                        NodalTemperatures,
                        conduction::{
                            NodalForcesThermal, NodalStiffnessesThermal,
                            ThermalConductionFiniteElementBlock,
                        },
                    },
                },
                math::test::{TestError, assert_eq_from_fd},
            };
            mod finite_difference {
                use super::*;
                const MODEL: Fourier = Fourier {
                    thermal_conductivity: 1.0,
                };
                #[test]
                fn potential() -> Result<(), TestError> {
                    let constitutive_model = MODEL;
                    let block = Block::<Fourier, $element, G, M, N, P>::from((
                        constitutive_model,
                        get_connectivity(),
                        get_reference_coordinates_block(),
                    ));
                    let mut finite_difference = 0.0;
                    let nodal_forces_fd: NodalForcesThermal = (0..D)
                        .map(|node| {
                            let mut nodal_temperatures = NodalTemperatures::zero(D);
                            nodal_temperatures[node] += 0.5 * EPSILON;
                            finite_difference = block.potential(&nodal_temperatures)?;
                            nodal_temperatures[node] -= EPSILON;
                            finite_difference -= block.potential(&nodal_temperatures)?;
                            Ok(finite_difference / EPSILON)
                        })
                        .collect::<Result<_, FiniteElementBlockError>>()?;
                    assert_eq_from_fd(
                        &nodal_forces_fd,
                        &block.nodal_forces(&NodalTemperatures::zero(D))?,
                    )
                }
                #[test]
                fn nodal_forces() -> Result<(), TestError> {
                    let constitutive_model = MODEL;
                    let block = Block::<Fourier, $element, G, M, N, P>::from((
                        constitutive_model,
                        get_connectivity(),
                        get_reference_coordinates_block(),
                    ));
                    let mut finite_difference = 0.0;
                    let nodal_stiffnesses_fd: NodalStiffnessesThermal = (0..D)
                        .map(|node_a| {
                            (0..D)
                                .map(|node_b| {
                                    let mut nodal_temperatures = NodalTemperatures::zero(D);
                                    nodal_temperatures[node_b] += 0.5 * EPSILON;
                                    finite_difference =
                                        block.nodal_forces(&nodal_temperatures)?[node_a];
                                    nodal_temperatures[node_b] -= EPSILON;
                                    finite_difference -=
                                        block.nodal_forces(&nodal_temperatures)?[node_a];
                                    Ok(finite_difference / EPSILON)
                                })
                                .collect()
                        })
                        .collect::<Result<_, FiniteElementBlockError>>()?;
                    assert_eq_from_fd(
                        &nodal_stiffnesses_fd,
                        &block.nodal_stiffnesses(&NodalTemperatures::zero(D))?,
                    )
                }
            }
        }
    };
}
pub(crate) use test_thermal;