conspire 0.7.0

The Rust interface to conspire.
Documentation
//! Finite element library.

pub mod block;
mod from;
pub mod solid;
pub mod thermal;

use crate::math::{
    Style, StyledError, TensorRank1Vec, TensorRank1Vec2D, TestError,
    optimize::{
        EqualityConstraint, FirstOrderOptimization, FirstOrderRootFinding, OptimizationError,
        SecondOrderOptimization, ZerothOrderRootFinding,
    },
    styled_error,
};
use std::fmt::Debug;

pub type NodalCoordinates<const D: usize> = TensorRank1Vec<D, 1>;
pub type NodalCoordinatesHistory<const D: usize> = TensorRank1Vec2D<D, 1>;
pub type NodalReferenceCoordinates<const D: usize> = TensorRank1Vec<D, 0>;
pub type NodalVelocities<const D: usize> = TensorRank1Vec<D, 1>;
pub type NodalVelocitiesHistory<const D: usize> = TensorRank1Vec2D<D, 1>;

#[derive(Debug)]
pub struct Model<B, const D: usize> {
    blocks: B,
    coordinates: NodalReferenceCoordinates<D>,
}

#[derive(Debug)]
pub struct Blocks<B1, B2>(B1, B2);

#[derive(Debug)]
pub struct ElasticViscoplasticAndElastic<B1, B2>(B1, B2);

pub trait ElementModel<const D: usize>
where
    Self: Debug,
{
    fn coordinates(&self) -> &NodalReferenceCoordinates<D>;
}

pub trait Elements
where
    Self: Debug,
{
    fn node_neighbors(&self, neighbors: &mut [Vec<usize>]);
}

impl<B, const D: usize> Elements for Model<B, D>
where
    B: Elements,
{
    fn node_neighbors(&self, neighbors: &mut [Vec<usize>]) {
        self.blocks.node_neighbors(neighbors)
    }
}

impl<B1, B2> Elements for Blocks<B1, B2>
where
    B1: Elements,
    B2: Elements,
{
    fn node_neighbors(&self, neighbors: &mut [Vec<usize>]) {
        self.0.node_neighbors(neighbors);
        self.1.node_neighbors(neighbors)
    }
}

impl<B1, B2> Elements for ElasticViscoplasticAndElastic<B1, B2>
where
    B1: Elements,
    B2: Elements,
{
    fn node_neighbors(&self, neighbors: &mut [Vec<usize>]) {
        self.0.node_neighbors(neighbors);
        self.1.node_neighbors(neighbors)
    }
}

impl<B, const D: usize> Model<B, D> {
    pub fn blocks(&self) -> &B {
        &self.blocks
    }
}

impl<B, const D: usize> ElementModel<D> for Model<B, D>
where
    B: Debug,
{
    fn coordinates(&self) -> &NodalReferenceCoordinates<D> {
        &self.coordinates
    }
}

pub enum ElementModelError {
    Upstream(String, String),
}

impl From<ElementModelError> for String {
    fn from(error: ElementModelError) -> Self {
        error.message(&Style::detect())
    }
}

impl StyledError for ElementModelError {
    fn message(&self, style: &Style) -> String {
        let c = style.frame;
        match self {
            Self::Upstream(error, model) => format!(
                "{error}{c}\n\
                In element model: {model}."
            ),
        }
    }
}

styled_error!(ElementModelError);

pub trait ZerothOrderRoot<X> {
    fn root(
        &self,
        equality_constraint: EqualityConstraint,
        solver: impl ZerothOrderRootFinding<X>,
    ) -> Result<X, OptimizationError>;
}

pub trait FirstOrderRoot<F, J, X> {
    fn root(
        &self,
        equality_constraint: EqualityConstraint,
        solver: impl FirstOrderRootFinding<F, J, X>,
    ) -> Result<X, OptimizationError>;
}

pub trait FirstOrderMinimize<F, X> {
    fn minimize(
        &self,
        equality_constraint: EqualityConstraint,
        solver: impl FirstOrderOptimization<F, X>,
    ) -> Result<X, OptimizationError>;
}

pub trait SecondOrderMinimize<F, J, H, X> {
    fn minimize(
        &self,
        equality_constraint: EqualityConstraint,
        solver: impl SecondOrderOptimization<F, J, H, X>,
    ) -> Result<X, OptimizationError>;
}

impl<B, const D: usize> From<(B, NodalReferenceCoordinates<D>)> for Model<B, D> {
    fn from((blocks, coordinates): (B, NodalReferenceCoordinates<D>)) -> Self {
        Self {
            blocks,
            coordinates,
        }
    }
}

impl From<ElementModelError> for TestError {
    fn from(error: ElementModelError) -> Self {
        Self {
            message: error.to_string(),
        }
    }
}