conspire 0.6.0

The Rust interface to conspire.
Documentation
use crate::{
    constitutive::solid::elastic::Elastic,
    fem::{
        Blocks, FiniteElementModel, FiniteElementModelError, FirstOrderRoot, Model,
        NodalCoordinates,
        block::{
            Block, element::solid::elastic::ElasticFiniteElement,
            solid::elastic::ElasticFiniteElementBlock,
        },
        solid::{NodalForcesSolid, NodalStiffnessesSolid, SolidFiniteElementModel},
    },
    math::optimize::{EqualityConstraint, FirstOrderRootFinding, OptimizationError},
};

pub trait ElasticFiniteElementModel
where
    Self: SolidFiniteElementModel,
{
    fn nodal_forces(
        &self,
        nodal_coordinates: &NodalCoordinates,
    ) -> Result<NodalForcesSolid, FiniteElementModelError>;
    fn nodal_stiffnesses(
        &self,
        nodal_coordinates: &NodalCoordinates,
    ) -> Result<NodalStiffnessesSolid, FiniteElementModelError>;
}

impl<B> ElasticFiniteElementModel for Model<B>
where
    B: ElasticFiniteElementModel,
{
    fn nodal_forces(
        &self,
        nodal_coordinates: &NodalCoordinates,
    ) -> Result<NodalForcesSolid, FiniteElementModelError> {
        self.blocks.nodal_forces(nodal_coordinates)
    }
    fn nodal_stiffnesses(
        &self,
        nodal_coordinates: &NodalCoordinates,
    ) -> Result<NodalStiffnessesSolid, FiniteElementModelError> {
        self.blocks.nodal_stiffnesses(nodal_coordinates)
    }
}

impl<B1, B2> ElasticFiniteElementModel for Blocks<B1, B2>
where
    B1: ElasticFiniteElementModel,
    B2: ElasticFiniteElementModel,
{
    fn nodal_forces(
        &self,
        nodal_coordinates: &NodalCoordinates,
    ) -> Result<NodalForcesSolid, FiniteElementModelError> {
        match Ok::<_, FiniteElementModelError>(
            self.0.nodal_forces(nodal_coordinates)? + self.1.nodal_forces(nodal_coordinates)?,
        ) {
            Ok(nodal_forces) => Ok(nodal_forces),
            Err(error) => Err(FiniteElementModelError::Upstream(
                format!("{error}"),
                format!("{self:?}"),
            )),
        }
    }
    fn nodal_stiffnesses(
        &self,
        nodal_coordinates: &NodalCoordinates,
    ) -> Result<NodalStiffnessesSolid, FiniteElementModelError> {
        match Ok::<_, FiniteElementModelError>(
            self.0.nodal_stiffnesses(nodal_coordinates)?
                + self.1.nodal_stiffnesses(nodal_coordinates)?,
        ) {
            Ok(nodal_stiffnesses) => Ok(nodal_stiffnesses),
            Err(error) => Err(FiniteElementModelError::Upstream(
                format!("{error}"),
                format!("{self:?}"),
            )),
        }
    }
}

impl<C, F, const G: usize, const M: usize, const N: usize, const P: usize> ElasticFiniteElementModel
    for Block<C, F, G, M, N, P>
where
    C: Elastic,
    F: ElasticFiniteElement<C, G, M, N, P>,
{
    fn nodal_forces(
        &self,
        nodal_coordinates: &NodalCoordinates,
    ) -> Result<NodalForcesSolid, FiniteElementModelError> {
        match ElasticFiniteElementBlock::nodal_forces(self, nodal_coordinates) {
            Ok(nodal_forces) => Ok(nodal_forces),
            Err(error) => Err(FiniteElementModelError::Upstream(
                format!("{error}"),
                format!("{self:?}"),
            )),
        }
    }
    fn nodal_stiffnesses(
        &self,
        nodal_coordinates: &NodalCoordinates,
    ) -> Result<NodalStiffnessesSolid, FiniteElementModelError> {
        match ElasticFiniteElementBlock::nodal_stiffnesses(self, nodal_coordinates) {
            Ok(nodal_stiffnesses) => Ok(nodal_stiffnesses),
            Err(error) => Err(FiniteElementModelError::Upstream(
                format!("{error}"),
                format!("{self:?}"),
            )),
        }
    }
}

impl<B> FirstOrderRoot<NodalForcesSolid, NodalStiffnessesSolid, NodalCoordinates> for Model<B>
where
    B: ElasticFiniteElementModel,
{
    fn root(
        &self,
        equality_constraint: EqualityConstraint,
        solver: impl FirstOrderRootFinding<NodalForcesSolid, NodalStiffnessesSolid, NodalCoordinates>,
    ) -> Result<NodalCoordinates, OptimizationError> {
        solver.root(
            |nodal_coordinates: &NodalCoordinates| Ok(self.nodal_forces(nodal_coordinates)?),
            |nodal_coordinates: &NodalCoordinates| Ok(self.nodal_stiffnesses(nodal_coordinates)?),
            self.coordinates().clone().into(),
            equality_constraint,
        )
    }
}