flavio 0.5.0

flavio welcomes you
Documentation
#[cfg(test)]
pub mod test;

pub mod triangle;

use super::*;

pub trait LinearSurfaceElement<
    'a,
    C,
    const G: usize,
    const M: usize,
    const N: usize,
    const O: usize,
> where
    C: Constitutive<'a>,
    Self: LinearElement<'a, C, G, M, N, O>,
{
    fn calculate_basis<const I: usize>(nodal_coordinates: &Coordinates<I, O>) -> Basis<I> {
        Self::calculate_standard_gradient_operator()
            .iter()
            .zip(nodal_coordinates.iter())
            .map(|(standard_gradient_operator_a, nodal_coordinates_a)| {
                standard_gradient_operator_a
                    .iter()
                    .map(|standard_gradient_operator_a_m| {
                        nodal_coordinates_a * standard_gradient_operator_a_m
                    })
                    .collect()
            })
            .sum()
    }
    fn calculate_deformation_gradient_linear_surface_element(
        &self,
        nodal_coordinates: &NodalCoordinates<O>,
    ) -> DeformationGradient {
        nodal_coordinates
            .iter()
            .zip(self.get_gradient_vectors().iter())
            .map(|(nodal_coordinate, gradient_vector)| {
                DeformationGradient::dyad(nodal_coordinate, gradient_vector)
            })
            .sum::<DeformationGradient>()
            + DeformationGradient::dyad(
                &Self::calculate_normal(nodal_coordinates),
                self.get_reference_normal(),
            )
    }
    fn calculate_deformation_gradient_rate_linear_surface_element(
        &self,
        nodal_coordinates: &NodalCoordinates<O>,
        nodal_velocities: &NodalVelocities<O>,
    ) -> DeformationGradientRate {
        nodal_velocities
            .iter()
            .zip(self.get_gradient_vectors().iter())
            .map(|(nodal_velocity, gradient_vector)| {
                DeformationGradientRate::dyad(nodal_velocity, gradient_vector)
            })
            .sum::<DeformationGradientRate>()
            + DeformationGradientRate::dyad(
                &Self::calculate_normal_rate(nodal_coordinates, nodal_velocities),
                self.get_reference_normal(),
            )
    }
    fn calculate_dual_basis<const I: usize>(nodal_coordinates: &Coordinates<I, O>) -> Basis<I> {
        let basis_vectors = Self::calculate_basis(nodal_coordinates);
        basis_vectors
            .iter()
            .map(|basis_vectors_m| {
                basis_vectors
                    .iter()
                    .map(|basis_vectors_n| basis_vectors_m * basis_vectors_n)
                    .collect()
            })
            .collect::<TensorRank2<M, I, I>>()
            .inverse()
            .iter()
            .map(|metric_tensor_m| {
                metric_tensor_m
                    .iter()
                    .zip(basis_vectors.iter())
                    .map(|(metric_tensor_mn, basis_vectors_n)| basis_vectors_n * metric_tensor_mn)
                    .sum()
            })
            .collect()
    }
    fn calculate_gradient_vectors_linear_surface_element(
        reference_nodal_coordinates: &ReferenceNodalCoordinates<O>,
    ) -> GradientVectors<N> {
        let reference_dual_basis_vectors = Self::calculate_dual_basis(reference_nodal_coordinates);
        Self::calculate_standard_gradient_operator()
            .iter()
            .map(|standard_gradient_operator_a| {
                standard_gradient_operator_a
                    .iter()
                    .zip(reference_dual_basis_vectors.iter())
                    .map(
                        |(standard_gradient_operator_a_m, dual_reference_basis_vector_m)| {
                            dual_reference_basis_vector_m * standard_gradient_operator_a_m
                        },
                    )
                    .sum()
            })
            .collect()
    }
    fn calculate_normal(nodal_coordinates: &NodalCoordinates<O>) -> Normal {
        let basis_vectors = Self::calculate_basis(nodal_coordinates);
        basis_vectors[0].cross(&basis_vectors[1]).normalized()
    }
    fn calculate_normal_gradients(nodal_coordinates: &Coordinates<1, O>) -> NormalGradients<O> {
        let basis_vectors = Self::calculate_basis(nodal_coordinates);
        let levi_civita_symbol = LEVI_CIVITA;
        let normalization = basis_vectors[0].cross(&basis_vectors[1]).norm();
        let normal_vector = basis_vectors[0].cross(&basis_vectors[1]) / normalization;
        Self::calculate_standard_gradient_operator().iter()
        .map(|standard_gradient_operator_a|
            levi_civita_symbol.iter()
            .map(|levi_civita_symbol_m|
                IDENTITY.iter()
                .zip(normal_vector.iter())
                .map(|(identity_i, normal_vector_i)|
                    levi_civita_symbol_m.iter()
                    .zip(basis_vectors[0].iter()
                    .zip(basis_vectors[1].iter()))
                    .map(|(levi_civita_symbol_mn, (basis_vector_0_n, basis_vector_1_n))|
                        levi_civita_symbol_mn.iter()
                        .zip(identity_i.iter()
                        .zip(normal_vector.iter()))
                        .map(|(levi_civita_symbol_mno, (identity_io, normal_vector_o))|
                            levi_civita_symbol_mno * (identity_io - normal_vector_i * normal_vector_o)
                        ).sum::<Scalar>() * (
                            standard_gradient_operator_a[0] * basis_vector_1_n
                          - standard_gradient_operator_a[1] * basis_vector_0_n
                        )
                    ).sum::<Scalar>() / normalization
                ).collect()
            ).collect()
        ).collect()
    }
    fn calculate_normal_rate(
        nodal_coordinates: &NodalCoordinates<O>,
        nodal_velocities: &NodalVelocities<O>,
    ) -> NormalRate {
        let basis_vectors = Self::calculate_basis(nodal_coordinates);
        let levi_civita_symbol = LEVI_CIVITA;
        let normalization = basis_vectors[0].cross(&basis_vectors[1]).norm();
        let normal_vector = basis_vectors[0].cross(&basis_vectors[1]) / normalization;
        let standard_gradient_operator = Self::calculate_standard_gradient_operator();
        IDENTITY.iter()
        .zip(normal_vector.iter())
        .map(|(identity_i, normal_vector_i)|
            nodal_velocities.iter()
            .zip(standard_gradient_operator.iter())
            .map(|(nodal_velocity_a, standard_gradient_operator_a)|
                levi_civita_symbol.iter()
                .zip(nodal_velocity_a.iter())
                .map(|(levi_civita_symbol_m, nodal_velocity_a_m)|
                    levi_civita_symbol_m.iter()
                    .zip(basis_vectors[0].iter()
                    .zip(basis_vectors[1].iter()))
                    .map(|(levi_civita_symbol_mn, (basis_vector_0_n, basis_vector_1_n))|
                        levi_civita_symbol_mn.iter()
                        .zip(identity_i.iter()
                        .zip(normal_vector.iter()))
                        .map(|(levi_civita_symbol_mno, (identity_io, normal_vector_o))|
                            levi_civita_symbol_mno * (identity_io - normal_vector_i * normal_vector_o)
                        ).sum::<Scalar>() * (
                            standard_gradient_operator_a[0] * basis_vector_1_n
                          - standard_gradient_operator_a[1] * basis_vector_0_n
                        )
                    ).sum::<Scalar>() * nodal_velocity_a_m
                ).sum::<Scalar>()
            ).sum::<Scalar>() / normalization
        ).collect()
    }
    fn calculate_normal_tangents(nodal_coordinates: &Coordinates<1, O>) -> NormalTangents<O> {
        let basis_vectors = Self::calculate_basis(nodal_coordinates);
        let levi_civita_symbol = LEVI_CIVITA;
        let normalization = basis_vectors[0].cross(&basis_vectors[1]).norm();
        let normal_gradients = Self::calculate_normal_gradients(nodal_coordinates);
        let normal_vector = basis_vectors[0].cross(&basis_vectors[1]) / normalization;
        let standard_gradient_operator = Self::calculate_standard_gradient_operator();
        normal_gradients.iter()
        .zip(standard_gradient_operator.iter())
        .map(|(normal_gradient_a, standard_gradient_operator_a)|
            normal_gradients.iter()
            .zip(standard_gradient_operator.iter())
            .map(|(normal_gradient_b, standard_gradient_operator_b)|
                normal_gradient_a.iter()
                .zip(levi_civita_symbol.iter())
                .map(|(normal_gradient_a_m, levi_civita_symbol_m)|
                    normal_gradient_b.iter()
                    .zip(levi_civita_symbol.iter()
                    .zip(levi_civita_symbol_m.iter()))
                    .map(|(normal_gradient_b_n, (levi_civita_symbol_n, levi_civita_symbol_mn))|
                        normal_gradient_a_m.iter()
                        .zip(normal_gradient_b_n.iter()
                        .zip(normal_vector.iter()
                        .zip(IDENTITY.iter())))
                        .map(|(normal_gradient_a_m_i, (normal_gradient_b_n_i, (normal_vector_i, identity_i)))|
                            (levi_civita_symbol_m.iter()
                            .zip(levi_civita_symbol_n.iter()
                            .zip(basis_vectors[0].iter()
                            .zip(basis_vectors[1].iter())))
                            .map(|(levi_civita_symbol_mr, (levi_civita_symbol_nr, (basis_vector_0_r, basis_vector_1_r)))|
                                levi_civita_symbol_mr.iter()
                                .zip(normal_vector.iter()
                                .zip(normal_gradient_b_n.iter()))
                                .map(|(levi_civita_symbol_mrs, (normal_vector_s, normal_gradient_b_n_s))|
                                    levi_civita_symbol_mrs * (
                                        normal_gradient_b_n_i * normal_vector_s
                                      + normal_gradient_b_n_s * normal_vector_i
                                    )
                                ).sum::<Scalar>() * (
                                    standard_gradient_operator_a[1] * basis_vector_0_r
                                  - standard_gradient_operator_a[0] * basis_vector_1_r
                                ) +
                                levi_civita_symbol_nr.iter()
                                .zip(normal_vector.iter())
                                .map(|(levi_civita_symbol_nrs, normal_vector_s)|
                                    levi_civita_symbol_nrs * normal_vector_s * normal_gradient_a_m_i
                                ).sum::<Scalar>() * (
                                    standard_gradient_operator_b[1] * basis_vector_0_r
                                  - standard_gradient_operator_b[0] * basis_vector_1_r
                                )
                            ).sum::<Scalar>() +
                            levi_civita_symbol_mn * (
                                identity_i - &normal_vector * normal_vector_i
                            ) * (
                                standard_gradient_operator_a[0] * standard_gradient_operator_b[1]
                              - standard_gradient_operator_a[1] * standard_gradient_operator_b[0]
                            )) / normalization
                        ).collect()
                    ).collect()
                ).collect()
            ).collect()
        ).collect()
    }
    fn calculate_reference_jacobian_linear_surface_element(
        reference_nodal_coordinates: &ReferenceNodalCoordinates<O>,
    ) -> Scalar {
        let reference_basis_vectors = Self::calculate_basis(reference_nodal_coordinates);
        reference_basis_vectors[0]
            .cross(&reference_basis_vectors[1])
            .norm()
    }
    fn calculate_reference_normal(
        reference_nodal_coordinates: &ReferenceNodalCoordinates<O>,
    ) -> ReferenceNormal {
        let dual_basis_vectors = Self::calculate_dual_basis(reference_nodal_coordinates);
        dual_basis_vectors[0]
            .cross(&dual_basis_vectors[1])
            .normalized()
    }
    fn get_reference_normal(&self) -> &ReferenceNormal;
}