Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

hybrid #81

Merged
merged 17 commits into from
Aug 6, 2024
11 changes: 8 additions & 3 deletions .github/workflows/Pages.yml
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
name: Pages
on:
push:
branches: [ "main" ]
branches: main
pull_request:
branches: [ "main" ]
branches: main
release:
types: [ "published" ]
types: published
permissions:
contents: read
pages: write
Expand All @@ -19,6 +19,11 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Toolchain
uses: actions-rs/toolchain@v1
with:
default: true
toolchain: stable
- name: Dev
run: |
mkdir -p _site/
Expand Down
13 changes: 10 additions & 3 deletions .github/workflows/Publish.yml
Original file line number Diff line number Diff line change
@@ -1,20 +1,27 @@
name: Publish
on:
pull_request:
branches: main
release:
branches: [ main ]
types: [ published ]
types: published
env:
CARGO_TERM_COLOR: always
jobs:
Publish:
if: github.event_name == 'release'
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Toolchain
uses: actions-rs/toolchain@v1
with:
default: true
toolchain: stable
- name: Package
run: cargo package
- name: Login
if: github.event_name == 'release'
run: cargo login ${{ secrets.CRATES_IO_TOKEN }}
- name: Publish
if: github.event_name == 'release'
run: cargo publish
14 changes: 12 additions & 2 deletions .github/workflows/Test.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: Test
on:
pull_request:
branches: [ main ]
branches: main
env:
CARGO_TERM_COLOR: always
jobs:
Expand All @@ -10,10 +10,20 @@ jobs:
fail-fast: false
matrix:
os: [macos-latest, windows-latest, ubuntu-latest]
toolchain:
- beta
- nightly
- stable
runs-on: ${{ matrix.os }}
steps:
- name: checkout
- name: Checkout
uses: actions/checkout@v4
- name: Toolchain
uses: actions-rs/toolchain@v1
with:
components: clippy
default: true
toolchain: ${{ matrix.toolchain }}
- name: Lint math
run: cargo clippy --release --features math -- -D warnings
- name: Lint mechanics
Expand Down
116 changes: 116 additions & 0 deletions src/constitutive/hybrid/elastic/additive/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
#[cfg(test)]
mod test;

use crate::
{
constitutive::
{
Constitutive,
Parameters,
hybrid::
{
Additive,
Hybrid
},
solid::
{
Solid,
elastic::Elastic
}
},
mechanics::
{
CauchyStress,
CauchyTangentStiffness,
DeformationGradient,
FirstPiolaKirchoffStress,
FirstPiolaKirchoffTangentStiffness,
Scalar,
SecondPiolaKirchoffStress,
SecondPiolaKirchoffTangentStiffness
}
};

/// Constitutive model implementation of hybrid elastic constitutive models that are based on the additive decomposition.
impl<'a, C1: Elastic<'a>, C2: Elastic<'a>> Constitutive<'a> for Additive<C1, C2>
{
/// Dummy method that will panic, use [Self::construct()] instead.
fn new(_parameters: Parameters<'a>) -> Self
{
panic!()
}
}

/// Solid constitutive model implementation of hybrid elastic constitutive models that are based on the additive decomposition.
impl<'a, C1: Elastic<'a>, C2: Elastic<'a>> Solid<'a> for Additive<C1, C2>
{
/// Dummy method that will panic.
fn get_bulk_modulus(&self) -> &Scalar
{
panic!()
}
/// Dummy method that will panic.
fn get_shear_modulus(&self) -> &Scalar
{
panic!()
}
}

/// Elastic constitutive model implementation of hybrid elastic constitutive models that are based on the additive decomposition.
impl<'a, C1: Elastic<'a>, C2: Elastic<'a>> Elastic<'a> for Additive<C1, C2>
{
/// Calculates and returns the Cauchy stress.
///
/// ```math
/// \boldsymbol{\sigma}(\mathbf{F}) = \boldsymbol{\sigma}_1(\mathbf{F}) + \boldsymbol{\sigma}_2(\mathbf{F})
/// ```
fn calculate_cauchy_stress(&self, deformation_gradient: &DeformationGradient) -> CauchyStress
{
self.get_constitutive_model_1().calculate_cauchy_stress(deformation_gradient) + self.get_constitutive_model_2().calculate_cauchy_stress(deformation_gradient)
}
/// Calculates and returns the tangent stiffness associated with the Cauchy stress.
///
/// ```math
/// \mathcal{T}(\mathbf{F}) = \mathcal{T}_1(\mathbf{F}) + \mathcal{T}_2(\mathbf{F})
/// ```
fn calculate_cauchy_tangent_stiffness(&self, deformation_gradient: &DeformationGradient) -> CauchyTangentStiffness
{
self.get_constitutive_model_1().calculate_cauchy_tangent_stiffness(deformation_gradient) + self.get_constitutive_model_2().calculate_cauchy_tangent_stiffness(deformation_gradient)
}
/// Calculates and returns the first Piola-Kirchoff stress.
///
/// ```math
/// \mathbf{P}(\mathbf{F}) = \mathbf{P}_1(\mathbf{F}) + \mathbf{P}_2(\mathbf{F})
/// ```
fn calculate_first_piola_kirchoff_stress(&self, deformation_gradient: &DeformationGradient) -> FirstPiolaKirchoffStress
{
self.get_constitutive_model_1().calculate_first_piola_kirchoff_stress(deformation_gradient) + self.get_constitutive_model_2().calculate_first_piola_kirchoff_stress(deformation_gradient)
}
/// Calculates and returns the tangent stiffness associated with the first Piola-Kirchoff stress.
///
/// ```math
/// \mathcal{C}(\mathbf{F}) = \mathcal{C}_1(\mathbf{F}) + \mathcal{C}_2(\mathbf{F})
/// ```
fn calculate_first_piola_kirchoff_tangent_stiffness(&self, deformation_gradient: &DeformationGradient) -> FirstPiolaKirchoffTangentStiffness
{
self.get_constitutive_model_1().calculate_first_piola_kirchoff_tangent_stiffness(deformation_gradient) + self.get_constitutive_model_2().calculate_first_piola_kirchoff_tangent_stiffness(deformation_gradient)
}
/// Calculates and returns the second Piola-Kirchoff stress.
///
/// ```math
/// \mathbf{S}(\mathbf{F}) = \mathbf{S}_1(\mathbf{F}) + \mathbf{S}_2(\mathbf{F})
/// ```
fn calculate_second_piola_kirchoff_stress(&self, deformation_gradient: &DeformationGradient) -> SecondPiolaKirchoffStress
{
self.get_constitutive_model_1().calculate_second_piola_kirchoff_stress(deformation_gradient) + self.get_constitutive_model_2().calculate_second_piola_kirchoff_stress(deformation_gradient)
}
/// Calculates and returns the tangent stiffness associated with the second Piola-Kirchoff stress.
///
/// ```math
/// \mathcal{G}(\mathbf{F}) = \mathcal{G}_1(\mathbf{F}) + \mathcal{G}_2(\mathbf{F})
/// ```
fn calculate_second_piola_kirchoff_tangent_stiffness(&self, deformation_gradient: &DeformationGradient) -> SecondPiolaKirchoffTangentStiffness
{
self.get_constitutive_model_1().calculate_second_piola_kirchoff_tangent_stiffness(deformation_gradient) + self.get_constitutive_model_2().calculate_second_piola_kirchoff_tangent_stiffness(deformation_gradient)
}
}
7 changes: 7 additions & 0 deletions src/constitutive/hybrid/elastic/additive/test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
use crate::constitutive::hybrid::
{
Additive,
elastic::test::test_hybrid_elastic_constitutive_models
};

test_hybrid_elastic_constitutive_models!(Additive);
5 changes: 5 additions & 0 deletions src/constitutive/hybrid/elastic/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#[cfg(test)]
mod test;

mod additive;
mod multiplicative;
169 changes: 169 additions & 0 deletions src/constitutive/hybrid/elastic/multiplicative/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
#[cfg(test)]
mod test;

use crate::
{
ABS_TOL,
constitutive::
{
Constitutive,
Parameters,
hybrid::
{
Hybrid,
Multiplicative,
MultiplicativeTrait
},
solid::
{
Solid,
elastic::Elastic
}
},
math::
{
TensorRank2,
TensorRank2Trait
},
mechanics::
{
CauchyStress,
CauchyTangentStiffness,
DeformationGradient,
FirstPiolaKirchoffStress,
FirstPiolaKirchoffTangentStiffness,
Scalar,
SecondPiolaKirchoffStress,
SecondPiolaKirchoffTangentStiffness
}
};

/// Constitutive model implementation of hybrid elastic constitutive models that are based on the multiplicative decomposition.
impl<'a, C1: Elastic<'a>, C2: Elastic<'a>> Constitutive<'a> for Multiplicative<C1, C2>
{
/// Dummy method that will panic, use [Self::construct()] instead.
fn new(_parameters: Parameters<'a>) -> Self
{
panic!()
}
}

/// Solid constitutive model implementation of hybrid elastic constitutive models that are based on the multiplicative decomposition.
impl<'a, C1: Elastic<'a>, C2: Elastic<'a>> Solid<'a> for Multiplicative<C1, C2>
{
/// Dummy method that will panic.
fn get_bulk_modulus(&self) -> &Scalar
{
panic!()
}
/// Dummy method that will panic.
fn get_shear_modulus(&self) -> &Scalar
{
panic!()
}
}

/// Elastic constitutive model implementation of hybrid elastic constitutive models that are based on the multiplicative decomposition.
impl<'a, C1: Elastic<'a>, C2: Elastic<'a>> Elastic<'a> for Multiplicative<C1, C2>
{
/// Calculates and returns the Cauchy stress.
///
/// ```math
/// \boldsymbol{\sigma}(\mathbf{F}) = \frac{1}{J_2}\,\boldsymbol{\sigma}_1(\mathbf{F}_1)
/// ```
fn calculate_cauchy_stress(&self, deformation_gradient: &DeformationGradient) -> CauchyStress
{
let (deformation_gradient_1, deformation_gradient_2) = self.calculate_deformation_gradients(deformation_gradient);
self.get_constitutive_model_1().calculate_cauchy_stress(&deformation_gradient_1) / deformation_gradient_2.determinant()
}
/// Dummy method that will panic.
fn calculate_cauchy_tangent_stiffness(&self, _: &DeformationGradient) -> CauchyTangentStiffness
{
panic!()
}
/// Calculates and returns the first Piola-Kirchoff stress.
///
/// ```math
/// \mathbf{P}(\mathbf{F}) = \mathbf{P}_1(\mathbf{F}_1)\cdot\mathbf{F}_2^{-T}
/// ```
fn calculate_first_piola_kirchoff_stress(&self, deformation_gradient: &DeformationGradient) -> FirstPiolaKirchoffStress
{
let (deformation_gradient_1, deformation_gradient_2) = self.calculate_deformation_gradients(deformation_gradient);
let deformation_gradient_2_inverse_transpose: TensorRank2<3, 0, 0> = deformation_gradient_2.inverse_transpose().into();
self.get_constitutive_model_1().calculate_first_piola_kirchoff_stress(&deformation_gradient_1) * deformation_gradient_2_inverse_transpose
}
/// Dummy method that will panic.
fn calculate_first_piola_kirchoff_tangent_stiffness(&self, _: &DeformationGradient) -> FirstPiolaKirchoffTangentStiffness
{
panic!()
}
/// Calculates and returns the second Piola-Kirchoff stress.
///
/// ```math
/// \mathbf{S}(\mathbf{F}) = \mathbf{F}_2^{-1}\cdot\mathbf{S}_1(\mathbf{F}_1)\cdot\mathbf{F}_2^{-T}
/// ```
fn calculate_second_piola_kirchoff_stress(&self, deformation_gradient: &DeformationGradient) -> SecondPiolaKirchoffStress
{
let (deformation_gradient_1, deformation_gradient_2) = self.calculate_deformation_gradients(deformation_gradient);
let deformation_gradient_2_inverse: TensorRank2<3, 0, 0> = deformation_gradient_2.inverse().into();
&deformation_gradient_2_inverse * self.get_constitutive_model_1().calculate_second_piola_kirchoff_stress(&deformation_gradient_1) * deformation_gradient_2_inverse.transpose()
}
/// Dummy method that will panic.
fn calculate_second_piola_kirchoff_tangent_stiffness(&self, _: &DeformationGradient) -> SecondPiolaKirchoffTangentStiffness
{
panic!()
}
}

/// Multiplicative hybrid constitutive model implementation of hybrid elastic constitutive models that are based on the multiplicative decomposition.
impl<'a, C1: Elastic<'a>, C2: Elastic<'a>> MultiplicativeTrait for Multiplicative<C1, C2>
{
fn calculate_deformation_gradients(&self, deformation_gradient: &DeformationGradient) -> (DeformationGradient, DeformationGradient)
{
if deformation_gradient.is_identity()
{
(DeformationGradient::identity(), DeformationGradient::identity())
}
else
{
let mut deformation_gradient_1 = DeformationGradient::identity();
let mut deformation_gradient_2 = deformation_gradient * 1.0;
let mut deformation_gradient_2_old = DeformationGradient::identity();
let mut deformation_gradient_2_inverse_transpose: TensorRank2<3, 0, 0>;
let mut residual: FirstPiolaKirchoffStress;
let mut residual_increment: FirstPiolaKirchoffStress;
let mut residual_norm = 1.0;
let mut residual_old = FirstPiolaKirchoffStress::zero();
let mut right_hand_side: FirstPiolaKirchoffStress;
let mut steps: u8 = 0;
let steps_maximum: u8 = 50;
let mut step_size: Scalar;
while steps < steps_maximum
{
deformation_gradient_1 = (deformation_gradient * deformation_gradient_2.inverse()).into();
deformation_gradient_2_inverse_transpose = deformation_gradient_2.inverse_transpose().into();
right_hand_side = (deformation_gradient_1.transpose() * self.get_constitutive_model_1().calculate_first_piola_kirchoff_stress(&deformation_gradient_1) * deformation_gradient_2_inverse_transpose).into();
residual = self.get_constitutive_model_2().calculate_first_piola_kirchoff_stress(&deformation_gradient_2) - right_hand_side;
residual_norm = residual.norm();
if residual_norm >= ABS_TOL
{
residual_increment = residual_old - &residual;
step_size = (deformation_gradient_2_old - &deformation_gradient_2).full_contraction(&residual_increment).abs() / residual_increment.norm_squared();
deformation_gradient_2_old = &deformation_gradient_2 * 1.0;
residual_old = &residual * 1.0;
deformation_gradient_2 -= residual * step_size;
}
else
{
break
}
steps += 1;
}
if residual_norm >= ABS_TOL && steps == steps_maximum
{
panic!("The maximum number of steps was reached before the tolerance was satisfied.")
}
(deformation_gradient_1, deformation_gradient_2)
}
}
}
7 changes: 7 additions & 0 deletions src/constitutive/hybrid/elastic/multiplicative/test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
use crate::constitutive::hybrid::
{
Multiplicative,
elastic::test::test_hybrid_elastic_constitutive_models_no_tangents
};

test_hybrid_elastic_constitutive_models_no_tangents!(Multiplicative);
Loading
Loading