From 5956dacea69ec1179a6fd9b642836d9eda3df500 Mon Sep 17 00:00:00 2001 From: Jean-Paul Pelteret Date: Mon, 5 Dec 2016 08:36:09 +0100 Subject: [PATCH] Standard transformations, and kinematics and tensors for elasticity. This commit adds a set of functions to perform various push forward / pull back operations that regularly feature in finite deformation mechanics. It also adds some standard tensor definitions for elasticity, as well as functions that compute kinematic quantities typically used in finite strain elasticity. Refers to discussion in dealii/code-gallery/#7. --- doc/doxygen/headers/physics.h | 165 ++ doc/doxygen/options.dox.in | 4 + doc/news/changes.h | 22 + .../deal.II/physics/elasticity/kinematics.h | 401 ++++ .../physics/elasticity/standard_tensors.h | 369 +++ include/deal.II/physics/transformations.h | 1135 +++++++++ source/CMakeLists.txt | 1 + source/physics/CMakeLists.txt | 34 + source/physics/elasticity/CMakeLists.txt | 34 + source/physics/elasticity/kinematics.cc | 23 + source/physics/elasticity/kinematics.inst.in | 78 + source/physics/elasticity/standard_tensors.cc | 49 + .../elasticity/standard_tensors.inst.in | 53 + source/physics/transformations.cc | 23 + source/physics/transformations.inst.in | 221 ++ tests/physics/CMakeLists.txt | 4 + tests/physics/elasticity-kinematics_01.cc | 190 ++ tests/physics/elasticity-kinematics_01.output | 2 + .../physics/elasticity-standard_tensors_01.cc | 140 ++ .../elasticity-standard_tensors_01.output | 2 + tests/physics/prm/parameters-step-44.prm | 75 + ...-standard_tensors-material_push_forward.cc | 2085 +++++++++++++++++ ...ndard_tensors-material_push_forward.output | 167 ++ .../step-44-standard_tensors-spatial.cc | 1970 ++++++++++++++++ .../step-44-standard_tensors-spatial.output | 167 ++ tests/physics/step-44.cc | 1988 ++++++++++++++++ tests/physics/step-44.output | 167 ++ 27 files changed, 9569 insertions(+) create mode 100644 doc/doxygen/headers/physics.h create mode 100644 include/deal.II/physics/elasticity/kinematics.h create mode 100644 include/deal.II/physics/elasticity/standard_tensors.h create mode 100644 include/deal.II/physics/transformations.h create mode 100644 source/physics/CMakeLists.txt create mode 100644 source/physics/elasticity/CMakeLists.txt create mode 100644 source/physics/elasticity/kinematics.cc create mode 100644 source/physics/elasticity/kinematics.inst.in create mode 100644 source/physics/elasticity/standard_tensors.cc create mode 100644 source/physics/elasticity/standard_tensors.inst.in create mode 100644 source/physics/transformations.cc create mode 100644 source/physics/transformations.inst.in create mode 100644 tests/physics/CMakeLists.txt create mode 100644 tests/physics/elasticity-kinematics_01.cc create mode 100644 tests/physics/elasticity-kinematics_01.output create mode 100644 tests/physics/elasticity-standard_tensors_01.cc create mode 100644 tests/physics/elasticity-standard_tensors_01.output create mode 100644 tests/physics/prm/parameters-step-44.prm create mode 100644 tests/physics/step-44-standard_tensors-material_push_forward.cc create mode 100644 tests/physics/step-44-standard_tensors-material_push_forward.output create mode 100644 tests/physics/step-44-standard_tensors-spatial.cc create mode 100644 tests/physics/step-44-standard_tensors-spatial.output create mode 100644 tests/physics/step-44.cc create mode 100644 tests/physics/step-44.output diff --git a/doc/doxygen/headers/physics.h b/doc/doxygen/headers/physics.h new file mode 100644 index 0000000000..eda1175e7f --- /dev/null +++ b/doc/doxygen/headers/physics.h @@ -0,0 +1,165 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2016 by the deal.II authors +// +// This file is part of the deal.II library. +// +// The deal.II library is free software; you can use it, redistribute +// it, and/or modify it under the terms of the GNU Lesser General +// Public License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// The full text of the license can be found in the file LICENSE at +// the top level of the deal.II distribution. +// +// --------------------------------------------------------------------- + +/** + * @defgroup physics Physics + * + * @brief A module dedicated to the implementation of functions and + * classes that relate to continuum physics, physical fields and materials. + */ + +/** + * A collection of namespaces and utilities to assist in the + * definition, construction and manipulation of data related to + * physical fields and materials. + */ +namespace Physics +{ + + /** + * A collection of operations to assist in the transformation of tensor + * quantities from the reference to spatial configuration, and vice versa. + * These types of transformation are typically used to re-express quantities + * measured or computed in one configuration in terms of a second configuration. + * + *

Notation

+ * + * We will use the same notation for the coordinates $\mathbf{X}, \mathbf{x}$, + * transformations $\varphi$, differential operator $\nabla_{0}$ and deformation + * gradient $\mathbf{F}$ as discussed for namespace Physics::Elasticity. + * + * As a further point on notation, we will follow Holzapfel (2007) and denote + * the push forward transformation as $\chi\left(\bullet\right)$ and + * the pull back transformation as $\chi^{-1}\left(\bullet\right)$. + * We will also use the annotation $\left(\bullet\right)^{\sharp}$ to indicate + * that a tensor $\left(\bullet\right)$ is a contravariant tensor, + * and $\left(\bullet\right)^{\flat}$ that it is covariant. In other + * words, these indices do not actually change the tensor, they just indicate + * the kind of object a particular tensor is. + * + * @note For these transformations, unless otherwise stated, we will strictly + * assume that all indices of the transformed tensors derive from one coordinate + * system; that is to say that they are not multi-point tensors (such as the + * Piola stress in elasticity). + * + * @ingroup physics + * + * @author Jean-Paul Pelteret, Andrew McBride, 2016 + */ + namespace Transformations + { + } + + /** + * This namespace provides a collection of definitions that + * conform to standard notation used in (nonlinear) elasticity. + * + *

Notation

+ * + * References for this notation include: + * @code{.bib} + @Book{Holzapfel2007a, + title = {Nonlinear solid mechanics. A Continuum Approach for Engineering}, + publisher = {John Wiley \& Sons Ltd.}, + year = {2007}, + author = {Holzapfel, G. A.}, + address = {West Sussex, England}, + note = {ISBN: 0-471-82304-X} + } + @Book{Wriggers2008a, + title = {Nonlinear finite element methods}, + publisher = {Springer Berlin Heidelberg}, + year = {2008}, + author = {Wriggers, P.}, + volume = {4}, + address = {Berlin, Germany}, + note = {ISBN: 978-3-540-71000-4}, + doi = {10.1007/978-3-540-71001-1} + } + * @endcode + * + * For convenience we will predefine some commonly referenced tensors and + * operations. + * Considering the position vector $\mathbf{X}$ in the referential (material) + * configuration, points $\mathbf{X}$ are transformed to points $\mathbf{x}$ + * in the current (spatial) configuration through the nonlinear map + * @f[ + * \mathbf{x} + * := \boldsymbol{\varphi} \left( \mathbf{X} \right) + * = \mathbf{X} + \mathbf{u}(\mathbf{X}) \, , + * @f] + * where the $\mathbf{u}(\mathbf{X})$ represents the displacement vector. + * From this we can compute the deformation gradient tensor as + * @f[ + * \mathbf{F} := \mathbf{I} + \nabla_{0}\mathbf{u} \, , + * @f] + * wherein the differential operator $\nabla_{0}$ is defined as + * $\frac{\partial}{\partial \mathbf{X}}$ and $\mathbf{I}$ is the identity + * tensor. + * + * Finally, two common tensor operators are represented by $\cdot$ and $:$ + * operators. These respectively represent a single and double contraction over + * the inner tensor indices. + * Vectors and second-order tensors are highlighted by bold font, while + * fourth-order tensors are denoted by calliagraphic font. + * + * One can think of fourth-order tensors as linear operators mapping second-order + * tensors (matrices) onto themselves in much the same way as matrices map + * vectors onto vectors. + * To provide some context to the implemented class members and functions, + * consider the following fundamental operations performed on tensors with special + * properties: + * + * If we represent a general second-order tensor as $\mathbf{A}$, then the general + * fourth-order unit tensors $\mathcal{I}$ and $\overline{\mathcal{I}}$ are + * defined by + * @f[ + * \mathbf{A} = \mathcal{I}:\mathbf{A} + * \qquad \text{and} \qquad + * \mathbf{A}^T = \overline{\mathcal{I}}:\mathbf{A} \, , + * @f] + * or, in indicial notation, + * @f[ + * I_{ijkl} = \delta_{ik}\delta_{jl} + * \qquad \text{and} \qquad + * \overline I_{ijkl} = \delta_{il}\delta_{jk} + * @f] + * with the Kronecker deltas taking their common definition. + * Note that $\mathcal{I} \neq \overline{\mathcal{I}}^T$. + * + * We then define the symmetric and skew-symmetric fourth-order unit tensors by + * @f[ + * \mathcal{S} := \dfrac{1}{2}[\mathcal{I} + \overline{\mathcal{I}}] + * \qquad \text{and} \qquad + * \mathcal{W} := \dfrac{1}{2}[\mathcal{I} - \overline{\mathcal{I}}] \, , + * @f] + * such that + * @f[ + * \mathcal{S}:\mathbf{A} = \dfrac{1}{2}[\mathbf{A} + \mathbf{A}^T] + * \qquad \text{and} \qquad + * \mathcal{W}:\mathbf{A} = \dfrac{1}{2}[\mathbf{A} - \mathbf{A}^T] \, . + * @f] + * The fourth-order symmetric tensor returned by identity_tensor() is + * $\mathcal{S}$. + * + * @author Jean-Paul Pelteret, Andrew McBride, 2016 + * + * @ingroup physics + */ + namespace Elasticity + { + } + +} diff --git a/doc/doxygen/options.dox.in b/doc/doxygen/options.dox.in index 98ab862678..e1c010deae 100644 --- a/doc/doxygen/options.dox.in +++ b/doc/doxygen/options.dox.in @@ -85,6 +85,10 @@ ALIASES += dealiiOperationIsMultithreaded="@note If deal.II is configured with t ALIASES += dealiiExceptionMessage{1}="@note The message that will be printed by this exception reads:
\1
" +ALIASES += dealiiWriggersA{2}="@note For a discussion of the background of this function, see P. Wriggers: \"Nonlinear finite element methods\" (2008), and in particular formula (\2) on p. \1 (or thereabouts). " + +ALIASES += dealiiHolzapfelA{2}="@note For a discussion of the background of this function, see G. A. Holzapfel: \"Nonlinear solid mechanics. A Continuum Approach for Engineering\" (2007), and in particular formula (\2) on p. \1 (or thereabouts). " + #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- diff --git a/doc/news/changes.h b/doc/news/changes.h index 633937745c..f3931b4895 100644 --- a/doc/news/changes.h +++ b/doc/news/changes.h @@ -235,6 +235,28 @@ inconvenience this causes.
    +
  1. New: Implemented some standard tensor definitions for elasticity in + Physics::Elasticity::StandardTensors. Within the newly implemented + Physics::Elasticity::Kinematics namespace are some standard + definitions of kinematic quantities commonly used in elasticity. +
    + (Jean-Paul Pelteret, Andrew McBride, 2016/12/05) +
  2. + +
  3. New: The Physics::Transformations namespace defines a number of operations + that can be used to push forward and pull back quantities to and from different + body configurations. +
    + (Jean-Paul Pelteret, Andrew McBride, 2016/12/05) +
  4. + +
  5. New: The Physics namespace is dedicated to defining useful + functions and other quantities that are regularly used in the implementation + of classical (multi-)physics problems. +
    + (Jean-Paul Pelteret, 2016/12/05) +
  6. +
  7. Improved: The step-37 tutorial program now shows the matrix-free multigrid solver based on MPI parallelization rather than only a serial version. Moreover, support for adaptively refined meshes has been added. diff --git a/include/deal.II/physics/elasticity/kinematics.h b/include/deal.II/physics/elasticity/kinematics.h new file mode 100644 index 0000000000..28fd56f831 --- /dev/null +++ b/include/deal.II/physics/elasticity/kinematics.h @@ -0,0 +1,401 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2016 by the deal.II authors +// +// This file is part of the deal.II library. +// +// The deal.II library is free software; you can use it, redistribute +// it, and/or modify it under the terms of the GNU Lesser General +// Public License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// The full text of the license can be found in the file LICENSE at +// the top level of the deal.II distribution. +// +// --------------------------------------------------------------------- + +#ifndef dealii__elasticity__kinematics_h +#define dealii__elasticity__kinematics_h + + +#include +#include +#include + +DEAL_II_NAMESPACE_OPEN + +namespace Physics +{ + + namespace Elasticity + { + + /** + * A collection of tensor definitions for deformation and strain measures, + * as well as a few special transformations, that conform to notation used in + * standard scientific literature, in particular the books of + * Holzapfel (2007) and Wriggers (2008). The citation for these references, + * as well as other notation used here, can be found in the description for + * the Physics::Elasticity namespace. + + * @note These hold specifically for the codimension + * 0 case, where the metric tensor is the identity tensor. + * + * @author Jean-Paul Pelteret, Andrew McBride, 2016 + */ + namespace Kinematics + { + + /** + * @name Deformation tensors + */ +//@{ + + /** + * Returns the deformation gradient tensor, + * as constructed from the material displacement gradient + * tensor @p Grad_u. + * The result is expressed as + * @f[ + * \mathbf{F} + * := \nabla_{0} \boldsymbol{\varphi} \left( \mathbf{X} \right) + * =\mathbf{I} + \nabla_{0}\mathbf{u} + * @f] + * where $\mathbf{u} = \mathbf{u}\left(\mathbf{X}\right)$ is the + * displacement at position $\mathbf{X}$ in the referential configuration. + * The differential operator $\nabla_{0}$ is defined as + * $\frac{\partial}{\partial \mathbf{X}}$. + * + * @dealiiWriggersA{23,3.14} + * @dealiiHolzapfelA{71,2.39} + */ + template + Tensor<2, dim, Number> + F (const Tensor<2, dim, Number> &Grad_u); + + /** + * Returns the isochoric counterpart of the deformation gradient + * tensor @p F . + * The result is expressed as + * @f[ + * \mathbf{F}^{\text{iso}} := J^{-1/\textrm{dim}} \mathbf{F} + * @f] + * where $J = \text{det}\left(\mathbf{F}\right)$. + * + * @dealiiWriggersA{29,3.28} + * @dealiiHolzapfelA{228,6.79} + */ + template + Tensor<2, dim, Number> + F_iso (const Tensor<2, dim, Number> &F); + + /** + * Returns the volumetric counterpart of the deformation gradient + * tensor @p F . + * The result is expressed as + * @f[ + * \mathbf{F}^{\text{vol}} := J^{1/\textrm{dim}} \mathbf{I} + * @f] + * where $J = \text{det}\left(\mathbf{F}\right)$. + * + * @dealiiWriggersA{29,3.28} + * @dealiiHolzapfelA{228,6.79} + */ + template + SymmetricTensor<2, dim, Number> + F_vol (const Tensor<2, dim, Number> &F); + + /** + * Returns the symmetric right Cauchy-Green deformation tensor, + * as constructed from the deformation gradient tensor @p F. + * The result is expressed as + * @f[ + * \mathbf{C} := \mathbf{F}^{T}\cdot\mathbf{F} \, . + * @f] + * + * @dealiiWriggersA{23,3.15} + * @dealiiHolzapfelA{78,2.65} + */ + template + SymmetricTensor<2, dim, Number> + C (const Tensor<2, dim, Number> &F); + + /** + * Returns the symmetric left Cauchy-Green deformation tensor, + * as constructed from the deformation gradient tensor @p F. + * The result is expressed as + * @f[ + * \mathbf{b} := \mathbf{F}\cdot\mathbf{F}^{T} \, . + * @f] + * + * @dealiiWriggersA{28,3.25} + * @dealiiHolzapfelA{81,2.79} + */ + template + SymmetricTensor<2, dim, Number> + b (const Tensor<2, dim, Number> &F); + +//@} + + /** + * @name Strain tensors + */ +//@{ + + /** + * Returns the symmetric Green-Lagrange strain tensor, + * as constructed from the deformation gradient tensor @p F. + * The result is expressed as + * @f[ + * \mathbf{E} := \frac{1}{2}[\mathbf{F}^{T}\cdot\mathbf{F} - \mathbf{I}] \, . + * @f] + * + * @dealiiWriggersA{23,3.15} + * @dealiiHolzapfelA{79,6.29} + */ + template + SymmetricTensor<2, dim, Number> + E (const Tensor<2, dim, Number> &F); + + /** + * Returns the symmetric small strain tensor, + * as constructed from the displacement gradient tensor @p Grad_u. + * The result is expressed as + * @f[ + * \boldsymbol{\varepsilon} := \frac{1}{2} \left[ \nabla_{0}\mathbf{u} + * + [\nabla_{0}\mathbf{u}]^{T} \right] \, . + * @f] + * where $\mathbf{u} = \mathbf{u}(\mathbf{X})$ is the displacement at position + * $\mathbf{X}$ in the referential configuration. + * The differential operator $\nabla_{0}$ is defined as + * $\frac{\partial}{\partial \mathbf{X}}$. + * + * @dealiiWriggersA{24,3.17} + */ + template + SymmetricTensor<2, dim, Number> + epsilon (const Tensor<2, dim, Number> &Grad_u); + + /** + * Returns the symmetric Almansi strain tensor, + * as constructed from the deformation gradient tensor @p F. + * The result is expressed as + * @f[ + * \mathbf{e} := \frac{1}{2} \left[ \mathbf{I} + * - \mathbf{F}^{-T}\cdot\mathbf{F}^{-1} \right] \, . + * @f] + * + * @dealiiWriggersA{30,3.35} + * @dealiiHolzapfelA{81,2.83} + */ + template + SymmetricTensor<2, dim, Number> + e (const Tensor<2, dim, Number> &F); + +//@} + + /** + * @name Strain rate tensors + */ +//@{ + + /** + * Returns the spatial velocity gradient tensor, + * as constructed from the deformation gradient tensor @p F + * and its material time derivative @p dF_dt (the material velocity + * gradient). + * The result is expressed as + * @f[ + * \mathbf{l} := \dot{\mathbf{F}}\cdot\mathbf{F}^{-1} \, . + * @f] + * + * @dealiiWriggersA{32,3.47} + * @dealiiHolzapfelA{96,2.141} + */ + template + Tensor<2, dim, Number> + l (const Tensor<2, dim, Number> &F, + const Tensor<2, dim, Number> &dF_dt); + + /** + * Returns the rate of deformation tensor (also known as the rate of strain + * tensor), as constructed from the deformation gradient tensor @p F + * and its material time derivative @p dF_dt (the material velocity + * gradient). + * The result is expressed as + * @f[ + * \mathbf{d} := \frac{1}{2} \left[ \mathbf{l} + \mathbf{l}^{T} \right] \, . + * @f] + * where + * @f[ + * \mathbf{l} = \dot{\mathbf{F}}\cdot\mathbf{F}^{-1} + * @f] + * is the spatial velocity gradient tensor. + * + * @dealiiWriggersA{32,3.49} + * @dealiiHolzapfelA{97,2.148} + */ + template + SymmetricTensor<2, dim, Number> + d (const Tensor<2, dim, Number> &F, + const Tensor<2, dim, Number> &dF_dt); + + /** + * Returns the rate of rotation tensor (also known as the vorticity + * tensor), as constructed from the deformation gradient tensor @p F + * and its material time derivative @p dF_dt (the material velocity + * gradient). + * The result is expressed as + * @f[ + * \mathbf{w} := \frac{1}{2} \left[ \mathbf{l} - \mathbf{l}^{T} \right] \, . + * @f] + * where + * @f[ + * \mathbf{l} = \dot{\mathbf{F}}\cdot\mathbf{F}^{-1} + * @f] + * is the spatial velocity gradient tensor. + * + * @dealiiHolzapfelA{97,2.149} + */ + template + Tensor<2, dim, Number> + w (const Tensor<2, dim, Number> &F, + const Tensor<2, dim, Number> &dF_dt); + +//@} + }; + + } +} + + + +#ifndef DOXYGEN + +// ------------------------- inline functions ------------------------ + + + +template +inline +Tensor<2, dim, Number> +Physics::Elasticity::Kinematics::F (const Tensor<2, dim, Number> &Grad_u) +{ + return StandardTensors::I + Grad_u; +} + + + +template +inline +Tensor<2, dim, Number> +Physics::Elasticity::Kinematics::F_iso (const Tensor<2, dim, Number> &F) +{ + return std::pow(determinant(F),-1.0/dim)*F; +} + + + +template +inline +SymmetricTensor<2, dim, Number> +Physics::Elasticity::Kinematics::F_vol (const Tensor<2, dim, Number> &F) +{ + return Number(std::pow(determinant(F),1.0/dim))*static_cast< SymmetricTensor<2,dim,Number> >(unit_symmetric_tensor()); +} + + + +template +inline +SymmetricTensor<2, dim, Number> +Physics::Elasticity::Kinematics::C (const Tensor<2, dim, Number> &F) +{ + return symmetrize(transpose(F)*F); +} + + + +template +inline +SymmetricTensor<2, dim, Number> +Physics::Elasticity::Kinematics::b (const Tensor<2, dim, Number> &F) +{ + return symmetrize(F*transpose(F)); +} + + + +template +inline +SymmetricTensor<2, dim, Number> +Physics::Elasticity::Kinematics::E (const Tensor<2, dim, Number> &F) +{ + return Number(0.5)*(C(F) - static_cast >(StandardTensors::I)); +} + + + +template +inline +SymmetricTensor<2, dim, Number> +Physics::Elasticity::Kinematics::epsilon (const Tensor<2, dim, Number> &Grad_u) +{ +// This is the equivalent to 0.5*symmetrize(Grad_u + transpose(Grad_u)); + return symmetrize(Grad_u); +} + + + +template +inline +SymmetricTensor<2, dim, Number> +Physics::Elasticity::Kinematics::e (const Tensor<2, dim, Number> &F) +{ + const Tensor<2, dim, Number> F_inv = invert(F); + return Number(0.5)*symmetrize(static_cast >(StandardTensors::I) - transpose(F_inv)*F_inv); +} + + + +template +inline +Tensor<2, dim, Number> +Physics::Elasticity::Kinematics::l ( + const Tensor<2, dim, Number> &F, + const Tensor<2, dim, Number> &dF_dt) +{ + return dF_dt*invert(F); +} + + + +template +inline +SymmetricTensor<2, dim, Number> +Physics::Elasticity::Kinematics::d ( + const Tensor<2, dim, Number> &F, + const Tensor<2, dim, Number> &dF_dt) +{ + return symmetrize(l(F,dF_dt)); +} + + + +template +inline +Tensor<2, dim, Number> +Physics::Elasticity::Kinematics::w ( + const Tensor<2, dim, Number> &F, + const Tensor<2, dim, Number> &dF_dt) +{ + // This could be implemented as w = l-d, but that would mean computing "l" + // a second time. + const Tensor<2,dim> grad_v = l(F,dF_dt); + return 0.5*(grad_v - transpose(grad_v)) ; +} + +#endif // DOXYGEN + +DEAL_II_NAMESPACE_CLOSE + +#endif diff --git a/include/deal.II/physics/elasticity/standard_tensors.h b/include/deal.II/physics/elasticity/standard_tensors.h new file mode 100644 index 0000000000..4a58ca08a9 --- /dev/null +++ b/include/deal.II/physics/elasticity/standard_tensors.h @@ -0,0 +1,369 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2016 by the deal.II authors +// +// This file is part of the deal.II library. +// +// The deal.II library is free software; you can use it, redistribute +// it, and/or modify it under the terms of the GNU Lesser General +// Public License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// The full text of the license can be found in the file LICENSE at +// the top level of the deal.II distribution. +// +// --------------------------------------------------------------------- + +#ifndef dealii__elasticity__standard_tensors_h +#define dealii__elasticity__standard_tensors_h + + +#include +#include + +DEAL_II_NAMESPACE_OPEN + +namespace Physics +{ + + namespace Elasticity + { + + /** + * A collection of tensor definitions that mostly conform to notation used + * in standard scientific literature, in particular the book of + * Wriggers (2008). The citation for this reference, as well as other + * notation used here, can be found in the description for the Physics::Elasticity + * namespace. + * + * @note These hold specifically for the codimension 0 case with a + * Cartesian basis, where the metric tensor is the identity tensor. + * + * @relates Tensor + * @relates SymmetricTensor + * @author Jean-Paul Pelteret, Andrew McBride, 2016 + */ + template + class StandardTensors + { + public: + + /** + * @name Metric tensors + */ +//@{ + + /** + * The second-order referential/spatial symmetric identity (metric) tensor + * $\mathbf{I}$. + * + * This is defined such that, for any rank-2 tensor or symmetric tensor, + * the following holds: + * @f[ + * \mathbf{I} \cdot \{ \bullet \} = \{ \bullet \} \cdot \mathbf{I} = + * \{ \bullet \} + * \qquad \text{and} \qquad + * \mathbf{I} : \{ \bullet \} = \textrm{trace} \{ \bullet \} \, . + * @f] + * + * This definition aligns with the rank-2 symmetric tensor returned by + * unit_symmetric_tensor(). If one is to interpret the tensor as a + * matrix, then this simply corresponds to the identity matrix. + */ + static const SymmetricTensor<2, dim> I; + + /** + * The fourth-order referential/spatial unit symmetric tensor $\mathcal{S}$. + * + * This is defined such that for a general rank-2 tensor $\{ \hat{\bullet} \}$ + * the following holds: + * @f[ + * \mathcal{S} : \{ \hat{\bullet} \} + * := \dfrac{1}{2}[\{ \hat{\bullet} \} + \{ \hat{\bullet} \}^T] \, . + * @f] + * + * As a corollary to this, for any second-order symmetric tensor $\{ \bullet \}$ + * @f[ + * \mathcal{S} : \{ \bullet \} + * = \{ \bullet \} : \mathcal{S} = \{ \bullet \} \, . + * @f] + * + * This definition aligns with the fourth-order symmetric tensor $\mathcal{S}$ + * introduced in the Physics::Elasticity namespace description and that + * which is returned by identity_tensor(). + * + * @note If you apply this to a standard tensor then it doesn't behave like + * the fourth-order identity tensor, but rather as a symmetrization operator. + */ + static const SymmetricTensor<4, dim> S; + + /** + * The fourth-order referential/spatial tensor $\mathbf{I} \otimes \mathbf{I}$. + * + * This is defined such that, for any rank-2 tensor, the following holds: + * @f[ + * [\mathbf{I} \otimes \mathbf{I}] : \{ \bullet \} = + * \textrm{trace}\{ \bullet \} \mathbf{I} \, . + * @f] + */ + static const SymmetricTensor<4, dim> IxI; + +//@} + + /** + * @name Projection operators + */ +//@{ + + /** + * The fourth-order spatial deviatoric tensor. Also known as the deviatoric + * operator, this tensor projects a second-order symmetric tensor onto a + * a deviatoric space (for which the hydrostatic component is removed). + * + * This is defined as + * @f[ + * \mathcal{P} + * := \mathcal{S} - \frac{1}{\textrm{dim}} \mathbf{I} \otimes \mathbf{I} + * @f] + * where $\mathcal{S}$ is the fourth-order unit symmetric tensor and + * $\mathbf{I}$ is the second-order identity tensor. + * + * For any second-order (spatial) symmetric tensor the following holds: + * @f[ + * \mathcal{P} : \{ \bullet \} + * := \{ \bullet \} - \frac{1}{\textrm{dim}} \left[ \{ \bullet \} : \mathbf{I} \right]\mathbf{I} + * = \mathcal{P}^{T} : \{ \bullet \} + * = \texttt{dev_P} \left( \{ \bullet \} \right) + * @f] + * and, therefore, + * @f[ + * \texttt{dev_P} \left( \{ \bullet \} \right) : \mathbf{I} + * = \textrm{trace}(\texttt{dev_P} \left( \{ \bullet \} \right)) = 0 \, . + * @f] + * + * This definition aligns with the fourth-order symmetric tensor that + * is returned by deviator_tensor(). + * + * @dealiiWriggersA{47,3.129} + * @dealiiHolzapfelA{232,6.105} + */ + static const SymmetricTensor<4, dim> dev_P; + + /** + * Returns the fourth-order referential deviatoric tensor, as constructed from + * the deformation gradient tensor @p F. + * Also known as the deviatoric operator, this tensor projects a second-order + * symmetric tensor onto a deviatoric space (for which the hydrostatic + * component is removed). + * + * This referential isochoric projection tensor is defined as + * @f[ + * \hat{\mathcal{P}} + * := \frac{\partial \bar{\mathbf{C}}}{\partial \mathbf{C}} + * @f] + * with + * @f[ + * \bar{\mathbf{C}} := J^{-2/\textrm{dim}} \mathbf{C} + * \qquad \text{,} \qquad + * \mathbf{C} = \mathbf{F}^{T}\cdot\mathbf{F} + * \qquad \text{and} \qquad + * J = \textrm{det}\mathbf{F} + * @f] + * such that, for any second-order (referential) symmetric tensor, + * the following holds: + * @f[ + * \{ \bullet \} : \hat{\mathcal{P}} + * := J^{-2/\textrm{dim}} \left[ \{ \bullet \} - \frac{1}{\textrm{dim}}\left[\mathbf{C} : \{ \bullet \}\right] \mathbf{C}^{-1} \right] + * = \texttt{Dev_P} \left( \{ \bullet \} \right) \, . + * @f] + * It can therefore be readily shown that + * @f[ + * \texttt{Dev_P} \left( \{ \bullet \} \right) : \mathbf{C} = 0 \, . + * @f] + * + * @note It may be observed that we have defined the tensor as the + * transpose of that adopted by Wriggers (2008). We have done this so that + * it may be strictly applied through the chain rule to achieve the + * definition of the second Piola-Kirchhoff stress, i.e. + * @f[ + * \mathbf{S} + * = 2\frac{\partial \psi \left( \bar{\mathbf{C}} \right)}{\partial \mathbf{C}} + * = 2\frac{\partial \psi \left( \bar{\mathbf{C}} \right)}{\partial \bar{\mathbf{C}}} + * : \frac{\partial \bar{\mathbf{C}}}{\partial \mathbf{C}} + * = \bar{\mathbf{S}} : \hat{\mathcal{P}} + * \equiv \hat{\mathcal{P}}^{T} : \bar{\mathbf{S}} \, . + * @f] + * + * @note Comparing the definition of this tensor in Holzapfel (2001) to that + * adopted here, the inclusion of the extra factor $J^{-2/\textrm{dim}}$ does not, + * at the outset, seem to be a reasonable choice. + * However, in the author's view it makes direct implementation of the + * expressions for isochoric (referential) stress contributions and their + * linearization simpler in practise. + * + * @dealiiWriggersA{46,3.125} + * @dealiiHolzapfelA{229,6.83} + */ + template + static SymmetricTensor<4, dim, Number> + Dev_P (const Tensor<2, dim, Number> &F); + + /** + * Returns the transpose of the fourth-order referential deviatoric tensor, + * as constructed from the deformation gradient tensor @p F. + * The result performs the following operation: + * @f[ + * \texttt{Dev_P_T} \{ \bullet \} = J^{-2/\textrm{dim}} \left[ \{ \bullet \} - + * \frac{1}{\textrm{dim}} \left[\mathbf{C}^{-1} : \{ \bullet \}\right] \mathbf{C} \right] + * := \hat{\mathcal{P}}^{T} : \{ \bullet \} + * @f] + */ + template + static SymmetricTensor<4, dim, Number> + Dev_P_T (const Tensor<2, dim, Number> &F); + +//@} + + /** + * @name Scalar derivatives + */ +//@{ + /** + * Returns the derivative of the volumetric Jacobian + * $J = \text{det} \mathbf{F}$ with respect to the right Cauchy-Green + * tensor, as constructed from the deformation gradient tensor @p F. + * The computed result is + * @f[ + * \frac{\partial J}{\partial \mathbf{C}} + * = \frac{1}{2} J \mathbf{C}^{-1} + * @f] + * with + * @f[ + * \mathbf{C} = \mathbf{F}^{T}\cdot\mathbf{F} \, . + * @f] + * + * @dealiiWriggersA{46,3.124} + * @dealiiHolzapfelA{228,6.82} + */ + template + static SymmetricTensor<2, dim, Number> + ddet_F_dC (const Tensor<2, dim, Number> &F); + +//@} + + /** + * @name Tensor derivatives + */ +//@{ + + /** + * Returns the derivative of the inverse of the right Cauchy-Green + * tensor with respect to the right Cauchy-Green tensor itself, + * as constructed from the deformation gradient tensor @p F. + * The result, accounting for symmetry, is defined in index notation as + * @f[ + * \left[ \frac{\partial \mathbf{C}^{-1}}{\partial \mathbf{C}} \right]_{IJKL} + * := -\frac{1}{2}[ C^{-1}_{IK}C^{-1}_{JL} + * + C^{-1}_{IL}C^{-1}_{JK} ] + * @f] + * + * @dealiiWriggersA{76,3.255} + */ + template + static SymmetricTensor<4, dim, Number> + dC_inv_dC (const Tensor<2, dim, Number> &F); + +//@} + }; + + } +} + + + +#ifndef DOXYGEN + +// ------------------------- inline functions ------------------------ + + +template +template +inline +SymmetricTensor<4, dim, Number> +Physics::Elasticity::StandardTensors::Dev_P (const Tensor<2, dim, Number> &F) +{ + const Number det_F = determinant(F); + Assert(det_F > Number(0.0), + ExcMessage("Deformation gradient has a negative determinant.")); + const Tensor<2,dim,Number> C_ns = transpose(F)*F; + const SymmetricTensor<2,dim,Number> C = symmetrize(C_ns); + const SymmetricTensor<2,dim,Number> C_inv = symmetrize(invert(C_ns)); + + // See Wriggers p46 equ 3.125 (but transpose indices) + SymmetricTensor<4,dim,Number> Dev_P = outer_product(C,C_inv); // Dev_P = C_x_C_inv + Dev_P /= -dim; // Dev_P = -[1/dim]C_x_C_inv + Dev_P += SymmetricTensor<4,dim,Number>(S); // Dev_P = S - [1/dim]C_x_C_inv + Dev_P *= std::pow(det_F, -2.0/dim); // Dev_P = J^{-2/dim} [S - [1/dim]C_x_C_inv] + + return Dev_P; +} + + + +template +template +inline +SymmetricTensor<4, dim, Number> +Physics::Elasticity::StandardTensors::Dev_P_T (const Tensor<2, dim, Number> &F) +{ + const Number det_F = determinant(F); + Assert(det_F > Number(0.0), + ExcMessage("Deformation gradient has a negative determinant.")); + const Tensor<2,dim,Number> C_ns = transpose(F)*F; + const SymmetricTensor<2,dim,Number> C = symmetrize(C_ns); + const SymmetricTensor<2,dim,Number> C_inv = symmetrize(invert(C_ns)); + + // See Wriggers p46 equ 3.125 (not transposed) + SymmetricTensor<4,dim,Number> Dev_P_T = outer_product(C_inv,C); // Dev_P = C_inv_x_C + Dev_P_T /= -dim; // Dev_P = -[1/dim]C_inv_x_C + Dev_P_T += SymmetricTensor<4,dim,Number>(S); // Dev_P = S - [1/dim]C_inv_x_C + Dev_P_T *= std::pow(det_F, -2.0/dim); // Dev_P = J^{-2/dim} [S - [1/dim]C_inv_x_C] + + return Dev_P_T; +} + + + +template +template +inline +SymmetricTensor<2, dim, Number> +Physics::Elasticity::StandardTensors::ddet_F_dC (const Tensor<2, dim, Number> &F) +{ + return Number(0.5)*determinant(F)*symmetrize(invert(transpose(F)*F)); +} + + + +template +template +inline +SymmetricTensor<4, dim, Number> +Physics::Elasticity::StandardTensors::dC_inv_dC (const Tensor<2, dim, Number> &F) +{ + const SymmetricTensor<2,dim,Number> C_inv = symmetrize(invert(transpose(F)*F)); + + SymmetricTensor<4,dim,Number> dC_inv_dC; + for (unsigned int A=0; A +#include + +DEAL_II_NAMESPACE_OPEN + + +namespace Physics +{ + + namespace Transformations + { + + /** + * Transformation of tensors that are defined in terms of a set of + * contravariant bases. Rank-1 and rank-2 contravariant tensors + * $\left(\bullet\right)^{\sharp} = \mathbf{T}$ (and its spatial counterpart + * $\mathbf{t}$) typically satisfy the relation + * @f[ + * \int_{V_{0}} \nabla_{0} \cdot \mathbf{T} \; dV + * = \int_{\partial V_{0}} \mathbf{T} \cdot \mathbf{N} \; dA + * = \int_{\partial V_{t}} \mathbf{T} \cdot \mathbf{n} \; da + * = \int_{V_{t}} \nabla \cdot \mathbf{t} \; dv + * @f] + * where $V_{0}$ and $V_{t}$ are respectively control volumes in the + * reference and spatial configurations, and their surfaces $\partial V_{0}$ + * and $\partial V_{t}$ have the outwards facing normals $\mathbf{N}$ and + * $\mathbf{n}$. + * + * @author Jean-Paul Pelteret, Andrew McBride, 2016 + */ + namespace Contravariant + { + + /** + * @name Push forward operations + */ +//@{ + + /** + * Returns the result of the push forward transformation on a + * contravariant vector, i.e. + * @f[ + * \chi\left(\bullet\right)^{\sharp} + * := \mathbf{F} \cdot \left(\bullet\right)^{\sharp} + * @f] + * + * @param[in] V The (referential) vector to be operated on + * @param[in] F The deformation gradient tensor $\mathbf{F} \left( \mathbf{X} \right)$ + * @return $\chi\left( \mathbf{V} \right)$ + */ + template + Tensor<1,dim,Number> + push_forward (const Tensor<1,dim,Number> &V, + const Tensor<2,dim,Number> &F); + + /** + * Returns the result of the push forward transformation on a rank-2 + * contravariant tensor, i.e. + * @f[ + * \chi\left(\bullet\right)^{\sharp} + * := \mathbf{F} \cdot \left(\bullet\right)^{\sharp} \cdot \mathbf{F}^{T} + * @f] + * + * @param[in] T The (referential) rank-2 tensor to be operated on + * @param[in] F The deformation gradient tensor $\mathbf{F} \left( \mathbf{X} \right)$ + * @return $\chi\left( \mathbf{T} \right)$ + */ + template + Tensor<2,dim,Number> + push_forward (const Tensor<2,dim,Number> &T, + const Tensor<2,dim,Number> &F); + + /** + * Returns the result of the push forward transformation on a rank-2 + * contravariant symmetric tensor, i.e. + * @f[ + * \chi\left(\bullet\right)^{\sharp} + * := \mathbf{F} \cdot \left(\bullet\right)^{\sharp} \cdot \mathbf{F}^{T} + * @f] + * + * @param[in] T The (referential) rank-2 symmetric tensor to be operated on + * @param[in] F The deformation gradient tensor $\mathbf{F} \left( \mathbf{X} \right)$ + * @return $\chi\left( \mathbf{T} \right)$ + */ + template + SymmetricTensor<2,dim,Number> + push_forward (const SymmetricTensor<2,dim,Number> &T, + const Tensor<2,dim,Number> &F); + + /** + * Returns the result of the push forward transformation on a rank-4 + * contravariant tensor, i.e. (in index notation) + * @f[ + * \left[ \chi\left(\bullet\right)^{\sharp} \right]_{ijkl} + * := F_{iI} F_{jJ} \left(\bullet\right)^{\sharp}_{IJKL} F_{kK} F_{lL} + * @f] + * + * @param[in] H The (referential) rank-4 tensor to be operated on + * @param[in] F The deformation gradient tensor $\mathbf{F} \left( \mathbf{X} \right)$ + * @return $\chi\left( \mathbf{H} \right)$ + */ + template + Tensor<4,dim,Number> + push_forward (const Tensor<4,dim,Number> &H, + const Tensor<2,dim,Number> &F); + + /** + * Returns the result of the push forward transformation on a rank-4 + * contravariant symmetric tensor, i.e. (in index notation) + * @f[ + * \left[ \chi\left(\bullet\right)^{\sharp} \right]_{ijkl} + * := F_{iI} F_{jJ} \left(\bullet\right)^{\sharp}_{IJKL} F_{kK} F_{lL} + * @f] + * + * @param[in] H The (referential) rank-4 symmetric tensor to be operated on + * @param[in] F The deformation gradient tensor $\mathbf{F} \left( \mathbf{X} \right)$ + * @return $\chi\left( \mathbf{H} \right)$ + */ + template + SymmetricTensor<4,dim,Number> + push_forward (const SymmetricTensor<4,dim,Number> &H, + const Tensor<2,dim,Number> &F); + +//@} + + /** + * @name Pull back operations + */ +//@{ + + /** + * Returns the result of the pull back transformation on a + * contravariant vector, i.e. + * @f[ + * \chi^{-1}\left(\bullet\right)^{\sharp} + * := \mathbf{F}^{-1} \cdot \left(\bullet\right)^{\sharp} + * @f] + * + * @param[in] v The (spatial) vector to be operated on + * @param[in] F The deformation gradient tensor $\mathbf{F} \left( \mathbf{X} \right)$ + * @return $\chi^{-1}\left( \mathbf{v} \right)$ + */ + template + Tensor<1,dim,Number> + pull_back (const Tensor<1,dim,Number> &v, + const Tensor<2,dim,Number> &F); + + /** + * Returns the result of the pull back transformation on a rank-2 + * contravariant tensor, i.e. + * @f[ + * \chi^{-1}\left(\bullet\right)^{\sharp} + * := \mathbf{F}^{-1} \cdot \left(\bullet\right)^{\sharp} \cdot \mathbf{F}^{-T} + * @f] + * + * @param[in] t The (spatial) tensor to be operated on + * @param[in] F The deformation gradient tensor $\mathbf{F} \left( \mathbf{X} \right)$ + * @return $\chi^{-1}\left( \mathbf{t} \right)$ + */ + template + Tensor<2,dim,Number> + pull_back (const Tensor<2,dim,Number> &t, + const Tensor<2,dim,Number> &F); + + /** + * Returns the result of the pull back transformation on a rank-2 + * contravariant symmetric tensor, i.e. + * @f[ + * \chi^{-1}\left(\bullet\right)^{\sharp} + * := \mathbf{F}^{-1} \cdot \left(\bullet\right)^{\sharp} \cdot \mathbf{F}^{-T} + * @f] + * + * @param[in] t The (spatial) symmetric tensor to be operated on + * @param[in] F The deformation gradient tensor $\mathbf{F} \left( \mathbf{X} \right)$ + * @return $\chi^{-1}\left( \mathbf{t} \right)$ + */ + template + SymmetricTensor<2,dim,Number> + pull_back (const SymmetricTensor<2,dim,Number> &t, + const Tensor<2,dim,Number> &F); + + /** + * Returns the result of the pull back transformation on a rank-4 + * contravariant tensor, i.e. (in index notation) + * @f[ + * \left[ \chi^{-1}\left(\bullet\right)^{\sharp} \right]_{IJKL} + * := F^{-1}_{Ii} F^{-1}_{Jj} \left(\bullet\right)^{\sharp}_{ijkl} F^{-1}_{Kk} F^{-1}_{Ll} + * @f] + * + * @param[in] h The (spatial) tensor to be operated on + * @param[in] F The deformation gradient tensor $\mathbf{F} \left( \mathbf{X} \right)$ + * @return $\chi^{-1}\left( \mathbf{h} \right)$ + */ + template + Tensor<4,dim,Number> + pull_back (const Tensor<4,dim,Number> &h, + const Tensor<2,dim,Number> &F); + + /** + * Returns the result of the pull back transformation on a rank-4 + * contravariant symmetric tensor, i.e. (in index notation) + * @f[ + * \left[ \chi^{-1}\left(\bullet\right)^{\sharp} \right]_{IJKL} + * := F^{-1}_{Ii} F^{-1}_{Jj} \left(\bullet\right)^{\sharp}_{ijkl} F^{-1}_{Kk} F^{-1}_{Ll} + * @f] + * + * @param[in] h The (spatial) symmetric tensor to be operated on + * @param[in] F The deformation gradient tensor $\mathbf{F} \left( \mathbf{X} \right)$ + * @return $\chi^{-1}\left( \mathbf{h} \right)$ + */ + template + SymmetricTensor<4,dim,Number> + pull_back (const SymmetricTensor<4,dim,Number> &h, + const Tensor<2,dim,Number> &F); + +//@} + } + + /** + * Transformation of tensors that are defined in terms of a set of + * covariant basis vectors. Rank-1 and rank-2 covariant tensors + * $\left(\bullet\right)^{\flat} = \mathbf{T}$ (and its spatial counterpart + * $\mathbf{t}$) typically satisfy the relation + * @f[ + * \int_{\partial V_{0}} \left[ \nabla_{0} \times \mathbf{T} \right] \cdot \mathbf{N} \; dA + * = \oint_{\partial A_{0}} \mathbf{T} \cdot \mathbf{L} \; dL + * = \oint_{\partial A_{t}} \mathbf{t} \cdot \mathbf{l} \; dl + * = \int_{\partial V_{t}} \left[ \nabla \times \mathbf{t} \right] \cdot \mathbf{n} \; da + * @f] + * where the control surfaces $\partial V_{0}$ and $\partial V_{t}$ with + * outwards facing normals $\mathbf{N}$ and $\mathbf{n}$ are bounded by the + * curves $\partial A_{0}$ and $\partial A_{0}$ that are, respectively, + * associated with the line directors $\mathbf{L}$ and $\mathbf{l}$. + * + * @author Jean-Paul Pelteret, Andrew McBride, 2016 + */ + namespace Covariant + { + + /** + * @name Push forward operations + */ +//@{ + + /** + * Returns the result of the push forward transformation on a covariant + * vector, i.e. + * @f[ + * \chi\left(\bullet\right)^{\flat} + * := \mathbf{F}^{-T} \cdot \left(\bullet\right)^{\flat} + * @f] + * + * @param[in] V The (referential) vector to be operated on + * @param[in] F The deformation gradient tensor $\mathbf{F} \left( \mathbf{X} \right)$ + * @return $\chi\left( \mathbf{V} \right)$ + */ + template + Tensor<1,dim,Number> + push_forward (const Tensor<1,dim,Number> &V, + const Tensor<2,dim,Number> &F); + + /** + * Returns the result of the push forward transformation on a rank-2 + * covariant tensor, i.e. + * @f[ + * \chi\left(\bullet\right)^{\flat} + * := \mathbf{F}^{-T} \cdot \left(\bullet\right)^{\flat} \cdot \mathbf{F}^{-1} + * @f] + * + * @param[in] T The (referential) rank-2 tensor to be operated on + * @param[in] F The deformation gradient tensor $\mathbf{F} \left( \mathbf{X} \right)$ + * @return $\chi\left( \mathbf{T} \right)$ + */ + template + Tensor<2,dim,Number> + push_forward (const Tensor<2,dim,Number> &T, + const Tensor<2,dim,Number> &F); + + /** + * Returns the result of the push forward transformation on a rank-2 + * covariant symmetric tensor, i.e. + * @f[ + * \chi\left(\bullet\right)^{\flat} + * := \mathbf{F}^{-T} \cdot \left(\bullet\right)^{\flat} \cdot \mathbf{F}^{-1} + * @f] + * + * @param[in] T The (referential) rank-2 symmetric tensor to be operated on + * @param[in] F The deformation gradient tensor $\mathbf{F} \left( \mathbf{X} \right)$ + * @return $\chi\left( \mathbf{T} \right)$ + */ + template + SymmetricTensor<2,dim,Number> + push_forward (const SymmetricTensor<2,dim,Number> &T, + const Tensor<2,dim,Number> &F); + + /** + * Returns the result of the push forward transformation on a rank-4 + * covariant tensor, i.e. (in index notation) + * @f[ + * \left[ \chi\left(\bullet\right)^{\flat} \right]_{ijkl} + * := F^{-T}_{iI} F^{-T}_{jJ} \left(\bullet\right)^{\flat}_{IJKL} F^{-T}_{kK} F^{-T}_{lL} + * @f] + * + * @param[in] H The (referential) rank-4 tensor to be operated on + * @param[in] F The deformation gradient tensor $\mathbf{F} \left( \mathbf{X} \right)$ + * @return $\chi\left( \mathbf{H} \right)$ + */ + template + Tensor<4,dim,Number> + push_forward (const Tensor<4,dim,Number> &H, + const Tensor<2,dim,Number> &F); + + /** + * Returns the result of the push forward transformation on a rank-4 + * covariant symmetric tensor, i.e. (in index notation) + * @f[ + * \left[ \chi\left(\bullet\right)^{\flat} \right]_{ijkl} + * := F^{-T}_{iI} F^{-T}_{jJ} \left(\bullet\right)^{\flat}_{IJKL} F^{-T}_{kK} F^{-T}_{lL} + * @f] + * + * @param[in] H The (referential) rank-4 symmetric tensor to be operated on + * @param[in] F The deformation gradient tensor $\mathbf{F} \left( \mathbf{X} \right)$ + * @return $\chi\left( \mathbf{H} \right)$ + */ + template + SymmetricTensor<4,dim,Number> + push_forward (const SymmetricTensor<4,dim,Number> &H, + const Tensor<2,dim,Number> &F); + +//@} + + /** + * @name Pull back operations + */ +//@{ + + /** + * Returns the result of the pull back transformation on a + * covariant vector, i.e. + * @f[ + * \chi^{-1}\left(\bullet\right)^{\flat} + * := \mathbf{F}^{T} \cdot \left(\bullet\right)^{\flat} + * @f] + * + * @param[in] v The (spatial) vector to be operated on + * @param[in] F The deformation gradient tensor $\mathbf{F} \left( \mathbf{X} \right)$ + * @return $\chi^{-1}\left( \mathbf{v} \right)$ + */ + template + Tensor<1,dim,Number> + pull_back (const Tensor<1,dim,Number> &v, + const Tensor<2,dim,Number> &F); + + /** + * Returns the result of the pull back transformation on a rank-2 + * covariant tensor, i.e. + * @f[ + * \chi^{-1}\left(\bullet\right)^{\flat} + * := \mathbf{F}^{T} \cdot \left(\bullet\right)^{\flat} \cdot \mathbf{F} + * @f] + * + * @param[in] t The (spatial) tensor to be operated on + * @param[in] F The deformation gradient tensor $\mathbf{F} \left( \mathbf{X} \right)$ + * @return $\chi^{-1}\left( \mathbf{t} \right)$ + */ + template + Tensor<2,dim,Number> + pull_back (const Tensor<2,dim,Number> &t, + const Tensor<2,dim,Number> &F); + + /** + * Returns the result of the pull back transformation on a rank-2 + * covariant symmetric tensor, i.e. + * @f[ + * \chi^{-1}\left(\bullet\right)^{\flat} + * := \mathbf{F}^{T} \cdot \left(\bullet\right)^{\flat} \cdot \mathbf{F} + * @f] + * + * @param[in] t The (spatial) symmetric tensor to be operated on + * @param[in] F The deformation gradient tensor $\mathbf{F} \left( \mathbf{X} \right)$ + * @return $\chi^{-1}\left( \mathbf{t} \right)$ + */ + template + SymmetricTensor<2,dim,Number> + pull_back (const SymmetricTensor<2,dim,Number> &t, + const Tensor<2,dim,Number> &F); + + /** + * Returns the result of the pull back transformation on a rank-4 + * contravariant tensor, i.e. (in index notation) + * @f[ + * \left[ \chi^{-1}\left(\bullet\right)^{\flat} \right]_{IJKL} + * := F^{T}_{Ii} F^{T}_{Jj} \left(\bullet\right)^{\flat}_{ijkl} F^{T}_{Kk} F^{T}_{Ll} + * @f] + * + * @param[in] h The (spatial) tensor to be operated on + * @param[in] F The deformation gradient tensor $\mathbf{F} \left( \mathbf{X} \right)$ + * @return $\chi^{-1}\left( \mathbf{h} \right)$ + */ + template + Tensor<4,dim,Number> + pull_back (const Tensor<4,dim,Number> &h, + const Tensor<2,dim,Number> &F); + + /** + * Returns the result of the pull back transformation on a rank-4 + * contravariant symmetric tensor, i.e. (in index notation) + * @f[ + * \left[ \chi^{-1}\left(\bullet\right)^{\flat} \right]_{IJKL} + * := F^{T}_{Ii} F^{T}_{Jj} \left(\bullet\right)^{\flat}_{ijkl} F^{T}_{Kk} F^{T}_{Ll} + * @f] + * + * @param[in] h The (spatial) symmetric tensor to be operated on + * @param[in] F The deformation gradient tensor $\mathbf{F} \left( \mathbf{X} \right)$ + * @return $\chi^{-1}\left( \mathbf{h} \right)$ + */ + template + SymmetricTensor<4,dim,Number> + pull_back (const SymmetricTensor<4,dim,Number> &h, + const Tensor<2,dim,Number> &F); + +//@} + } + + /** + * Transformation of tensors that are defined in terms of a set of + * contravariant basis vectors and scale with the inverse of the volume + * change associated with the mapping. + * + * @author Jean-Paul Pelteret, Andrew McBride, 2016 + */ + namespace Piola + { + + /** + * @name Push forward operations + */ +//@{ + + /** + * Returns the result of the push forward transformation on a + * contravariant vector, i.e. + * @f[ + * \textrm{det} \mathbf{F}^{-1} \; \chi\left(\bullet\right)^{\sharp} + * := \frac{1}{\textrm{det} \mathbf{F}} \; \mathbf{F} \cdot \left(\bullet\right)^{\sharp} + * @f] + * + * @param[in] V The (referential) vector to be operated on + * @param[in] F The deformation gradient tensor $\mathbf{F} \left( \mathbf{X} \right)$ + * @return $\frac{1}{\textrm{det} \mathbf{F}} \; \chi\left( \mathbf{V} \right)$ + */ + template + Tensor<1,dim,Number> + push_forward (const Tensor<1,dim,Number> &V, + const Tensor<2,dim,Number> &F); + + /** + * Returns the result of the push forward transformation on a rank-2 + * contravariant tensor, i.e. + * @f[ + * \textrm{det} \mathbf{F}^{-1} \; \chi\left(\bullet\right)^{\sharp} + * := \frac{1}{\textrm{det} \mathbf{F}} \; \mathbf{F} \cdot \left(\bullet\right)^{\sharp} \cdot \mathbf{F}^{T} + * @f] + * + * @param[in] T The (referential) rank-2 tensor to be operated on + * @param[in] F The deformation gradient tensor $\mathbf{F} \left( \mathbf{X} \right)$ + * @return $\frac{1}{\textrm{det} \mathbf{F}} \; \chi\left( \mathbf{T} \right)$ + */ + template + Tensor<2,dim,Number> + push_forward (const Tensor<2,dim,Number> &T, + const Tensor<2,dim,Number> &F); + + /** + * Returns the result of the push forward transformation on a rank-2 + * contravariant symmetric tensor, i.e. + * @f[ + * \textrm{det} \mathbf{F}^{-1} \; \chi\left(\bullet\right)^{\sharp} + * := \frac{1}{\textrm{det} \mathbf{F}} \; \mathbf{F} \cdot \left(\bullet\right)^{\sharp} \cdot \mathbf{F}^{T} + * @f] + * + * @param[in] T The (referential) rank-2 symmetric tensor to be operated on + * @param[in] F The deformation gradient tensor $\mathbf{F} \left( \mathbf{X} \right)$ + * @return $\frac{1}{\textrm{det} \mathbf{F}} \; \chi\left( \mathbf{T} \right)$ + */ + template + SymmetricTensor<2,dim,Number> + push_forward (const SymmetricTensor<2,dim,Number> &T, + const Tensor<2,dim,Number> &F); + + /** + * Returns the result of the push forward transformation on a rank-4 + * contravariant tensor, i.e. (in index notation) + * @f[ + * \textrm{det} \mathbf{F}^{-1} \; \left[ \chi\left(\bullet\right)^{\sharp} \right]_{ijkl} + * := \frac{1}{\textrm{det} \mathbf{F}} \; F_{iI} F_{jJ} \left(\bullet\right)^{\sharp}_{IJKL} F_{kK} F_{lL} + * @f] + * + * @param[in] H The (referential) rank-4 tensor to be operated on + * @param[in] F The deformation gradient tensor $\mathbf{F} \left( \mathbf{X} \right)$ + * @return $\frac{1}{\textrm{det} \mathbf{F}} \; \chi\left( \mathbf{H} \right)$ + */ + template + Tensor<4,dim,Number> + push_forward (const Tensor<4,dim,Number> &H, + const Tensor<2,dim,Number> &F); + + /** + * Returns the result of the push forward transformation on a rank-4 + * contravariant symmetric tensor, i.e. (in index notation) + * @f[ + * \textrm{det} \mathbf{F}^{-1} \; \left[ \chi\left(\bullet\right)^{\sharp} \right]_{ijkl} + * := \frac{1}{\textrm{det} \mathbf{F}} \; F_{iI} F_{jJ} \left(\bullet\right)^{\sharp}_{IJKL} F_{kK} F_{lL} + * @f] + * + * @param[in] H The (referential) rank-4 symmetric tensor to be operated on + * @param[in] F The deformation gradient tensor $\mathbf{F} \left( \mathbf{X} \right)$ + * @return $\frac{1}{\textrm{det} \mathbf{F}} \; \chi\left( \mathbf{H} \right)$ + */ + template + SymmetricTensor<4,dim,Number> + push_forward (const SymmetricTensor<4,dim,Number> &H, + const Tensor<2,dim,Number> &F); + +//@} + + /** + * @name Pull back operations + */ +//@{ + + /** + * Returns the result of the pull back transformation on a + * contravariant vector, i.e. + * @f[ + * \textrm{det} \mathbf{F} \; \chi^{-1}\left(\bullet\right)^{\sharp} + * := \textrm{det} \mathbf{F} \; \mathbf{F}^{-1} \cdot \left(\bullet\right)^{\sharp} + * @f] + * + * @param[in] v The (spatial) vector to be operated on + * @param[in] F The deformation gradient tensor $\mathbf{F} \left( \mathbf{X} \right)$ + * @return $\textrm{det} \mathbf{F} \; \chi^{-1}\left( \mathbf{v} \right)$ + */ + template + Tensor<1,dim,Number> + pull_back (const Tensor<1,dim,Number> &v, + const Tensor<2,dim,Number> &F); + + /** + * Returns the result of the pull back transformation on a rank-2 + * contravariant tensor, i.e. + * @f[ + * \textrm{det} \mathbf{F} \; \chi^{-1}\left(\bullet\right)^{\sharp} + * := \textrm{det} \mathbf{F} \; \mathbf{F}^{-1} \cdot \left(\bullet\right)^{\sharp} \cdot \mathbf{F}^{-T} + * @f] + * + * @param[in] t The (spatial) tensor to be operated on + * @param[in] F The deformation gradient tensor $\mathbf{F} \left( \mathbf{X} \right)$ + * @return $\textrm{det} \mathbf{F} \; \chi^{-1}\left( \mathbf{t} \right)$ + */ + template + Tensor<2,dim,Number> + pull_back (const Tensor<2,dim,Number> &t, + const Tensor<2,dim,Number> &F); + + /** + * Returns the result of the pull back transformation on a rank-2 + * contravariant symmetric tensor, i.e. + * @f[ + * \textrm{det} \mathbf{F} \; \chi^{-1}\left(\bullet\right)^{\sharp} + * := \textrm{det} \mathbf{F} \; \mathbf{F}^{-1} \cdot \left(\bullet\right)^{\sharp} \cdot \mathbf{F}^{-T} + * @f] + * + * @param[in] t The (spatial) symmetric tensor to be operated on + * @param[in] F The deformation gradient tensor $\mathbf{F} \left( \mathbf{X} \right)$ + * @return $\textrm{det} \mathbf{F} \; \chi^{-1}\left( \mathbf{t} \right)$ + */ + template + SymmetricTensor<2,dim,Number> + pull_back (const SymmetricTensor<2,dim,Number> &t, + const Tensor<2,dim,Number> &F); + + /** + * Returns the result of the pull back transformation on a rank-4 + * contravariant tensor, i.e. (in index notation) + * @f[ + * \textrm{det} \mathbf{F} \; \left[ \chi^{-1}\left(\bullet\right)^{\sharp} \right]_{IJKL} + * := \textrm{det} \mathbf{F} \; F^{-1}_{Ii} F^{-1}_{Jj} \left(\bullet\right)^{\sharp}_{ijkl} F^{-1}_{Kk} F^{-1}_{Ll} + * @f] + * + * @param[in] h The (spatial) tensor to be operated on + * @param[in] F The deformation gradient tensor $\mathbf{F} \left( \mathbf{X} \right)$ + * @return $\textrm{det} \mathbf{F} \; \chi^{-1}\left( \mathbf{h} \right)$ + */ + template + Tensor<4,dim,Number> + pull_back (const Tensor<4,dim,Number> &h, + const Tensor<2,dim,Number> &F); + + /** + * Returns the result of the pull back transformation on a rank-4 + * contravariant symmetric tensor, i.e. (in index notation) + * @f[ + * \textrm{det} \mathbf{F} \; \left[ \chi^{-1}\left(\bullet\right)^{\sharp} \right]_{IJKL} + * := \textrm{det} \mathbf{F} \; F^{-1}_{Ii} F^{-1}_{Jj} \left(\bullet\right)^{\sharp}_{ijkl} F^{-1}_{Kk} F^{-1}_{Ll} + * @f] + * + * @param[in] h The (spatial) symmetric tensor to be operated on + * @param[in] F The deformation gradient tensor $\mathbf{F} \left( \mathbf{X} \right)$ + * @return $\textrm{det} \mathbf{F} \; \chi^{-1}\left( \mathbf{h} \right)$ + */ + template + SymmetricTensor<4,dim,Number> + pull_back (const SymmetricTensor<4,dim,Number> &h, + const Tensor<2,dim,Number> &F); + +//@} + } + + /** + * @name Special operations + */ +//@{ + + /** + * Returns the result of applying Nanson's formula for the transformation of + * the material surface area element $d\mathbf{A}$ to the current surfaces + * area element $d\mathbf{a}$ under the nonlinear transformation map + * $\mathbf{x} = \boldsymbol{\varphi} \left( \mathbf{X} \right)$. + * + * The returned result is the spatial normal scaled by the ratio of areas + * between the reference and spatial surface elements, i.e. + * @f[ + * \mathbf{n} \frac{da}{dA} + * := \textrm{det} \mathbf{F} \, \mathbf{F}^{-T} \cdot \mathbf{N} + * = \textrm{cof} \mathbf{F} \cdot \mathbf{N} \, . + * @f] + * + * @param[in] N The referential normal unit vector $\mathbf{N}$ + * @param[in] F The deformation gradient tensor $\mathbf{F} \left( \mathbf{X} \right)$ + * @return The scaled spatial normal vector $\mathbf{n} \frac{da}{dA}$ + * + * @dealiiHolzapfelA{75,2.55} + * @dealiiWriggersA{23,3.11} + */ + template + Tensor<1,dim,Number> + nansons_formula (const Tensor<1,dim,Number> &N, + const Tensor<2,dim,Number> &F); + +//@} + }; + +} + + + +#ifndef DOXYGEN + +// ------------------------- inline functions ------------------------ + +namespace internal +{ + namespace Physics + { + namespace + { + template + inline + Tensor<1,dim,Number> + transformation_contraction (const Tensor<1,dim,Number> &V, + const Tensor<2,dim,Number> &F) + { + return contract<1,0>(F, V); + } + + + + template + inline + Tensor<2,dim,Number> + transformation_contraction (const Tensor<2,dim,Number> &T, + const Tensor<2,dim,Number> &F) + { + return contract<1,1>(F,contract<1,0>(F, T)); + } + + + + template + inline + dealii::SymmetricTensor<2,dim,Number> + transformation_contraction (const dealii::SymmetricTensor<2,dim,Number> &T, + const Tensor<2,dim,Number> &F) + { + Tensor<2,dim,Number> tmp_1; + for (unsigned int i=0; i out; + for (unsigned int i=0; i + inline + Tensor<4,dim,Number> + transformation_contraction (const Tensor<4,dim,Number> &H, + const Tensor<2,dim,Number> &F) + { + // Its significantly quicker (in 3d) to push forward + // each index individually + return contract<1,3>(F,contract<1,2>(F,contract<1,1>(F,contract<1,0>(F, H)))); + } + + + + template + inline + dealii::SymmetricTensor<4,dim,Number> + transformation_contraction (const dealii::SymmetricTensor<4,dim,Number> &H, + const Tensor<2,dim,Number> &F) + { + // Its significantly quicker (in 3d) to push forward + // each index individually + + Tensor<4,dim,Number> tmp_1; + for (unsigned int i=0; i tmp_2; + for (unsigned int i=0; i out; + for (unsigned int i=0; i +inline +Tensor<1,dim,Number> +Physics::Transformations::Contravariant::push_forward (const Tensor<1,dim,Number> &V, + const Tensor<2,dim,Number> &F) +{ + return internal::Physics::transformation_contraction(V,F); +} + + + +template +inline +Tensor<2,dim,Number> +Physics::Transformations::Contravariant::push_forward (const Tensor<2,dim,Number> &T, + const Tensor<2,dim,Number> &F) +{ + return internal::Physics::transformation_contraction(T,F); +} + + + +template +inline +SymmetricTensor<2,dim,Number> +Physics::Transformations::Contravariant::push_forward (const SymmetricTensor<2,dim,Number> &T, + const Tensor<2,dim,Number> &F) +{ + return internal::Physics::transformation_contraction(T,F); +} + + + +template +inline +Tensor<4,dim,Number> +Physics::Transformations::Contravariant::push_forward (const Tensor<4,dim,Number> &H, + const Tensor<2,dim,Number> &F) +{ + return internal::Physics::transformation_contraction(H,F); +} + + + +template +inline +SymmetricTensor<4,dim,Number> +Physics::Transformations::Contravariant::push_forward (const SymmetricTensor<4,dim,Number> &H, + const Tensor<2,dim,Number> &F) +{ + return internal::Physics::transformation_contraction(H,F); +} + + + +template +inline +Tensor<1,dim,Number> +Physics::Transformations::Contravariant::pull_back (const Tensor<1,dim,Number> &v, + const Tensor<2,dim,Number> &F) +{ + return internal::Physics::transformation_contraction(v,invert(F)); +} + + + +template +inline +Tensor<2,dim,Number> +Physics::Transformations::Contravariant::pull_back (const Tensor<2,dim,Number> &t, + const Tensor<2,dim,Number> &F) +{ + return internal::Physics::transformation_contraction(t,invert(F)); +} + + + +template +inline +SymmetricTensor<2,dim,Number> +Physics::Transformations::Contravariant::pull_back (const SymmetricTensor<2,dim,Number> &t, + const Tensor<2,dim,Number> &F) +{ + return internal::Physics::transformation_contraction(t,invert(F)); +} + + + +template +inline +Tensor<4,dim,Number> +Physics::Transformations::Contravariant::pull_back (const Tensor<4,dim,Number> &h, + const Tensor<2,dim,Number> &F) +{ + return internal::Physics::transformation_contraction(h,invert(F)); +} + + + +template +inline +SymmetricTensor<4,dim,Number> +Physics::Transformations::Contravariant::pull_back (const SymmetricTensor<4,dim,Number> &h, + const Tensor<2,dim,Number> &F) +{ + return internal::Physics::transformation_contraction(h,invert(F)); +} + + + +template +inline +Tensor<1,dim,Number> +Physics::Transformations::Covariant::push_forward (const Tensor<1,dim,Number> &V, + const Tensor<2,dim,Number> &F) +{ + return internal::Physics::transformation_contraction(V,transpose(invert(F))); +} + + + +template +inline +Tensor<2,dim,Number> +Physics::Transformations::Covariant::push_forward (const Tensor<2,dim,Number> &T, + const Tensor<2,dim,Number> &F) +{ + return internal::Physics::transformation_contraction(T,transpose(invert(F))); +} + + + +template +inline +SymmetricTensor<2,dim,Number> +Physics::Transformations::Covariant::push_forward (const SymmetricTensor<2,dim,Number> &T, + const Tensor<2,dim,Number> &F) +{ + return internal::Physics::transformation_contraction(T,transpose(invert(F))); +} + + + +template +inline +Tensor<4,dim,Number> +Physics::Transformations::Covariant::push_forward (const Tensor<4,dim,Number> &H, + const Tensor<2,dim,Number> &F) +{ + return internal::Physics::transformation_contraction(H,transpose(invert(F))); +} + + + +template +inline +SymmetricTensor<4,dim,Number> +Physics::Transformations::Covariant::push_forward (const SymmetricTensor<4,dim,Number> &H, + const Tensor<2,dim,Number> &F) +{ + return internal::Physics::transformation_contraction(H,transpose(invert(F))); +} + + + +template +inline +Tensor<1,dim,Number> +Physics::Transformations::Covariant::pull_back (const Tensor<1,dim,Number> &v, + const Tensor<2,dim,Number> &F) +{ + return internal::Physics::transformation_contraction(v,transpose(F)); +} + + + +template +inline +Tensor<2,dim,Number> +Physics::Transformations::Covariant::pull_back (const Tensor<2,dim,Number> &t, + const Tensor<2,dim,Number> &F) +{ + return internal::Physics::transformation_contraction(t,transpose(F)); +} + + + +template +inline +SymmetricTensor<2,dim,Number> +Physics::Transformations::Covariant::pull_back (const SymmetricTensor<2,dim,Number> &t, + const Tensor<2,dim,Number> &F) +{ + return internal::Physics::transformation_contraction(t,transpose(F)); +} + + + +template +inline +Tensor<4,dim,Number> +Physics::Transformations::Covariant::pull_back (const Tensor<4,dim,Number> &h, + const Tensor<2,dim,Number> &F) +{ + return internal::Physics::transformation_contraction(h,transpose(F)); +} + + + +template +inline +SymmetricTensor<4,dim,Number> +Physics::Transformations::Covariant::pull_back (const SymmetricTensor<4,dim,Number> &h, + const Tensor<2,dim,Number> &F) +{ + return internal::Physics::transformation_contraction(h,transpose(F)); +} + + + +template +inline +Tensor<1,dim,Number> +Physics::Transformations::Piola::push_forward (const Tensor<1,dim,Number> &V, + const Tensor<2,dim,Number> &F) +{ + return Number(1.0/determinant(F))*Contravariant::push_forward(V,F); +} + + + +template +inline +Tensor<2,dim,Number> +Physics::Transformations::Piola::push_forward (const Tensor<2,dim,Number> &T, + const Tensor<2,dim,Number> &F) +{ + return Number(1.0/determinant(F))*Contravariant::push_forward(T,F); +} + + + +template +inline +SymmetricTensor<2,dim,Number> +Physics::Transformations::Piola::push_forward (const SymmetricTensor<2,dim,Number> &T, + const Tensor<2,dim,Number> &F) +{ + return Number(1.0/determinant(F))*Contravariant::push_forward(T,F); +} + + + +template +inline +Tensor<4,dim,Number> +Physics::Transformations::Piola::push_forward (const Tensor<4,dim,Number> &H, + const Tensor<2,dim,Number> &F) +{ + return Number(1.0/determinant(F))*Contravariant::push_forward(H,F); +} + + + +template +inline +SymmetricTensor<4,dim,Number> +Physics::Transformations::Piola::push_forward (const SymmetricTensor<4,dim,Number> &H, + const Tensor<2,dim,Number> &F) +{ + return Number(1.0/determinant(F))*Contravariant::push_forward(H,F); +} + + + +template +inline +Tensor<1,dim,Number> +Physics::Transformations::Piola::pull_back (const Tensor<1,dim,Number> &v, + const Tensor<2,dim,Number> &F) +{ + return Number(determinant(F))*Contravariant::pull_back(v,F); +} + + + +template +inline +Tensor<2,dim,Number> +Physics::Transformations::Piola::pull_back (const Tensor<2,dim,Number> &t, + const Tensor<2,dim,Number> &F) +{ + return Number(determinant(F))*Contravariant::pull_back(t,F); +} + + + +template +inline +SymmetricTensor<2,dim,Number> +Physics::Transformations::Piola::pull_back (const SymmetricTensor<2,dim,Number> &t, + const Tensor<2,dim,Number> &F) +{ + return Number(determinant(F))*Contravariant::pull_back(t,F); +} + + + +template +inline +Tensor<4,dim,Number> +Physics::Transformations::Piola::pull_back (const Tensor<4,dim,Number> &h, + const Tensor<2,dim,Number> &F) +{ + return Number(determinant(F))*Contravariant::pull_back(h,F); +} + + + +template +inline +SymmetricTensor<4,dim,Number> +Physics::Transformations::Piola::pull_back (const SymmetricTensor<4,dim,Number> &h, + const Tensor<2,dim,Number> &F) +{ + return Number(determinant(F))*Contravariant::pull_back(h,F); +} + + + +template +inline Tensor<1,dim,Number> +Physics::Transformations::nansons_formula (const Tensor<1,dim,Number> &N, + const Tensor<2,dim,Number> &F) +{ + return cofactor(F)*N; +} + +#endif // DOXYGEN + +DEAL_II_NAMESPACE_CLOSE + +#endif diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index 4d3e8f7b4f..b78b0a0f1b 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -48,6 +48,7 @@ ADD_SUBDIRECTORY(integrators) ADD_SUBDIRECTORY(matrix_free) ADD_SUBDIRECTORY(meshworker) ADD_SUBDIRECTORY(opencascade) +ADD_SUBDIRECTORY(physics) FOREACH(build ${DEAL_II_BUILD_TYPES}) STRING(TOLOWER ${build} build_lowercase) diff --git a/source/physics/CMakeLists.txt b/source/physics/CMakeLists.txt new file mode 100644 index 0000000000..392846dc2c --- /dev/null +++ b/source/physics/CMakeLists.txt @@ -0,0 +1,34 @@ +## --------------------------------------------------------------------- +## +## Copyright (C) 2016 by the deal.II authors +## +## This file is part of the deal.II library. +## +## The deal.II library is free software; you can use it, redistribute +## it, and/or modify it under the terms of the GNU Lesser General +## Public License as published by the Free Software Foundation; either +## version 2.1 of the License, or (at your option) any later version. +## The full text of the license can be found in the file LICENSE at +## the top level of the deal.II distribution. +## +## --------------------------------------------------------------------- + +# Expand instantiations in subdirectories +ADD_SUBDIRECTORY("elasticity") + +INCLUDE_DIRECTORIES(BEFORE ${CMAKE_CURRENT_BINARY_DIR}) + +SET(_src + transformations.cc + ) + +SET(_inst + transformations.inst.in + ) + +FILE(GLOB _header + ${CMAKE_SOURCE_DIR}/include/deal.II/physics/*.h + ) + +DEAL_II_ADD_LIBRARY(obj_physics OBJECT ${_src} ${_header} ${_inst}) +EXPAND_INSTANTIATIONS(obj_physics "${_inst}") diff --git a/source/physics/elasticity/CMakeLists.txt b/source/physics/elasticity/CMakeLists.txt new file mode 100644 index 0000000000..62d884a604 --- /dev/null +++ b/source/physics/elasticity/CMakeLists.txt @@ -0,0 +1,34 @@ +## --------------------------------------------------------------------- +## +## Copyright (C) 2016 by the deal.II authors +## +## This file is part of the deal.II library. +## +## The deal.II library is free software; you can use it, redistribute +## it, and/or modify it under the terms of the GNU Lesser General +## Public License as published by the Free Software Foundation; either +## version 2.1 of the License, or (at your option) any later version. +## The full text of the license can be found in the file LICENSE at +## the top level of the deal.II distribution. +## +## --------------------------------------------------------------------- + + +INCLUDE_DIRECTORIES(BEFORE ${CMAKE_CURRENT_BINARY_DIR}) + +SET(_src + kinematics.cc + standard_tensors.cc + ) + +SET(_inst + kinematics.inst.in + standard_tensors.inst.in + ) + +FILE(GLOB _header + ${CMAKE_SOURCE_DIR}/include/deal.II/physics/elasticity/*.h + ) + +DEAL_II_ADD_LIBRARY(obj_physics_elasticity OBJECT ${_src} ${_header} ${_inst}) +EXPAND_INSTANTIATIONS(obj_physics_elasticity "${_inst}") diff --git a/source/physics/elasticity/kinematics.cc b/source/physics/elasticity/kinematics.cc new file mode 100644 index 0000000000..c3c6fc04d5 --- /dev/null +++ b/source/physics/elasticity/kinematics.cc @@ -0,0 +1,23 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2016 by the deal.II authors +// +// This file is part of the deal.II library. +// +// The deal.II library is free software; you can use it, redistribute +// it, and/or modify it under the terms of the GNU Lesser General +// Public License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// The full text of the license can be found in the file LICENSE at +// the top level of the deal.II distribution. +// +// --------------------------------------------------------------------- + +#include + +DEAL_II_NAMESPACE_OPEN + +// explicit instantiations +#include "kinematics.inst" + +DEAL_II_NAMESPACE_CLOSE diff --git a/source/physics/elasticity/kinematics.inst.in b/source/physics/elasticity/kinematics.inst.in new file mode 100644 index 0000000000..8c34b48144 --- /dev/null +++ b/source/physics/elasticity/kinematics.inst.in @@ -0,0 +1,78 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2016 by the deal.II authors +// +// This file is part of the deal.II library. +// +// The deal.II library is free software; you can use it, redistribute +// it, and/or modify it under the terms of the GNU Lesser General +// Public License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// The full text of the license can be found in the file LICENSE at +// the top level of the deal.II distribution. +// +// --------------------------------------------------------------------- + + +for (deal_II_dimension : DIMENSIONS; number : REAL_SCALARS) +{ + + namespace Physics + \{ + namespace Elasticity + \{ + namespace Kinematics + \{ + template + Tensor<2,deal_II_dimension,number> + F(const Tensor<2,deal_II_dimension,number>&); + + template + Tensor<2,deal_II_dimension,number> + F_iso(const Tensor<2,deal_II_dimension,number>&); + + template + SymmetricTensor<2,deal_II_dimension,number> + F_vol(const Tensor<2,deal_II_dimension,number>&); + + template + SymmetricTensor<2,deal_II_dimension,number> + C(const Tensor<2,deal_II_dimension,number>&); + + template + SymmetricTensor<2,deal_II_dimension,number> + b(const Tensor<2,deal_II_dimension,number>&); + + template + SymmetricTensor<2,deal_II_dimension,number> + E(const Tensor<2,deal_II_dimension,number>&); + + template + SymmetricTensor<2,deal_II_dimension,number> + epsilon(const Tensor<2,deal_II_dimension,number>&); + + template + SymmetricTensor<2,deal_II_dimension,number> + e(const Tensor<2,deal_II_dimension,number>&); + + template + Tensor<2,deal_II_dimension,number> + l( + const Tensor<2,deal_II_dimension,number>&, + const Tensor<2,deal_II_dimension,number>&); + + template + SymmetricTensor<2,deal_II_dimension,number> + d( + const Tensor<2,deal_II_dimension,number>&, + const Tensor<2,deal_II_dimension,number>&); + + template + Tensor<2,deal_II_dimension,number> + w( + const Tensor<2,deal_II_dimension,number>&, + const Tensor<2,deal_II_dimension,number>&); + \} + \} + \} +} diff --git a/source/physics/elasticity/standard_tensors.cc b/source/physics/elasticity/standard_tensors.cc new file mode 100644 index 0000000000..02db6735c5 --- /dev/null +++ b/source/physics/elasticity/standard_tensors.cc @@ -0,0 +1,49 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2016 by the deal.II authors +// +// This file is part of the deal.II library. +// +// The deal.II library is free software; you can use it, redistribute +// it, and/or modify it under the terms of the GNU Lesser General +// Public License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// The full text of the license can be found in the file LICENSE at +// the top level of the deal.II distribution. +// +// --------------------------------------------------------------------- + +#include +#include + +DEAL_II_NAMESPACE_OPEN + + +template +const SymmetricTensor<2, dim> +Physics::Elasticity::StandardTensors::I = unit_symmetric_tensor(); + + + +template +const SymmetricTensor<4, dim> +Physics::Elasticity::StandardTensors::S = identity_tensor(); + + + +template +const SymmetricTensor<4, dim> +Physics::Elasticity::StandardTensors::IxI = outer_product(unit_symmetric_tensor(), + unit_symmetric_tensor()); + + + +template +const SymmetricTensor<4, dim> +Physics::Elasticity::StandardTensors::dev_P = deviator_tensor(); + + +// explicit instantiations +#include "standard_tensors.inst" + +DEAL_II_NAMESPACE_CLOSE diff --git a/source/physics/elasticity/standard_tensors.inst.in b/source/physics/elasticity/standard_tensors.inst.in new file mode 100644 index 0000000000..fd415e2a3b --- /dev/null +++ b/source/physics/elasticity/standard_tensors.inst.in @@ -0,0 +1,53 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2016 by the deal.II authors +// +// This file is part of the deal.II library. +// +// The deal.II library is free software; you can use it, redistribute +// it, and/or modify it under the terms of the GNU Lesser General +// Public License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// The full text of the license can be found in the file LICENSE at +// the top level of the deal.II distribution. +// +// --------------------------------------------------------------------- + + +for (deal_II_dimension : DIMENSIONS) +{ + namespace Physics + \{ + namespace Elasticity + \{ + template + class StandardTensors; + \} + \} +} + + +for (deal_II_dimension : DIMENSIONS; number : REAL_SCALARS) +{ + namespace Physics + \{ + namespace Elasticity + \{ + template + SymmetricTensor<4,deal_II_dimension,number> + StandardTensors::Dev_P(const Tensor<2,deal_II_dimension,number> &); + + template + SymmetricTensor<4,deal_II_dimension,number> + StandardTensors::Dev_P_T(const Tensor<2,deal_II_dimension,number> &); + + template + SymmetricTensor<2,deal_II_dimension,number> + StandardTensors::ddet_F_dC(const Tensor<2,deal_II_dimension,number> &); + + template + SymmetricTensor<4,deal_II_dimension,number> + StandardTensors::dC_inv_dC(const Tensor<2,deal_II_dimension,number> &); + \} + \} +} diff --git a/source/physics/transformations.cc b/source/physics/transformations.cc new file mode 100644 index 0000000000..cf5fe4eb80 --- /dev/null +++ b/source/physics/transformations.cc @@ -0,0 +1,23 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2016 by the deal.II authors +// +// This file is part of the deal.II library. +// +// The deal.II library is free software; you can use it, redistribute +// it, and/or modify it under the terms of the GNU Lesser General +// Public License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// The full text of the license can be found in the file LICENSE at +// the top level of the deal.II distribution. +// +// --------------------------------------------------------------------- + +#include + +DEAL_II_NAMESPACE_OPEN + +// explicit instantiations +#include "transformations.inst" + +DEAL_II_NAMESPACE_CLOSE diff --git a/source/physics/transformations.inst.in b/source/physics/transformations.inst.in new file mode 100644 index 0000000000..be632643bb --- /dev/null +++ b/source/physics/transformations.inst.in @@ -0,0 +1,221 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2016 by the deal.II authors +// +// This file is part of the deal.II library. +// +// The deal.II library is free software; you can use it, redistribute +// it, and/or modify it under the terms of the GNU Lesser General +// Public License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// The full text of the license can be found in the file LICENSE at +// the top level of the deal.II distribution. +// +// --------------------------------------------------------------------- + + +for (deal_II_dimension : DIMENSIONS; number : REAL_SCALARS) +{ + + namespace Physics + \{ + namespace Transformations + \{ + template + Tensor<1,deal_II_dimension,number> + nansons_formula ( + const Tensor<1,deal_II_dimension,number> &, + const Tensor<2,deal_II_dimension,number> &); + + namespace Contravariant + \{ + template + Tensor<1,deal_II_dimension,number> + push_forward ( + const Tensor<1,deal_II_dimension,number> &, + const Tensor<2,deal_II_dimension,number> &); + + template + Tensor<2,deal_II_dimension,number> + push_forward ( + const Tensor<2,deal_II_dimension,number> &, + const Tensor<2,deal_II_dimension,number> &); + + template + SymmetricTensor<2,deal_II_dimension,number> + push_forward ( + const SymmetricTensor<2,deal_II_dimension,number> &, + const Tensor<2,deal_II_dimension,number> &); + + template + Tensor<4,deal_II_dimension,number> + push_forward ( + const Tensor<4,deal_II_dimension,number> &, + const Tensor<2,deal_II_dimension,number> &); + + template + SymmetricTensor<4,deal_II_dimension,number> + push_forward ( + const SymmetricTensor<4,deal_II_dimension,number> &, + const Tensor<2,deal_II_dimension,number> &); + + template + Tensor<1,deal_II_dimension,number> + pull_back ( + const Tensor<1,deal_II_dimension,number> &, + const Tensor<2,deal_II_dimension,number> &); + + template + Tensor<2,deal_II_dimension,number> + pull_back ( + const Tensor<2,deal_II_dimension,number> &, + const Tensor<2,deal_II_dimension,number> &); + + template + SymmetricTensor<2,deal_II_dimension,number> + pull_back ( + const SymmetricTensor<2,deal_II_dimension,number> &, + const Tensor<2,deal_II_dimension,number> &); + + template + Tensor<4,deal_II_dimension,number> + pull_back ( + const Tensor<4,deal_II_dimension,number> &, + const Tensor<2,deal_II_dimension,number> &); + + template + SymmetricTensor<4,deal_II_dimension,number> + pull_back ( + const SymmetricTensor<4,deal_II_dimension,number> &, + const Tensor<2,deal_II_dimension,number> &); + \} + + namespace Covariant + \{ + template + Tensor<1,deal_II_dimension,number> + push_forward ( + const Tensor<1,deal_II_dimension,number> &, + const Tensor<2,deal_II_dimension,number> &); + + template + Tensor<2,deal_II_dimension,number> + push_forward ( + const Tensor<2,deal_II_dimension,number> &, + const Tensor<2,deal_II_dimension,number> &); + + template + SymmetricTensor<2,deal_II_dimension,number> + push_forward ( + const SymmetricTensor<2,deal_II_dimension,number> &, + const Tensor<2,deal_II_dimension,number> &); + + template + Tensor<4,deal_II_dimension,number> + push_forward ( + const Tensor<4,deal_II_dimension,number> &, + const Tensor<2,deal_II_dimension,number> &); + + template + SymmetricTensor<4,deal_II_dimension,number> + push_forward ( + const SymmetricTensor<4,deal_II_dimension,number> &, + const Tensor<2,deal_II_dimension,number> &); + + template + Tensor<1,deal_II_dimension,number> + pull_back ( + const Tensor<1,deal_II_dimension,number> &, + const Tensor<2,deal_II_dimension,number> &); + + template + Tensor<2,deal_II_dimension,number> + pull_back ( + const Tensor<2,deal_II_dimension,number> &, + const Tensor<2,deal_II_dimension,number> &); + + template + SymmetricTensor<2,deal_II_dimension,number> + pull_back ( + const SymmetricTensor<2,deal_II_dimension,number> &, + const Tensor<2,deal_II_dimension,number> &); + + template + Tensor<4,deal_II_dimension,number> + pull_back ( + const Tensor<4,deal_II_dimension,number> &, + const Tensor<2,deal_II_dimension,number> &); + + template + SymmetricTensor<4,deal_II_dimension,number> + pull_back ( + const SymmetricTensor<4,deal_II_dimension,number> &, + const Tensor<2,deal_II_dimension,number> &); + \} + + namespace Piola + \{ + template + Tensor<1,deal_II_dimension,number> + push_forward ( + const Tensor<1,deal_II_dimension,number> &, + const Tensor<2,deal_II_dimension,number> &); + + template + Tensor<2,deal_II_dimension,number> + push_forward ( + const Tensor<2,deal_II_dimension,number> &, + const Tensor<2,deal_II_dimension,number> &); + + template + SymmetricTensor<2,deal_II_dimension,number> + push_forward ( + const SymmetricTensor<2,deal_II_dimension,number> &, + const Tensor<2,deal_II_dimension,number> &); + + template + Tensor<4,deal_II_dimension,number> + push_forward ( + const Tensor<4,deal_II_dimension,number> &, + const Tensor<2,deal_II_dimension,number> &); + + template + SymmetricTensor<4,deal_II_dimension,number> + push_forward ( + const SymmetricTensor<4,deal_II_dimension,number> &, + const Tensor<2,deal_II_dimension,number> &); + + template + Tensor<1,deal_II_dimension,number> + pull_back ( + const Tensor<1,deal_II_dimension,number> &, + const Tensor<2,deal_II_dimension,number> &); + + template + Tensor<2,deal_II_dimension,number> + pull_back ( + const Tensor<2,deal_II_dimension,number> &, + const Tensor<2,deal_II_dimension,number> &); + + template + SymmetricTensor<2,deal_II_dimension,number> + pull_back ( + const SymmetricTensor<2,deal_II_dimension,number> &, + const Tensor<2,deal_II_dimension,number> &); + + template + Tensor<4,deal_II_dimension,number> + pull_back ( + const Tensor<4,deal_II_dimension,number> &, + const Tensor<2,deal_II_dimension,number> &); + + template + SymmetricTensor<4,deal_II_dimension,number> + pull_back ( + const SymmetricTensor<4,deal_II_dimension,number> &, + const Tensor<2,deal_II_dimension,number> &); + \} + + \} + \} +} diff --git a/tests/physics/CMakeLists.txt b/tests/physics/CMakeLists.txt new file mode 100644 index 0000000000..f8ac3eb029 --- /dev/null +++ b/tests/physics/CMakeLists.txt @@ -0,0 +1,4 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.8.9) +INCLUDE(../setup_testsubproject.cmake) +PROJECT(testsuite CXX) +DEAL_II_PICKUP_TESTS() diff --git a/tests/physics/elasticity-kinematics_01.cc b/tests/physics/elasticity-kinematics_01.cc new file mode 100644 index 0000000000..1b7921564f --- /dev/null +++ b/tests/physics/elasticity-kinematics_01.cc @@ -0,0 +1,190 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2016 by the deal.II authors +// +// This file is part of the deal.II library. +// +// The deal.II library is free software; you can use it, redistribute +// it, and/or modify it under the terms of the GNU Lesser General +// Public License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// The full text of the license can be found in the file LICENSE at +// the top level of the deal.II distribution. +// +// --------------------------------------------------------------------- + + +// test kinematic tensor definitions + +#include "../tests.h" +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +using namespace dealii; +using namespace dealii::Physics; +using namespace dealii::Physics::Elasticity; + +template +void +test_kinematic_tensors () +{ + const FESystem fe (FE_Q(1), dim); + const QGauss qf (2); + Triangulation tria; + GridGenerator::hyper_cube(tria, -1, 1); + DoFHandler dof_handler (tria); + dof_handler.distribute_dofs(fe); + + Vector soln_t (dof_handler.n_dofs()); + Vector soln_t1 (dof_handler.n_dofs()); + + for (typename DoFHandler::active_cell_iterator + cell = dof_handler.begin_active(); + cell != dof_handler.end(); ++cell) + { + for (unsigned int v=0; v::vertices_per_cell; ++v) + if (std::abs(cell->vertex(v)[0] - 1.0) < 1e-9) + soln_t[cell->vertex_dof_index(v,0)] = 1.0; + } + + const double delta_t = 2.0; + Vector dot_soln_t = soln_t; + dot_soln_t -= soln_t1; + dot_soln_t *= (1.0/delta_t); + + FEValuesExtractors::Vector u_fe (0); + std::vector< Tensor<2,dim> > qp_Grad_u_t; + std::vector< Tensor<2,dim> > qp_Grad_u_t1; + std::vector< Tensor<2,dim> > qp_dot_Grad_u_t; + std::vector< Tensor<2,dim> > qp_dot_grad_u_t; + + FEValues fe_values (fe, qf, update_gradients); + MappingQEulerian q1_mapping(1, dof_handler, soln_t); + FEValues fe_values_mapped (q1_mapping, fe, qf, update_gradients); + + for (typename DoFHandler::active_cell_iterator + cell = dof_handler.begin_active(); + cell != dof_handler.end(); ++cell) + { + fe_values.reinit(cell); + fe_values_mapped.reinit(cell); + + const unsigned int n_q_points = fe_values.get_quadrature().size(); + qp_Grad_u_t.resize(n_q_points); + qp_Grad_u_t1.resize(n_q_points); + qp_dot_Grad_u_t.resize(n_q_points); + qp_dot_grad_u_t.resize(n_q_points); + + fe_values[u_fe].get_function_gradients(soln_t, qp_Grad_u_t); + fe_values[u_fe].get_function_gradients(soln_t1, qp_Grad_u_t1); + fe_values[u_fe].get_function_gradients(dot_soln_t, qp_dot_Grad_u_t); + + fe_values_mapped[u_fe].get_function_gradients(dot_soln_t, qp_dot_grad_u_t); + + for (unsigned int q_point=0; q_point &Grad_u = qp_Grad_u_t[q_point]; + const Tensor<2,dim> &Grad_u_t1 = qp_Grad_u_t1[q_point]; + + // --- Rate independent --- + + // Deformation gradient tensor + const Tensor<2,dim> F_t1 = Kinematics::F(Grad_u_t1); + Assert((F_t1 - unit_symmetric_tensor()).norm() < tol, + ExcMessage("Incorrect computation of F_t1")); + const Tensor<2,dim> F = Kinematics::F(Grad_u); + Assert((F - (static_cast< Tensor<2,dim> >(unit_symmetric_tensor()) + Grad_u)).norm() < tol, + ExcMessage("Incorrect computation of F")); + + // Volumetric / isochoric split of deformation gradient + Assert(determinant(F) != 1.0, + ExcMessage("No volume change - cannot test vol/iso split")); + Assert(std::abs(determinant(Kinematics::F_iso(F)) - 1.0) < tol, + ExcMessage("F_iso is not volume preserving")); + Assert(std::abs(determinant(Kinematics::F_vol(F)) - determinant(F)) < tol, + ExcMessage("F_vol has no dilatating action")); + + // Right Cauchy-Green tensor + Assert((static_cast< Tensor<2,dim> >(Kinematics::C(F)) - transpose(F)*F).norm() < tol, + ExcMessage("Incorrect computation of C")); + + // Left Cauchy-Green tensor + Assert((static_cast< Tensor<2,dim> >(Kinematics::b(F)) - F*transpose(F)).norm() < tol, + ExcMessage("Incorrect computation of b")); + + // Small strain tensor + Assert((static_cast< Tensor<2,dim> >(Kinematics::epsilon(Grad_u)) - 0.5*(Grad_u + transpose(Grad_u))).norm() < tol, + ExcMessage("Incorrect computation of epsilon")); + + // Green-Lagrange strain tensor + Assert((static_cast< Tensor<2,dim> >(Kinematics::E(F)) - 0.5*(Grad_u + transpose(Grad_u) + transpose(Grad_u)*Grad_u)).norm() < tol, + ExcMessage("Incorrect computation of E")); + + // Almansi strain tensor + // Holzapfel 2.82 + Assert((static_cast< Tensor<2,dim> >(Kinematics::e(F)) - transpose(invert(F))*static_cast< Tensor<2,dim> >(Kinematics::E(F))*invert(F)).norm() < tol, + ExcMessage("Incorrect computation of e")); + + // --- Rate dependent --- + + // Material rates + const Tensor<2,dim> &F_dot = qp_dot_Grad_u_t[q_point]; + + // Material rate of deformation gradient tensor + Assert((F_dot - (1.0/delta_t)*(Grad_u-Grad_u_t1)).norm() < tol, + ExcMessage("Incorrect computation of F_dot")); + + // Spatial gradients + const Tensor<2,dim> &dot_grad_u = qp_dot_grad_u_t[q_point]; + + // Spatial velocity gradient + Assert((static_cast< Tensor<2,dim> >(Kinematics::l(F,F_dot)) - dot_grad_u).norm() < tol, + ExcMessage("Incorrect computation of l")); + + // Rate of deformation tensor + Assert((static_cast< Tensor<2,dim> >(Kinematics::d(F,F_dot)) - 0.5*(dot_grad_u + transpose(dot_grad_u))).norm() < tol, + ExcMessage("Incorrect computation of d")); + + // Rate of spin tensor + Assert((static_cast< Tensor<2,dim> >(Kinematics::w(F,F_dot)) - 0.5*(dot_grad_u - transpose(dot_grad_u))).norm() < tol, + ExcMessage("Incorrect computation of w")); + } + } +} + +int main () +{ + std::ofstream logfile("output"); + deallog << std::setprecision(3); + deallog.attach(logfile); + deallog.threshold_double(1.e-10); + + test_kinematic_tensors<2> (); + test_kinematic_tensors<3> (); + + deallog << "OK" << std::endl; +} diff --git a/tests/physics/elasticity-kinematics_01.output b/tests/physics/elasticity-kinematics_01.output new file mode 100644 index 0000000000..0fd8fc12f0 --- /dev/null +++ b/tests/physics/elasticity-kinematics_01.output @@ -0,0 +1,2 @@ + +DEAL::OK diff --git a/tests/physics/elasticity-standard_tensors_01.cc b/tests/physics/elasticity-standard_tensors_01.cc new file mode 100644 index 0000000000..2e9b08c4d8 --- /dev/null +++ b/tests/physics/elasticity-standard_tensors_01.cc @@ -0,0 +1,140 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2016 by the deal.II authors +// +// This file is part of the deal.II library. +// +// The deal.II library is free software; you can use it, redistribute +// it, and/or modify it under the terms of the GNU Lesser General +// Public License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// The full text of the license can be found in the file LICENSE at +// the top level of the deal.II distribution. +// +// --------------------------------------------------------------------- + + +// test standard tensor definitions + +#include "../tests.h" +#include +#include +#include +#include +#include +#include + +using namespace dealii::Physics::Elasticity; + +const double c10 = 10.0; +const double c01 = 20.0; + +// Consider a Mooney-Rivlin material: +// psi = c10.(I1 - dim) + c01.(I2 - dim) +// where I1 = I1(C), I2 = I2(C) +// Then dI1/dC = I and dI2/dC = I1.I - C +// and S = 2 dpsi/dC +template +SymmetricTensor<2,dim> +get_S (const Tensor<2,dim> &F) +{ + const SymmetricTensor<2,dim> C = symmetrize(transpose(F)*F); + const double I1 = first_invariant(C); + return 2.0*c10*StandardTensors::I + + 2.0*c01*(I1*StandardTensors::I - C); +} +// For isotropic media, tau = 2.b.dpsi/db == 2.dpsi/db . b +// where b = F.F^{T}, I1(b) == I1(C) and +// I2(b) == I2(C) +template +SymmetricTensor<2,dim> +get_tau (const Tensor<2,dim> &F) +{ + const SymmetricTensor<2,dim> b = symmetrize(F*transpose(F)); + const double I1 = first_invariant(b); + const SymmetricTensor<2,dim> + tmp = 2.0*c10*StandardTensors::I + + 2.0*c01*(I1*StandardTensors::I - b); + return symmetrize(static_cast< Tensor<2,dim> >(tmp)*static_cast< Tensor<2,dim> >(b)); +} + +template +void +test_standard_tensors () +{ + SymmetricTensor<2,dim> t; + for (unsigned int i=0; i::I*t - trace(t)) < 1e-14, + ExcInternalError()); + AssertThrow (std::fabs (t*StandardTensors::I - trace(t)) < 1e-14, + ExcInternalError()); + + // Check fourth-order identity tensor II: + AssertThrow (std::fabs ((StandardTensors::S*t - t).norm()) < 1e-14, + ExcInternalError()); + AssertThrow (std::fabs ((t*StandardTensors::S - t).norm()) < 1e-14, + ExcInternalError()); + + // Check fourth-order tensor IxI: + AssertThrow (std::fabs ((StandardTensors::IxI*t - trace(t)*unit_symmetric_tensor()).norm()) < 1e-14, + ExcInternalError()); + AssertThrow (std::fabs ((t*StandardTensors::IxI - trace(t)*unit_symmetric_tensor()).norm()) < 1e-14, + ExcInternalError()); + + // Check spatial deviatoric tensor dev_P: + AssertThrow (std::fabs ((StandardTensors::dev_P*t - (t - (trace(t)/dim)*unit_symmetric_tensor())).norm()) < 1e-14, + ExcInternalError()); + AssertThrow (std::fabs ((t*StandardTensors::dev_P - (t - (trace(t)/dim)*unit_symmetric_tensor())).norm()) < 1e-14, + ExcInternalError()); + + // Check referential deviatoric tensor Dev_P: + Tensor<2,dim> F (unit_symmetric_tensor()); + F[0][1] = 0.5; + F[1][0] = 0.25; + const Tensor<2,dim> F_inv = invert(F); + + // Pull-back a fictitious stress tensor, project it onto a deviatoric space, and + // then push it forward again + // tau = F.S.F^{T} --> S = F^{-1}*tau*F^{-T} + const SymmetricTensor<2,dim> s = symmetrize(F_inv*static_cast< Tensor<2,dim> >(t)*transpose(F_inv)); + const SymmetricTensor<2,dim> Dev_P_T_x_s = StandardTensors::Dev_P_T(F)*s; + const SymmetricTensor<2,dim> s_x_Dev_P = s*StandardTensors::Dev_P(F); + + // Note: The extra factor J^{2/dim} arises due to the definition of Dev_P + // including the factor J^{-2/dim}. Ultimately the stress definitions + // for s,t do not align with those required to have the direct relationship + // s*Dev_P == dev_P*t. For this we would need S = 2.dW/dC|_{C=\bar{C}} and + // t = F.S.F^{T} and \bar{C} = det(F)^{-2/dim} F^{T}.F . + AssertThrow (std::fabs ((symmetrize(std::pow(determinant(F), 2.0/dim)*F*static_cast< Tensor<2,dim> >(s_x_Dev_P)*transpose(F)) - StandardTensors::dev_P*t).norm()) < 1e-14, + ExcInternalError()); + AssertThrow (std::fabs ((symmetrize(std::pow(determinant(F), 2.0/dim)*F*static_cast< Tensor<2,dim> >(Dev_P_T_x_s)*transpose(F)) - StandardTensors::dev_P*t).norm()) < 1e-14, + ExcInternalError()); + + // Repeat the above exercise for a "real" material response + const Tensor<2,dim> F_bar = std::pow(determinant(F), -1.0/dim)*F; + const SymmetricTensor<2,dim> S_bar = get_S(F_bar); + const SymmetricTensor<2,dim> tau_bar = symmetrize(F_bar*static_cast< Tensor<2,dim> >(S_bar)*transpose(F_bar)); // Note: tau_bar = tau(F) |_{F = F_bar} + AssertThrow (std::fabs ((tau_bar - get_tau(F_bar)).norm()) < 1e-9, + ExcInternalError()); + const SymmetricTensor<2,dim> S_iso = S_bar*StandardTensors::Dev_P(F); + const SymmetricTensor<2,dim> tau_iso = StandardTensors::dev_P*tau_bar; + AssertThrow (std::fabs ((symmetrize(F*static_cast< Tensor<2,dim> >(S_iso)*transpose(F)) - tau_iso).norm()) < 1e-9, + ExcInternalError()); +} + +int main () +{ + std::ofstream logfile("output"); + deallog << std::setprecision(3); + deallog.attach(logfile); + deallog.threshold_double(1.e-10); + + test_standard_tensors<2> (); + test_standard_tensors<3> (); + + deallog << "OK" << std::endl; +} diff --git a/tests/physics/elasticity-standard_tensors_01.output b/tests/physics/elasticity-standard_tensors_01.output new file mode 100644 index 0000000000..0fd8fc12f0 --- /dev/null +++ b/tests/physics/elasticity-standard_tensors_01.output @@ -0,0 +1,2 @@ + +DEAL::OK diff --git a/tests/physics/prm/parameters-step-44.prm b/tests/physics/prm/parameters-step-44.prm new file mode 100644 index 0000000000..d803fc8955 --- /dev/null +++ b/tests/physics/prm/parameters-step-44.prm @@ -0,0 +1,75 @@ +# Listing of Parameters +# --------------------- +subsection Finite element system + # Displacement system polynomial order + set Polynomial degree = 1 + + # Gauss quadrature order + set Quadrature order = 2 +end + + +subsection Geometry + # Global refinement level + set Global refinement = 2 + + # Global grid scaling factor + set Grid scale = 1e-3 + + # Ratio of applied pressure to reference pressure + set Pressure ratio p/p0 = 100 +end + + +subsection Linear solver + # Linear solver iterations (multiples of the system matrix size) + # In 2-d, this value is best set at 2. In 3-d, a value of 1 work fine. + set Max iteration multiplier = 2 + + # Linear solver residual (scaled by residual norm) + set Residual = 1e-6 + + # Use static condensation and solve a 1-block system, or solve + # the full 3-block system using Linear Operators and the Schur + # complement + set Use static condensation = true + + # Preconditioner type + set Preconditioner type = ssor + + # Preconditioner relaxation value + set Preconditioner relaxation = 0.65 + + # Type of solver used to solve the linear system + set Solver type = CG +end + + +subsection Material properties + # Poisson's ratio + set Poisson's ratio = 0.4999 + + # Shear modulus + set Shear modulus = 80.194e6 +end + + +subsection Nonlinear solver + # Number of Newton-Raphson iterations allowed + set Max iterations Newton-Raphson = 10 + + # Displacement error tolerance + set Tolerance displacement = 1.0e-6 + + # Force residual tolerance + set Tolerance force = 1.0e-9 +end + + +subsection Time + # End time + set End time = 1 + + # Time step size + set Time step size = 0.1 +end diff --git a/tests/physics/step-44-standard_tensors-material_push_forward.cc b/tests/physics/step-44-standard_tensors-material_push_forward.cc new file mode 100644 index 0000000000..5fec894681 --- /dev/null +++ b/tests/physics/step-44-standard_tensors-material_push_forward.cc @@ -0,0 +1,2085 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2016 by the deal.II authors +// +// This file is part of the deal.II library. +// +// The deal.II library is free software; you can use it, redistribute +// it, and/or modify it under the terms of the GNU Lesser General +// Public License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// The full text of the license can be found in the file LICENSE at +// the top level of the deal.II distribution. +// +// --------------------------------------------------------------------- + +// A version of step-44 that checks that some of the definitions for standard +// tensors and kinematic quantities for elasticity are computed correctly +// Here the material is defined using referential quantities which are then +// pushed forward through the predefined transformations + +#include "../tests.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +namespace Step44 +{ + using namespace dealii; + namespace Parameters + { + struct FESystem + { + unsigned int poly_degree; + unsigned int quad_order; + static void + declare_parameters(ParameterHandler &prm); + void + parse_parameters(ParameterHandler &prm); + }; + void FESystem::declare_parameters(ParameterHandler &prm) + { + prm.enter_subsection("Finite element system"); + { + prm.declare_entry("Polynomial degree", "2", + Patterns::Integer(0), + "Displacement system polynomial order"); + prm.declare_entry("Quadrature order", "3", + Patterns::Integer(0), + "Gauss quadrature order"); + } + prm.leave_subsection(); + } + void FESystem::parse_parameters(ParameterHandler &prm) + { + prm.enter_subsection("Finite element system"); + { + poly_degree = prm.get_integer("Polynomial degree"); + quad_order = prm.get_integer("Quadrature order"); + } + prm.leave_subsection(); + } + struct Geometry + { + unsigned int global_refinement; + double scale; + double p_p0; + static void + declare_parameters(ParameterHandler &prm); + void + parse_parameters(ParameterHandler &prm); + }; + void Geometry::declare_parameters(ParameterHandler &prm) + { + prm.enter_subsection("Geometry"); + { + prm.declare_entry("Global refinement", "2", + Patterns::Integer(0), + "Global refinement level"); + prm.declare_entry("Grid scale", "1e-3", + Patterns::Double(0.0), + "Global grid scaling factor"); + prm.declare_entry("Pressure ratio p/p0", "100", + Patterns::Selection("20|40|60|80|100"), + "Ratio of applied pressure to reference pressure"); + } + prm.leave_subsection(); + } + void Geometry::parse_parameters(ParameterHandler &prm) + { + prm.enter_subsection("Geometry"); + { + global_refinement = prm.get_integer("Global refinement"); + scale = prm.get_double("Grid scale"); + p_p0 = prm.get_double("Pressure ratio p/p0"); + } + prm.leave_subsection(); + } + struct Materials + { + double nu; + double mu; + static void + declare_parameters(ParameterHandler &prm); + void + parse_parameters(ParameterHandler &prm); + }; + void Materials::declare_parameters(ParameterHandler &prm) + { + prm.enter_subsection("Material properties"); + { + prm.declare_entry("Poisson's ratio", "0.4999", + Patterns::Double(-1.0,0.5), + "Poisson's ratio"); + prm.declare_entry("Shear modulus", "80.194e6", + Patterns::Double(), + "Shear modulus"); + } + prm.leave_subsection(); + } + void Materials::parse_parameters(ParameterHandler &prm) + { + prm.enter_subsection("Material properties"); + { + nu = prm.get_double("Poisson's ratio"); + mu = prm.get_double("Shear modulus"); + } + prm.leave_subsection(); + } + struct LinearSolver + { + std::string type_lin; + double tol_lin; + double max_iterations_lin; + bool use_static_condensation; + std::string preconditioner_type; + double preconditioner_relaxation; + static void + declare_parameters(ParameterHandler &prm); + void + parse_parameters(ParameterHandler &prm); + }; + void LinearSolver::declare_parameters(ParameterHandler &prm) + { + prm.enter_subsection("Linear solver"); + { + prm.declare_entry("Solver type", "CG", + Patterns::Selection("CG|Direct"), + "Type of solver used to solve the linear system"); + prm.declare_entry("Residual", "1e-6", + Patterns::Double(0.0), + "Linear solver residual (scaled by residual norm)"); + prm.declare_entry("Max iteration multiplier", "1", + Patterns::Double(0.0), + "Linear solver iterations (multiples of the system matrix size)"); + prm.declare_entry("Use static condensation", "true", + Patterns::Bool(), + "Solve the full block system or a reduced problem"); + prm.declare_entry("Preconditioner type", "ssor", + Patterns::Selection("jacobi|ssor"), + "Type of preconditioner"); + prm.declare_entry("Preconditioner relaxation", "0.65", + Patterns::Double(0.0), + "Preconditioner relaxation value"); + } + prm.leave_subsection(); + } + void LinearSolver::parse_parameters(ParameterHandler &prm) + { + prm.enter_subsection("Linear solver"); + { + type_lin = prm.get("Solver type"); + tol_lin = prm.get_double("Residual"); + max_iterations_lin = prm.get_double("Max iteration multiplier"); + use_static_condensation = prm.get_bool("Use static condensation"); + preconditioner_type = prm.get("Preconditioner type"); + preconditioner_relaxation = prm.get_double("Preconditioner relaxation"); + } + prm.leave_subsection(); + } + struct NonlinearSolver + { + unsigned int max_iterations_NR; + double tol_f; + double tol_u; + static void + declare_parameters(ParameterHandler &prm); + void + parse_parameters(ParameterHandler &prm); + }; + void NonlinearSolver::declare_parameters(ParameterHandler &prm) + { + prm.enter_subsection("Nonlinear solver"); + { + prm.declare_entry("Max iterations Newton-Raphson", "10", + Patterns::Integer(0), + "Number of Newton-Raphson iterations allowed"); + prm.declare_entry("Tolerance force", "1.0e-9", + Patterns::Double(0.0), + "Force residual tolerance"); + prm.declare_entry("Tolerance displacement", "1.0e-6", + Patterns::Double(0.0), + "Displacement error tolerance"); + } + prm.leave_subsection(); + } + void NonlinearSolver::parse_parameters(ParameterHandler &prm) + { + prm.enter_subsection("Nonlinear solver"); + { + max_iterations_NR = prm.get_integer("Max iterations Newton-Raphson"); + tol_f = prm.get_double("Tolerance force"); + tol_u = prm.get_double("Tolerance displacement"); + } + prm.leave_subsection(); + } + struct Time + { + double delta_t; + double end_time; + static void + declare_parameters(ParameterHandler &prm); + void + parse_parameters(ParameterHandler &prm); + }; + void Time::declare_parameters(ParameterHandler &prm) + { + prm.enter_subsection("Time"); + { + prm.declare_entry("End time", "1", + Patterns::Double(), + "End time"); + prm.declare_entry("Time step size", "0.1", + Patterns::Double(), + "Time step size"); + } + prm.leave_subsection(); + } + void Time::parse_parameters(ParameterHandler &prm) + { + prm.enter_subsection("Time"); + { + end_time = prm.get_double("End time"); + delta_t = prm.get_double("Time step size"); + } + prm.leave_subsection(); + } + struct AllParameters : public FESystem, + public Geometry, + public Materials, + public LinearSolver, + public NonlinearSolver, + public Time + { + AllParameters(const std::string &input_file); + static void + declare_parameters(ParameterHandler &prm); + void + parse_parameters(ParameterHandler &prm); + }; + AllParameters::AllParameters(const std::string &input_file) + { + ParameterHandler prm; + declare_parameters(prm); + prm.read_input(input_file); + parse_parameters(prm); + } + void AllParameters::declare_parameters(ParameterHandler &prm) + { + FESystem::declare_parameters(prm); + Geometry::declare_parameters(prm); + Materials::declare_parameters(prm); + LinearSolver::declare_parameters(prm); + NonlinearSolver::declare_parameters(prm); + Time::declare_parameters(prm); + } + void AllParameters::parse_parameters(ParameterHandler &prm) + { + FESystem::parse_parameters(prm); + Geometry::parse_parameters(prm); + Materials::parse_parameters(prm); + LinearSolver::parse_parameters(prm); + NonlinearSolver::parse_parameters(prm); + Time::parse_parameters(prm); + } + } + class Time + { + public: + Time (const double time_end, + const double delta_t) + : + timestep(0), + time_current(0.0), + time_end(time_end), + delta_t(delta_t) + {} + virtual ~Time() + {} + double current() const + { + return time_current; + } + double end() const + { + return time_end; + } + double get_delta_t() const + { + return delta_t; + } + unsigned int get_timestep() const + { + return timestep; + } + void increment() + { + time_current += delta_t; + ++timestep; + } + private: + unsigned int timestep; + double time_current; + const double time_end; + const double delta_t; + }; + template + class Material_Compressible_Neo_Hook_Three_Field + { + public: + Material_Compressible_Neo_Hook_Three_Field(const double mu, + const double nu) + : + kappa((2.0 * mu * (1.0 + nu)) / (3.0 * (1.0 - 2.0 * nu))), + c_1(mu / 2.0), + p_tilde(0.0), + J_tilde(1.0), + det_F(1.0), + F(Physics::Elasticity::StandardTensors::I), + C_inv(Physics::Elasticity::StandardTensors::I) + { + Assert(kappa > 0, ExcInternalError()); + } + ~Material_Compressible_Neo_Hook_Three_Field() + {} + void update_material_data(const Tensor<2, dim> &F_in, + const double p_tilde_in, + const double J_tilde_in) + { + F = F_in; + det_F = determinant(F); + const Tensor<2,dim> F_iso = Physics::Elasticity::Kinematics::F_iso(F); + C_inv = symmetrize(invert(transpose(F)*F)); + p_tilde = p_tilde_in; + J_tilde = J_tilde_in; + Assert(det_F > 0, ExcInternalError()); + } + SymmetricTensor<2, dim> get_tau() const + { + // Zero strain --> zero stress + if (std::abs(det_F-1.0) > 1e-9) + { + static const double tol = 1e-12; + + // Verify the push-forward transformation + Assert((Physics::Transformations::Contravariant::push_forward(get_S_vol(), F)-get_tau_vol()).norm()/get_tau_vol().norm() < tol, ExcInternalError()); + Assert((Physics::Transformations::Contravariant::push_forward(get_S_iso(), F)-get_tau_iso()).norm()/get_tau_iso().norm() < tol, ExcInternalError()); + + // Verify the pull-back transformation + Assert((Physics::Transformations::Contravariant::pull_back(get_tau_vol(), F)-get_S_vol()).norm()/get_S_vol().norm() < tol, ExcInternalError()); + Assert((Physics::Transformations::Contravariant::pull_back(get_tau_iso(), F)-get_S_iso()).norm()/get_S_iso().norm() < tol, ExcInternalError()); + } + else + { + static const double tol = 1e-9; + + // Verify the push-forward transformation + Assert((Physics::Transformations::Contravariant::push_forward(get_S_vol(), F)-get_tau_vol()).norm() < tol, ExcInternalError()); + Assert((Physics::Transformations::Contravariant::push_forward(get_S_iso(), F)-get_tau_iso()).norm() < tol, ExcInternalError()); + + // Verify the pull-back transformation + Assert((Physics::Transformations::Contravariant::pull_back(get_tau_vol(), F)-get_S_vol()).norm() < tol, ExcInternalError()); + Assert((Physics::Transformations::Contravariant::pull_back(get_tau_iso(), F)-get_S_iso()).norm() < tol, ExcInternalError()); + } + + return Physics::Transformations::Contravariant::push_forward(get_S_iso() + get_S_vol(), F); + } + SymmetricTensor<4, dim> get_Jc() const + { + // Zero strain --> zero stress + if (std::abs(det_F-1.0) > 1e-9) + { + static const double tol = 1e-9; + + // Verify the push-forward transformation + Assert((Physics::Transformations::Contravariant::push_forward(get_H_vol(), F)-get_Jc_vol()).norm()/get_Jc_vol().norm() < tol, ExcInternalError()); + Assert((Physics::Transformations::Contravariant::push_forward(get_H_iso(), F)-get_Jc_iso()).norm()/get_Jc_iso().norm() < tol, ExcInternalError()); + + // Verify the pull-back transformation + Assert((Physics::Transformations::Contravariant::pull_back(get_Jc_vol(), F)-get_H_vol()).norm()/get_H_vol().norm() < tol, ExcInternalError()); + Assert((Physics::Transformations::Contravariant::pull_back(get_Jc_iso(), F)-get_H_iso()).norm()/get_H_iso().norm() < tol, ExcInternalError()); + } + else + { + static const double tol = 1e-6; + + // Verify the push-forward transformation + Assert((Physics::Transformations::Contravariant::push_forward(get_H_vol(), F)-get_Jc_vol()).norm() < tol, ExcInternalError()); + Assert((Physics::Transformations::Contravariant::push_forward(get_H_iso(), F)-get_Jc_iso()).norm() < tol, ExcInternalError()); + + // Verify the pull-back transformation + Assert((Physics::Transformations::Contravariant::pull_back(get_Jc_vol(), F)-get_H_vol()).norm() < tol, ExcInternalError()); + Assert((Physics::Transformations::Contravariant::pull_back(get_Jc_iso(), F)-get_H_iso()).norm() < tol, ExcInternalError()); + } + + return Physics::Transformations::Contravariant::push_forward(get_H_vol() + get_H_iso(), F); + } + double get_dPsi_vol_dJ() const + { + return (kappa / 2.0) * (J_tilde - 1.0 / J_tilde); + } + double get_d2Psi_vol_dJ2() const + { + return ( (kappa / 2.0) * (1.0 + 1.0 / (J_tilde * J_tilde))); + } + double get_det_F() const + { + return det_F; + } + double get_p_tilde() const + { + return p_tilde; + } + double get_J_tilde() const + { + return J_tilde; + } + protected: + const double kappa; + const double c_1; + double p_tilde; + double J_tilde; + double det_F; + Tensor<2, dim> F; + SymmetricTensor<2, dim> C_inv; + SymmetricTensor<2, dim> get_S_vol() const + { + // See Wriggers2008 equ 3.304 (3.126 == one field) + return p_tilde * det_F * C_inv; + } + SymmetricTensor<2, dim> get_S_iso() const + { + // Expansion of stress defintion via chain rule + return get_S_bar()*Physics::Elasticity::StandardTensors::Dev_P(F); + } + SymmetricTensor<2, dim> get_S_bar() const + { + // Derived from energy function + return 2.0 * c_1 * Physics::Elasticity::StandardTensors::I; + } + SymmetricTensor<4, dim> get_H_vol() const + { + const SymmetricTensor<4, dim> C_inv_x_C_inv + = outer_product(C_inv,C_inv); + return p_tilde * det_F + * ( C_inv_x_C_inv + + (2.0 * Physics::Elasticity::StandardTensors::dC_inv_dC(F)) ); + } + SymmetricTensor<4, dim> get_H_iso() const + { + // See Wriggers2008 (equ 3.253 == one field) + const SymmetricTensor<2,dim> C = Physics::Elasticity::Kinematics::C(F); + const SymmetricTensor<4, dim> C_inv_x_C_inv + = outer_product(C_inv,C_inv); + const SymmetricTensor<2, dim> S_bar = get_S_bar(); + const SymmetricTensor<2, dim> S_iso = get_S_iso(); + const SymmetricTensor<4, dim> S_iso_x_C_inv + = outer_product(S_iso,C_inv); + const SymmetricTensor<4, dim> C_inv_x_S_iso + = outer_product(C_inv,S_iso); + const SymmetricTensor<4, dim> H_bar = get_H_bar(); + + // Note: The is an unfortunate mistake in Wriggers2008 equ 3.253 relating + // to the first term here (the second term in the Wriggers2008 equation). + // --> The reference formula has the wrong sign for this term. + // See Pelteret2013 equ A.37 for the correct expression + // https://open.uct.ac.za/handle/11427/9519 + // http://jean-paul.pelteret.co.za/wp-content/papercite-data/pdf/pelteret2013b-phd_thesis.pdf + return - (2.0 / dim) * (S_bar*(std::pow(det_F, -2.0/dim)*C)) + * ((1.0 / dim)*C_inv_x_C_inv + Physics::Elasticity::StandardTensors::dC_inv_dC(F)) + - (2.0 / dim) * (S_iso_x_C_inv + C_inv_x_S_iso) + + Physics::Elasticity::StandardTensors::Dev_P_T(F) * H_bar + * Physics::Elasticity::StandardTensors::Dev_P(F); + } + SymmetricTensor<4, dim> get_H_bar() const + { + return SymmetricTensor<4, dim>(); + } + + //=== ALTERNATIVE IMPLEMENTATION === + SymmetricTensor<2, dim> get_tau_vol() const + { + return p_tilde * det_F * Physics::Elasticity::StandardTensors::I; + } + SymmetricTensor<2, dim> get_tau_iso() const + { + return Physics::Elasticity::StandardTensors::dev_P * get_tau_bar(); + } + SymmetricTensor<2, dim> get_tau_bar() const + { + const Tensor<2,dim> F_iso = Physics::Elasticity::Kinematics::F_iso(F); + const SymmetricTensor<2,dim> b_bar = Physics::Elasticity::Kinematics::b(F_iso); + return 2.0 * c_1 * b_bar; + } + SymmetricTensor<4, dim> get_Jc_vol() const + { + return p_tilde * det_F + * ( Physics::Elasticity::StandardTensors::IxI + - (2.0 * Physics::Elasticity::StandardTensors::S) ); + } + SymmetricTensor<4, dim> get_Jc_iso() const + { + const SymmetricTensor<2, dim> tau_bar = get_tau_bar(); + const SymmetricTensor<2, dim> tau_iso = get_tau_iso(); + const SymmetricTensor<4, dim> tau_iso_x_I + = outer_product(tau_iso, + Physics::Elasticity::StandardTensors::I); + const SymmetricTensor<4, dim> I_x_tau_iso + = outer_product(Physics::Elasticity::StandardTensors::I, + tau_iso); + const SymmetricTensor<4, dim> c_bar = get_c_bar(); + return (2.0 / dim) * trace(tau_bar) + * Physics::Elasticity::StandardTensors::dev_P + - (2.0 / dim) * (tau_iso_x_I + I_x_tau_iso) + + Physics::Elasticity::StandardTensors::dev_P * c_bar + * Physics::Elasticity::StandardTensors::dev_P; + } + SymmetricTensor<4, dim> get_c_bar() const + { + return SymmetricTensor<4, dim>(); + } + }; + template + class PointHistory + { + public: + PointHistory() + : + F_inv(Physics::Elasticity::StandardTensors::I), + tau(SymmetricTensor<2, dim>()), + d2Psi_vol_dJ2(0.0), + dPsi_vol_dJ(0.0), + Jc(SymmetricTensor<4, dim>()) + {} + virtual ~PointHistory() + {} + void setup_lqp (const Parameters::AllParameters ¶meters) + { + material.reset(new Material_Compressible_Neo_Hook_Three_Field(parameters.mu, + parameters.nu)); + update_values(Tensor<2, dim>(), 0.0, 1.0); + } + void update_values (const Tensor<2, dim> &Grad_u_n, + const double p_tilde, + const double J_tilde) + { + const Tensor<2, dim> F = Physics::Elasticity::Kinematics::F(Grad_u_n); + material->update_material_data(F, p_tilde, J_tilde); + F_inv = invert(F); + tau = material->get_tau(); + Jc = material->get_Jc(); + dPsi_vol_dJ = material->get_dPsi_vol_dJ(); + d2Psi_vol_dJ2 = material->get_d2Psi_vol_dJ2(); + } + double get_J_tilde() const + { + return material->get_J_tilde(); + } + double get_det_F() const + { + return material->get_det_F(); + } + const Tensor<2, dim> &get_F_inv() const + { + return F_inv; + } + double get_p_tilde() const + { + return material->get_p_tilde(); + } + const SymmetricTensor<2, dim> &get_tau() const + { + return tau; + } + double get_dPsi_vol_dJ() const + { + return dPsi_vol_dJ; + } + double get_d2Psi_vol_dJ2() const + { + return d2Psi_vol_dJ2; + } + const SymmetricTensor<4, dim> &get_Jc() const + { + return Jc; + } + private: + std_cxx11::shared_ptr< Material_Compressible_Neo_Hook_Three_Field > material; + Tensor<2, dim> F_inv; + SymmetricTensor<2, dim> tau; + double d2Psi_vol_dJ2; + double dPsi_vol_dJ; + SymmetricTensor<4, dim> Jc; + }; + template + class Solid + { + public: + Solid(const std::string &input_file); + virtual + ~Solid(); + void + run(); + private: + struct PerTaskData_K; + struct ScratchData_K; + struct PerTaskData_RHS; + struct ScratchData_RHS; + struct PerTaskData_SC; + struct ScratchData_SC; + struct PerTaskData_UQPH; + struct ScratchData_UQPH; + void + make_grid(); + void + system_setup(); + void + determine_component_extractors(); + void + assemble_system_tangent(); + void + assemble_system_tangent_one_cell(const typename DoFHandler::active_cell_iterator &cell, + ScratchData_K &scratch, + PerTaskData_K &data) const; + void + copy_local_to_global_K(const PerTaskData_K &data); + void + assemble_system_rhs(); + void + assemble_system_rhs_one_cell(const typename DoFHandler::active_cell_iterator &cell, + ScratchData_RHS &scratch, + PerTaskData_RHS &data) const; + void + copy_local_to_global_rhs(const PerTaskData_RHS &data); + void + assemble_sc(); + void + assemble_sc_one_cell(const typename DoFHandler::active_cell_iterator &cell, + ScratchData_SC &scratch, + PerTaskData_SC &data); + void + copy_local_to_global_sc(const PerTaskData_SC &data); + void + make_constraints(const int &it_nr); + void + setup_qph(); + void + update_qph_incremental(const BlockVector &solution_delta); + void + update_qph_incremental_one_cell(const typename DoFHandler::active_cell_iterator &cell, + ScratchData_UQPH &scratch, + PerTaskData_UQPH &data); + void + copy_local_to_global_UQPH(const PerTaskData_UQPH &/*data*/) + {} + void + solve_nonlinear_timestep(BlockVector &solution_delta); + std::pair + solve_linear_system(BlockVector &newton_update); + BlockVector + get_total_solution(const BlockVector &solution_delta) const; + void + output_results() const; + Parameters::AllParameters parameters; + double vol_reference; + Triangulation triangulation; + Time time; + mutable TimerOutput timer; + CellDataStorage::cell_iterator, + PointHistory > quadrature_point_history; + const unsigned int degree; + const FESystem fe; + DoFHandler dof_handler_ref; + const unsigned int dofs_per_cell; + const FEValuesExtractors::Vector u_fe; + const FEValuesExtractors::Scalar p_fe; + const FEValuesExtractors::Scalar J_fe; + static const unsigned int n_blocks = 3; + static const unsigned int n_components = dim + 2; + static const unsigned int first_u_component = 0; + static const unsigned int p_component = dim; + static const unsigned int J_component = dim + 1; + enum + { + u_dof = 0, + p_dof = 1, + J_dof = 2 + }; + std::vector dofs_per_block; + std::vector element_indices_u; + std::vector element_indices_p; + std::vector element_indices_J; + const QGauss qf_cell; + const QGauss qf_face; + const unsigned int n_q_points; + const unsigned int n_q_points_f; + ConstraintMatrix constraints; + BlockSparsityPattern sparsity_pattern; + BlockSparseMatrix tangent_matrix; + BlockVector system_rhs; + BlockVector solution_n; + ConditionalOStream pcout; + struct Errors + { + Errors() + : + norm(1.0), u(1.0), p(1.0), J(1.0) + {} + void reset() + { + norm = 1.0; + u = 1.0; + p = 1.0; + J = 1.0; + } + void normalise(const Errors &rhs) + { + if (rhs.norm != 0.0) + norm /= rhs.norm; + if (rhs.u != 0.0) + u /= rhs.u; + if (rhs.p != 0.0) + p /= rhs.p; + if (rhs.J != 0.0) + J /= rhs.J; + } + double norm, u, p, J; + }; + Errors error_residual, error_residual_0, error_residual_norm, error_update, + error_update_0, error_update_norm; + void + get_error_residual(Errors &error_residual); + void + get_error_update(const BlockVector &newton_update, + Errors &error_update); + std::pair + get_error_dilation() const; + double + compute_vol_current () const; + void + print_conv_header(); + void + print_conv_footer(); + }; + template + Solid::Solid(const std::string &input_file) + : + parameters(input_file), + triangulation(Triangulation::maximum_smoothing), + time(parameters.end_time, parameters.delta_t), + timer(deallog.get_file_stream(), + TimerOutput::never, + TimerOutput::wall_times), + degree(parameters.poly_degree), + fe(FE_Q(parameters.poly_degree), dim, // displacement + FE_DGPMonomial(parameters.poly_degree - 1), 1, // pressure + FE_DGPMonomial(parameters.poly_degree - 1), 1), // dilatation + dof_handler_ref(triangulation), + dofs_per_cell (fe.dofs_per_cell), + u_fe(first_u_component), + p_fe(p_component), + J_fe(J_component), + dofs_per_block(n_blocks), + qf_cell(parameters.quad_order), + qf_face(parameters.quad_order), + n_q_points (qf_cell.size()), + n_q_points_f (qf_face.size()), + pcout(deallog.get_file_stream()) + { + Assert(dim==2 || dim==3, ExcMessage("This problem only works in 2 or 3 space dimensions.")); + determine_component_extractors(); + } + template + Solid::~Solid() + { + dof_handler_ref.clear(); + } + template + void Solid::run() + { + make_grid(); + system_setup(); + { + ConstraintMatrix constraints; + constraints.close(); + const ComponentSelectFunction + J_mask (J_component, n_components); + VectorTools::project (dof_handler_ref, + constraints, + QGauss(degree+2), + J_mask, + solution_n); + } + output_results(); + time.increment(); + BlockVector solution_delta(dofs_per_block); + while (time.current() < time.end()) + { + solution_delta = 0.0; + solve_nonlinear_timestep(solution_delta); + solution_n += solution_delta; + output_results(); + time.increment(); + } + } + template + struct Solid::PerTaskData_K + { + FullMatrix cell_matrix; + std::vector local_dof_indices; + PerTaskData_K(const unsigned int dofs_per_cell) + : + cell_matrix(dofs_per_cell, dofs_per_cell), + local_dof_indices(dofs_per_cell) + {} + void reset() + { + cell_matrix = 0.0; + } + }; + template + struct Solid::ScratchData_K + { + FEValues fe_values_ref; + std::vector > Nx; + std::vector > > grad_Nx; + std::vector > > symm_grad_Nx; + ScratchData_K(const FiniteElement &fe_cell, + const QGauss &qf_cell, + const UpdateFlags uf_cell) + : + fe_values_ref(fe_cell, qf_cell, uf_cell), + Nx(qf_cell.size(), + std::vector(fe_cell.dofs_per_cell)), + grad_Nx(qf_cell.size(), + std::vector >(fe_cell.dofs_per_cell)), + symm_grad_Nx(qf_cell.size(), + std::vector > + (fe_cell.dofs_per_cell)) + {} + ScratchData_K(const ScratchData_K &rhs) + : + fe_values_ref(rhs.fe_values_ref.get_fe(), + rhs.fe_values_ref.get_quadrature(), + rhs.fe_values_ref.get_update_flags()), + Nx(rhs.Nx), + grad_Nx(rhs.grad_Nx), + symm_grad_Nx(rhs.symm_grad_Nx) + {} + void reset() + { + const unsigned int n_q_points = Nx.size(); + const unsigned int n_dofs_per_cell = Nx[0].size(); + for (unsigned int q_point = 0; q_point < n_q_points; ++q_point) + { + Assert( Nx[q_point].size() == n_dofs_per_cell, ExcInternalError()); + Assert( grad_Nx[q_point].size() == n_dofs_per_cell, + ExcInternalError()); + Assert( symm_grad_Nx[q_point].size() == n_dofs_per_cell, + ExcInternalError()); + for (unsigned int k = 0; k < n_dofs_per_cell; ++k) + { + Nx[q_point][k] = 0.0; + grad_Nx[q_point][k] = 0.0; + symm_grad_Nx[q_point][k] = 0.0; + } + } + } + }; + template + struct Solid::PerTaskData_RHS + { + Vector cell_rhs; + std::vector local_dof_indices; + PerTaskData_RHS(const unsigned int dofs_per_cell) + : + cell_rhs(dofs_per_cell), + local_dof_indices(dofs_per_cell) + {} + void reset() + { + cell_rhs = 0.0; + } + }; + template + struct Solid::ScratchData_RHS + { + FEValues fe_values_ref; + FEFaceValues fe_face_values_ref; + std::vector > Nx; + std::vector > > symm_grad_Nx; + ScratchData_RHS(const FiniteElement &fe_cell, + const QGauss &qf_cell, const UpdateFlags uf_cell, + const QGauss & qf_face, const UpdateFlags uf_face) + : + fe_values_ref(fe_cell, qf_cell, uf_cell), + fe_face_values_ref(fe_cell, qf_face, uf_face), + Nx(qf_cell.size(), + std::vector(fe_cell.dofs_per_cell)), + symm_grad_Nx(qf_cell.size(), + std::vector > + (fe_cell.dofs_per_cell)) + {} + ScratchData_RHS(const ScratchData_RHS &rhs) + : + fe_values_ref(rhs.fe_values_ref.get_fe(), + rhs.fe_values_ref.get_quadrature(), + rhs.fe_values_ref.get_update_flags()), + fe_face_values_ref(rhs.fe_face_values_ref.get_fe(), + rhs.fe_face_values_ref.get_quadrature(), + rhs.fe_face_values_ref.get_update_flags()), + Nx(rhs.Nx), + symm_grad_Nx(rhs.symm_grad_Nx) + {} + void reset() + { + const unsigned int n_q_points = Nx.size(); + const unsigned int n_dofs_per_cell = Nx[0].size(); + for (unsigned int q_point = 0; q_point < n_q_points; ++q_point) + { + Assert( Nx[q_point].size() == n_dofs_per_cell, ExcInternalError()); + Assert( symm_grad_Nx[q_point].size() == n_dofs_per_cell, + ExcInternalError()); + for (unsigned int k = 0; k < n_dofs_per_cell; ++k) + { + Nx[q_point][k] = 0.0; + symm_grad_Nx[q_point][k] = 0.0; + } + } + } + }; + template + struct Solid::PerTaskData_SC + { + FullMatrix cell_matrix; + std::vector local_dof_indices; + FullMatrix k_orig; + FullMatrix k_pu; + FullMatrix k_pJ; + FullMatrix k_JJ; + FullMatrix k_pJ_inv; + FullMatrix k_bbar; + FullMatrix A; + FullMatrix B; + FullMatrix C; + PerTaskData_SC(const unsigned int dofs_per_cell, + const unsigned int n_u, + const unsigned int n_p, + const unsigned int n_J) + : + cell_matrix(dofs_per_cell, dofs_per_cell), + local_dof_indices(dofs_per_cell), + k_orig(dofs_per_cell, dofs_per_cell), + k_pu(n_p, n_u), + k_pJ(n_p, n_J), + k_JJ(n_J, n_J), + k_pJ_inv(n_p, n_J), + k_bbar(n_u, n_u), + A(n_J,n_u), + B(n_J, n_u), + C(n_p, n_u) + {} + void reset() + {} + }; + template + struct Solid::ScratchData_SC + { + void reset() + {} + }; + template + struct Solid::PerTaskData_UQPH + { + void reset() + {} + }; + template + struct Solid::ScratchData_UQPH + { + const BlockVector &solution_total; + std::vector > solution_grads_u_total; + std::vector solution_values_p_total; + std::vector solution_values_J_total; + FEValues fe_values_ref; + ScratchData_UQPH(const FiniteElement &fe_cell, + const QGauss &qf_cell, + const UpdateFlags uf_cell, + const BlockVector &solution_total) + : + solution_total(solution_total), + solution_grads_u_total(qf_cell.size()), + solution_values_p_total(qf_cell.size()), + solution_values_J_total(qf_cell.size()), + fe_values_ref(fe_cell, qf_cell, uf_cell) + {} + ScratchData_UQPH(const ScratchData_UQPH &rhs) + : + solution_total(rhs.solution_total), + solution_grads_u_total(rhs.solution_grads_u_total), + solution_values_p_total(rhs.solution_values_p_total), + solution_values_J_total(rhs.solution_values_J_total), + fe_values_ref(rhs.fe_values_ref.get_fe(), + rhs.fe_values_ref.get_quadrature(), + rhs.fe_values_ref.get_update_flags()) + {} + void reset() + { + const unsigned int n_q_points = solution_grads_u_total.size(); + for (unsigned int q = 0; q < n_q_points; ++q) + { + solution_grads_u_total[q] = 0.0; + solution_values_p_total[q] = 0.0; + solution_values_J_total[q] = 0.0; + } + } + }; + template + void Solid::make_grid() + { + GridGenerator::hyper_rectangle(triangulation, + (dim==3 ? Point(0.0, 0.0, 0.0) : Point(0.0, 0.0)), + (dim==3 ? Point(1.0, 1.0, 1.0) : Point(1.0, 1.0)), + true); + GridTools::scale(parameters.scale, triangulation); + triangulation.refine_global(std::max (1U, parameters.global_refinement)); + vol_reference = GridTools::volume(triangulation); + pcout << "Grid:\n\t Reference volume: " << vol_reference << std::endl; + typename Triangulation::active_cell_iterator cell = + triangulation.begin_active(), endc = triangulation.end(); + for (; cell != endc; ++cell) + for (unsigned int face = 0; + face < GeometryInfo::faces_per_cell; ++face) + { + if (cell->face(face)->at_boundary() == true + && + cell->face(face)->center()[1] == 1.0 * parameters.scale) + { + if (dim==3) + { + if (cell->face(face)->center()[0] < 0.5 * parameters.scale + && + cell->face(face)->center()[2] < 0.5 * parameters.scale) + cell->face(face)->set_boundary_id(6); + } + else + { + if (cell->face(face)->center()[0] < 0.5 * parameters.scale) + cell->face(face)->set_boundary_id(6); + } + } + } + } + template + void Solid::system_setup() + { + timer.enter_subsection("Setup system"); + std::vector block_component(n_components, u_dof); // Displacement + block_component[p_component] = p_dof; // Pressure + block_component[J_component] = J_dof; // Dilatation + dof_handler_ref.distribute_dofs(fe); + DoFRenumbering::Cuthill_McKee(dof_handler_ref); + DoFRenumbering::component_wise(dof_handler_ref, block_component); + DoFTools::count_dofs_per_block(dof_handler_ref, dofs_per_block, + block_component); + pcout << "Triangulation:" + << "\n\t Number of active cells: " << triangulation.n_active_cells() + << "\n\t Number of degrees of freedom: " << dof_handler_ref.n_dofs() + << std::endl; + tangent_matrix.clear(); + { + const types::global_dof_index n_dofs_u = dofs_per_block[u_dof]; + const types::global_dof_index n_dofs_p = dofs_per_block[p_dof]; + const types::global_dof_index n_dofs_J = dofs_per_block[J_dof]; + BlockDynamicSparsityPattern dsp(n_blocks, n_blocks); + dsp.block(u_dof, u_dof).reinit(n_dofs_u, n_dofs_u); + dsp.block(u_dof, p_dof).reinit(n_dofs_u, n_dofs_p); + dsp.block(u_dof, J_dof).reinit(n_dofs_u, n_dofs_J); + dsp.block(p_dof, u_dof).reinit(n_dofs_p, n_dofs_u); + dsp.block(p_dof, p_dof).reinit(n_dofs_p, n_dofs_p); + dsp.block(p_dof, J_dof).reinit(n_dofs_p, n_dofs_J); + dsp.block(J_dof, u_dof).reinit(n_dofs_J, n_dofs_u); + dsp.block(J_dof, p_dof).reinit(n_dofs_J, n_dofs_p); + dsp.block(J_dof, J_dof).reinit(n_dofs_J, n_dofs_J); + dsp.collect_sizes(); + Table<2, DoFTools::Coupling> coupling(n_components, n_components); + for (unsigned int ii = 0; ii < n_components; ++ii) + for (unsigned int jj = 0; jj < n_components; ++jj) + if (((ii < p_component) && (jj == J_component)) + || ((ii == J_component) && (jj < p_component)) + || ((ii == p_component) && (jj == p_component))) + coupling[ii][jj] = DoFTools::none; + else + coupling[ii][jj] = DoFTools::always; + DoFTools::make_sparsity_pattern(dof_handler_ref, + coupling, + dsp, + constraints, + false); + sparsity_pattern.copy_from(dsp); + } + tangent_matrix.reinit(sparsity_pattern); + system_rhs.reinit(dofs_per_block); + system_rhs.collect_sizes(); + solution_n.reinit(dofs_per_block); + solution_n.collect_sizes(); + setup_qph(); + timer.leave_subsection(); + } + template + void + Solid::determine_component_extractors() + { + element_indices_u.clear(); + element_indices_p.clear(); + element_indices_J.clear(); + for (unsigned int k = 0; k < fe.dofs_per_cell; ++k) + { + const unsigned int k_group = fe.system_to_base_index(k).first.first; + if (k_group == u_dof) + element_indices_u.push_back(k); + else if (k_group == p_dof) + element_indices_p.push_back(k); + else if (k_group == J_dof) + element_indices_J.push_back(k); + else + { + Assert(k_group <= J_dof, ExcInternalError()); + } + } + } + template + void Solid::setup_qph() + { + pcout << " Setting up quadrature point data..." << std::endl; + quadrature_point_history.initialize(triangulation.begin_active(), + triangulation.end(), + n_q_points); + for (typename Triangulation::active_cell_iterator cell = + triangulation.begin_active(); cell != triangulation.end(); ++cell) + { + const std::vector > > lqph = + quadrature_point_history.get_data(cell); + Assert(lqph.size() == n_q_points, ExcInternalError()); + for (unsigned int q_point = 0; q_point < n_q_points; ++q_point) + lqph[q_point]->setup_lqp(parameters); + } + } + template + void Solid::update_qph_incremental(const BlockVector &solution_delta) + { + timer.enter_subsection("Update QPH data"); + pcout << " UQPH " << std::flush; + const BlockVector solution_total(get_total_solution(solution_delta)); + const UpdateFlags uf_UQPH(update_values | update_gradients); + PerTaskData_UQPH per_task_data_UQPH; + ScratchData_UQPH scratch_data_UQPH(fe, qf_cell, uf_UQPH, solution_total); + WorkStream::run(dof_handler_ref.begin_active(), + dof_handler_ref.end(), + *this, + &Solid::update_qph_incremental_one_cell, + &Solid::copy_local_to_global_UQPH, + scratch_data_UQPH, + per_task_data_UQPH); + timer.leave_subsection(); + } + template + void + Solid::update_qph_incremental_one_cell(const typename DoFHandler::active_cell_iterator &cell, + ScratchData_UQPH &scratch, + PerTaskData_UQPH &/*data*/) + { + const std::vector > > lqph = + quadrature_point_history.get_data(cell); + Assert(lqph.size() == n_q_points, ExcInternalError()); + Assert(scratch.solution_grads_u_total.size() == n_q_points, + ExcInternalError()); + Assert(scratch.solution_values_p_total.size() == n_q_points, + ExcInternalError()); + Assert(scratch.solution_values_J_total.size() == n_q_points, + ExcInternalError()); + scratch.reset(); + scratch.fe_values_ref.reinit(cell); + scratch.fe_values_ref[u_fe].get_function_gradients(scratch.solution_total, + scratch.solution_grads_u_total); + scratch.fe_values_ref[p_fe].get_function_values(scratch.solution_total, + scratch.solution_values_p_total); + scratch.fe_values_ref[J_fe].get_function_values(scratch.solution_total, + scratch.solution_values_J_total); + for (unsigned int q_point = 0; q_point < n_q_points; ++q_point) + lqph[q_point]->update_values(scratch.solution_grads_u_total[q_point], + scratch.solution_values_p_total[q_point], + scratch.solution_values_J_total[q_point]); + } + template + void + Solid::solve_nonlinear_timestep(BlockVector &solution_delta) + { + pcout << std::endl << "Timestep " << time.get_timestep() << " @ " + << time.current() << "s" << std::endl; + BlockVector newton_update(dofs_per_block); + error_residual.reset(); + error_residual_0.reset(); + error_residual_norm.reset(); + error_update.reset(); + error_update_0.reset(); + error_update_norm.reset(); + print_conv_header(); + unsigned int newton_iteration = 0; + for (; newton_iteration < parameters.max_iterations_NR; + ++newton_iteration) + { + pcout << " " << std::setw(2) << newton_iteration << " " << std::flush; + tangent_matrix = 0.0; + system_rhs = 0.0; + assemble_system_rhs(); + get_error_residual(error_residual); + if (newton_iteration == 0) + error_residual_0 = error_residual; + error_residual_norm = error_residual; + error_residual_norm.normalise(error_residual_0); + if (newton_iteration > 0 && error_update_norm.u <= parameters.tol_u + && error_residual_norm.u <= parameters.tol_f) + { + pcout << " CONVERGED! " << std::endl; + print_conv_footer(); + break; + } + assemble_system_tangent(); + make_constraints(newton_iteration); + constraints.condense(tangent_matrix, system_rhs); + const std::pair + lin_solver_output = solve_linear_system(newton_update); + get_error_update(newton_update, error_update); + if (newton_iteration == 0) + error_update_0 = error_update; + error_update_norm = error_update; + error_update_norm.normalise(error_update_0); + solution_delta += newton_update; + update_qph_incremental(solution_delta); + pcout << " | " << std::fixed << std::setprecision(3) << std::setw(7) + << std::scientific << lin_solver_output.first << " " + << lin_solver_output.second << " " << error_residual_norm.norm + << " " << error_residual_norm.u << " " + << error_residual_norm.p << " " << error_residual_norm.J + << " " << error_update_norm.norm << " " << error_update_norm.u + << " " << error_update_norm.p << " " << error_update_norm.J + << " " << std::endl; + } + AssertThrow (newton_iteration <= parameters.max_iterations_NR, + ExcMessage("No convergence in nonlinear solver!")); + } + template + void Solid::print_conv_header() + { + static const unsigned int l_width = 155; + for (unsigned int i = 0; i < l_width; ++i) + pcout << "_"; + pcout << std::endl; + pcout << " SOLVER STEP " + << " | LIN_IT LIN_RES RES_NORM " + << " RES_U RES_P RES_J NU_NORM " + << " NU_U NU_P NU_J " << std::endl; + for (unsigned int i = 0; i < l_width; ++i) + pcout << "_"; + pcout << std::endl; + } + template + void Solid::print_conv_footer() + { + static const unsigned int l_width = 155; + for (unsigned int i = 0; i < l_width; ++i) + pcout << "_"; + pcout << std::endl; + const std::pair error_dil = get_error_dilation(); + pcout << "Relative errors:" << std::endl + << "Displacement:\t" << error_update.u / error_update_0.u << std::endl + << "Force: \t\t" << error_residual.u / error_residual_0.u << std::endl + << "Dilatation:\t" << error_dil.first << std::endl + << "v / V_0:\t" << error_dil.second *vol_reference << " / " << vol_reference + << " = " << error_dil.second << std::endl; + } + template + double + Solid::compute_vol_current() const + { + double vol_current = 0.0; + FEValues fe_values_ref(fe, qf_cell, update_JxW_values); + for (typename Triangulation::active_cell_iterator + cell = triangulation.begin_active(); + cell != triangulation.end(); ++cell) + { + fe_values_ref.reinit(cell); + const std::vector > > lqph = + quadrature_point_history.get_data(cell); + Assert(lqph.size() == n_q_points, ExcInternalError()); + for (unsigned int q_point = 0; q_point < n_q_points; ++q_point) + { + const double det_F_qp = lqph[q_point]->get_det_F(); + const double JxW = fe_values_ref.JxW(q_point); + vol_current += det_F_qp * JxW; + } + } + Assert(vol_current > 0.0, ExcInternalError()); + return vol_current; + } + template + std::pair + Solid::get_error_dilation() const + { + double dil_L2_error = 0.0; + FEValues fe_values_ref(fe, qf_cell, update_JxW_values); + for (typename Triangulation::active_cell_iterator + cell = triangulation.begin_active(); + cell != triangulation.end(); ++cell) + { + fe_values_ref.reinit(cell); + const std::vector > > lqph = + quadrature_point_history.get_data(cell); + Assert(lqph.size() == n_q_points, ExcInternalError()); + for (unsigned int q_point = 0; q_point < n_q_points; ++q_point) + { + const double det_F_qp = lqph[q_point]->get_det_F(); + const double J_tilde_qp = lqph[q_point]->get_J_tilde(); + const double the_error_qp_squared = std::pow((det_F_qp - J_tilde_qp), + 2); + const double JxW = fe_values_ref.JxW(q_point); + dil_L2_error += the_error_qp_squared * JxW; + } + } + return std::make_pair(std::sqrt(dil_L2_error), + compute_vol_current() / vol_reference); + } + template + void Solid::get_error_residual(Errors &error_residual) + { + BlockVector error_res(dofs_per_block); + for (unsigned int i = 0; i < dof_handler_ref.n_dofs(); ++i) + if (!constraints.is_constrained(i)) + error_res(i) = system_rhs(i); + error_residual.norm = error_res.l2_norm(); + error_residual.u = error_res.block(u_dof).l2_norm(); + error_residual.p = error_res.block(p_dof).l2_norm(); + error_residual.J = error_res.block(J_dof).l2_norm(); + } + template + void Solid::get_error_update(const BlockVector &newton_update, + Errors &error_update) + { + BlockVector error_ud(dofs_per_block); + for (unsigned int i = 0; i < dof_handler_ref.n_dofs(); ++i) + if (!constraints.is_constrained(i)) + error_ud(i) = newton_update(i); + error_update.norm = error_ud.l2_norm(); + error_update.u = error_ud.block(u_dof).l2_norm(); + error_update.p = error_ud.block(p_dof).l2_norm(); + error_update.J = error_ud.block(J_dof).l2_norm(); + } + template + BlockVector + Solid::get_total_solution(const BlockVector &solution_delta) const + { + BlockVector solution_total(solution_n); + solution_total += solution_delta; + return solution_total; + } + template + void Solid::assemble_system_tangent() + { + timer.enter_subsection("Assemble tangent matrix"); + pcout << " ASM_K " << std::flush; + tangent_matrix = 0.0; + const UpdateFlags uf_cell(update_values | + update_gradients | + update_JxW_values); + PerTaskData_K per_task_data(dofs_per_cell); + ScratchData_K scratch_data(fe, qf_cell, uf_cell); + WorkStream::run(dof_handler_ref.begin_active(), + dof_handler_ref.end(), + std_cxx11::bind(&Solid::assemble_system_tangent_one_cell, + this, + std_cxx11::_1, + std_cxx11::_2, + std_cxx11::_3), + std_cxx11::bind(&Solid::copy_local_to_global_K, + this, + std_cxx11::_1), + scratch_data, + per_task_data); + timer.leave_subsection(); + } + template + void Solid::copy_local_to_global_K(const PerTaskData_K &data) + { + for (unsigned int i = 0; i < dofs_per_cell; ++i) + for (unsigned int j = 0; j < dofs_per_cell; ++j) + tangent_matrix.add(data.local_dof_indices[i], + data.local_dof_indices[j], + data.cell_matrix(i, j)); + } + template + void + Solid::assemble_system_tangent_one_cell(const typename DoFHandler::active_cell_iterator &cell, + ScratchData_K &scratch, + PerTaskData_K &data) const + { + data.reset(); + scratch.reset(); + scratch.fe_values_ref.reinit(cell); + cell->get_dof_indices(data.local_dof_indices); + const std::vector > > lqph = + quadrature_point_history.get_data(cell); + Assert(lqph.size() == n_q_points, ExcInternalError()); + for (unsigned int q_point = 0; q_point < n_q_points; ++q_point) + { + const Tensor<2, dim> F_inv = lqph[q_point]->get_F_inv(); + for (unsigned int k = 0; k < dofs_per_cell; ++k) + { + const unsigned int k_group = fe.system_to_base_index(k).first.first; + if (k_group == u_dof) + { + scratch.grad_Nx[q_point][k] = scratch.fe_values_ref[u_fe].gradient(k, q_point) + * F_inv; + scratch.symm_grad_Nx[q_point][k] = symmetrize(scratch.grad_Nx[q_point][k]); + } + else if (k_group == p_dof) + scratch.Nx[q_point][k] = scratch.fe_values_ref[p_fe].value(k, + q_point); + else if (k_group == J_dof) + scratch.Nx[q_point][k] = scratch.fe_values_ref[J_fe].value(k, + q_point); + else + Assert(k_group <= J_dof, ExcInternalError()); + } + } + for (unsigned int q_point = 0; q_point < n_q_points; ++q_point) + { + const Tensor<2, dim> tau = lqph[q_point]->get_tau(); + const SymmetricTensor<4, dim> Jc = lqph[q_point]->get_Jc(); + const double d2Psi_vol_dJ2 = lqph[q_point]->get_d2Psi_vol_dJ2(); + const double det_F = lqph[q_point]->get_det_F(); + const std::vector + &N = scratch.Nx[q_point]; + const std::vector > + &symm_grad_Nx = scratch.symm_grad_Nx[q_point]; + const std::vector > + &grad_Nx = scratch.grad_Nx[q_point]; + const double JxW = scratch.fe_values_ref.JxW(q_point); + for (unsigned int i = 0; i < dofs_per_cell; ++i) + { + const unsigned int component_i = fe.system_to_component_index(i).first; + const unsigned int i_group = fe.system_to_base_index(i).first.first; + for (unsigned int j = 0; j <= i; ++j) + { + const unsigned int component_j = fe.system_to_component_index(j).first; + const unsigned int j_group = fe.system_to_base_index(j).first.first; + if ((i_group == j_group) && (i_group == u_dof)) + { + data.cell_matrix(i, j) += symm_grad_Nx[i] * Jc // The material contribution: + * symm_grad_Nx[j] * JxW; + if (component_i == component_j) // geometrical stress contribution + data.cell_matrix(i, j) += grad_Nx[i][component_i] * tau + * grad_Nx[j][component_j] * JxW; + } + else if ((i_group == p_dof) && (j_group == u_dof)) + { + data.cell_matrix(i, j) += N[i] * det_F + * (symm_grad_Nx[j] + * Physics::Elasticity::StandardTensors::I) + * JxW; + } + else if ((i_group == J_dof) && (j_group == p_dof)) + data.cell_matrix(i, j) -= N[i] * N[j] * JxW; + else if ((i_group == j_group) && (i_group == J_dof)) + data.cell_matrix(i, j) += N[i] * d2Psi_vol_dJ2 * N[j] * JxW; + else + Assert((i_group <= J_dof) && (j_group <= J_dof), + ExcInternalError()); + } + } + } + for (unsigned int i = 0; i < dofs_per_cell; ++i) + for (unsigned int j = i + 1; j < dofs_per_cell; ++j) + data.cell_matrix(i, j) = data.cell_matrix(j, i); + } + template + void Solid::assemble_system_rhs() + { + timer.enter_subsection("Assemble system right-hand side"); + pcout << " ASM_R " << std::flush; + system_rhs = 0.0; + const UpdateFlags uf_cell(update_values | + update_gradients | + update_JxW_values); + const UpdateFlags uf_face(update_values | + update_normal_vectors | + update_JxW_values); + PerTaskData_RHS per_task_data(dofs_per_cell); + ScratchData_RHS scratch_data(fe, qf_cell, uf_cell, qf_face, uf_face); + WorkStream::run(dof_handler_ref.begin_active(), + dof_handler_ref.end(), + std_cxx11::bind(&Solid::assemble_system_rhs_one_cell, + this, + std_cxx11::_1, + std_cxx11::_2, + std_cxx11::_3), + std_cxx11::bind(&Solid::copy_local_to_global_rhs, + this, + std_cxx11::_1), + scratch_data, + per_task_data); + timer.leave_subsection(); + } + template + void Solid::copy_local_to_global_rhs(const PerTaskData_RHS &data) + { + for (unsigned int i = 0; i < dofs_per_cell; ++i) + system_rhs(data.local_dof_indices[i]) += data.cell_rhs(i); + } + template + void + Solid::assemble_system_rhs_one_cell(const typename DoFHandler::active_cell_iterator &cell, + ScratchData_RHS &scratch, + PerTaskData_RHS &data) const + { + data.reset(); + scratch.reset(); + scratch.fe_values_ref.reinit(cell); + cell->get_dof_indices(data.local_dof_indices); + const std::vector > > lqph = + quadrature_point_history.get_data(cell); + Assert(lqph.size() == n_q_points, ExcInternalError()); + for (unsigned int q_point = 0; q_point < n_q_points; ++q_point) + { + const Tensor<2, dim> F_inv = lqph[q_point]->get_F_inv(); + for (unsigned int k = 0; k < dofs_per_cell; ++k) + { + const unsigned int k_group = fe.system_to_base_index(k).first.first; + if (k_group == u_dof) + scratch.symm_grad_Nx[q_point][k] + = symmetrize(scratch.fe_values_ref[u_fe].gradient(k, q_point) + * F_inv); + else if (k_group == p_dof) + scratch.Nx[q_point][k] = scratch.fe_values_ref[p_fe].value(k, + q_point); + else if (k_group == J_dof) + scratch.Nx[q_point][k] = scratch.fe_values_ref[J_fe].value(k, + q_point); + else + Assert(k_group <= J_dof, ExcInternalError()); + } + } + for (unsigned int q_point = 0; q_point < n_q_points; ++q_point) + { + const SymmetricTensor<2, dim> tau = lqph[q_point]->get_tau(); + const double det_F = lqph[q_point]->get_det_F(); + const double J_tilde = lqph[q_point]->get_J_tilde(); + const double p_tilde = lqph[q_point]->get_p_tilde(); + const double dPsi_vol_dJ = lqph[q_point]->get_dPsi_vol_dJ(); + const std::vector + &N = scratch.Nx[q_point]; + const std::vector > + &symm_grad_Nx = scratch.symm_grad_Nx[q_point]; + const double JxW = scratch.fe_values_ref.JxW(q_point); + for (unsigned int i = 0; i < dofs_per_cell; ++i) + { + const unsigned int i_group = fe.system_to_base_index(i).first.first; + if (i_group == u_dof) + data.cell_rhs(i) -= (symm_grad_Nx[i] * tau) * JxW; + else if (i_group == p_dof) + data.cell_rhs(i) -= N[i] * (det_F - J_tilde) * JxW; + else if (i_group == J_dof) + data.cell_rhs(i) -= N[i] * (dPsi_vol_dJ - p_tilde) * JxW; + else + Assert(i_group <= J_dof, ExcInternalError()); + } + } + for (unsigned int face = 0; face < GeometryInfo::faces_per_cell; + ++face) + if (cell->face(face)->at_boundary() == true + && cell->face(face)->boundary_id() == 6) + { + scratch.fe_face_values_ref.reinit(cell, face); + for (unsigned int f_q_point = 0; f_q_point < n_q_points_f; + ++f_q_point) + { + const Tensor<1, dim> &N = + scratch.fe_face_values_ref.normal_vector(f_q_point); + static const double p0 = -4.0 + / + (parameters.scale * parameters.scale); + const double time_ramp = (time.current() / time.end()); + const double pressure = p0 * parameters.p_p0 * time_ramp; + const Tensor<1, dim> traction = pressure * N; + for (unsigned int i = 0; i < dofs_per_cell; ++i) + { + const unsigned int i_group = + fe.system_to_base_index(i).first.first; + if (i_group == u_dof) + { + const unsigned int component_i = + fe.system_to_component_index(i).first; + const double Ni = + scratch.fe_face_values_ref.shape_value(i, + f_q_point); + const double JxW = scratch.fe_face_values_ref.JxW( + f_q_point); + data.cell_rhs(i) += (Ni * traction[component_i]) + * JxW; + } + } + } + } + } + template + void Solid::make_constraints(const int &it_nr) + { + pcout << " CST " << std::flush; + if (it_nr > 1) + return; + constraints.clear(); + const bool apply_dirichlet_bc = (it_nr == 0); + const FEValuesExtractors::Scalar x_displacement(0); + const FEValuesExtractors::Scalar y_displacement(1); + { + const int boundary_id = 0; + if (apply_dirichlet_bc == true) + VectorTools::interpolate_boundary_values(dof_handler_ref, + boundary_id, + ZeroFunction(n_components), + constraints, + fe.component_mask(x_displacement)); + else + VectorTools::interpolate_boundary_values(dof_handler_ref, + boundary_id, + ZeroFunction(n_components), + constraints, + fe.component_mask(x_displacement)); + } + { + const int boundary_id = 2; + if (apply_dirichlet_bc == true) + VectorTools::interpolate_boundary_values(dof_handler_ref, + boundary_id, + ZeroFunction(n_components), + constraints, + fe.component_mask(y_displacement)); + else + VectorTools::interpolate_boundary_values(dof_handler_ref, + boundary_id, + ZeroFunction(n_components), + constraints, + fe.component_mask(y_displacement)); + } + if (dim==3) + { + const FEValuesExtractors::Scalar z_displacement(2); + { + const int boundary_id = 3; + if (apply_dirichlet_bc == true) + VectorTools::interpolate_boundary_values(dof_handler_ref, + boundary_id, + ZeroFunction(n_components), + constraints, + (fe.component_mask(x_displacement) + | + fe.component_mask(z_displacement))); + else + VectorTools::interpolate_boundary_values(dof_handler_ref, + boundary_id, + ZeroFunction(n_components), + constraints, + (fe.component_mask(x_displacement) + | + fe.component_mask(z_displacement))); + } + { + const int boundary_id = 4; + if (apply_dirichlet_bc == true) + VectorTools::interpolate_boundary_values(dof_handler_ref, + boundary_id, + ZeroFunction(n_components), + constraints, + fe.component_mask(z_displacement)); + else + VectorTools::interpolate_boundary_values(dof_handler_ref, + boundary_id, + ZeroFunction(n_components), + constraints, + fe.component_mask(z_displacement)); + } + { + const int boundary_id = 6; + if (apply_dirichlet_bc == true) + VectorTools::interpolate_boundary_values(dof_handler_ref, + boundary_id, + ZeroFunction(n_components), + constraints, + (fe.component_mask(x_displacement) + | + fe.component_mask(z_displacement))); + else + VectorTools::interpolate_boundary_values(dof_handler_ref, + boundary_id, + ZeroFunction(n_components), + constraints, + (fe.component_mask(x_displacement) + | + fe.component_mask(z_displacement))); + } + } + else + { + { + const int boundary_id = 3; + if (apply_dirichlet_bc == true) + VectorTools::interpolate_boundary_values(dof_handler_ref, + boundary_id, + ZeroFunction(n_components), + constraints, + (fe.component_mask(x_displacement))); + else + VectorTools::interpolate_boundary_values(dof_handler_ref, + boundary_id, + ZeroFunction(n_components), + constraints, + (fe.component_mask(x_displacement))); + } + { + const int boundary_id = 6; + if (apply_dirichlet_bc == true) + VectorTools::interpolate_boundary_values(dof_handler_ref, + boundary_id, + ZeroFunction(n_components), + constraints, + (fe.component_mask(x_displacement))); + else + VectorTools::interpolate_boundary_values(dof_handler_ref, + boundary_id, + ZeroFunction(n_components), + constraints, + (fe.component_mask(x_displacement))); + } + } + constraints.close(); + } + template + void Solid::assemble_sc() + { + timer.enter_subsection("Perform static condensation"); + pcout << " ASM_SC " << std::flush; + PerTaskData_SC per_task_data(dofs_per_cell, element_indices_u.size(), + element_indices_p.size(), + element_indices_J.size()); + ScratchData_SC scratch_data; + WorkStream::run(dof_handler_ref.begin_active(), + dof_handler_ref.end(), + *this, + &Solid::assemble_sc_one_cell, + &Solid::copy_local_to_global_sc, + scratch_data, + per_task_data); + timer.leave_subsection(); + } + template + void Solid::copy_local_to_global_sc(const PerTaskData_SC &data) + { + for (unsigned int i = 0; i < dofs_per_cell; ++i) + for (unsigned int j = 0; j < dofs_per_cell; ++j) + tangent_matrix.add(data.local_dof_indices[i], + data.local_dof_indices[j], + data.cell_matrix(i, j)); + } + template + void + Solid::assemble_sc_one_cell(const typename DoFHandler::active_cell_iterator &cell, + ScratchData_SC &scratch, + PerTaskData_SC &data) + { + data.reset(); + scratch.reset(); + cell->get_dof_indices(data.local_dof_indices); + data.k_orig.extract_submatrix_from(tangent_matrix, + data.local_dof_indices, + data.local_dof_indices); + data.k_pu.extract_submatrix_from(data.k_orig, + element_indices_p, + element_indices_u); + data.k_pJ.extract_submatrix_from(data.k_orig, + element_indices_p, + element_indices_J); + data.k_JJ.extract_submatrix_from(data.k_orig, + element_indices_J, + element_indices_J); + data.k_pJ_inv.invert(data.k_pJ); + data.k_pJ_inv.mmult(data.A, data.k_pu); + data.k_JJ.mmult(data.B, data.A); + data.k_pJ_inv.Tmmult(data.C, data.B); + data.k_pu.Tmmult(data.k_bbar, data.C); + data.k_bbar.scatter_matrix_to(element_indices_u, + element_indices_u, + data.cell_matrix); + data.k_pJ_inv.add(-1.0, data.k_pJ); + data.k_pJ_inv.scatter_matrix_to(element_indices_p, + element_indices_J, + data.cell_matrix); + } + template + std::pair + Solid::solve_linear_system(BlockVector &newton_update) + { + unsigned int lin_it = 0; + double lin_res = 0.0; + if (parameters.use_static_condensation == true) + { + BlockVector A(dofs_per_block); + BlockVector B(dofs_per_block); + { + assemble_sc(); + tangent_matrix.block(p_dof, J_dof).vmult(A.block(J_dof), + system_rhs.block(p_dof)); + tangent_matrix.block(J_dof, J_dof).vmult(B.block(J_dof), + A.block(J_dof)); + A.block(J_dof) = system_rhs.block(J_dof); + A.block(J_dof) -= B.block(J_dof); + tangent_matrix.block(p_dof, J_dof).Tvmult(A.block(p_dof), + A.block(J_dof)); + tangent_matrix.block(u_dof, p_dof).vmult(A.block(u_dof), + A.block(p_dof)); + system_rhs.block(u_dof) -= A.block(u_dof); + timer.enter_subsection("Linear solver"); + pcout << " SLV " << std::flush; + if (parameters.type_lin == "CG") + { + const int solver_its = tangent_matrix.block(u_dof, u_dof).m() + * parameters.max_iterations_lin; + const double tol_sol = parameters.tol_lin + * system_rhs.block(u_dof).l2_norm(); + SolverControl solver_control(solver_its, tol_sol); + GrowingVectorMemory > GVM; + SolverCG > solver_CG(solver_control, GVM); + PreconditionSelector, Vector > + preconditioner (parameters.preconditioner_type, + parameters.preconditioner_relaxation); + preconditioner.use_matrix(tangent_matrix.block(u_dof, u_dof)); + solver_CG.solve(tangent_matrix.block(u_dof, u_dof), + newton_update.block(u_dof), + system_rhs.block(u_dof), + preconditioner); + lin_it = solver_control.last_step(); + lin_res = solver_control.last_value(); + } + else if (parameters.type_lin == "Direct") + { + SparseDirectUMFPACK A_direct; + A_direct.initialize(tangent_matrix.block(u_dof, u_dof)); + A_direct.vmult(newton_update.block(u_dof), system_rhs.block(u_dof)); + lin_it = 1; + lin_res = 0.0; + } + else + Assert (false, ExcMessage("Linear solver type not implemented")); + timer.leave_subsection(); + } + constraints.distribute(newton_update); + timer.enter_subsection("Linear solver postprocessing"); + pcout << " PP " << std::flush; + { + tangent_matrix.block(p_dof, u_dof).vmult(A.block(p_dof), + newton_update.block(u_dof)); + A.block(p_dof) *= -1.0; + A.block(p_dof) += system_rhs.block(p_dof); + tangent_matrix.block(p_dof, J_dof).vmult(newton_update.block(J_dof), + A.block(p_dof)); + } + constraints.distribute(newton_update); + { + tangent_matrix.block(J_dof, J_dof).vmult(A.block(J_dof), + newton_update.block(J_dof)); + A.block(J_dof) *= -1.0; + A.block(J_dof) += system_rhs.block(J_dof); + tangent_matrix.block(p_dof, J_dof).Tvmult(newton_update.block(p_dof), + A.block(J_dof)); + } + constraints.distribute(newton_update); + timer.leave_subsection(); + } + else + { + pcout << " ------ " << std::flush; + timer.enter_subsection("Linear solver"); + pcout << " SLV " << std::flush; + if (parameters.type_lin == "CG") + { + const Vector &f_u = system_rhs.block(u_dof); + const Vector &f_p = system_rhs.block(p_dof); + const Vector &f_J = system_rhs.block(J_dof); + Vector &d_u = newton_update.block(u_dof); + Vector &d_p = newton_update.block(p_dof); + Vector &d_J = newton_update.block(J_dof); + const auto K_uu = linear_operator(tangent_matrix.block(u_dof, u_dof)); + const auto K_up = linear_operator(tangent_matrix.block(u_dof, p_dof)); + const auto K_pu = linear_operator(tangent_matrix.block(p_dof, u_dof)); + const auto K_Jp = linear_operator(tangent_matrix.block(J_dof, p_dof)); + const auto K_JJ = linear_operator(tangent_matrix.block(J_dof, J_dof)); + PreconditionSelector< SparseMatrix, Vector > + preconditioner_K_Jp_inv ("jacobi"); + preconditioner_K_Jp_inv.use_matrix(tangent_matrix.block(J_dof, p_dof)); + ReductionControl solver_control_K_Jp_inv (tangent_matrix.block(J_dof, p_dof).m() * parameters.max_iterations_lin, + 1.0e-30, parameters.tol_lin); + SolverSelector< Vector > solver_K_Jp_inv; + solver_K_Jp_inv.select("cg"); + solver_K_Jp_inv.set_control(solver_control_K_Jp_inv); + const auto K_Jp_inv = inverse_operator(K_Jp, + solver_K_Jp_inv, + preconditioner_K_Jp_inv); + const auto K_pJ_inv = transpose_operator(K_Jp_inv); + const auto K_pp_bar = K_Jp_inv * K_JJ * K_pJ_inv; + const auto K_uu_bar_bar = K_up * K_pp_bar * K_pu; + const auto K_uu_con = K_uu + K_uu_bar_bar; + PreconditionSelector< SparseMatrix, Vector > + preconditioner_K_con_inv (parameters.preconditioner_type, + parameters.preconditioner_relaxation); + preconditioner_K_con_inv.use_matrix(tangent_matrix.block(u_dof, u_dof)); + ReductionControl solver_control_K_con_inv (tangent_matrix.block(u_dof, u_dof).m() * parameters.max_iterations_lin, + 1.0e-30, parameters.tol_lin); + SolverSelector< Vector > solver_K_con_inv; + solver_K_con_inv.select("cg"); + solver_K_con_inv.set_control(solver_control_K_con_inv); + const auto K_uu_con_inv = inverse_operator(K_uu_con, + solver_K_con_inv, + preconditioner_K_con_inv); + d_u = K_uu_con_inv*(f_u - K_up*(K_Jp_inv*f_J - K_pp_bar*f_p)); + timer.leave_subsection(); + timer.enter_subsection("Linear solver postprocessing"); + pcout << " PP " << std::flush; + d_J = K_pJ_inv*(f_p - K_pu*d_u); + d_p = K_Jp_inv*(f_J - K_JJ*d_J); + lin_it = solver_control_K_con_inv.last_step(); + lin_res = solver_control_K_con_inv.last_value(); + } + else if (parameters.type_lin == "Direct") + { + SparseDirectUMFPACK A_direct; + A_direct.initialize(tangent_matrix); + A_direct.vmult(newton_update, system_rhs); + lin_it = 1; + lin_res = 0.0; + pcout << " -- " << std::flush; + } + else + Assert (false, ExcMessage("Linear solver type not implemented")); + timer.leave_subsection(); + constraints.distribute(newton_update); + } + return std::make_pair(lin_it, lin_res); + } + template + void Solid::output_results() const + { + DataOut data_out; + std::vector + data_component_interpretation(dim, + DataComponentInterpretation::component_is_part_of_vector); + data_component_interpretation.push_back(DataComponentInterpretation::component_is_scalar); + data_component_interpretation.push_back(DataComponentInterpretation::component_is_scalar); + std::vector solution_name(dim, "displacement"); + solution_name.push_back("pressure"); + solution_name.push_back("dilatation"); + data_out.attach_dof_handler(dof_handler_ref); + data_out.add_data_vector(solution_n, + solution_name, + DataOut::type_dof_data, + data_component_interpretation); + Vector soln(solution_n.size()); + for (unsigned int i = 0; i < soln.size(); ++i) + soln(i) = solution_n(i); + MappingQEulerian q_mapping(degree, dof_handler_ref, soln); + data_out.build_patches(q_mapping, degree); + std::ostringstream filename; + filename << "solution-" << dim << "d-" << time.get_timestep() << ".vtk"; + std::ofstream output(filename.str().c_str()); + data_out.write_vtk(output); + } +} +int main (int argc,char **argv) +{ + std::ofstream logfile("output"); + deallog.attach(logfile); + deallog.depth_file(0); + deallog.threshold_double(1.e-10); + + Utilities::MPI::MPI_InitFinalize mpi_initialization (argc, argv, testing_max_num_threads()); + + using namespace dealii; + using namespace Step44; + try + { + const unsigned int dim = 3; + Solid solid(SOURCE_DIR "/prm/parameters-step-44.prm"); + solid.run(); + } + catch (std::exception &exc) + { + std::cerr << std::endl << std::endl + << "----------------------------------------------------" + << std::endl; + std::cerr << "Exception on processing: " << std::endl << exc.what() + << std::endl << "Aborting!" << std::endl + << "----------------------------------------------------" + << std::endl; + return 1; + } + catch (...) + { + std::cerr << std::endl << std::endl + << "----------------------------------------------------" + << std::endl; + std::cerr << "Unknown exception!" << std::endl << "Aborting!" + << std::endl + << "----------------------------------------------------" + << std::endl; + return 1; + } + return 0; +} diff --git a/tests/physics/step-44-standard_tensors-material_push_forward.output b/tests/physics/step-44-standard_tensors-material_push_forward.output new file mode 100644 index 0000000000..d0fa5247d0 --- /dev/null +++ b/tests/physics/step-44-standard_tensors-material_push_forward.output @@ -0,0 +1,167 @@ + +Grid: + Reference volume: 1.00000e-09 +Triangulation: + Number of active cells: 64 + Number of degrees of freedom: 503 + Setting up quadrature point data... + +Timestep 1 @ 0.100000s +___________________________________________________________________________________________________________________________________________________________ + SOLVER STEP | LIN_IT LIN_RES RES_NORM RES_U RES_P RES_J NU_NORM NU_U NU_P NU_J +___________________________________________________________________________________________________________________________________________________________ + 0 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 134 1.879e-06 1.000e+00 1.000e+00 0.000e+00 0.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 + 1 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 96 8.427e-04 8.085e-02 8.085e-02 7.076e-13 3.053e-08 9.395e-02 3.598e-02 9.395e-02 9.397e-02 + 2 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 122 4.107e-06 8.861e-04 8.861e-04 2.254e-15 1.997e-10 8.585e-04 1.975e-04 8.585e-04 8.586e-04 + 3 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 151 4.885e-11 1.098e-06 1.098e-06 4.211e-20 2.153e-14 9.953e-07 1.498e-07 9.953e-07 9.953e-07 + 4 ASM_R CONVERGED! +___________________________________________________________________________________________________________________________________________________________ +Relative errors: +Displacement: 1.498e-07 +Force: 1.303e-11 +Dilatation: 3.484e-07 +v / V_0: 1.000e-09 / 1.000e-09 = 1.000e+00 + +Timestep 2 @ 2.000e-01s +___________________________________________________________________________________________________________________________________________________________ + SOLVER STEP | LIN_IT LIN_RES RES_NORM RES_U RES_P RES_J NU_NORM NU_U NU_P NU_J +___________________________________________________________________________________________________________________________________________________________ + 0 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 130 3.594e-06 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 + 1 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 96 8.305e-04 8.472e-02 8.472e-02 2.288e+13 6.462e+06 1.096e-01 4.023e-02 1.096e-01 1.096e-01 + 2 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 114 5.935e-06 9.844e-04 9.844e-04 8.970e+10 6.258e+04 1.154e-03 2.984e-04 1.154e-03 1.154e-03 + 3 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 152 8.425e-11 1.584e-06 1.584e-06 2.131e+06 8.412e+00 2.765e-06 4.710e-07 2.765e-06 2.765e-06 + 4 ASM_R CONVERGED! +___________________________________________________________________________________________________________________________________________________________ +Relative errors: +Displacement: 4.710e-07 +Force: 2.247e-11 +Dilatation: 7.035e-07 +v / V_0: 1.000e-09 / 1.000e-09 = 1.000e+00 + +Timestep 3 @ 3.000e-01s +___________________________________________________________________________________________________________________________________________________________ + SOLVER STEP | LIN_IT LIN_RES RES_NORM RES_U RES_P RES_J NU_NORM NU_U NU_P NU_J +___________________________________________________________________________________________________________________________________________________________ + 0 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 130 2.941e-06 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 + 1 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 92 1.169e-03 9.356e-02 9.356e-02 4.455e+12 4.460e+06 1.131e-01 4.961e-02 1.131e-01 1.131e-01 + 2 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 111 3.956e-06 9.355e-04 9.355e-04 2.153e+10 4.528e+04 1.417e-03 4.916e-04 1.417e-03 1.417e-03 + 3 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 147 2.074e-10 1.047e-06 1.047e-06 1.149e+06 7.409e+00 1.115e-06 2.439e-07 1.115e-06 1.115e-06 + 4 ASM_R CONVERGED! +___________________________________________________________________________________________________________________________________________________________ +Relative errors: +Displacement: 2.439e-07 +Force: 5.530e-11 +Dilatation: 1.059e-06 +v / V_0: 1.000e-09 / 1.000e-09 = 1.000e+00 + +Timestep 4 @ 4.000e-01s +___________________________________________________________________________________________________________________________________________________________ + SOLVER STEP | LIN_IT LIN_RES RES_NORM RES_U RES_P RES_J NU_NORM NU_U NU_P NU_J +___________________________________________________________________________________________________________________________________________________________ + 0 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 130 2.007e-06 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 + 1 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 91 1.042e-03 1.069e-01 1.069e-01 8.138e+12 4.014e+06 9.761e-02 6.072e-02 9.761e-02 9.762e-02 + 2 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 110 6.023e-06 1.449e-03 1.449e-03 4.399e+10 2.545e+04 1.897e-03 8.054e-04 1.897e-03 1.897e-03 + 3 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 143 9.161e-10 1.660e-06 1.660e-06 6.590e+06 1.212e+01 1.847e-06 7.736e-07 1.847e-06 1.848e-06 + 4 ASM_R CONVERGED! +___________________________________________________________________________________________________________________________________________________________ +Relative errors: +Displacement: 7.736e-07 +Force: 2.443e-10 +Dilatation: 1.407e-06 +v / V_0: 1.000e-09 / 1.000e-09 = 1.000e+00 + +Timestep 5 @ 5.000e-01s +___________________________________________________________________________________________________________________________________________________________ + SOLVER STEP | LIN_IT LIN_RES RES_NORM RES_U RES_P RES_J NU_NORM NU_U NU_P NU_J +___________________________________________________________________________________________________________________________________________________________ + 0 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 129 2.191e-06 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 + 1 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 94 6.965e-04 1.179e-01 1.179e-01 1.267e+12 3.437e+06 7.328e-02 6.923e-02 7.328e-02 7.329e-02 + 2 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 114 4.389e-06 2.309e-03 2.309e-03 7.096e+09 8.901e+03 2.289e-03 1.160e-03 2.289e-03 2.289e-03 + 3 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 138 1.580e-09 1.557e-06 1.557e-06 2.454e+06 1.600e+01 1.620e-06 5.738e-07 1.620e-06 1.620e-06 + 4 ASM_R CONVERGED! +___________________________________________________________________________________________________________________________________________________________ +Relative errors: +Displacement: 5.738e-07 +Force: 4.213e-10 +Dilatation: 1.742e-06 +v / V_0: 1.000e-09 / 1.000e-09 = 1.000e+00 + +Timestep 6 @ 6.000e-01s +___________________________________________________________________________________________________________________________________________________________ + SOLVER STEP | LIN_IT LIN_RES RES_NORM RES_U RES_P RES_J NU_NORM NU_U NU_P NU_J +___________________________________________________________________________________________________________________________________________________________ + 0 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 132 1.414e-06 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 + 1 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 97 6.939e-04 1.230e-01 1.230e-01 2.558e+12 3.978e+06 5.486e-02 7.377e-02 5.486e-02 5.488e-02 + 2 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 118 5.820e-06 2.713e-03 2.713e-03 1.385e+10 4.458e+03 2.263e-03 1.405e-03 2.263e-03 2.263e-03 + 3 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 142 2.281e-09 2.218e-06 2.218e-06 7.015e+06 1.794e+01 2.396e-06 6.484e-07 2.396e-06 2.397e-06 + 4 ASM_R CONVERGED! +___________________________________________________________________________________________________________________________________________________________ +Relative errors: +Displacement: 6.484e-07 +Force: 6.081e-10 +Dilatation: 2.057e-06 +v / V_0: 1.000e-09 / 1.000e-09 = 1.000e+00 + +Timestep 7 @ 7.000e-01s +___________________________________________________________________________________________________________________________________________________________ + SOLVER STEP | LIN_IT LIN_RES RES_NORM RES_U RES_P RES_J NU_NORM NU_U NU_P NU_J +___________________________________________________________________________________________________________________________________________________________ + 0 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 132 2.699e-06 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 + 1 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 93 7.507e-04 1.234e-01 1.234e-01 1.426e+12 3.501e+06 4.453e-02 7.478e-02 4.453e-02 4.455e-02 + 2 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 116 4.617e-06 2.691e-03 2.691e-03 7.526e+09 2.451e+03 2.060e-03 1.491e-03 2.060e-03 2.060e-03 + 3 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 147 1.854e-09 1.977e-06 1.977e-06 4.103e+06 1.274e+01 2.026e-06 7.866e-07 2.026e-06 2.026e-06 + 4 ASM_R CONVERGED! +___________________________________________________________________________________________________________________________________________________________ +Relative errors: +Displacement: 7.866e-07 +Force: 4.943e-10 +Dilatation: 2.353e-06 +v / V_0: 1.000e-09 / 1.000e-09 = 1.000e+00 + +Timestep 8 @ 8.000e-01s +___________________________________________________________________________________________________________________________________________________________ + SOLVER STEP | LIN_IT LIN_RES RES_NORM RES_U RES_P RES_J NU_NORM NU_U NU_P NU_J +___________________________________________________________________________________________________________________________________________________________ + 0 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 135 3.661e-06 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 + 1 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 89 5.904e-04 1.207e-01 1.207e-01 1.432e+12 3.128e+06 3.820e-02 7.299e-02 3.820e-02 3.822e-02 + 2 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 123 1.810e-06 2.483e-03 2.483e-03 7.548e+09 1.749e+03 1.678e-03 1.443e-03 1.678e-03 1.678e-03 + 3 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 151 9.941e-10 1.233e-06 1.233e-06 3.771e+06 7.563e+00 1.039e-06 6.005e-07 1.039e-06 1.039e-06 + 4 ASM_R CONVERGED! +___________________________________________________________________________________________________________________________________________________________ +Relative errors: +Displacement: 6.005e-07 +Force: 2.651e-10 +Dilatation: 2.632e-06 +v / V_0: 1.000e-09 / 1.000e-09 = 1.000e+00 + +Timestep 9 @ 9.000e-01s +___________________________________________________________________________________________________________________________________________________________ + SOLVER STEP | LIN_IT LIN_RES RES_NORM RES_U RES_P RES_J NU_NORM NU_U NU_P NU_J +___________________________________________________________________________________________________________________________________________________________ + 0 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 131 3.539e-06 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 + 1 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 92 4.407e-04 1.155e-01 1.155e-01 1.759e+12 3.580e+06 3.352e-02 6.924e-02 3.352e-02 3.353e-02 + 2 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 130 1.937e-06 2.235e-03 2.235e-03 8.944e+09 1.778e+03 1.331e-03 1.252e-03 1.331e-03 1.331e-03 + 3 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 154 9.421e-10 1.043e-06 1.043e-06 3.554e+06 5.187e+00 1.008e-06 4.678e-07 1.008e-06 1.008e-06 + 4 ASM_R CONVERGED! +___________________________________________________________________________________________________________________________________________________________ +Relative errors: +Displacement: 4.678e-07 +Force: 2.512e-10 +Dilatation: 2.899e-06 +v / V_0: 1.000e-09 / 1.000e-09 = 1.000e+00 + +Timestep 10 @ 1.000e+00s +___________________________________________________________________________________________________________________________________________________________ + SOLVER STEP | LIN_IT LIN_RES RES_NORM RES_U RES_P RES_J NU_NORM NU_U NU_P NU_J +___________________________________________________________________________________________________________________________________________________________ + 0 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 137 1.947e-06 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 + 1 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 92 3.365e-04 1.085e-01 1.085e-01 2.423e+12 3.045e+06 3.001e-02 6.447e-02 3.001e-02 3.003e-02 + 2 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 129 1.208e-06 1.904e-03 1.904e-03 1.130e+10 1.284e+03 9.595e-04 1.011e-03 9.595e-04 9.595e-04 + 3 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 159 4.322e-10 6.904e-07 6.904e-07 3.233e+06 2.368e+00 5.895e-07 3.490e-07 5.895e-07 5.897e-07 + 4 ASM_R CONVERGED! +___________________________________________________________________________________________________________________________________________________________ +Relative errors: +Displacement: 3.490e-07 +Force: 1.153e-10 +Dilatation: 3.157e-06 +v / V_0: 1.000e-09 / 1.000e-09 = 1.000e+00 diff --git a/tests/physics/step-44-standard_tensors-spatial.cc b/tests/physics/step-44-standard_tensors-spatial.cc new file mode 100644 index 0000000000..fd86f3cab8 --- /dev/null +++ b/tests/physics/step-44-standard_tensors-spatial.cc @@ -0,0 +1,1970 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2016 by the deal.II authors +// +// This file is part of the deal.II library. +// +// The deal.II library is free software; you can use it, redistribute +// it, and/or modify it under the terms of the GNU Lesser General +// Public License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// The full text of the license can be found in the file LICENSE at +// the top level of the deal.II distribution. +// +// --------------------------------------------------------------------- + +// A version of step-44 that checks that some of the definitions for standard +// tensors and kinematic quantities for elasticity are computed correctly + +#include "../tests.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +namespace Step44 +{ + using namespace dealii; + namespace Parameters + { + struct FESystem + { + unsigned int poly_degree; + unsigned int quad_order; + static void + declare_parameters(ParameterHandler &prm); + void + parse_parameters(ParameterHandler &prm); + }; + void FESystem::declare_parameters(ParameterHandler &prm) + { + prm.enter_subsection("Finite element system"); + { + prm.declare_entry("Polynomial degree", "2", + Patterns::Integer(0), + "Displacement system polynomial order"); + prm.declare_entry("Quadrature order", "3", + Patterns::Integer(0), + "Gauss quadrature order"); + } + prm.leave_subsection(); + } + void FESystem::parse_parameters(ParameterHandler &prm) + { + prm.enter_subsection("Finite element system"); + { + poly_degree = prm.get_integer("Polynomial degree"); + quad_order = prm.get_integer("Quadrature order"); + } + prm.leave_subsection(); + } + struct Geometry + { + unsigned int global_refinement; + double scale; + double p_p0; + static void + declare_parameters(ParameterHandler &prm); + void + parse_parameters(ParameterHandler &prm); + }; + void Geometry::declare_parameters(ParameterHandler &prm) + { + prm.enter_subsection("Geometry"); + { + prm.declare_entry("Global refinement", "2", + Patterns::Integer(0), + "Global refinement level"); + prm.declare_entry("Grid scale", "1e-3", + Patterns::Double(0.0), + "Global grid scaling factor"); + prm.declare_entry("Pressure ratio p/p0", "100", + Patterns::Selection("20|40|60|80|100"), + "Ratio of applied pressure to reference pressure"); + } + prm.leave_subsection(); + } + void Geometry::parse_parameters(ParameterHandler &prm) + { + prm.enter_subsection("Geometry"); + { + global_refinement = prm.get_integer("Global refinement"); + scale = prm.get_double("Grid scale"); + p_p0 = prm.get_double("Pressure ratio p/p0"); + } + prm.leave_subsection(); + } + struct Materials + { + double nu; + double mu; + static void + declare_parameters(ParameterHandler &prm); + void + parse_parameters(ParameterHandler &prm); + }; + void Materials::declare_parameters(ParameterHandler &prm) + { + prm.enter_subsection("Material properties"); + { + prm.declare_entry("Poisson's ratio", "0.4999", + Patterns::Double(-1.0,0.5), + "Poisson's ratio"); + prm.declare_entry("Shear modulus", "80.194e6", + Patterns::Double(), + "Shear modulus"); + } + prm.leave_subsection(); + } + void Materials::parse_parameters(ParameterHandler &prm) + { + prm.enter_subsection("Material properties"); + { + nu = prm.get_double("Poisson's ratio"); + mu = prm.get_double("Shear modulus"); + } + prm.leave_subsection(); + } + struct LinearSolver + { + std::string type_lin; + double tol_lin; + double max_iterations_lin; + bool use_static_condensation; + std::string preconditioner_type; + double preconditioner_relaxation; + static void + declare_parameters(ParameterHandler &prm); + void + parse_parameters(ParameterHandler &prm); + }; + void LinearSolver::declare_parameters(ParameterHandler &prm) + { + prm.enter_subsection("Linear solver"); + { + prm.declare_entry("Solver type", "CG", + Patterns::Selection("CG|Direct"), + "Type of solver used to solve the linear system"); + prm.declare_entry("Residual", "1e-6", + Patterns::Double(0.0), + "Linear solver residual (scaled by residual norm)"); + prm.declare_entry("Max iteration multiplier", "1", + Patterns::Double(0.0), + "Linear solver iterations (multiples of the system matrix size)"); + prm.declare_entry("Use static condensation", "true", + Patterns::Bool(), + "Solve the full block system or a reduced problem"); + prm.declare_entry("Preconditioner type", "ssor", + Patterns::Selection("jacobi|ssor"), + "Type of preconditioner"); + prm.declare_entry("Preconditioner relaxation", "0.65", + Patterns::Double(0.0), + "Preconditioner relaxation value"); + } + prm.leave_subsection(); + } + void LinearSolver::parse_parameters(ParameterHandler &prm) + { + prm.enter_subsection("Linear solver"); + { + type_lin = prm.get("Solver type"); + tol_lin = prm.get_double("Residual"); + max_iterations_lin = prm.get_double("Max iteration multiplier"); + use_static_condensation = prm.get_bool("Use static condensation"); + preconditioner_type = prm.get("Preconditioner type"); + preconditioner_relaxation = prm.get_double("Preconditioner relaxation"); + } + prm.leave_subsection(); + } + struct NonlinearSolver + { + unsigned int max_iterations_NR; + double tol_f; + double tol_u; + static void + declare_parameters(ParameterHandler &prm); + void + parse_parameters(ParameterHandler &prm); + }; + void NonlinearSolver::declare_parameters(ParameterHandler &prm) + { + prm.enter_subsection("Nonlinear solver"); + { + prm.declare_entry("Max iterations Newton-Raphson", "10", + Patterns::Integer(0), + "Number of Newton-Raphson iterations allowed"); + prm.declare_entry("Tolerance force", "1.0e-9", + Patterns::Double(0.0), + "Force residual tolerance"); + prm.declare_entry("Tolerance displacement", "1.0e-6", + Patterns::Double(0.0), + "Displacement error tolerance"); + } + prm.leave_subsection(); + } + void NonlinearSolver::parse_parameters(ParameterHandler &prm) + { + prm.enter_subsection("Nonlinear solver"); + { + max_iterations_NR = prm.get_integer("Max iterations Newton-Raphson"); + tol_f = prm.get_double("Tolerance force"); + tol_u = prm.get_double("Tolerance displacement"); + } + prm.leave_subsection(); + } + struct Time + { + double delta_t; + double end_time; + static void + declare_parameters(ParameterHandler &prm); + void + parse_parameters(ParameterHandler &prm); + }; + void Time::declare_parameters(ParameterHandler &prm) + { + prm.enter_subsection("Time"); + { + prm.declare_entry("End time", "1", + Patterns::Double(), + "End time"); + prm.declare_entry("Time step size", "0.1", + Patterns::Double(), + "Time step size"); + } + prm.leave_subsection(); + } + void Time::parse_parameters(ParameterHandler &prm) + { + prm.enter_subsection("Time"); + { + end_time = prm.get_double("End time"); + delta_t = prm.get_double("Time step size"); + } + prm.leave_subsection(); + } + struct AllParameters : public FESystem, + public Geometry, + public Materials, + public LinearSolver, + public NonlinearSolver, + public Time + { + AllParameters(const std::string &input_file); + static void + declare_parameters(ParameterHandler &prm); + void + parse_parameters(ParameterHandler &prm); + }; + AllParameters::AllParameters(const std::string &input_file) + { + ParameterHandler prm; + declare_parameters(prm); + prm.read_input(input_file); + parse_parameters(prm); + } + void AllParameters::declare_parameters(ParameterHandler &prm) + { + FESystem::declare_parameters(prm); + Geometry::declare_parameters(prm); + Materials::declare_parameters(prm); + LinearSolver::declare_parameters(prm); + NonlinearSolver::declare_parameters(prm); + Time::declare_parameters(prm); + } + void AllParameters::parse_parameters(ParameterHandler &prm) + { + FESystem::parse_parameters(prm); + Geometry::parse_parameters(prm); + Materials::parse_parameters(prm); + LinearSolver::parse_parameters(prm); + NonlinearSolver::parse_parameters(prm); + Time::parse_parameters(prm); + } + } + class Time + { + public: + Time (const double time_end, + const double delta_t) + : + timestep(0), + time_current(0.0), + time_end(time_end), + delta_t(delta_t) + {} + virtual ~Time() + {} + double current() const + { + return time_current; + } + double end() const + { + return time_end; + } + double get_delta_t() const + { + return delta_t; + } + unsigned int get_timestep() const + { + return timestep; + } + void increment() + { + time_current += delta_t; + ++timestep; + } + private: + unsigned int timestep; + double time_current; + const double time_end; + const double delta_t; + }; + template + class Material_Compressible_Neo_Hook_Three_Field + { + public: + Material_Compressible_Neo_Hook_Three_Field(const double mu, + const double nu) + : + kappa((2.0 * mu * (1.0 + nu)) / (3.0 * (1.0 - 2.0 * nu))), + c_1(mu / 2.0), + det_F(1.0), + p_tilde(0.0), + J_tilde(1.0), + b_bar(Physics::Elasticity::StandardTensors::I) + { + Assert(kappa > 0, ExcInternalError()); + } + ~Material_Compressible_Neo_Hook_Three_Field() + {} + void update_material_data(const Tensor<2, dim> &F, + const double p_tilde_in, + const double J_tilde_in) + { + det_F = determinant(F); + const Tensor<2,dim> F_iso = Physics::Elasticity::Kinematics::F_iso(F); + b_bar = Physics::Elasticity::Kinematics::b(F_iso); + p_tilde = p_tilde_in; + J_tilde = J_tilde_in; + Assert(det_F > 0, ExcInternalError()); + } + SymmetricTensor<2, dim> get_tau() + { + return get_tau_iso() + get_tau_vol(); + } + SymmetricTensor<4, dim> get_Jc() const + { + return get_Jc_vol() + get_Jc_iso(); + } + double get_dPsi_vol_dJ() const + { + return (kappa / 2.0) * (J_tilde - 1.0 / J_tilde); + } + double get_d2Psi_vol_dJ2() const + { + return ( (kappa / 2.0) * (1.0 + 1.0 / (J_tilde * J_tilde))); + } + double get_det_F() const + { + return det_F; + } + double get_p_tilde() const + { + return p_tilde; + } + double get_J_tilde() const + { + return J_tilde; + } + protected: + const double kappa; + const double c_1; + double det_F; + double p_tilde; + double J_tilde; + SymmetricTensor<2, dim> b_bar; + SymmetricTensor<2, dim> get_tau_vol() const + { + return p_tilde * det_F * Physics::Elasticity::StandardTensors::I; + } + SymmetricTensor<2, dim> get_tau_iso() const + { + return Physics::Elasticity::StandardTensors::dev_P * get_tau_bar(); + } + SymmetricTensor<2, dim> get_tau_bar() const + { + return 2.0 * c_1 * b_bar; + } + SymmetricTensor<4, dim> get_Jc_vol() const + { + return p_tilde * det_F + * ( Physics::Elasticity::StandardTensors::IxI + - (2.0 * Physics::Elasticity::StandardTensors::S) ); + } + SymmetricTensor<4, dim> get_Jc_iso() const + { + const SymmetricTensor<2, dim> tau_bar = get_tau_bar(); + const SymmetricTensor<2, dim> tau_iso = get_tau_iso(); + const SymmetricTensor<4, dim> tau_iso_x_I + = outer_product(tau_iso, + Physics::Elasticity::StandardTensors::I); + const SymmetricTensor<4, dim> I_x_tau_iso + = outer_product(Physics::Elasticity::StandardTensors::I, + tau_iso); + const SymmetricTensor<4, dim> c_bar = get_c_bar(); + return (2.0 / dim) * trace(tau_bar) + * Physics::Elasticity::StandardTensors::dev_P + - (2.0 / dim) * (tau_iso_x_I + I_x_tau_iso) + + Physics::Elasticity::StandardTensors::dev_P * c_bar + * Physics::Elasticity::StandardTensors::dev_P; + } + SymmetricTensor<4, dim> get_c_bar() const + { + return SymmetricTensor<4, dim>(); + } + }; + template + class PointHistory + { + public: + PointHistory() + : + F_inv(Physics::Elasticity::StandardTensors::I), + tau(SymmetricTensor<2, dim>()), + d2Psi_vol_dJ2(0.0), + dPsi_vol_dJ(0.0), + Jc(SymmetricTensor<4, dim>()) + {} + virtual ~PointHistory() + {} + void setup_lqp (const Parameters::AllParameters ¶meters) + { + material.reset(new Material_Compressible_Neo_Hook_Three_Field(parameters.mu, + parameters.nu)); + update_values(Tensor<2, dim>(), 0.0, 1.0); + } + void update_values (const Tensor<2, dim> &Grad_u_n, + const double p_tilde, + const double J_tilde) + { + const Tensor<2, dim> F = Physics::Elasticity::Kinematics::F(Grad_u_n); + material->update_material_data(F, p_tilde, J_tilde); + F_inv = invert(F); + tau = material->get_tau(); + Jc = material->get_Jc(); + dPsi_vol_dJ = material->get_dPsi_vol_dJ(); + d2Psi_vol_dJ2 = material->get_d2Psi_vol_dJ2(); + } + double get_J_tilde() const + { + return material->get_J_tilde(); + } + double get_det_F() const + { + return material->get_det_F(); + } + const Tensor<2, dim> &get_F_inv() const + { + return F_inv; + } + double get_p_tilde() const + { + return material->get_p_tilde(); + } + const SymmetricTensor<2, dim> &get_tau() const + { + return tau; + } + double get_dPsi_vol_dJ() const + { + return dPsi_vol_dJ; + } + double get_d2Psi_vol_dJ2() const + { + return d2Psi_vol_dJ2; + } + const SymmetricTensor<4, dim> &get_Jc() const + { + return Jc; + } + private: + std_cxx11::shared_ptr< Material_Compressible_Neo_Hook_Three_Field > material; + Tensor<2, dim> F_inv; + SymmetricTensor<2, dim> tau; + double d2Psi_vol_dJ2; + double dPsi_vol_dJ; + SymmetricTensor<4, dim> Jc; + }; + template + class Solid + { + public: + Solid(const std::string &input_file); + virtual + ~Solid(); + void + run(); + private: + struct PerTaskData_K; + struct ScratchData_K; + struct PerTaskData_RHS; + struct ScratchData_RHS; + struct PerTaskData_SC; + struct ScratchData_SC; + struct PerTaskData_UQPH; + struct ScratchData_UQPH; + void + make_grid(); + void + system_setup(); + void + determine_component_extractors(); + void + assemble_system_tangent(); + void + assemble_system_tangent_one_cell(const typename DoFHandler::active_cell_iterator &cell, + ScratchData_K &scratch, + PerTaskData_K &data) const; + void + copy_local_to_global_K(const PerTaskData_K &data); + void + assemble_system_rhs(); + void + assemble_system_rhs_one_cell(const typename DoFHandler::active_cell_iterator &cell, + ScratchData_RHS &scratch, + PerTaskData_RHS &data) const; + void + copy_local_to_global_rhs(const PerTaskData_RHS &data); + void + assemble_sc(); + void + assemble_sc_one_cell(const typename DoFHandler::active_cell_iterator &cell, + ScratchData_SC &scratch, + PerTaskData_SC &data); + void + copy_local_to_global_sc(const PerTaskData_SC &data); + void + make_constraints(const int &it_nr); + void + setup_qph(); + void + update_qph_incremental(const BlockVector &solution_delta); + void + update_qph_incremental_one_cell(const typename DoFHandler::active_cell_iterator &cell, + ScratchData_UQPH &scratch, + PerTaskData_UQPH &data); + void + copy_local_to_global_UQPH(const PerTaskData_UQPH &/*data*/) + {} + void + solve_nonlinear_timestep(BlockVector &solution_delta); + std::pair + solve_linear_system(BlockVector &newton_update); + BlockVector + get_total_solution(const BlockVector &solution_delta) const; + void + output_results() const; + Parameters::AllParameters parameters; + double vol_reference; + Triangulation triangulation; + Time time; + mutable TimerOutput timer; + CellDataStorage::cell_iterator, + PointHistory > quadrature_point_history; + const unsigned int degree; + const FESystem fe; + DoFHandler dof_handler_ref; + const unsigned int dofs_per_cell; + const FEValuesExtractors::Vector u_fe; + const FEValuesExtractors::Scalar p_fe; + const FEValuesExtractors::Scalar J_fe; + static const unsigned int n_blocks = 3; + static const unsigned int n_components = dim + 2; + static const unsigned int first_u_component = 0; + static const unsigned int p_component = dim; + static const unsigned int J_component = dim + 1; + enum + { + u_dof = 0, + p_dof = 1, + J_dof = 2 + }; + std::vector dofs_per_block; + std::vector element_indices_u; + std::vector element_indices_p; + std::vector element_indices_J; + const QGauss qf_cell; + const QGauss qf_face; + const unsigned int n_q_points; + const unsigned int n_q_points_f; + ConstraintMatrix constraints; + BlockSparsityPattern sparsity_pattern; + BlockSparseMatrix tangent_matrix; + BlockVector system_rhs; + BlockVector solution_n; + ConditionalOStream pcout; + struct Errors + { + Errors() + : + norm(1.0), u(1.0), p(1.0), J(1.0) + {} + void reset() + { + norm = 1.0; + u = 1.0; + p = 1.0; + J = 1.0; + } + void normalise(const Errors &rhs) + { + if (rhs.norm != 0.0) + norm /= rhs.norm; + if (rhs.u != 0.0) + u /= rhs.u; + if (rhs.p != 0.0) + p /= rhs.p; + if (rhs.J != 0.0) + J /= rhs.J; + } + double norm, u, p, J; + }; + Errors error_residual, error_residual_0, error_residual_norm, error_update, + error_update_0, error_update_norm; + void + get_error_residual(Errors &error_residual); + void + get_error_update(const BlockVector &newton_update, + Errors &error_update); + std::pair + get_error_dilation() const; + double + compute_vol_current () const; + void + print_conv_header(); + void + print_conv_footer(); + }; + template + Solid::Solid(const std::string &input_file) + : + parameters(input_file), + triangulation(Triangulation::maximum_smoothing), + time(parameters.end_time, parameters.delta_t), + timer(deallog.get_file_stream(), + TimerOutput::never, + TimerOutput::wall_times), + degree(parameters.poly_degree), + fe(FE_Q(parameters.poly_degree), dim, // displacement + FE_DGPMonomial(parameters.poly_degree - 1), 1, // pressure + FE_DGPMonomial(parameters.poly_degree - 1), 1), // dilatation + dof_handler_ref(triangulation), + dofs_per_cell (fe.dofs_per_cell), + u_fe(first_u_component), + p_fe(p_component), + J_fe(J_component), + dofs_per_block(n_blocks), + qf_cell(parameters.quad_order), + qf_face(parameters.quad_order), + n_q_points (qf_cell.size()), + n_q_points_f (qf_face.size()), + pcout(deallog.get_file_stream()) + { + Assert(dim==2 || dim==3, ExcMessage("This problem only works in 2 or 3 space dimensions.")); + determine_component_extractors(); + } + template + Solid::~Solid() + { + dof_handler_ref.clear(); + } + template + void Solid::run() + { + make_grid(); + system_setup(); + { + ConstraintMatrix constraints; + constraints.close(); + const ComponentSelectFunction + J_mask (J_component, n_components); + VectorTools::project (dof_handler_ref, + constraints, + QGauss(degree+2), + J_mask, + solution_n); + } + output_results(); + time.increment(); + BlockVector solution_delta(dofs_per_block); + while (time.current() < time.end()) + { + solution_delta = 0.0; + solve_nonlinear_timestep(solution_delta); + solution_n += solution_delta; + output_results(); + time.increment(); + } + } + template + struct Solid::PerTaskData_K + { + FullMatrix cell_matrix; + std::vector local_dof_indices; + PerTaskData_K(const unsigned int dofs_per_cell) + : + cell_matrix(dofs_per_cell, dofs_per_cell), + local_dof_indices(dofs_per_cell) + {} + void reset() + { + cell_matrix = 0.0; + } + }; + template + struct Solid::ScratchData_K + { + FEValues fe_values_ref; + std::vector > Nx; + std::vector > > grad_Nx; + std::vector > > symm_grad_Nx; + ScratchData_K(const FiniteElement &fe_cell, + const QGauss &qf_cell, + const UpdateFlags uf_cell) + : + fe_values_ref(fe_cell, qf_cell, uf_cell), + Nx(qf_cell.size(), + std::vector(fe_cell.dofs_per_cell)), + grad_Nx(qf_cell.size(), + std::vector >(fe_cell.dofs_per_cell)), + symm_grad_Nx(qf_cell.size(), + std::vector > + (fe_cell.dofs_per_cell)) + {} + ScratchData_K(const ScratchData_K &rhs) + : + fe_values_ref(rhs.fe_values_ref.get_fe(), + rhs.fe_values_ref.get_quadrature(), + rhs.fe_values_ref.get_update_flags()), + Nx(rhs.Nx), + grad_Nx(rhs.grad_Nx), + symm_grad_Nx(rhs.symm_grad_Nx) + {} + void reset() + { + const unsigned int n_q_points = Nx.size(); + const unsigned int n_dofs_per_cell = Nx[0].size(); + for (unsigned int q_point = 0; q_point < n_q_points; ++q_point) + { + Assert( Nx[q_point].size() == n_dofs_per_cell, ExcInternalError()); + Assert( grad_Nx[q_point].size() == n_dofs_per_cell, + ExcInternalError()); + Assert( symm_grad_Nx[q_point].size() == n_dofs_per_cell, + ExcInternalError()); + for (unsigned int k = 0; k < n_dofs_per_cell; ++k) + { + Nx[q_point][k] = 0.0; + grad_Nx[q_point][k] = 0.0; + symm_grad_Nx[q_point][k] = 0.0; + } + } + } + }; + template + struct Solid::PerTaskData_RHS + { + Vector cell_rhs; + std::vector local_dof_indices; + PerTaskData_RHS(const unsigned int dofs_per_cell) + : + cell_rhs(dofs_per_cell), + local_dof_indices(dofs_per_cell) + {} + void reset() + { + cell_rhs = 0.0; + } + }; + template + struct Solid::ScratchData_RHS + { + FEValues fe_values_ref; + FEFaceValues fe_face_values_ref; + std::vector > Nx; + std::vector > > symm_grad_Nx; + ScratchData_RHS(const FiniteElement &fe_cell, + const QGauss &qf_cell, const UpdateFlags uf_cell, + const QGauss & qf_face, const UpdateFlags uf_face) + : + fe_values_ref(fe_cell, qf_cell, uf_cell), + fe_face_values_ref(fe_cell, qf_face, uf_face), + Nx(qf_cell.size(), + std::vector(fe_cell.dofs_per_cell)), + symm_grad_Nx(qf_cell.size(), + std::vector > + (fe_cell.dofs_per_cell)) + {} + ScratchData_RHS(const ScratchData_RHS &rhs) + : + fe_values_ref(rhs.fe_values_ref.get_fe(), + rhs.fe_values_ref.get_quadrature(), + rhs.fe_values_ref.get_update_flags()), + fe_face_values_ref(rhs.fe_face_values_ref.get_fe(), + rhs.fe_face_values_ref.get_quadrature(), + rhs.fe_face_values_ref.get_update_flags()), + Nx(rhs.Nx), + symm_grad_Nx(rhs.symm_grad_Nx) + {} + void reset() + { + const unsigned int n_q_points = Nx.size(); + const unsigned int n_dofs_per_cell = Nx[0].size(); + for (unsigned int q_point = 0; q_point < n_q_points; ++q_point) + { + Assert( Nx[q_point].size() == n_dofs_per_cell, ExcInternalError()); + Assert( symm_grad_Nx[q_point].size() == n_dofs_per_cell, + ExcInternalError()); + for (unsigned int k = 0; k < n_dofs_per_cell; ++k) + { + Nx[q_point][k] = 0.0; + symm_grad_Nx[q_point][k] = 0.0; + } + } + } + }; + template + struct Solid::PerTaskData_SC + { + FullMatrix cell_matrix; + std::vector local_dof_indices; + FullMatrix k_orig; + FullMatrix k_pu; + FullMatrix k_pJ; + FullMatrix k_JJ; + FullMatrix k_pJ_inv; + FullMatrix k_bbar; + FullMatrix A; + FullMatrix B; + FullMatrix C; + PerTaskData_SC(const unsigned int dofs_per_cell, + const unsigned int n_u, + const unsigned int n_p, + const unsigned int n_J) + : + cell_matrix(dofs_per_cell, dofs_per_cell), + local_dof_indices(dofs_per_cell), + k_orig(dofs_per_cell, dofs_per_cell), + k_pu(n_p, n_u), + k_pJ(n_p, n_J), + k_JJ(n_J, n_J), + k_pJ_inv(n_p, n_J), + k_bbar(n_u, n_u), + A(n_J,n_u), + B(n_J, n_u), + C(n_p, n_u) + {} + void reset() + {} + }; + template + struct Solid::ScratchData_SC + { + void reset() + {} + }; + template + struct Solid::PerTaskData_UQPH + { + void reset() + {} + }; + template + struct Solid::ScratchData_UQPH + { + const BlockVector &solution_total; + std::vector > solution_grads_u_total; + std::vector solution_values_p_total; + std::vector solution_values_J_total; + FEValues fe_values_ref; + ScratchData_UQPH(const FiniteElement &fe_cell, + const QGauss &qf_cell, + const UpdateFlags uf_cell, + const BlockVector &solution_total) + : + solution_total(solution_total), + solution_grads_u_total(qf_cell.size()), + solution_values_p_total(qf_cell.size()), + solution_values_J_total(qf_cell.size()), + fe_values_ref(fe_cell, qf_cell, uf_cell) + {} + ScratchData_UQPH(const ScratchData_UQPH &rhs) + : + solution_total(rhs.solution_total), + solution_grads_u_total(rhs.solution_grads_u_total), + solution_values_p_total(rhs.solution_values_p_total), + solution_values_J_total(rhs.solution_values_J_total), + fe_values_ref(rhs.fe_values_ref.get_fe(), + rhs.fe_values_ref.get_quadrature(), + rhs.fe_values_ref.get_update_flags()) + {} + void reset() + { + const unsigned int n_q_points = solution_grads_u_total.size(); + for (unsigned int q = 0; q < n_q_points; ++q) + { + solution_grads_u_total[q] = 0.0; + solution_values_p_total[q] = 0.0; + solution_values_J_total[q] = 0.0; + } + } + }; + template + void Solid::make_grid() + { + GridGenerator::hyper_rectangle(triangulation, + (dim==3 ? Point(0.0, 0.0, 0.0) : Point(0.0, 0.0)), + (dim==3 ? Point(1.0, 1.0, 1.0) : Point(1.0, 1.0)), + true); + GridTools::scale(parameters.scale, triangulation); + triangulation.refine_global(std::max (1U, parameters.global_refinement)); + vol_reference = GridTools::volume(triangulation); + pcout << "Grid:\n\t Reference volume: " << vol_reference << std::endl; + typename Triangulation::active_cell_iterator cell = + triangulation.begin_active(), endc = triangulation.end(); + for (; cell != endc; ++cell) + for (unsigned int face = 0; + face < GeometryInfo::faces_per_cell; ++face) + { + if (cell->face(face)->at_boundary() == true + && + cell->face(face)->center()[1] == 1.0 * parameters.scale) + { + if (dim==3) + { + if (cell->face(face)->center()[0] < 0.5 * parameters.scale + && + cell->face(face)->center()[2] < 0.5 * parameters.scale) + cell->face(face)->set_boundary_id(6); + } + else + { + if (cell->face(face)->center()[0] < 0.5 * parameters.scale) + cell->face(face)->set_boundary_id(6); + } + } + } + } + template + void Solid::system_setup() + { + timer.enter_subsection("Setup system"); + std::vector block_component(n_components, u_dof); // Displacement + block_component[p_component] = p_dof; // Pressure + block_component[J_component] = J_dof; // Dilatation + dof_handler_ref.distribute_dofs(fe); + DoFRenumbering::Cuthill_McKee(dof_handler_ref); + DoFRenumbering::component_wise(dof_handler_ref, block_component); + DoFTools::count_dofs_per_block(dof_handler_ref, dofs_per_block, + block_component); + pcout << "Triangulation:" + << "\n\t Number of active cells: " << triangulation.n_active_cells() + << "\n\t Number of degrees of freedom: " << dof_handler_ref.n_dofs() + << std::endl; + tangent_matrix.clear(); + { + const types::global_dof_index n_dofs_u = dofs_per_block[u_dof]; + const types::global_dof_index n_dofs_p = dofs_per_block[p_dof]; + const types::global_dof_index n_dofs_J = dofs_per_block[J_dof]; + BlockDynamicSparsityPattern dsp(n_blocks, n_blocks); + dsp.block(u_dof, u_dof).reinit(n_dofs_u, n_dofs_u); + dsp.block(u_dof, p_dof).reinit(n_dofs_u, n_dofs_p); + dsp.block(u_dof, J_dof).reinit(n_dofs_u, n_dofs_J); + dsp.block(p_dof, u_dof).reinit(n_dofs_p, n_dofs_u); + dsp.block(p_dof, p_dof).reinit(n_dofs_p, n_dofs_p); + dsp.block(p_dof, J_dof).reinit(n_dofs_p, n_dofs_J); + dsp.block(J_dof, u_dof).reinit(n_dofs_J, n_dofs_u); + dsp.block(J_dof, p_dof).reinit(n_dofs_J, n_dofs_p); + dsp.block(J_dof, J_dof).reinit(n_dofs_J, n_dofs_J); + dsp.collect_sizes(); + Table<2, DoFTools::Coupling> coupling(n_components, n_components); + for (unsigned int ii = 0; ii < n_components; ++ii) + for (unsigned int jj = 0; jj < n_components; ++jj) + if (((ii < p_component) && (jj == J_component)) + || ((ii == J_component) && (jj < p_component)) + || ((ii == p_component) && (jj == p_component))) + coupling[ii][jj] = DoFTools::none; + else + coupling[ii][jj] = DoFTools::always; + DoFTools::make_sparsity_pattern(dof_handler_ref, + coupling, + dsp, + constraints, + false); + sparsity_pattern.copy_from(dsp); + } + tangent_matrix.reinit(sparsity_pattern); + system_rhs.reinit(dofs_per_block); + system_rhs.collect_sizes(); + solution_n.reinit(dofs_per_block); + solution_n.collect_sizes(); + setup_qph(); + timer.leave_subsection(); + } + template + void + Solid::determine_component_extractors() + { + element_indices_u.clear(); + element_indices_p.clear(); + element_indices_J.clear(); + for (unsigned int k = 0; k < fe.dofs_per_cell; ++k) + { + const unsigned int k_group = fe.system_to_base_index(k).first.first; + if (k_group == u_dof) + element_indices_u.push_back(k); + else if (k_group == p_dof) + element_indices_p.push_back(k); + else if (k_group == J_dof) + element_indices_J.push_back(k); + else + { + Assert(k_group <= J_dof, ExcInternalError()); + } + } + } + template + void Solid::setup_qph() + { + pcout << " Setting up quadrature point data..." << std::endl; + quadrature_point_history.initialize(triangulation.begin_active(), + triangulation.end(), + n_q_points); + for (typename Triangulation::active_cell_iterator cell = + triangulation.begin_active(); cell != triangulation.end(); ++cell) + { + const std::vector > > lqph = + quadrature_point_history.get_data(cell); + Assert(lqph.size() == n_q_points, ExcInternalError()); + for (unsigned int q_point = 0; q_point < n_q_points; ++q_point) + lqph[q_point]->setup_lqp(parameters); + } + } + template + void Solid::update_qph_incremental(const BlockVector &solution_delta) + { + timer.enter_subsection("Update QPH data"); + pcout << " UQPH " << std::flush; + const BlockVector solution_total(get_total_solution(solution_delta)); + const UpdateFlags uf_UQPH(update_values | update_gradients); + PerTaskData_UQPH per_task_data_UQPH; + ScratchData_UQPH scratch_data_UQPH(fe, qf_cell, uf_UQPH, solution_total); + WorkStream::run(dof_handler_ref.begin_active(), + dof_handler_ref.end(), + *this, + &Solid::update_qph_incremental_one_cell, + &Solid::copy_local_to_global_UQPH, + scratch_data_UQPH, + per_task_data_UQPH); + timer.leave_subsection(); + } + template + void + Solid::update_qph_incremental_one_cell(const typename DoFHandler::active_cell_iterator &cell, + ScratchData_UQPH &scratch, + PerTaskData_UQPH &/*data*/) + { + const std::vector > > lqph = + quadrature_point_history.get_data(cell); + Assert(lqph.size() == n_q_points, ExcInternalError()); + Assert(scratch.solution_grads_u_total.size() == n_q_points, + ExcInternalError()); + Assert(scratch.solution_values_p_total.size() == n_q_points, + ExcInternalError()); + Assert(scratch.solution_values_J_total.size() == n_q_points, + ExcInternalError()); + scratch.reset(); + scratch.fe_values_ref.reinit(cell); + scratch.fe_values_ref[u_fe].get_function_gradients(scratch.solution_total, + scratch.solution_grads_u_total); + scratch.fe_values_ref[p_fe].get_function_values(scratch.solution_total, + scratch.solution_values_p_total); + scratch.fe_values_ref[J_fe].get_function_values(scratch.solution_total, + scratch.solution_values_J_total); + for (unsigned int q_point = 0; q_point < n_q_points; ++q_point) + lqph[q_point]->update_values(scratch.solution_grads_u_total[q_point], + scratch.solution_values_p_total[q_point], + scratch.solution_values_J_total[q_point]); + } + template + void + Solid::solve_nonlinear_timestep(BlockVector &solution_delta) + { + pcout << std::endl << "Timestep " << time.get_timestep() << " @ " + << time.current() << "s" << std::endl; + BlockVector newton_update(dofs_per_block); + error_residual.reset(); + error_residual_0.reset(); + error_residual_norm.reset(); + error_update.reset(); + error_update_0.reset(); + error_update_norm.reset(); + print_conv_header(); + unsigned int newton_iteration = 0; + for (; newton_iteration < parameters.max_iterations_NR; + ++newton_iteration) + { + pcout << " " << std::setw(2) << newton_iteration << " " << std::flush; + tangent_matrix = 0.0; + system_rhs = 0.0; + assemble_system_rhs(); + get_error_residual(error_residual); + if (newton_iteration == 0) + error_residual_0 = error_residual; + error_residual_norm = error_residual; + error_residual_norm.normalise(error_residual_0); + if (newton_iteration > 0 && error_update_norm.u <= parameters.tol_u + && error_residual_norm.u <= parameters.tol_f) + { + pcout << " CONVERGED! " << std::endl; + print_conv_footer(); + break; + } + assemble_system_tangent(); + make_constraints(newton_iteration); + constraints.condense(tangent_matrix, system_rhs); + const std::pair + lin_solver_output = solve_linear_system(newton_update); + get_error_update(newton_update, error_update); + if (newton_iteration == 0) + error_update_0 = error_update; + error_update_norm = error_update; + error_update_norm.normalise(error_update_0); + solution_delta += newton_update; + update_qph_incremental(solution_delta); + pcout << " | " << std::fixed << std::setprecision(3) << std::setw(7) + << std::scientific << lin_solver_output.first << " " + << lin_solver_output.second << " " << error_residual_norm.norm + << " " << error_residual_norm.u << " " + << error_residual_norm.p << " " << error_residual_norm.J + << " " << error_update_norm.norm << " " << error_update_norm.u + << " " << error_update_norm.p << " " << error_update_norm.J + << " " << std::endl; + } + AssertThrow (newton_iteration <= parameters.max_iterations_NR, + ExcMessage("No convergence in nonlinear solver!")); + } + template + void Solid::print_conv_header() + { + static const unsigned int l_width = 155; + for (unsigned int i = 0; i < l_width; ++i) + pcout << "_"; + pcout << std::endl; + pcout << " SOLVER STEP " + << " | LIN_IT LIN_RES RES_NORM " + << " RES_U RES_P RES_J NU_NORM " + << " NU_U NU_P NU_J " << std::endl; + for (unsigned int i = 0; i < l_width; ++i) + pcout << "_"; + pcout << std::endl; + } + template + void Solid::print_conv_footer() + { + static const unsigned int l_width = 155; + for (unsigned int i = 0; i < l_width; ++i) + pcout << "_"; + pcout << std::endl; + const std::pair error_dil = get_error_dilation(); + pcout << "Relative errors:" << std::endl + << "Displacement:\t" << error_update.u / error_update_0.u << std::endl + << "Force: \t\t" << error_residual.u / error_residual_0.u << std::endl + << "Dilatation:\t" << error_dil.first << std::endl + << "v / V_0:\t" << error_dil.second *vol_reference << " / " << vol_reference + << " = " << error_dil.second << std::endl; + } + template + double + Solid::compute_vol_current() const + { + double vol_current = 0.0; + FEValues fe_values_ref(fe, qf_cell, update_JxW_values); + for (typename Triangulation::active_cell_iterator + cell = triangulation.begin_active(); + cell != triangulation.end(); ++cell) + { + fe_values_ref.reinit(cell); + const std::vector > > lqph = + quadrature_point_history.get_data(cell); + Assert(lqph.size() == n_q_points, ExcInternalError()); + for (unsigned int q_point = 0; q_point < n_q_points; ++q_point) + { + const double det_F_qp = lqph[q_point]->get_det_F(); + const double JxW = fe_values_ref.JxW(q_point); + vol_current += det_F_qp * JxW; + } + } + Assert(vol_current > 0.0, ExcInternalError()); + return vol_current; + } + template + std::pair + Solid::get_error_dilation() const + { + double dil_L2_error = 0.0; + FEValues fe_values_ref(fe, qf_cell, update_JxW_values); + for (typename Triangulation::active_cell_iterator + cell = triangulation.begin_active(); + cell != triangulation.end(); ++cell) + { + fe_values_ref.reinit(cell); + const std::vector > > lqph = + quadrature_point_history.get_data(cell); + Assert(lqph.size() == n_q_points, ExcInternalError()); + for (unsigned int q_point = 0; q_point < n_q_points; ++q_point) + { + const double det_F_qp = lqph[q_point]->get_det_F(); + const double J_tilde_qp = lqph[q_point]->get_J_tilde(); + const double the_error_qp_squared = std::pow((det_F_qp - J_tilde_qp), + 2); + const double JxW = fe_values_ref.JxW(q_point); + dil_L2_error += the_error_qp_squared * JxW; + } + } + return std::make_pair(std::sqrt(dil_L2_error), + compute_vol_current() / vol_reference); + } + template + void Solid::get_error_residual(Errors &error_residual) + { + BlockVector error_res(dofs_per_block); + for (unsigned int i = 0; i < dof_handler_ref.n_dofs(); ++i) + if (!constraints.is_constrained(i)) + error_res(i) = system_rhs(i); + error_residual.norm = error_res.l2_norm(); + error_residual.u = error_res.block(u_dof).l2_norm(); + error_residual.p = error_res.block(p_dof).l2_norm(); + error_residual.J = error_res.block(J_dof).l2_norm(); + } + template + void Solid::get_error_update(const BlockVector &newton_update, + Errors &error_update) + { + BlockVector error_ud(dofs_per_block); + for (unsigned int i = 0; i < dof_handler_ref.n_dofs(); ++i) + if (!constraints.is_constrained(i)) + error_ud(i) = newton_update(i); + error_update.norm = error_ud.l2_norm(); + error_update.u = error_ud.block(u_dof).l2_norm(); + error_update.p = error_ud.block(p_dof).l2_norm(); + error_update.J = error_ud.block(J_dof).l2_norm(); + } + template + BlockVector + Solid::get_total_solution(const BlockVector &solution_delta) const + { + BlockVector solution_total(solution_n); + solution_total += solution_delta; + return solution_total; + } + template + void Solid::assemble_system_tangent() + { + timer.enter_subsection("Assemble tangent matrix"); + pcout << " ASM_K " << std::flush; + tangent_matrix = 0.0; + const UpdateFlags uf_cell(update_values | + update_gradients | + update_JxW_values); + PerTaskData_K per_task_data(dofs_per_cell); + ScratchData_K scratch_data(fe, qf_cell, uf_cell); + WorkStream::run(dof_handler_ref.begin_active(), + dof_handler_ref.end(), + std_cxx11::bind(&Solid::assemble_system_tangent_one_cell, + this, + std_cxx11::_1, + std_cxx11::_2, + std_cxx11::_3), + std_cxx11::bind(&Solid::copy_local_to_global_K, + this, + std_cxx11::_1), + scratch_data, + per_task_data); + timer.leave_subsection(); + } + template + void Solid::copy_local_to_global_K(const PerTaskData_K &data) + { + for (unsigned int i = 0; i < dofs_per_cell; ++i) + for (unsigned int j = 0; j < dofs_per_cell; ++j) + tangent_matrix.add(data.local_dof_indices[i], + data.local_dof_indices[j], + data.cell_matrix(i, j)); + } + template + void + Solid::assemble_system_tangent_one_cell(const typename DoFHandler::active_cell_iterator &cell, + ScratchData_K &scratch, + PerTaskData_K &data) const + { + data.reset(); + scratch.reset(); + scratch.fe_values_ref.reinit(cell); + cell->get_dof_indices(data.local_dof_indices); + const std::vector > > lqph = + quadrature_point_history.get_data(cell); + Assert(lqph.size() == n_q_points, ExcInternalError()); + for (unsigned int q_point = 0; q_point < n_q_points; ++q_point) + { + const Tensor<2, dim> F_inv = lqph[q_point]->get_F_inv(); + for (unsigned int k = 0; k < dofs_per_cell; ++k) + { + const unsigned int k_group = fe.system_to_base_index(k).first.first; + if (k_group == u_dof) + { + scratch.grad_Nx[q_point][k] = scratch.fe_values_ref[u_fe].gradient(k, q_point) + * F_inv; + scratch.symm_grad_Nx[q_point][k] = symmetrize(scratch.grad_Nx[q_point][k]); + } + else if (k_group == p_dof) + scratch.Nx[q_point][k] = scratch.fe_values_ref[p_fe].value(k, + q_point); + else if (k_group == J_dof) + scratch.Nx[q_point][k] = scratch.fe_values_ref[J_fe].value(k, + q_point); + else + Assert(k_group <= J_dof, ExcInternalError()); + } + } + for (unsigned int q_point = 0; q_point < n_q_points; ++q_point) + { + const Tensor<2, dim> tau = lqph[q_point]->get_tau(); + const SymmetricTensor<4, dim> Jc = lqph[q_point]->get_Jc(); + const double d2Psi_vol_dJ2 = lqph[q_point]->get_d2Psi_vol_dJ2(); + const double det_F = lqph[q_point]->get_det_F(); + const std::vector + &N = scratch.Nx[q_point]; + const std::vector > + &symm_grad_Nx = scratch.symm_grad_Nx[q_point]; + const std::vector > + &grad_Nx = scratch.grad_Nx[q_point]; + const double JxW = scratch.fe_values_ref.JxW(q_point); + for (unsigned int i = 0; i < dofs_per_cell; ++i) + { + const unsigned int component_i = fe.system_to_component_index(i).first; + const unsigned int i_group = fe.system_to_base_index(i).first.first; + for (unsigned int j = 0; j <= i; ++j) + { + const unsigned int component_j = fe.system_to_component_index(j).first; + const unsigned int j_group = fe.system_to_base_index(j).first.first; + if ((i_group == j_group) && (i_group == u_dof)) + { + data.cell_matrix(i, j) += symm_grad_Nx[i] * Jc // The material contribution: + * symm_grad_Nx[j] * JxW; + if (component_i == component_j) // geometrical stress contribution + data.cell_matrix(i, j) += grad_Nx[i][component_i] * tau + * grad_Nx[j][component_j] * JxW; + } + else if ((i_group == p_dof) && (j_group == u_dof)) + { + data.cell_matrix(i, j) += N[i] * det_F + * (symm_grad_Nx[j] + * Physics::Elasticity::StandardTensors::I) + * JxW; + } + else if ((i_group == J_dof) && (j_group == p_dof)) + data.cell_matrix(i, j) -= N[i] * N[j] * JxW; + else if ((i_group == j_group) && (i_group == J_dof)) + data.cell_matrix(i, j) += N[i] * d2Psi_vol_dJ2 * N[j] * JxW; + else + Assert((i_group <= J_dof) && (j_group <= J_dof), + ExcInternalError()); + } + } + } + for (unsigned int i = 0; i < dofs_per_cell; ++i) + for (unsigned int j = i + 1; j < dofs_per_cell; ++j) + data.cell_matrix(i, j) = data.cell_matrix(j, i); + } + template + void Solid::assemble_system_rhs() + { + timer.enter_subsection("Assemble system right-hand side"); + pcout << " ASM_R " << std::flush; + system_rhs = 0.0; + const UpdateFlags uf_cell(update_values | + update_gradients | + update_JxW_values); + const UpdateFlags uf_face(update_values | + update_normal_vectors | + update_JxW_values); + PerTaskData_RHS per_task_data(dofs_per_cell); + ScratchData_RHS scratch_data(fe, qf_cell, uf_cell, qf_face, uf_face); + WorkStream::run(dof_handler_ref.begin_active(), + dof_handler_ref.end(), + std_cxx11::bind(&Solid::assemble_system_rhs_one_cell, + this, + std_cxx11::_1, + std_cxx11::_2, + std_cxx11::_3), + std_cxx11::bind(&Solid::copy_local_to_global_rhs, + this, + std_cxx11::_1), + scratch_data, + per_task_data); + timer.leave_subsection(); + } + template + void Solid::copy_local_to_global_rhs(const PerTaskData_RHS &data) + { + for (unsigned int i = 0; i < dofs_per_cell; ++i) + system_rhs(data.local_dof_indices[i]) += data.cell_rhs(i); + } + template + void + Solid::assemble_system_rhs_one_cell(const typename DoFHandler::active_cell_iterator &cell, + ScratchData_RHS &scratch, + PerTaskData_RHS &data) const + { + data.reset(); + scratch.reset(); + scratch.fe_values_ref.reinit(cell); + cell->get_dof_indices(data.local_dof_indices); + const std::vector > > lqph = + quadrature_point_history.get_data(cell); + Assert(lqph.size() == n_q_points, ExcInternalError()); + for (unsigned int q_point = 0; q_point < n_q_points; ++q_point) + { + const Tensor<2, dim> F_inv = lqph[q_point]->get_F_inv(); + for (unsigned int k = 0; k < dofs_per_cell; ++k) + { + const unsigned int k_group = fe.system_to_base_index(k).first.first; + if (k_group == u_dof) + scratch.symm_grad_Nx[q_point][k] + = symmetrize(scratch.fe_values_ref[u_fe].gradient(k, q_point) + * F_inv); + else if (k_group == p_dof) + scratch.Nx[q_point][k] = scratch.fe_values_ref[p_fe].value(k, + q_point); + else if (k_group == J_dof) + scratch.Nx[q_point][k] = scratch.fe_values_ref[J_fe].value(k, + q_point); + else + Assert(k_group <= J_dof, ExcInternalError()); + } + } + for (unsigned int q_point = 0; q_point < n_q_points; ++q_point) + { + const SymmetricTensor<2, dim> tau = lqph[q_point]->get_tau(); + const double det_F = lqph[q_point]->get_det_F(); + const double J_tilde = lqph[q_point]->get_J_tilde(); + const double p_tilde = lqph[q_point]->get_p_tilde(); + const double dPsi_vol_dJ = lqph[q_point]->get_dPsi_vol_dJ(); + const std::vector + &N = scratch.Nx[q_point]; + const std::vector > + &symm_grad_Nx = scratch.symm_grad_Nx[q_point]; + const double JxW = scratch.fe_values_ref.JxW(q_point); + for (unsigned int i = 0; i < dofs_per_cell; ++i) + { + const unsigned int i_group = fe.system_to_base_index(i).first.first; + if (i_group == u_dof) + data.cell_rhs(i) -= (symm_grad_Nx[i] * tau) * JxW; + else if (i_group == p_dof) + data.cell_rhs(i) -= N[i] * (det_F - J_tilde) * JxW; + else if (i_group == J_dof) + data.cell_rhs(i) -= N[i] * (dPsi_vol_dJ - p_tilde) * JxW; + else + Assert(i_group <= J_dof, ExcInternalError()); + } + } + for (unsigned int face = 0; face < GeometryInfo::faces_per_cell; + ++face) + if (cell->face(face)->at_boundary() == true + && cell->face(face)->boundary_id() == 6) + { + scratch.fe_face_values_ref.reinit(cell, face); + for (unsigned int f_q_point = 0; f_q_point < n_q_points_f; + ++f_q_point) + { + const Tensor<1, dim> &N = + scratch.fe_face_values_ref.normal_vector(f_q_point); + static const double p0 = -4.0 + / + (parameters.scale * parameters.scale); + const double time_ramp = (time.current() / time.end()); + const double pressure = p0 * parameters.p_p0 * time_ramp; + const Tensor<1, dim> traction = pressure * N; + for (unsigned int i = 0; i < dofs_per_cell; ++i) + { + const unsigned int i_group = + fe.system_to_base_index(i).first.first; + if (i_group == u_dof) + { + const unsigned int component_i = + fe.system_to_component_index(i).first; + const double Ni = + scratch.fe_face_values_ref.shape_value(i, + f_q_point); + const double JxW = scratch.fe_face_values_ref.JxW( + f_q_point); + data.cell_rhs(i) += (Ni * traction[component_i]) + * JxW; + } + } + } + } + } + template + void Solid::make_constraints(const int &it_nr) + { + pcout << " CST " << std::flush; + if (it_nr > 1) + return; + constraints.clear(); + const bool apply_dirichlet_bc = (it_nr == 0); + const FEValuesExtractors::Scalar x_displacement(0); + const FEValuesExtractors::Scalar y_displacement(1); + { + const int boundary_id = 0; + if (apply_dirichlet_bc == true) + VectorTools::interpolate_boundary_values(dof_handler_ref, + boundary_id, + ZeroFunction(n_components), + constraints, + fe.component_mask(x_displacement)); + else + VectorTools::interpolate_boundary_values(dof_handler_ref, + boundary_id, + ZeroFunction(n_components), + constraints, + fe.component_mask(x_displacement)); + } + { + const int boundary_id = 2; + if (apply_dirichlet_bc == true) + VectorTools::interpolate_boundary_values(dof_handler_ref, + boundary_id, + ZeroFunction(n_components), + constraints, + fe.component_mask(y_displacement)); + else + VectorTools::interpolate_boundary_values(dof_handler_ref, + boundary_id, + ZeroFunction(n_components), + constraints, + fe.component_mask(y_displacement)); + } + if (dim==3) + { + const FEValuesExtractors::Scalar z_displacement(2); + { + const int boundary_id = 3; + if (apply_dirichlet_bc == true) + VectorTools::interpolate_boundary_values(dof_handler_ref, + boundary_id, + ZeroFunction(n_components), + constraints, + (fe.component_mask(x_displacement) + | + fe.component_mask(z_displacement))); + else + VectorTools::interpolate_boundary_values(dof_handler_ref, + boundary_id, + ZeroFunction(n_components), + constraints, + (fe.component_mask(x_displacement) + | + fe.component_mask(z_displacement))); + } + { + const int boundary_id = 4; + if (apply_dirichlet_bc == true) + VectorTools::interpolate_boundary_values(dof_handler_ref, + boundary_id, + ZeroFunction(n_components), + constraints, + fe.component_mask(z_displacement)); + else + VectorTools::interpolate_boundary_values(dof_handler_ref, + boundary_id, + ZeroFunction(n_components), + constraints, + fe.component_mask(z_displacement)); + } + { + const int boundary_id = 6; + if (apply_dirichlet_bc == true) + VectorTools::interpolate_boundary_values(dof_handler_ref, + boundary_id, + ZeroFunction(n_components), + constraints, + (fe.component_mask(x_displacement) + | + fe.component_mask(z_displacement))); + else + VectorTools::interpolate_boundary_values(dof_handler_ref, + boundary_id, + ZeroFunction(n_components), + constraints, + (fe.component_mask(x_displacement) + | + fe.component_mask(z_displacement))); + } + } + else + { + { + const int boundary_id = 3; + if (apply_dirichlet_bc == true) + VectorTools::interpolate_boundary_values(dof_handler_ref, + boundary_id, + ZeroFunction(n_components), + constraints, + (fe.component_mask(x_displacement))); + else + VectorTools::interpolate_boundary_values(dof_handler_ref, + boundary_id, + ZeroFunction(n_components), + constraints, + (fe.component_mask(x_displacement))); + } + { + const int boundary_id = 6; + if (apply_dirichlet_bc == true) + VectorTools::interpolate_boundary_values(dof_handler_ref, + boundary_id, + ZeroFunction(n_components), + constraints, + (fe.component_mask(x_displacement))); + else + VectorTools::interpolate_boundary_values(dof_handler_ref, + boundary_id, + ZeroFunction(n_components), + constraints, + (fe.component_mask(x_displacement))); + } + } + constraints.close(); + } + template + void Solid::assemble_sc() + { + timer.enter_subsection("Perform static condensation"); + pcout << " ASM_SC " << std::flush; + PerTaskData_SC per_task_data(dofs_per_cell, element_indices_u.size(), + element_indices_p.size(), + element_indices_J.size()); + ScratchData_SC scratch_data; + WorkStream::run(dof_handler_ref.begin_active(), + dof_handler_ref.end(), + *this, + &Solid::assemble_sc_one_cell, + &Solid::copy_local_to_global_sc, + scratch_data, + per_task_data); + timer.leave_subsection(); + } + template + void Solid::copy_local_to_global_sc(const PerTaskData_SC &data) + { + for (unsigned int i = 0; i < dofs_per_cell; ++i) + for (unsigned int j = 0; j < dofs_per_cell; ++j) + tangent_matrix.add(data.local_dof_indices[i], + data.local_dof_indices[j], + data.cell_matrix(i, j)); + } + template + void + Solid::assemble_sc_one_cell(const typename DoFHandler::active_cell_iterator &cell, + ScratchData_SC &scratch, + PerTaskData_SC &data) + { + data.reset(); + scratch.reset(); + cell->get_dof_indices(data.local_dof_indices); + data.k_orig.extract_submatrix_from(tangent_matrix, + data.local_dof_indices, + data.local_dof_indices); + data.k_pu.extract_submatrix_from(data.k_orig, + element_indices_p, + element_indices_u); + data.k_pJ.extract_submatrix_from(data.k_orig, + element_indices_p, + element_indices_J); + data.k_JJ.extract_submatrix_from(data.k_orig, + element_indices_J, + element_indices_J); + data.k_pJ_inv.invert(data.k_pJ); + data.k_pJ_inv.mmult(data.A, data.k_pu); + data.k_JJ.mmult(data.B, data.A); + data.k_pJ_inv.Tmmult(data.C, data.B); + data.k_pu.Tmmult(data.k_bbar, data.C); + data.k_bbar.scatter_matrix_to(element_indices_u, + element_indices_u, + data.cell_matrix); + data.k_pJ_inv.add(-1.0, data.k_pJ); + data.k_pJ_inv.scatter_matrix_to(element_indices_p, + element_indices_J, + data.cell_matrix); + } + template + std::pair + Solid::solve_linear_system(BlockVector &newton_update) + { + unsigned int lin_it = 0; + double lin_res = 0.0; + if (parameters.use_static_condensation == true) + { + BlockVector A(dofs_per_block); + BlockVector B(dofs_per_block); + { + assemble_sc(); + tangent_matrix.block(p_dof, J_dof).vmult(A.block(J_dof), + system_rhs.block(p_dof)); + tangent_matrix.block(J_dof, J_dof).vmult(B.block(J_dof), + A.block(J_dof)); + A.block(J_dof) = system_rhs.block(J_dof); + A.block(J_dof) -= B.block(J_dof); + tangent_matrix.block(p_dof, J_dof).Tvmult(A.block(p_dof), + A.block(J_dof)); + tangent_matrix.block(u_dof, p_dof).vmult(A.block(u_dof), + A.block(p_dof)); + system_rhs.block(u_dof) -= A.block(u_dof); + timer.enter_subsection("Linear solver"); + pcout << " SLV " << std::flush; + if (parameters.type_lin == "CG") + { + const int solver_its = tangent_matrix.block(u_dof, u_dof).m() + * parameters.max_iterations_lin; + const double tol_sol = parameters.tol_lin + * system_rhs.block(u_dof).l2_norm(); + SolverControl solver_control(solver_its, tol_sol); + GrowingVectorMemory > GVM; + SolverCG > solver_CG(solver_control, GVM); + PreconditionSelector, Vector > + preconditioner (parameters.preconditioner_type, + parameters.preconditioner_relaxation); + preconditioner.use_matrix(tangent_matrix.block(u_dof, u_dof)); + solver_CG.solve(tangent_matrix.block(u_dof, u_dof), + newton_update.block(u_dof), + system_rhs.block(u_dof), + preconditioner); + lin_it = solver_control.last_step(); + lin_res = solver_control.last_value(); + } + else if (parameters.type_lin == "Direct") + { + SparseDirectUMFPACK A_direct; + A_direct.initialize(tangent_matrix.block(u_dof, u_dof)); + A_direct.vmult(newton_update.block(u_dof), system_rhs.block(u_dof)); + lin_it = 1; + lin_res = 0.0; + } + else + Assert (false, ExcMessage("Linear solver type not implemented")); + timer.leave_subsection(); + } + constraints.distribute(newton_update); + timer.enter_subsection("Linear solver postprocessing"); + pcout << " PP " << std::flush; + { + tangent_matrix.block(p_dof, u_dof).vmult(A.block(p_dof), + newton_update.block(u_dof)); + A.block(p_dof) *= -1.0; + A.block(p_dof) += system_rhs.block(p_dof); + tangent_matrix.block(p_dof, J_dof).vmult(newton_update.block(J_dof), + A.block(p_dof)); + } + constraints.distribute(newton_update); + { + tangent_matrix.block(J_dof, J_dof).vmult(A.block(J_dof), + newton_update.block(J_dof)); + A.block(J_dof) *= -1.0; + A.block(J_dof) += system_rhs.block(J_dof); + tangent_matrix.block(p_dof, J_dof).Tvmult(newton_update.block(p_dof), + A.block(J_dof)); + } + constraints.distribute(newton_update); + timer.leave_subsection(); + } + else + { + pcout << " ------ " << std::flush; + timer.enter_subsection("Linear solver"); + pcout << " SLV " << std::flush; + if (parameters.type_lin == "CG") + { + const Vector &f_u = system_rhs.block(u_dof); + const Vector &f_p = system_rhs.block(p_dof); + const Vector &f_J = system_rhs.block(J_dof); + Vector &d_u = newton_update.block(u_dof); + Vector &d_p = newton_update.block(p_dof); + Vector &d_J = newton_update.block(J_dof); + const auto K_uu = linear_operator(tangent_matrix.block(u_dof, u_dof)); + const auto K_up = linear_operator(tangent_matrix.block(u_dof, p_dof)); + const auto K_pu = linear_operator(tangent_matrix.block(p_dof, u_dof)); + const auto K_Jp = linear_operator(tangent_matrix.block(J_dof, p_dof)); + const auto K_JJ = linear_operator(tangent_matrix.block(J_dof, J_dof)); + PreconditionSelector< SparseMatrix, Vector > + preconditioner_K_Jp_inv ("jacobi"); + preconditioner_K_Jp_inv.use_matrix(tangent_matrix.block(J_dof, p_dof)); + ReductionControl solver_control_K_Jp_inv (tangent_matrix.block(J_dof, p_dof).m() * parameters.max_iterations_lin, + 1.0e-30, parameters.tol_lin); + SolverSelector< Vector > solver_K_Jp_inv; + solver_K_Jp_inv.select("cg"); + solver_K_Jp_inv.set_control(solver_control_K_Jp_inv); + const auto K_Jp_inv = inverse_operator(K_Jp, + solver_K_Jp_inv, + preconditioner_K_Jp_inv); + const auto K_pJ_inv = transpose_operator(K_Jp_inv); + const auto K_pp_bar = K_Jp_inv * K_JJ * K_pJ_inv; + const auto K_uu_bar_bar = K_up * K_pp_bar * K_pu; + const auto K_uu_con = K_uu + K_uu_bar_bar; + PreconditionSelector< SparseMatrix, Vector > + preconditioner_K_con_inv (parameters.preconditioner_type, + parameters.preconditioner_relaxation); + preconditioner_K_con_inv.use_matrix(tangent_matrix.block(u_dof, u_dof)); + ReductionControl solver_control_K_con_inv (tangent_matrix.block(u_dof, u_dof).m() * parameters.max_iterations_lin, + 1.0e-30, parameters.tol_lin); + SolverSelector< Vector > solver_K_con_inv; + solver_K_con_inv.select("cg"); + solver_K_con_inv.set_control(solver_control_K_con_inv); + const auto K_uu_con_inv = inverse_operator(K_uu_con, + solver_K_con_inv, + preconditioner_K_con_inv); + d_u = K_uu_con_inv*(f_u - K_up*(K_Jp_inv*f_J - K_pp_bar*f_p)); + timer.leave_subsection(); + timer.enter_subsection("Linear solver postprocessing"); + pcout << " PP " << std::flush; + d_J = K_pJ_inv*(f_p - K_pu*d_u); + d_p = K_Jp_inv*(f_J - K_JJ*d_J); + lin_it = solver_control_K_con_inv.last_step(); + lin_res = solver_control_K_con_inv.last_value(); + } + else if (parameters.type_lin == "Direct") + { + SparseDirectUMFPACK A_direct; + A_direct.initialize(tangent_matrix); + A_direct.vmult(newton_update, system_rhs); + lin_it = 1; + lin_res = 0.0; + pcout << " -- " << std::flush; + } + else + Assert (false, ExcMessage("Linear solver type not implemented")); + timer.leave_subsection(); + constraints.distribute(newton_update); + } + return std::make_pair(lin_it, lin_res); + } + template + void Solid::output_results() const + { + DataOut data_out; + std::vector + data_component_interpretation(dim, + DataComponentInterpretation::component_is_part_of_vector); + data_component_interpretation.push_back(DataComponentInterpretation::component_is_scalar); + data_component_interpretation.push_back(DataComponentInterpretation::component_is_scalar); + std::vector solution_name(dim, "displacement"); + solution_name.push_back("pressure"); + solution_name.push_back("dilatation"); + data_out.attach_dof_handler(dof_handler_ref); + data_out.add_data_vector(solution_n, + solution_name, + DataOut::type_dof_data, + data_component_interpretation); + Vector soln(solution_n.size()); + for (unsigned int i = 0; i < soln.size(); ++i) + soln(i) = solution_n(i); + MappingQEulerian q_mapping(degree, dof_handler_ref, soln); + data_out.build_patches(q_mapping, degree); + std::ostringstream filename; + filename << "solution-" << dim << "d-" << time.get_timestep() << ".vtk"; + std::ofstream output(filename.str().c_str()); + data_out.write_vtk(output); + } +} +int main (int argc,char **argv) +{ + std::ofstream logfile("output"); + deallog.attach(logfile); + deallog.depth_file(0); + deallog.threshold_double(1.e-10); + + Utilities::MPI::MPI_InitFinalize mpi_initialization (argc, argv, testing_max_num_threads()); + using namespace dealii; + using namespace Step44; + try + { + const unsigned int dim = 3; + Solid solid(SOURCE_DIR "/prm/parameters-step-44.prm"); + solid.run(); + } + catch (std::exception &exc) + { + std::cerr << std::endl << std::endl + << "----------------------------------------------------" + << std::endl; + std::cerr << "Exception on processing: " << std::endl << exc.what() + << std::endl << "Aborting!" << std::endl + << "----------------------------------------------------" + << std::endl; + return 1; + } + catch (...) + { + std::cerr << std::endl << std::endl + << "----------------------------------------------------" + << std::endl; + std::cerr << "Unknown exception!" << std::endl << "Aborting!" + << std::endl + << "----------------------------------------------------" + << std::endl; + return 1; + } + return 0; +} diff --git a/tests/physics/step-44-standard_tensors-spatial.output b/tests/physics/step-44-standard_tensors-spatial.output new file mode 100644 index 0000000000..546f183a94 --- /dev/null +++ b/tests/physics/step-44-standard_tensors-spatial.output @@ -0,0 +1,167 @@ + +Grid: + Reference volume: 1.00000e-09 +Triangulation: + Number of active cells: 64 + Number of degrees of freedom: 503 + Setting up quadrature point data... + +Timestep 1 @ 0.100000s +___________________________________________________________________________________________________________________________________________________________ + SOLVER STEP | LIN_IT LIN_RES RES_NORM RES_U RES_P RES_J NU_NORM NU_U NU_P NU_J +___________________________________________________________________________________________________________________________________________________________ + 0 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 134 1.879e-06 1.000e+00 1.000e+00 0.000e+00 0.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 + 1 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 96 1.114e-03 8.085e-02 8.085e-02 7.076e-13 3.053e-08 9.396e-02 3.598e-02 9.396e-02 9.397e-02 + 2 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 123 2.213e-06 9.284e-04 9.284e-04 2.254e-15 1.996e-10 8.786e-04 1.975e-04 8.786e-04 8.788e-04 + 3 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 151 3.555e-11 5.917e-07 5.917e-07 4.211e-20 2.312e-14 6.259e-07 1.495e-07 6.259e-07 6.259e-07 + 4 ASM_R CONVERGED! +___________________________________________________________________________________________________________________________________________________________ +Relative errors: +Displacement: 1.495e-07 +Force: 9.480e-12 +Dilatation: 3.484e-07 +v / V_0: 1.000e-09 / 1.000e-09 = 1.000e+00 + +Timestep 2 @ 2.000e-01s +___________________________________________________________________________________________________________________________________________________________ + SOLVER STEP | LIN_IT LIN_RES RES_NORM RES_U RES_P RES_J NU_NORM NU_U NU_P NU_J +___________________________________________________________________________________________________________________________________________________________ + 0 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 134 1.864e-06 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 + 1 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 92 1.055e-03 8.472e-02 8.472e-02 2.306e+13 6.107e+06 1.096e-01 4.023e-02 1.096e-01 1.097e-01 + 2 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 115 4.858e-06 9.620e-04 9.620e-04 9.042e+10 5.919e+04 1.142e-03 3.104e-04 1.142e-03 1.142e-03 + 3 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 151 8.675e-11 1.296e-06 1.296e-06 2.300e+06 7.668e+00 2.098e-06 4.733e-07 2.098e-06 2.098e-06 + 4 ASM_R CONVERGED! +___________________________________________________________________________________________________________________________________________________________ +Relative errors: +Displacement: 4.733e-07 +Force: 2.313e-11 +Dilatation: 7.035e-07 +v / V_0: 1.000e-09 / 1.000e-09 = 1.000e+00 + +Timestep 3 @ 3.000e-01s +___________________________________________________________________________________________________________________________________________________________ + SOLVER STEP | LIN_IT LIN_RES RES_NORM RES_U RES_P RES_J NU_NORM NU_U NU_P NU_J +___________________________________________________________________________________________________________________________________________________________ + 0 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 130 2.213e-06 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 + 1 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 95 1.501e-03 9.356e-02 9.356e-02 4.481e+12 4.677e+06 1.130e-01 4.961e-02 1.130e-01 1.131e-01 + 2 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 110 7.323e-06 1.013e-03 1.013e-03 2.165e+10 4.746e+04 1.479e-03 4.834e-04 1.479e-03 1.480e-03 + 3 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 143 2.610e-10 1.948e-06 1.948e-06 1.157e+06 7.005e+00 2.141e-06 2.425e-07 2.141e-06 2.142e-06 + 4 ASM_R CONVERGED! +___________________________________________________________________________________________________________________________________________________________ +Relative errors: +Displacement: 2.425e-07 +Force: 6.959e-11 +Dilatation: 1.059e-06 +v / V_0: 1.000e-09 / 1.000e-09 = 1.000e+00 + +Timestep 4 @ 4.000e-01s +___________________________________________________________________________________________________________________________________________________________ + SOLVER STEP | LIN_IT LIN_RES RES_NORM RES_U RES_P RES_J NU_NORM NU_U NU_P NU_J +___________________________________________________________________________________________________________________________________________________________ + 0 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 130 1.859e-06 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 + 1 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 91 1.185e-03 1.069e-01 1.069e-01 8.200e+12 3.902e+06 9.765e-02 6.072e-02 9.765e-02 9.767e-02 + 2 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 110 6.518e-06 1.440e-03 1.440e-03 4.432e+10 2.477e+04 1.897e-03 8.054e-04 1.897e-03 1.897e-03 + 3 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 143 9.331e-10 1.764e-06 1.764e-06 6.641e+06 1.187e+01 2.206e-06 7.739e-07 2.206e-06 2.207e-06 + 4 ASM_R CONVERGED! +___________________________________________________________________________________________________________________________________________________________ +Relative errors: +Displacement: 7.739e-07 +Force: 2.488e-10 +Dilatation: 1.407e-06 +v / V_0: 1.000e-09 / 1.000e-09 = 1.000e+00 + +Timestep 5 @ 5.000e-01s +___________________________________________________________________________________________________________________________________________________________ + SOLVER STEP | LIN_IT LIN_RES RES_NORM RES_U RES_P RES_J NU_NORM NU_U NU_P NU_J +___________________________________________________________________________________________________________________________________________________________ + 0 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 129 3.277e-06 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 + 1 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 94 7.466e-04 1.179e-01 1.179e-01 1.282e+12 3.596e+06 7.328e-02 6.923e-02 7.328e-02 7.329e-02 + 2 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 113 6.856e-06 2.300e-03 2.300e-03 7.177e+09 9.311e+03 2.297e-03 1.160e-03 2.297e-03 2.297e-03 + 3 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 140 1.920e-09 2.134e-06 2.134e-06 2.482e+06 1.673e+01 5.052e-06 5.744e-07 5.052e-06 5.053e-06 + 4 ASM_R CONVERGED! +___________________________________________________________________________________________________________________________________________________________ +Relative errors: +Displacement: 5.744e-07 +Force: 5.119e-10 +Dilatation: 1.742e-06 +v / V_0: 1.000e-09 / 1.000e-09 = 1.000e+00 + +Timestep 6 @ 6.000e-01s +___________________________________________________________________________________________________________________________________________________________ + SOLVER STEP | LIN_IT LIN_RES RES_NORM RES_U RES_P RES_J NU_NORM NU_U NU_P NU_J +___________________________________________________________________________________________________________________________________________________________ + 0 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 132 1.418e-06 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 + 1 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 98 5.446e-04 1.230e-01 1.230e-01 2.598e+12 3.341e+06 5.486e-02 7.377e-02 5.486e-02 5.488e-02 + 2 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 118 4.807e-06 2.689e-03 2.689e-03 1.406e+10 3.742e+03 2.236e-03 1.405e-03 2.236e-03 2.236e-03 + 3 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 144 3.117e-09 1.929e-06 1.929e-06 7.125e+06 1.493e+01 2.063e-06 6.477e-07 2.063e-06 2.063e-06 + 4 ASM_R CONVERGED! +___________________________________________________________________________________________________________________________________________________________ +Relative errors: +Displacement: 6.477e-07 +Force: 8.310e-10 +Dilatation: 2.057e-06 +v / V_0: 1.000e-09 / 1.000e-09 = 1.000e+00 + +Timestep 7 @ 7.000e-01s +___________________________________________________________________________________________________________________________________________________________ + SOLVER STEP | LIN_IT LIN_RES RES_NORM RES_U RES_P RES_J NU_NORM NU_U NU_P NU_J +___________________________________________________________________________________________________________________________________________________________ + 0 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 132 2.877e-06 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 + 1 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 93 7.438e-04 1.234e-01 1.234e-01 1.458e+12 3.481e+06 4.451e-02 7.478e-02 4.451e-02 4.453e-02 + 2 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 124 1.896e-06 2.709e-03 2.709e-03 7.695e+09 2.434e+03 2.080e-03 1.491e-03 2.080e-03 2.080e-03 + 3 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 147 1.532e-09 1.449e-06 1.449e-06 4.195e+06 1.295e+01 1.160e-06 6.105e-07 1.160e-06 1.160e-06 + 4 ASM_R CONVERGED! +___________________________________________________________________________________________________________________________________________________________ +Relative errors: +Displacement: 6.105e-07 +Force: 4.084e-10 +Dilatation: 2.353e-06 +v / V_0: 1.000e-09 / 1.000e-09 = 1.000e+00 + +Timestep 8 @ 8.000e-01s +___________________________________________________________________________________________________________________________________________________________ + SOLVER STEP | LIN_IT LIN_RES RES_NORM RES_U RES_P RES_J NU_NORM NU_U NU_P NU_J +___________________________________________________________________________________________________________________________________________________________ + 0 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 134 3.355e-06 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 + 1 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 96 4.568e-04 1.207e-01 1.207e-01 1.347e+12 2.889e+06 3.818e-02 7.299e-02 3.818e-02 3.820e-02 + 2 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 124 1.981e-06 2.507e-03 2.507e-03 7.100e+09 1.614e+03 1.731e-03 1.428e-03 1.731e-03 1.731e-03 + 3 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 151 9.525e-10 1.147e-06 1.147e-06 3.504e+06 7.450e+00 1.053e-06 6.004e-07 1.053e-06 1.053e-06 + 4 ASM_R CONVERGED! +___________________________________________________________________________________________________________________________________________________________ +Relative errors: +Displacement: 6.004e-07 +Force: 2.540e-10 +Dilatation: 2.632e-06 +v / V_0: 1.000e-09 / 1.000e-09 = 1.000e+00 + +Timestep 9 @ 9.000e-01s +___________________________________________________________________________________________________________________________________________________________ + SOLVER STEP | LIN_IT LIN_RES RES_NORM RES_U RES_P RES_J NU_NORM NU_U NU_P NU_J +___________________________________________________________________________________________________________________________________________________________ + 0 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 138 2.296e-06 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 + 1 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 96 3.492e-04 1.155e-01 1.155e-01 1.888e+12 3.080e+06 3.352e-02 6.924e-02 3.352e-02 3.353e-02 + 2 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 129 1.002e-06 2.234e-03 2.234e-03 9.602e+09 1.530e+03 1.336e-03 1.247e-03 1.336e-03 1.336e-03 + 3 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 153 6.417e-10 8.777e-07 8.777e-07 3.805e+06 4.375e+00 6.542e-07 4.685e-07 6.542e-07 6.543e-07 + 4 ASM_R CONVERGED! +___________________________________________________________________________________________________________________________________________________________ +Relative errors: +Displacement: 4.685e-07 +Force: 1.711e-10 +Dilatation: 2.899e-06 +v / V_0: 1.000e-09 / 1.000e-09 = 1.000e+00 + +Timestep 10 @ 1.000e+00s +___________________________________________________________________________________________________________________________________________________________ + SOLVER STEP | LIN_IT LIN_RES RES_NORM RES_U RES_P RES_J NU_NORM NU_U NU_P NU_J +___________________________________________________________________________________________________________________________________________________________ + 0 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 137 2.024e-06 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 + 1 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 96 2.728e-04 1.085e-01 1.085e-01 2.721e+12 3.072e+06 3.002e-02 6.447e-02 3.002e-02 3.004e-02 + 2 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 129 1.029e-06 1.897e-03 1.897e-03 1.269e+10 1.296e+03 9.517e-04 1.008e-03 9.517e-04 9.517e-04 + 3 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 159 3.020e-10 6.524e-07 6.524e-07 3.633e+06 2.365e+00 5.342e-07 3.493e-07 5.342e-07 5.344e-07 + 4 ASM_R CONVERGED! +___________________________________________________________________________________________________________________________________________________________ +Relative errors: +Displacement: 3.493e-07 +Force: 8.052e-11 +Dilatation: 3.157e-06 +v / V_0: 1.000e-09 / 1.000e-09 = 1.000e+00 diff --git a/tests/physics/step-44.cc b/tests/physics/step-44.cc new file mode 100644 index 0000000000..ff475be415 --- /dev/null +++ b/tests/physics/step-44.cc @@ -0,0 +1,1988 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2016 by the deal.II authors +// +// This file is part of the deal.II library. +// +// The deal.II library is free software; you can use it, redistribute +// it, and/or modify it under the terms of the GNU Lesser General +// Public License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// The full text of the license can be found in the file LICENSE at +// the top level of the deal.II distribution. +// +// --------------------------------------------------------------------- + +// This is a copy of step-44 (git rev 3f7e617) to use as a base-line for +// results produced via different approaches to be compared to. + +#include "../tests.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +namespace Step44 +{ + using namespace dealii; + namespace Parameters + { + struct FESystem + { + unsigned int poly_degree; + unsigned int quad_order; + static void + declare_parameters(ParameterHandler &prm); + void + parse_parameters(ParameterHandler &prm); + }; + void FESystem::declare_parameters(ParameterHandler &prm) + { + prm.enter_subsection("Finite element system"); + { + prm.declare_entry("Polynomial degree", "2", + Patterns::Integer(0), + "Displacement system polynomial order"); + prm.declare_entry("Quadrature order", "3", + Patterns::Integer(0), + "Gauss quadrature order"); + } + prm.leave_subsection(); + } + void FESystem::parse_parameters(ParameterHandler &prm) + { + prm.enter_subsection("Finite element system"); + { + poly_degree = prm.get_integer("Polynomial degree"); + quad_order = prm.get_integer("Quadrature order"); + } + prm.leave_subsection(); + } + struct Geometry + { + unsigned int global_refinement; + double scale; + double p_p0; + static void + declare_parameters(ParameterHandler &prm); + void + parse_parameters(ParameterHandler &prm); + }; + void Geometry::declare_parameters(ParameterHandler &prm) + { + prm.enter_subsection("Geometry"); + { + prm.declare_entry("Global refinement", "2", + Patterns::Integer(0), + "Global refinement level"); + prm.declare_entry("Grid scale", "1e-3", + Patterns::Double(0.0), + "Global grid scaling factor"); + prm.declare_entry("Pressure ratio p/p0", "100", + Patterns::Selection("20|40|60|80|100"), + "Ratio of applied pressure to reference pressure"); + } + prm.leave_subsection(); + } + void Geometry::parse_parameters(ParameterHandler &prm) + { + prm.enter_subsection("Geometry"); + { + global_refinement = prm.get_integer("Global refinement"); + scale = prm.get_double("Grid scale"); + p_p0 = prm.get_double("Pressure ratio p/p0"); + } + prm.leave_subsection(); + } + struct Materials + { + double nu; + double mu; + static void + declare_parameters(ParameterHandler &prm); + void + parse_parameters(ParameterHandler &prm); + }; + void Materials::declare_parameters(ParameterHandler &prm) + { + prm.enter_subsection("Material properties"); + { + prm.declare_entry("Poisson's ratio", "0.4999", + Patterns::Double(-1.0,0.5), + "Poisson's ratio"); + prm.declare_entry("Shear modulus", "80.194e6", + Patterns::Double(), + "Shear modulus"); + } + prm.leave_subsection(); + } + void Materials::parse_parameters(ParameterHandler &prm) + { + prm.enter_subsection("Material properties"); + { + nu = prm.get_double("Poisson's ratio"); + mu = prm.get_double("Shear modulus"); + } + prm.leave_subsection(); + } + struct LinearSolver + { + std::string type_lin; + double tol_lin; + double max_iterations_lin; + bool use_static_condensation; + std::string preconditioner_type; + double preconditioner_relaxation; + static void + declare_parameters(ParameterHandler &prm); + void + parse_parameters(ParameterHandler &prm); + }; + void LinearSolver::declare_parameters(ParameterHandler &prm) + { + prm.enter_subsection("Linear solver"); + { + prm.declare_entry("Solver type", "CG", + Patterns::Selection("CG|Direct"), + "Type of solver used to solve the linear system"); + prm.declare_entry("Residual", "1e-6", + Patterns::Double(0.0), + "Linear solver residual (scaled by residual norm)"); + prm.declare_entry("Max iteration multiplier", "1", + Patterns::Double(0.0), + "Linear solver iterations (multiples of the system matrix size)"); + prm.declare_entry("Use static condensation", "true", + Patterns::Bool(), + "Solve the full block system or a reduced problem"); + prm.declare_entry("Preconditioner type", "ssor", + Patterns::Selection("jacobi|ssor"), + "Type of preconditioner"); + prm.declare_entry("Preconditioner relaxation", "0.65", + Patterns::Double(0.0), + "Preconditioner relaxation value"); + } + prm.leave_subsection(); + } + void LinearSolver::parse_parameters(ParameterHandler &prm) + { + prm.enter_subsection("Linear solver"); + { + type_lin = prm.get("Solver type"); + tol_lin = prm.get_double("Residual"); + max_iterations_lin = prm.get_double("Max iteration multiplier"); + use_static_condensation = prm.get_bool("Use static condensation"); + preconditioner_type = prm.get("Preconditioner type"); + preconditioner_relaxation = prm.get_double("Preconditioner relaxation"); + } + prm.leave_subsection(); + } + struct NonlinearSolver + { + unsigned int max_iterations_NR; + double tol_f; + double tol_u; + static void + declare_parameters(ParameterHandler &prm); + void + parse_parameters(ParameterHandler &prm); + }; + void NonlinearSolver::declare_parameters(ParameterHandler &prm) + { + prm.enter_subsection("Nonlinear solver"); + { + prm.declare_entry("Max iterations Newton-Raphson", "10", + Patterns::Integer(0), + "Number of Newton-Raphson iterations allowed"); + prm.declare_entry("Tolerance force", "1.0e-9", + Patterns::Double(0.0), + "Force residual tolerance"); + prm.declare_entry("Tolerance displacement", "1.0e-6", + Patterns::Double(0.0), + "Displacement error tolerance"); + } + prm.leave_subsection(); + } + void NonlinearSolver::parse_parameters(ParameterHandler &prm) + { + prm.enter_subsection("Nonlinear solver"); + { + max_iterations_NR = prm.get_integer("Max iterations Newton-Raphson"); + tol_f = prm.get_double("Tolerance force"); + tol_u = prm.get_double("Tolerance displacement"); + } + prm.leave_subsection(); + } + struct Time + { + double delta_t; + double end_time; + static void + declare_parameters(ParameterHandler &prm); + void + parse_parameters(ParameterHandler &prm); + }; + void Time::declare_parameters(ParameterHandler &prm) + { + prm.enter_subsection("Time"); + { + prm.declare_entry("End time", "1", + Patterns::Double(), + "End time"); + prm.declare_entry("Time step size", "0.1", + Patterns::Double(), + "Time step size"); + } + prm.leave_subsection(); + } + void Time::parse_parameters(ParameterHandler &prm) + { + prm.enter_subsection("Time"); + { + end_time = prm.get_double("End time"); + delta_t = prm.get_double("Time step size"); + } + prm.leave_subsection(); + } + struct AllParameters : public FESystem, + public Geometry, + public Materials, + public LinearSolver, + public NonlinearSolver, + public Time + { + AllParameters(const std::string &input_file); + static void + declare_parameters(ParameterHandler &prm); + void + parse_parameters(ParameterHandler &prm); + }; + AllParameters::AllParameters(const std::string &input_file) + { + ParameterHandler prm; + declare_parameters(prm); + prm.read_input(input_file); + parse_parameters(prm); + } + void AllParameters::declare_parameters(ParameterHandler &prm) + { + FESystem::declare_parameters(prm); + Geometry::declare_parameters(prm); + Materials::declare_parameters(prm); + LinearSolver::declare_parameters(prm); + NonlinearSolver::declare_parameters(prm); + Time::declare_parameters(prm); + } + void AllParameters::parse_parameters(ParameterHandler &prm) + { + FESystem::parse_parameters(prm); + Geometry::parse_parameters(prm); + Materials::parse_parameters(prm); + LinearSolver::parse_parameters(prm); + NonlinearSolver::parse_parameters(prm); + Time::parse_parameters(prm); + } + } + template + class StandardTensors + { + public: + static const SymmetricTensor<2, dim> I; + static const SymmetricTensor<4, dim> IxI; + static const SymmetricTensor<4, dim> II; + static const SymmetricTensor<4, dim> dev_P; + }; + template + const SymmetricTensor<2, dim> + StandardTensors::I = unit_symmetric_tensor(); + template + const SymmetricTensor<4, dim> + StandardTensors::IxI = outer_product(I, I); + template + const SymmetricTensor<4, dim> + StandardTensors::II = identity_tensor(); + template + const SymmetricTensor<4, dim> + StandardTensors::dev_P = deviator_tensor(); + class Time + { + public: + Time (const double time_end, + const double delta_t) + : + timestep(0), + time_current(0.0), + time_end(time_end), + delta_t(delta_t) + {} + virtual ~Time() + {} + double current() const + { + return time_current; + } + double end() const + { + return time_end; + } + double get_delta_t() const + { + return delta_t; + } + unsigned int get_timestep() const + { + return timestep; + } + void increment() + { + time_current += delta_t; + ++timestep; + } + private: + unsigned int timestep; + double time_current; + const double time_end; + const double delta_t; + }; + template + class Material_Compressible_Neo_Hook_Three_Field + { + public: + Material_Compressible_Neo_Hook_Three_Field(const double mu, + const double nu) + : + kappa((2.0 * mu * (1.0 + nu)) / (3.0 * (1.0 - 2.0 * nu))), + c_1(mu / 2.0), + det_F(1.0), + p_tilde(0.0), + J_tilde(1.0), + b_bar(StandardTensors::I) + { + Assert(kappa > 0, ExcInternalError()); + } + ~Material_Compressible_Neo_Hook_Three_Field() + {} + void update_material_data(const Tensor<2, dim> &F, + const double p_tilde_in, + const double J_tilde_in) + { + det_F = determinant(F); + b_bar = std::pow(det_F, -2.0 / dim) * symmetrize(F * transpose(F)); + p_tilde = p_tilde_in; + J_tilde = J_tilde_in; + Assert(det_F > 0, ExcInternalError()); + } + SymmetricTensor<2, dim> get_tau() + { + return get_tau_iso() + get_tau_vol(); + } + SymmetricTensor<4, dim> get_Jc() const + { + return get_Jc_vol() + get_Jc_iso(); + } + double get_dPsi_vol_dJ() const + { + return (kappa / 2.0) * (J_tilde - 1.0 / J_tilde); + } + double get_d2Psi_vol_dJ2() const + { + return ( (kappa / 2.0) * (1.0 + 1.0 / (J_tilde * J_tilde))); + } + double get_det_F() const + { + return det_F; + } + double get_p_tilde() const + { + return p_tilde; + } + double get_J_tilde() const + { + return J_tilde; + } + protected: + const double kappa; + const double c_1; + double det_F; + double p_tilde; + double J_tilde; + SymmetricTensor<2, dim> b_bar; + SymmetricTensor<2, dim> get_tau_vol() const + { + return p_tilde * det_F * StandardTensors::I; + } + SymmetricTensor<2, dim> get_tau_iso() const + { + return StandardTensors::dev_P * get_tau_bar(); + } + SymmetricTensor<2, dim> get_tau_bar() const + { + return 2.0 * c_1 * b_bar; + } + SymmetricTensor<4, dim> get_Jc_vol() const + { + return p_tilde * det_F + * ( StandardTensors::IxI + - (2.0 * StandardTensors::II) ); + } + SymmetricTensor<4, dim> get_Jc_iso() const + { + const SymmetricTensor<2, dim> tau_bar = get_tau_bar(); + const SymmetricTensor<2, dim> tau_iso = get_tau_iso(); + const SymmetricTensor<4, dim> tau_iso_x_I + = outer_product(tau_iso, + StandardTensors::I); + const SymmetricTensor<4, dim> I_x_tau_iso + = outer_product(StandardTensors::I, + tau_iso); + const SymmetricTensor<4, dim> c_bar = get_c_bar(); + return (2.0 / dim) * trace(tau_bar) + * StandardTensors::dev_P + - (2.0 / dim) * (tau_iso_x_I + I_x_tau_iso) + + StandardTensors::dev_P * c_bar + * StandardTensors::dev_P; + } + SymmetricTensor<4, dim> get_c_bar() const + { + return SymmetricTensor<4, dim>(); + } + }; + template + class PointHistory + { + public: + PointHistory() + : + F_inv(StandardTensors::I), + tau(SymmetricTensor<2, dim>()), + d2Psi_vol_dJ2(0.0), + dPsi_vol_dJ(0.0), + Jc(SymmetricTensor<4, dim>()) + {} + virtual ~PointHistory() + {} + void setup_lqp (const Parameters::AllParameters ¶meters) + { + material.reset(new Material_Compressible_Neo_Hook_Three_Field(parameters.mu, + parameters.nu)); + update_values(Tensor<2, dim>(), 0.0, 1.0); + } + void update_values (const Tensor<2, dim> &Grad_u_n, + const double p_tilde, + const double J_tilde) + { + const Tensor<2, dim> F + = (Tensor<2, dim>(StandardTensors::I) + + Grad_u_n); + material->update_material_data(F, p_tilde, J_tilde); + F_inv = invert(F); + tau = material->get_tau(); + Jc = material->get_Jc(); + dPsi_vol_dJ = material->get_dPsi_vol_dJ(); + d2Psi_vol_dJ2 = material->get_d2Psi_vol_dJ2(); + } + double get_J_tilde() const + { + return material->get_J_tilde(); + } + double get_det_F() const + { + return material->get_det_F(); + } + const Tensor<2, dim> &get_F_inv() const + { + return F_inv; + } + double get_p_tilde() const + { + return material->get_p_tilde(); + } + const SymmetricTensor<2, dim> &get_tau() const + { + return tau; + } + double get_dPsi_vol_dJ() const + { + return dPsi_vol_dJ; + } + double get_d2Psi_vol_dJ2() const + { + return d2Psi_vol_dJ2; + } + const SymmetricTensor<4, dim> &get_Jc() const + { + return Jc; + } + private: + std_cxx11::shared_ptr< Material_Compressible_Neo_Hook_Three_Field > material; + Tensor<2, dim> F_inv; + SymmetricTensor<2, dim> tau; + double d2Psi_vol_dJ2; + double dPsi_vol_dJ; + SymmetricTensor<4, dim> Jc; + }; + template + class Solid + { + public: + Solid(const std::string &input_file); + virtual + ~Solid(); + void + run(); + private: + struct PerTaskData_K; + struct ScratchData_K; + struct PerTaskData_RHS; + struct ScratchData_RHS; + struct PerTaskData_SC; + struct ScratchData_SC; + struct PerTaskData_UQPH; + struct ScratchData_UQPH; + void + make_grid(); + void + system_setup(); + void + determine_component_extractors(); + void + assemble_system_tangent(); + void + assemble_system_tangent_one_cell(const typename DoFHandler::active_cell_iterator &cell, + ScratchData_K &scratch, + PerTaskData_K &data) const; + void + copy_local_to_global_K(const PerTaskData_K &data); + void + assemble_system_rhs(); + void + assemble_system_rhs_one_cell(const typename DoFHandler::active_cell_iterator &cell, + ScratchData_RHS &scratch, + PerTaskData_RHS &data) const; + void + copy_local_to_global_rhs(const PerTaskData_RHS &data); + void + assemble_sc(); + void + assemble_sc_one_cell(const typename DoFHandler::active_cell_iterator &cell, + ScratchData_SC &scratch, + PerTaskData_SC &data); + void + copy_local_to_global_sc(const PerTaskData_SC &data); + void + make_constraints(const int &it_nr); + void + setup_qph(); + void + update_qph_incremental(const BlockVector &solution_delta); + void + update_qph_incremental_one_cell(const typename DoFHandler::active_cell_iterator &cell, + ScratchData_UQPH &scratch, + PerTaskData_UQPH &data); + void + copy_local_to_global_UQPH(const PerTaskData_UQPH &/*data*/) + {} + void + solve_nonlinear_timestep(BlockVector &solution_delta); + std::pair + solve_linear_system(BlockVector &newton_update); + BlockVector + get_total_solution(const BlockVector &solution_delta) const; + void + output_results() const; + Parameters::AllParameters parameters; + double vol_reference; + Triangulation triangulation; + Time time; + mutable TimerOutput timer; + CellDataStorage::cell_iterator, + PointHistory > quadrature_point_history; + const unsigned int degree; + const FESystem fe; + DoFHandler dof_handler_ref; + const unsigned int dofs_per_cell; + const FEValuesExtractors::Vector u_fe; + const FEValuesExtractors::Scalar p_fe; + const FEValuesExtractors::Scalar J_fe; + static const unsigned int n_blocks = 3; + static const unsigned int n_components = dim + 2; + static const unsigned int first_u_component = 0; + static const unsigned int p_component = dim; + static const unsigned int J_component = dim + 1; + enum + { + u_dof = 0, + p_dof = 1, + J_dof = 2 + }; + std::vector dofs_per_block; + std::vector element_indices_u; + std::vector element_indices_p; + std::vector element_indices_J; + const QGauss qf_cell; + const QGauss qf_face; + const unsigned int n_q_points; + const unsigned int n_q_points_f; + ConstraintMatrix constraints; + BlockSparsityPattern sparsity_pattern; + BlockSparseMatrix tangent_matrix; + BlockVector system_rhs; + BlockVector solution_n; + ConditionalOStream pcout; + struct Errors + { + Errors() + : + norm(1.0), u(1.0), p(1.0), J(1.0) + {} + void reset() + { + norm = 1.0; + u = 1.0; + p = 1.0; + J = 1.0; + } + void normalise(const Errors &rhs) + { + if (rhs.norm != 0.0) + norm /= rhs.norm; + if (rhs.u != 0.0) + u /= rhs.u; + if (rhs.p != 0.0) + p /= rhs.p; + if (rhs.J != 0.0) + J /= rhs.J; + } + double norm, u, p, J; + }; + Errors error_residual, error_residual_0, error_residual_norm, error_update, + error_update_0, error_update_norm; + void + get_error_residual(Errors &error_residual); + void + get_error_update(const BlockVector &newton_update, + Errors &error_update); + std::pair + get_error_dilation() const; + double + compute_vol_current () const; + void + print_conv_header(); + void + print_conv_footer(); + }; + template + Solid::Solid(const std::string &input_file) + : + parameters(input_file), + triangulation(Triangulation::maximum_smoothing), + time(parameters.end_time, parameters.delta_t), + timer(deallog.get_file_stream(), + TimerOutput::never, + TimerOutput::wall_times), + degree(parameters.poly_degree), + fe(FE_Q(parameters.poly_degree), dim, // displacement + FE_DGPMonomial(parameters.poly_degree - 1), 1, // pressure + FE_DGPMonomial(parameters.poly_degree - 1), 1), // dilatation + dof_handler_ref(triangulation), + dofs_per_cell (fe.dofs_per_cell), + u_fe(first_u_component), + p_fe(p_component), + J_fe(J_component), + dofs_per_block(n_blocks), + qf_cell(parameters.quad_order), + qf_face(parameters.quad_order), + n_q_points (qf_cell.size()), + n_q_points_f (qf_face.size()), + pcout(deallog.get_file_stream()) + { + Assert(dim==2 || dim==3, ExcMessage("This problem only works in 2 or 3 space dimensions.")); + determine_component_extractors(); + } + template + Solid::~Solid() + { + dof_handler_ref.clear(); + } + template + void Solid::run() + { + make_grid(); + system_setup(); + { + ConstraintMatrix constraints; + constraints.close(); + const ComponentSelectFunction + J_mask (J_component, n_components); + VectorTools::project (dof_handler_ref, + constraints, + QGauss(degree+2), + J_mask, + solution_n); + } + output_results(); + time.increment(); + BlockVector solution_delta(dofs_per_block); + while (time.current() < time.end()) + { + solution_delta = 0.0; + solve_nonlinear_timestep(solution_delta); + solution_n += solution_delta; + output_results(); + time.increment(); + } + } + template + struct Solid::PerTaskData_K + { + FullMatrix cell_matrix; + std::vector local_dof_indices; + PerTaskData_K(const unsigned int dofs_per_cell) + : + cell_matrix(dofs_per_cell, dofs_per_cell), + local_dof_indices(dofs_per_cell) + {} + void reset() + { + cell_matrix = 0.0; + } + }; + template + struct Solid::ScratchData_K + { + FEValues fe_values_ref; + std::vector > Nx; + std::vector > > grad_Nx; + std::vector > > symm_grad_Nx; + ScratchData_K(const FiniteElement &fe_cell, + const QGauss &qf_cell, + const UpdateFlags uf_cell) + : + fe_values_ref(fe_cell, qf_cell, uf_cell), + Nx(qf_cell.size(), + std::vector(fe_cell.dofs_per_cell)), + grad_Nx(qf_cell.size(), + std::vector >(fe_cell.dofs_per_cell)), + symm_grad_Nx(qf_cell.size(), + std::vector > + (fe_cell.dofs_per_cell)) + {} + ScratchData_K(const ScratchData_K &rhs) + : + fe_values_ref(rhs.fe_values_ref.get_fe(), + rhs.fe_values_ref.get_quadrature(), + rhs.fe_values_ref.get_update_flags()), + Nx(rhs.Nx), + grad_Nx(rhs.grad_Nx), + symm_grad_Nx(rhs.symm_grad_Nx) + {} + void reset() + { + const unsigned int n_q_points = Nx.size(); + const unsigned int n_dofs_per_cell = Nx[0].size(); + for (unsigned int q_point = 0; q_point < n_q_points; ++q_point) + { + Assert( Nx[q_point].size() == n_dofs_per_cell, ExcInternalError()); + Assert( grad_Nx[q_point].size() == n_dofs_per_cell, + ExcInternalError()); + Assert( symm_grad_Nx[q_point].size() == n_dofs_per_cell, + ExcInternalError()); + for (unsigned int k = 0; k < n_dofs_per_cell; ++k) + { + Nx[q_point][k] = 0.0; + grad_Nx[q_point][k] = 0.0; + symm_grad_Nx[q_point][k] = 0.0; + } + } + } + }; + template + struct Solid::PerTaskData_RHS + { + Vector cell_rhs; + std::vector local_dof_indices; + PerTaskData_RHS(const unsigned int dofs_per_cell) + : + cell_rhs(dofs_per_cell), + local_dof_indices(dofs_per_cell) + {} + void reset() + { + cell_rhs = 0.0; + } + }; + template + struct Solid::ScratchData_RHS + { + FEValues fe_values_ref; + FEFaceValues fe_face_values_ref; + std::vector > Nx; + std::vector > > symm_grad_Nx; + ScratchData_RHS(const FiniteElement &fe_cell, + const QGauss &qf_cell, const UpdateFlags uf_cell, + const QGauss & qf_face, const UpdateFlags uf_face) + : + fe_values_ref(fe_cell, qf_cell, uf_cell), + fe_face_values_ref(fe_cell, qf_face, uf_face), + Nx(qf_cell.size(), + std::vector(fe_cell.dofs_per_cell)), + symm_grad_Nx(qf_cell.size(), + std::vector > + (fe_cell.dofs_per_cell)) + {} + ScratchData_RHS(const ScratchData_RHS &rhs) + : + fe_values_ref(rhs.fe_values_ref.get_fe(), + rhs.fe_values_ref.get_quadrature(), + rhs.fe_values_ref.get_update_flags()), + fe_face_values_ref(rhs.fe_face_values_ref.get_fe(), + rhs.fe_face_values_ref.get_quadrature(), + rhs.fe_face_values_ref.get_update_flags()), + Nx(rhs.Nx), + symm_grad_Nx(rhs.symm_grad_Nx) + {} + void reset() + { + const unsigned int n_q_points = Nx.size(); + const unsigned int n_dofs_per_cell = Nx[0].size(); + for (unsigned int q_point = 0; q_point < n_q_points; ++q_point) + { + Assert( Nx[q_point].size() == n_dofs_per_cell, ExcInternalError()); + Assert( symm_grad_Nx[q_point].size() == n_dofs_per_cell, + ExcInternalError()); + for (unsigned int k = 0; k < n_dofs_per_cell; ++k) + { + Nx[q_point][k] = 0.0; + symm_grad_Nx[q_point][k] = 0.0; + } + } + } + }; + template + struct Solid::PerTaskData_SC + { + FullMatrix cell_matrix; + std::vector local_dof_indices; + FullMatrix k_orig; + FullMatrix k_pu; + FullMatrix k_pJ; + FullMatrix k_JJ; + FullMatrix k_pJ_inv; + FullMatrix k_bbar; + FullMatrix A; + FullMatrix B; + FullMatrix C; + PerTaskData_SC(const unsigned int dofs_per_cell, + const unsigned int n_u, + const unsigned int n_p, + const unsigned int n_J) + : + cell_matrix(dofs_per_cell, dofs_per_cell), + local_dof_indices(dofs_per_cell), + k_orig(dofs_per_cell, dofs_per_cell), + k_pu(n_p, n_u), + k_pJ(n_p, n_J), + k_JJ(n_J, n_J), + k_pJ_inv(n_p, n_J), + k_bbar(n_u, n_u), + A(n_J,n_u), + B(n_J, n_u), + C(n_p, n_u) + {} + void reset() + {} + }; + template + struct Solid::ScratchData_SC + { + void reset() + {} + }; + template + struct Solid::PerTaskData_UQPH + { + void reset() + {} + }; + template + struct Solid::ScratchData_UQPH + { + const BlockVector &solution_total; + std::vector > solution_grads_u_total; + std::vector solution_values_p_total; + std::vector solution_values_J_total; + FEValues fe_values_ref; + ScratchData_UQPH(const FiniteElement &fe_cell, + const QGauss &qf_cell, + const UpdateFlags uf_cell, + const BlockVector &solution_total) + : + solution_total(solution_total), + solution_grads_u_total(qf_cell.size()), + solution_values_p_total(qf_cell.size()), + solution_values_J_total(qf_cell.size()), + fe_values_ref(fe_cell, qf_cell, uf_cell) + {} + ScratchData_UQPH(const ScratchData_UQPH &rhs) + : + solution_total(rhs.solution_total), + solution_grads_u_total(rhs.solution_grads_u_total), + solution_values_p_total(rhs.solution_values_p_total), + solution_values_J_total(rhs.solution_values_J_total), + fe_values_ref(rhs.fe_values_ref.get_fe(), + rhs.fe_values_ref.get_quadrature(), + rhs.fe_values_ref.get_update_flags()) + {} + void reset() + { + const unsigned int n_q_points = solution_grads_u_total.size(); + for (unsigned int q = 0; q < n_q_points; ++q) + { + solution_grads_u_total[q] = 0.0; + solution_values_p_total[q] = 0.0; + solution_values_J_total[q] = 0.0; + } + } + }; + template + void Solid::make_grid() + { + GridGenerator::hyper_rectangle(triangulation, + (dim==3 ? Point(0.0, 0.0, 0.0) : Point(0.0, 0.0)), + (dim==3 ? Point(1.0, 1.0, 1.0) : Point(1.0, 1.0)), + true); + GridTools::scale(parameters.scale, triangulation); + triangulation.refine_global(std::max (1U, parameters.global_refinement)); + vol_reference = GridTools::volume(triangulation); + pcout << "Grid:\n\t Reference volume: " << vol_reference << std::endl; + typename Triangulation::active_cell_iterator cell = + triangulation.begin_active(), endc = triangulation.end(); + for (; cell != endc; ++cell) + for (unsigned int face = 0; + face < GeometryInfo::faces_per_cell; ++face) + { + if (cell->face(face)->at_boundary() == true + && + cell->face(face)->center()[1] == 1.0 * parameters.scale) + { + if (dim==3) + { + if (cell->face(face)->center()[0] < 0.5 * parameters.scale + && + cell->face(face)->center()[2] < 0.5 * parameters.scale) + cell->face(face)->set_boundary_id(6); + } + else + { + if (cell->face(face)->center()[0] < 0.5 * parameters.scale) + cell->face(face)->set_boundary_id(6); + } + } + } + } + template + void Solid::system_setup() + { + timer.enter_subsection("Setup system"); + std::vector block_component(n_components, u_dof); // Displacement + block_component[p_component] = p_dof; // Pressure + block_component[J_component] = J_dof; // Dilatation + dof_handler_ref.distribute_dofs(fe); + DoFRenumbering::Cuthill_McKee(dof_handler_ref); + DoFRenumbering::component_wise(dof_handler_ref, block_component); + DoFTools::count_dofs_per_block(dof_handler_ref, dofs_per_block, + block_component); + pcout << "Triangulation:" + << "\n\t Number of active cells: " << triangulation.n_active_cells() + << "\n\t Number of degrees of freedom: " << dof_handler_ref.n_dofs() + << std::endl; + tangent_matrix.clear(); + { + const types::global_dof_index n_dofs_u = dofs_per_block[u_dof]; + const types::global_dof_index n_dofs_p = dofs_per_block[p_dof]; + const types::global_dof_index n_dofs_J = dofs_per_block[J_dof]; + BlockDynamicSparsityPattern dsp(n_blocks, n_blocks); + dsp.block(u_dof, u_dof).reinit(n_dofs_u, n_dofs_u); + dsp.block(u_dof, p_dof).reinit(n_dofs_u, n_dofs_p); + dsp.block(u_dof, J_dof).reinit(n_dofs_u, n_dofs_J); + dsp.block(p_dof, u_dof).reinit(n_dofs_p, n_dofs_u); + dsp.block(p_dof, p_dof).reinit(n_dofs_p, n_dofs_p); + dsp.block(p_dof, J_dof).reinit(n_dofs_p, n_dofs_J); + dsp.block(J_dof, u_dof).reinit(n_dofs_J, n_dofs_u); + dsp.block(J_dof, p_dof).reinit(n_dofs_J, n_dofs_p); + dsp.block(J_dof, J_dof).reinit(n_dofs_J, n_dofs_J); + dsp.collect_sizes(); + Table<2, DoFTools::Coupling> coupling(n_components, n_components); + for (unsigned int ii = 0; ii < n_components; ++ii) + for (unsigned int jj = 0; jj < n_components; ++jj) + if (((ii < p_component) && (jj == J_component)) + || ((ii == J_component) && (jj < p_component)) + || ((ii == p_component) && (jj == p_component))) + coupling[ii][jj] = DoFTools::none; + else + coupling[ii][jj] = DoFTools::always; + DoFTools::make_sparsity_pattern(dof_handler_ref, + coupling, + dsp, + constraints, + false); + sparsity_pattern.copy_from(dsp); + } + tangent_matrix.reinit(sparsity_pattern); + system_rhs.reinit(dofs_per_block); + system_rhs.collect_sizes(); + solution_n.reinit(dofs_per_block); + solution_n.collect_sizes(); + setup_qph(); + timer.leave_subsection(); + } + template + void + Solid::determine_component_extractors() + { + element_indices_u.clear(); + element_indices_p.clear(); + element_indices_J.clear(); + for (unsigned int k = 0; k < fe.dofs_per_cell; ++k) + { + const unsigned int k_group = fe.system_to_base_index(k).first.first; + if (k_group == u_dof) + element_indices_u.push_back(k); + else if (k_group == p_dof) + element_indices_p.push_back(k); + else if (k_group == J_dof) + element_indices_J.push_back(k); + else + { + Assert(k_group <= J_dof, ExcInternalError()); + } + } + } + template + void Solid::setup_qph() + { + pcout << " Setting up quadrature point data..." << std::endl; + quadrature_point_history.initialize(triangulation.begin_active(), + triangulation.end(), + n_q_points); + for (typename Triangulation::active_cell_iterator cell = + triangulation.begin_active(); cell != triangulation.end(); ++cell) + { + const std::vector > > lqph = + quadrature_point_history.get_data(cell); + Assert(lqph.size() == n_q_points, ExcInternalError()); + for (unsigned int q_point = 0; q_point < n_q_points; ++q_point) + lqph[q_point]->setup_lqp(parameters); + } + } + template + void Solid::update_qph_incremental(const BlockVector &solution_delta) + { + timer.enter_subsection("Update QPH data"); + pcout << " UQPH " << std::flush; + const BlockVector solution_total(get_total_solution(solution_delta)); + const UpdateFlags uf_UQPH(update_values | update_gradients); + PerTaskData_UQPH per_task_data_UQPH; + ScratchData_UQPH scratch_data_UQPH(fe, qf_cell, uf_UQPH, solution_total); + WorkStream::run(dof_handler_ref.begin_active(), + dof_handler_ref.end(), + *this, + &Solid::update_qph_incremental_one_cell, + &Solid::copy_local_to_global_UQPH, + scratch_data_UQPH, + per_task_data_UQPH); + timer.leave_subsection(); + } + template + void + Solid::update_qph_incremental_one_cell(const typename DoFHandler::active_cell_iterator &cell, + ScratchData_UQPH &scratch, + PerTaskData_UQPH &/*data*/) + { + const std::vector > > lqph = + quadrature_point_history.get_data(cell); + Assert(lqph.size() == n_q_points, ExcInternalError()); + Assert(scratch.solution_grads_u_total.size() == n_q_points, + ExcInternalError()); + Assert(scratch.solution_values_p_total.size() == n_q_points, + ExcInternalError()); + Assert(scratch.solution_values_J_total.size() == n_q_points, + ExcInternalError()); + scratch.reset(); + scratch.fe_values_ref.reinit(cell); + scratch.fe_values_ref[u_fe].get_function_gradients(scratch.solution_total, + scratch.solution_grads_u_total); + scratch.fe_values_ref[p_fe].get_function_values(scratch.solution_total, + scratch.solution_values_p_total); + scratch.fe_values_ref[J_fe].get_function_values(scratch.solution_total, + scratch.solution_values_J_total); + for (unsigned int q_point = 0; q_point < n_q_points; ++q_point) + lqph[q_point]->update_values(scratch.solution_grads_u_total[q_point], + scratch.solution_values_p_total[q_point], + scratch.solution_values_J_total[q_point]); + } + template + void + Solid::solve_nonlinear_timestep(BlockVector &solution_delta) + { + pcout << std::endl << "Timestep " << time.get_timestep() << " @ " + << time.current() << "s" << std::endl; + BlockVector newton_update(dofs_per_block); + error_residual.reset(); + error_residual_0.reset(); + error_residual_norm.reset(); + error_update.reset(); + error_update_0.reset(); + error_update_norm.reset(); + print_conv_header(); + unsigned int newton_iteration = 0; + for (; newton_iteration < parameters.max_iterations_NR; + ++newton_iteration) + { + pcout << " " << std::setw(2) << newton_iteration << " " << std::flush; + tangent_matrix = 0.0; + system_rhs = 0.0; + assemble_system_rhs(); + get_error_residual(error_residual); + if (newton_iteration == 0) + error_residual_0 = error_residual; + error_residual_norm = error_residual; + error_residual_norm.normalise(error_residual_0); + if (newton_iteration > 0 && error_update_norm.u <= parameters.tol_u + && error_residual_norm.u <= parameters.tol_f) + { + pcout << " CONVERGED! " << std::endl; + print_conv_footer(); + break; + } + assemble_system_tangent(); + make_constraints(newton_iteration); + constraints.condense(tangent_matrix, system_rhs); + const std::pair + lin_solver_output = solve_linear_system(newton_update); + get_error_update(newton_update, error_update); + if (newton_iteration == 0) + error_update_0 = error_update; + error_update_norm = error_update; + error_update_norm.normalise(error_update_0); + solution_delta += newton_update; + update_qph_incremental(solution_delta); + pcout << " | " << std::fixed << std::setprecision(3) << std::setw(7) + << std::scientific << lin_solver_output.first << " " + << lin_solver_output.second << " " << error_residual_norm.norm + << " " << error_residual_norm.u << " " + << error_residual_norm.p << " " << error_residual_norm.J + << " " << error_update_norm.norm << " " << error_update_norm.u + << " " << error_update_norm.p << " " << error_update_norm.J + << " " << std::endl; + } + AssertThrow (newton_iteration <= parameters.max_iterations_NR, + ExcMessage("No convergence in nonlinear solver!")); + } + template + void Solid::print_conv_header() + { + static const unsigned int l_width = 155; + for (unsigned int i = 0; i < l_width; ++i) + pcout << "_"; + pcout << std::endl; + pcout << " SOLVER STEP " + << " | LIN_IT LIN_RES RES_NORM " + << " RES_U RES_P RES_J NU_NORM " + << " NU_U NU_P NU_J " << std::endl; + for (unsigned int i = 0; i < l_width; ++i) + pcout << "_"; + pcout << std::endl; + } + template + void Solid::print_conv_footer() + { + static const unsigned int l_width = 155; + for (unsigned int i = 0; i < l_width; ++i) + pcout << "_"; + pcout << std::endl; + const std::pair error_dil = get_error_dilation(); + pcout << "Relative errors:" << std::endl + << "Displacement:\t" << error_update.u / error_update_0.u << std::endl + << "Force: \t\t" << error_residual.u / error_residual_0.u << std::endl + << "Dilatation:\t" << error_dil.first << std::endl + << "v / V_0:\t" << error_dil.second *vol_reference << " / " << vol_reference + << " = " << error_dil.second << std::endl; + } + template + double + Solid::compute_vol_current() const + { + double vol_current = 0.0; + FEValues fe_values_ref(fe, qf_cell, update_JxW_values); + for (typename Triangulation::active_cell_iterator + cell = triangulation.begin_active(); + cell != triangulation.end(); ++cell) + { + fe_values_ref.reinit(cell); + const std::vector > > lqph = + quadrature_point_history.get_data(cell); + Assert(lqph.size() == n_q_points, ExcInternalError()); + for (unsigned int q_point = 0; q_point < n_q_points; ++q_point) + { + const double det_F_qp = lqph[q_point]->get_det_F(); + const double JxW = fe_values_ref.JxW(q_point); + vol_current += det_F_qp * JxW; + } + } + Assert(vol_current > 0.0, ExcInternalError()); + return vol_current; + } + template + std::pair + Solid::get_error_dilation() const + { + double dil_L2_error = 0.0; + FEValues fe_values_ref(fe, qf_cell, update_JxW_values); + for (typename Triangulation::active_cell_iterator + cell = triangulation.begin_active(); + cell != triangulation.end(); ++cell) + { + fe_values_ref.reinit(cell); + const std::vector > > lqph = + quadrature_point_history.get_data(cell); + Assert(lqph.size() == n_q_points, ExcInternalError()); + for (unsigned int q_point = 0; q_point < n_q_points; ++q_point) + { + const double det_F_qp = lqph[q_point]->get_det_F(); + const double J_tilde_qp = lqph[q_point]->get_J_tilde(); + const double the_error_qp_squared = std::pow((det_F_qp - J_tilde_qp), + 2); + const double JxW = fe_values_ref.JxW(q_point); + dil_L2_error += the_error_qp_squared * JxW; + } + } + return std::make_pair(std::sqrt(dil_L2_error), + compute_vol_current() / vol_reference); + } + template + void Solid::get_error_residual(Errors &error_residual) + { + BlockVector error_res(dofs_per_block); + for (unsigned int i = 0; i < dof_handler_ref.n_dofs(); ++i) + if (!constraints.is_constrained(i)) + error_res(i) = system_rhs(i); + error_residual.norm = error_res.l2_norm(); + error_residual.u = error_res.block(u_dof).l2_norm(); + error_residual.p = error_res.block(p_dof).l2_norm(); + error_residual.J = error_res.block(J_dof).l2_norm(); + } + template + void Solid::get_error_update(const BlockVector &newton_update, + Errors &error_update) + { + BlockVector error_ud(dofs_per_block); + for (unsigned int i = 0; i < dof_handler_ref.n_dofs(); ++i) + if (!constraints.is_constrained(i)) + error_ud(i) = newton_update(i); + error_update.norm = error_ud.l2_norm(); + error_update.u = error_ud.block(u_dof).l2_norm(); + error_update.p = error_ud.block(p_dof).l2_norm(); + error_update.J = error_ud.block(J_dof).l2_norm(); + } + template + BlockVector + Solid::get_total_solution(const BlockVector &solution_delta) const + { + BlockVector solution_total(solution_n); + solution_total += solution_delta; + return solution_total; + } + template + void Solid::assemble_system_tangent() + { + timer.enter_subsection("Assemble tangent matrix"); + pcout << " ASM_K " << std::flush; + tangent_matrix = 0.0; + const UpdateFlags uf_cell(update_values | + update_gradients | + update_JxW_values); + PerTaskData_K per_task_data(dofs_per_cell); + ScratchData_K scratch_data(fe, qf_cell, uf_cell); + WorkStream::run(dof_handler_ref.begin_active(), + dof_handler_ref.end(), + std_cxx11::bind(&Solid::assemble_system_tangent_one_cell, + this, + std_cxx11::_1, + std_cxx11::_2, + std_cxx11::_3), + std_cxx11::bind(&Solid::copy_local_to_global_K, + this, + std_cxx11::_1), + scratch_data, + per_task_data); + timer.leave_subsection(); + } + template + void Solid::copy_local_to_global_K(const PerTaskData_K &data) + { + for (unsigned int i = 0; i < dofs_per_cell; ++i) + for (unsigned int j = 0; j < dofs_per_cell; ++j) + tangent_matrix.add(data.local_dof_indices[i], + data.local_dof_indices[j], + data.cell_matrix(i, j)); + } + template + void + Solid::assemble_system_tangent_one_cell(const typename DoFHandler::active_cell_iterator &cell, + ScratchData_K &scratch, + PerTaskData_K &data) const + { + data.reset(); + scratch.reset(); + scratch.fe_values_ref.reinit(cell); + cell->get_dof_indices(data.local_dof_indices); + const std::vector > > lqph = + quadrature_point_history.get_data(cell); + Assert(lqph.size() == n_q_points, ExcInternalError()); + for (unsigned int q_point = 0; q_point < n_q_points; ++q_point) + { + const Tensor<2, dim> F_inv = lqph[q_point]->get_F_inv(); + for (unsigned int k = 0; k < dofs_per_cell; ++k) + { + const unsigned int k_group = fe.system_to_base_index(k).first.first; + if (k_group == u_dof) + { + scratch.grad_Nx[q_point][k] = scratch.fe_values_ref[u_fe].gradient(k, q_point) + * F_inv; + scratch.symm_grad_Nx[q_point][k] = symmetrize(scratch.grad_Nx[q_point][k]); + } + else if (k_group == p_dof) + scratch.Nx[q_point][k] = scratch.fe_values_ref[p_fe].value(k, + q_point); + else if (k_group == J_dof) + scratch.Nx[q_point][k] = scratch.fe_values_ref[J_fe].value(k, + q_point); + else + Assert(k_group <= J_dof, ExcInternalError()); + } + } + for (unsigned int q_point = 0; q_point < n_q_points; ++q_point) + { + const Tensor<2, dim> tau = lqph[q_point]->get_tau(); + const SymmetricTensor<4, dim> Jc = lqph[q_point]->get_Jc(); + const double d2Psi_vol_dJ2 = lqph[q_point]->get_d2Psi_vol_dJ2(); + const double det_F = lqph[q_point]->get_det_F(); + const std::vector + &N = scratch.Nx[q_point]; + const std::vector > + &symm_grad_Nx = scratch.symm_grad_Nx[q_point]; + const std::vector > + &grad_Nx = scratch.grad_Nx[q_point]; + const double JxW = scratch.fe_values_ref.JxW(q_point); + for (unsigned int i = 0; i < dofs_per_cell; ++i) + { + const unsigned int component_i = fe.system_to_component_index(i).first; + const unsigned int i_group = fe.system_to_base_index(i).first.first; + for (unsigned int j = 0; j <= i; ++j) + { + const unsigned int component_j = fe.system_to_component_index(j).first; + const unsigned int j_group = fe.system_to_base_index(j).first.first; + if ((i_group == j_group) && (i_group == u_dof)) + { + data.cell_matrix(i, j) += symm_grad_Nx[i] * Jc // The material contribution: + * symm_grad_Nx[j] * JxW; + if (component_i == component_j) // geometrical stress contribution + data.cell_matrix(i, j) += grad_Nx[i][component_i] * tau + * grad_Nx[j][component_j] * JxW; + } + else if ((i_group == p_dof) && (j_group == u_dof)) + { + data.cell_matrix(i, j) += N[i] * det_F + * (symm_grad_Nx[j] + * StandardTensors::I) + * JxW; + } + else if ((i_group == J_dof) && (j_group == p_dof)) + data.cell_matrix(i, j) -= N[i] * N[j] * JxW; + else if ((i_group == j_group) && (i_group == J_dof)) + data.cell_matrix(i, j) += N[i] * d2Psi_vol_dJ2 * N[j] * JxW; + else + Assert((i_group <= J_dof) && (j_group <= J_dof), + ExcInternalError()); + } + } + } + for (unsigned int i = 0; i < dofs_per_cell; ++i) + for (unsigned int j = i + 1; j < dofs_per_cell; ++j) + data.cell_matrix(i, j) = data.cell_matrix(j, i); + } + template + void Solid::assemble_system_rhs() + { + timer.enter_subsection("Assemble system right-hand side"); + pcout << " ASM_R " << std::flush; + system_rhs = 0.0; + const UpdateFlags uf_cell(update_values | + update_gradients | + update_JxW_values); + const UpdateFlags uf_face(update_values | + update_normal_vectors | + update_JxW_values); + PerTaskData_RHS per_task_data(dofs_per_cell); + ScratchData_RHS scratch_data(fe, qf_cell, uf_cell, qf_face, uf_face); + WorkStream::run(dof_handler_ref.begin_active(), + dof_handler_ref.end(), + std_cxx11::bind(&Solid::assemble_system_rhs_one_cell, + this, + std_cxx11::_1, + std_cxx11::_2, + std_cxx11::_3), + std_cxx11::bind(&Solid::copy_local_to_global_rhs, + this, + std_cxx11::_1), + scratch_data, + per_task_data); + timer.leave_subsection(); + } + template + void Solid::copy_local_to_global_rhs(const PerTaskData_RHS &data) + { + for (unsigned int i = 0; i < dofs_per_cell; ++i) + system_rhs(data.local_dof_indices[i]) += data.cell_rhs(i); + } + template + void + Solid::assemble_system_rhs_one_cell(const typename DoFHandler::active_cell_iterator &cell, + ScratchData_RHS &scratch, + PerTaskData_RHS &data) const + { + data.reset(); + scratch.reset(); + scratch.fe_values_ref.reinit(cell); + cell->get_dof_indices(data.local_dof_indices); + const std::vector > > lqph = + quadrature_point_history.get_data(cell); + Assert(lqph.size() == n_q_points, ExcInternalError()); + for (unsigned int q_point = 0; q_point < n_q_points; ++q_point) + { + const Tensor<2, dim> F_inv = lqph[q_point]->get_F_inv(); + for (unsigned int k = 0; k < dofs_per_cell; ++k) + { + const unsigned int k_group = fe.system_to_base_index(k).first.first; + if (k_group == u_dof) + scratch.symm_grad_Nx[q_point][k] + = symmetrize(scratch.fe_values_ref[u_fe].gradient(k, q_point) + * F_inv); + else if (k_group == p_dof) + scratch.Nx[q_point][k] = scratch.fe_values_ref[p_fe].value(k, + q_point); + else if (k_group == J_dof) + scratch.Nx[q_point][k] = scratch.fe_values_ref[J_fe].value(k, + q_point); + else + Assert(k_group <= J_dof, ExcInternalError()); + } + } + for (unsigned int q_point = 0; q_point < n_q_points; ++q_point) + { + const SymmetricTensor<2, dim> tau = lqph[q_point]->get_tau(); + const double det_F = lqph[q_point]->get_det_F(); + const double J_tilde = lqph[q_point]->get_J_tilde(); + const double p_tilde = lqph[q_point]->get_p_tilde(); + const double dPsi_vol_dJ = lqph[q_point]->get_dPsi_vol_dJ(); + const std::vector + &N = scratch.Nx[q_point]; + const std::vector > + &symm_grad_Nx = scratch.symm_grad_Nx[q_point]; + const double JxW = scratch.fe_values_ref.JxW(q_point); + for (unsigned int i = 0; i < dofs_per_cell; ++i) + { + const unsigned int i_group = fe.system_to_base_index(i).first.first; + if (i_group == u_dof) + data.cell_rhs(i) -= (symm_grad_Nx[i] * tau) * JxW; + else if (i_group == p_dof) + data.cell_rhs(i) -= N[i] * (det_F - J_tilde) * JxW; + else if (i_group == J_dof) + data.cell_rhs(i) -= N[i] * (dPsi_vol_dJ - p_tilde) * JxW; + else + Assert(i_group <= J_dof, ExcInternalError()); + } + } + for (unsigned int face = 0; face < GeometryInfo::faces_per_cell; + ++face) + if (cell->face(face)->at_boundary() == true + && cell->face(face)->boundary_id() == 6) + { + scratch.fe_face_values_ref.reinit(cell, face); + for (unsigned int f_q_point = 0; f_q_point < n_q_points_f; + ++f_q_point) + { + const Tensor<1, dim> &N = + scratch.fe_face_values_ref.normal_vector(f_q_point); + static const double p0 = -4.0 + / + (parameters.scale * parameters.scale); + const double time_ramp = (time.current() / time.end()); + const double pressure = p0 * parameters.p_p0 * time_ramp; + const Tensor<1, dim> traction = pressure * N; + for (unsigned int i = 0; i < dofs_per_cell; ++i) + { + const unsigned int i_group = + fe.system_to_base_index(i).first.first; + if (i_group == u_dof) + { + const unsigned int component_i = + fe.system_to_component_index(i).first; + const double Ni = + scratch.fe_face_values_ref.shape_value(i, + f_q_point); + const double JxW = scratch.fe_face_values_ref.JxW( + f_q_point); + data.cell_rhs(i) += (Ni * traction[component_i]) + * JxW; + } + } + } + } + } + template + void Solid::make_constraints(const int &it_nr) + { + pcout << " CST " << std::flush; + if (it_nr > 1) + return; + constraints.clear(); + const bool apply_dirichlet_bc = (it_nr == 0); + const FEValuesExtractors::Scalar x_displacement(0); + const FEValuesExtractors::Scalar y_displacement(1); + { + const int boundary_id = 0; + if (apply_dirichlet_bc == true) + VectorTools::interpolate_boundary_values(dof_handler_ref, + boundary_id, + ZeroFunction(n_components), + constraints, + fe.component_mask(x_displacement)); + else + VectorTools::interpolate_boundary_values(dof_handler_ref, + boundary_id, + ZeroFunction(n_components), + constraints, + fe.component_mask(x_displacement)); + } + { + const int boundary_id = 2; + if (apply_dirichlet_bc == true) + VectorTools::interpolate_boundary_values(dof_handler_ref, + boundary_id, + ZeroFunction(n_components), + constraints, + fe.component_mask(y_displacement)); + else + VectorTools::interpolate_boundary_values(dof_handler_ref, + boundary_id, + ZeroFunction(n_components), + constraints, + fe.component_mask(y_displacement)); + } + if (dim==3) + { + const FEValuesExtractors::Scalar z_displacement(2); + { + const int boundary_id = 3; + if (apply_dirichlet_bc == true) + VectorTools::interpolate_boundary_values(dof_handler_ref, + boundary_id, + ZeroFunction(n_components), + constraints, + (fe.component_mask(x_displacement) + | + fe.component_mask(z_displacement))); + else + VectorTools::interpolate_boundary_values(dof_handler_ref, + boundary_id, + ZeroFunction(n_components), + constraints, + (fe.component_mask(x_displacement) + | + fe.component_mask(z_displacement))); + } + { + const int boundary_id = 4; + if (apply_dirichlet_bc == true) + VectorTools::interpolate_boundary_values(dof_handler_ref, + boundary_id, + ZeroFunction(n_components), + constraints, + fe.component_mask(z_displacement)); + else + VectorTools::interpolate_boundary_values(dof_handler_ref, + boundary_id, + ZeroFunction(n_components), + constraints, + fe.component_mask(z_displacement)); + } + { + const int boundary_id = 6; + if (apply_dirichlet_bc == true) + VectorTools::interpolate_boundary_values(dof_handler_ref, + boundary_id, + ZeroFunction(n_components), + constraints, + (fe.component_mask(x_displacement) + | + fe.component_mask(z_displacement))); + else + VectorTools::interpolate_boundary_values(dof_handler_ref, + boundary_id, + ZeroFunction(n_components), + constraints, + (fe.component_mask(x_displacement) + | + fe.component_mask(z_displacement))); + } + } + else + { + { + const int boundary_id = 3; + if (apply_dirichlet_bc == true) + VectorTools::interpolate_boundary_values(dof_handler_ref, + boundary_id, + ZeroFunction(n_components), + constraints, + (fe.component_mask(x_displacement))); + else + VectorTools::interpolate_boundary_values(dof_handler_ref, + boundary_id, + ZeroFunction(n_components), + constraints, + (fe.component_mask(x_displacement))); + } + { + const int boundary_id = 6; + if (apply_dirichlet_bc == true) + VectorTools::interpolate_boundary_values(dof_handler_ref, + boundary_id, + ZeroFunction(n_components), + constraints, + (fe.component_mask(x_displacement))); + else + VectorTools::interpolate_boundary_values(dof_handler_ref, + boundary_id, + ZeroFunction(n_components), + constraints, + (fe.component_mask(x_displacement))); + } + } + constraints.close(); + } + template + void Solid::assemble_sc() + { + timer.enter_subsection("Perform static condensation"); + pcout << " ASM_SC " << std::flush; + PerTaskData_SC per_task_data(dofs_per_cell, element_indices_u.size(), + element_indices_p.size(), + element_indices_J.size()); + ScratchData_SC scratch_data; + WorkStream::run(dof_handler_ref.begin_active(), + dof_handler_ref.end(), + *this, + &Solid::assemble_sc_one_cell, + &Solid::copy_local_to_global_sc, + scratch_data, + per_task_data); + timer.leave_subsection(); + } + template + void Solid::copy_local_to_global_sc(const PerTaskData_SC &data) + { + for (unsigned int i = 0; i < dofs_per_cell; ++i) + for (unsigned int j = 0; j < dofs_per_cell; ++j) + tangent_matrix.add(data.local_dof_indices[i], + data.local_dof_indices[j], + data.cell_matrix(i, j)); + } + template + void + Solid::assemble_sc_one_cell(const typename DoFHandler::active_cell_iterator &cell, + ScratchData_SC &scratch, + PerTaskData_SC &data) + { + data.reset(); + scratch.reset(); + cell->get_dof_indices(data.local_dof_indices); + data.k_orig.extract_submatrix_from(tangent_matrix, + data.local_dof_indices, + data.local_dof_indices); + data.k_pu.extract_submatrix_from(data.k_orig, + element_indices_p, + element_indices_u); + data.k_pJ.extract_submatrix_from(data.k_orig, + element_indices_p, + element_indices_J); + data.k_JJ.extract_submatrix_from(data.k_orig, + element_indices_J, + element_indices_J); + data.k_pJ_inv.invert(data.k_pJ); + data.k_pJ_inv.mmult(data.A, data.k_pu); + data.k_JJ.mmult(data.B, data.A); + data.k_pJ_inv.Tmmult(data.C, data.B); + data.k_pu.Tmmult(data.k_bbar, data.C); + data.k_bbar.scatter_matrix_to(element_indices_u, + element_indices_u, + data.cell_matrix); + data.k_pJ_inv.add(-1.0, data.k_pJ); + data.k_pJ_inv.scatter_matrix_to(element_indices_p, + element_indices_J, + data.cell_matrix); + } + template + std::pair + Solid::solve_linear_system(BlockVector &newton_update) + { + unsigned int lin_it = 0; + double lin_res = 0.0; + if (parameters.use_static_condensation == true) + { + BlockVector A(dofs_per_block); + BlockVector B(dofs_per_block); + { + assemble_sc(); + tangent_matrix.block(p_dof, J_dof).vmult(A.block(J_dof), + system_rhs.block(p_dof)); + tangent_matrix.block(J_dof, J_dof).vmult(B.block(J_dof), + A.block(J_dof)); + A.block(J_dof) = system_rhs.block(J_dof); + A.block(J_dof) -= B.block(J_dof); + tangent_matrix.block(p_dof, J_dof).Tvmult(A.block(p_dof), + A.block(J_dof)); + tangent_matrix.block(u_dof, p_dof).vmult(A.block(u_dof), + A.block(p_dof)); + system_rhs.block(u_dof) -= A.block(u_dof); + timer.enter_subsection("Linear solver"); + pcout << " SLV " << std::flush; + if (parameters.type_lin == "CG") + { + const int solver_its = tangent_matrix.block(u_dof, u_dof).m() + * parameters.max_iterations_lin; + const double tol_sol = parameters.tol_lin + * system_rhs.block(u_dof).l2_norm(); + SolverControl solver_control(solver_its, tol_sol); + GrowingVectorMemory > GVM; + SolverCG > solver_CG(solver_control, GVM); + PreconditionSelector, Vector > + preconditioner (parameters.preconditioner_type, + parameters.preconditioner_relaxation); + preconditioner.use_matrix(tangent_matrix.block(u_dof, u_dof)); + solver_CG.solve(tangent_matrix.block(u_dof, u_dof), + newton_update.block(u_dof), + system_rhs.block(u_dof), + preconditioner); + lin_it = solver_control.last_step(); + lin_res = solver_control.last_value(); + } + else if (parameters.type_lin == "Direct") + { + SparseDirectUMFPACK A_direct; + A_direct.initialize(tangent_matrix.block(u_dof, u_dof)); + A_direct.vmult(newton_update.block(u_dof), system_rhs.block(u_dof)); + lin_it = 1; + lin_res = 0.0; + } + else + Assert (false, ExcMessage("Linear solver type not implemented")); + timer.leave_subsection(); + } + constraints.distribute(newton_update); + timer.enter_subsection("Linear solver postprocessing"); + pcout << " PP " << std::flush; + { + tangent_matrix.block(p_dof, u_dof).vmult(A.block(p_dof), + newton_update.block(u_dof)); + A.block(p_dof) *= -1.0; + A.block(p_dof) += system_rhs.block(p_dof); + tangent_matrix.block(p_dof, J_dof).vmult(newton_update.block(J_dof), + A.block(p_dof)); + } + constraints.distribute(newton_update); + { + tangent_matrix.block(J_dof, J_dof).vmult(A.block(J_dof), + newton_update.block(J_dof)); + A.block(J_dof) *= -1.0; + A.block(J_dof) += system_rhs.block(J_dof); + tangent_matrix.block(p_dof, J_dof).Tvmult(newton_update.block(p_dof), + A.block(J_dof)); + } + constraints.distribute(newton_update); + timer.leave_subsection(); + } + else + { + pcout << " ------ " << std::flush; + timer.enter_subsection("Linear solver"); + pcout << " SLV " << std::flush; + if (parameters.type_lin == "CG") + { + const Vector &f_u = system_rhs.block(u_dof); + const Vector &f_p = system_rhs.block(p_dof); + const Vector &f_J = system_rhs.block(J_dof); + Vector &d_u = newton_update.block(u_dof); + Vector &d_p = newton_update.block(p_dof); + Vector &d_J = newton_update.block(J_dof); + const auto K_uu = linear_operator(tangent_matrix.block(u_dof, u_dof)); + const auto K_up = linear_operator(tangent_matrix.block(u_dof, p_dof)); + const auto K_pu = linear_operator(tangent_matrix.block(p_dof, u_dof)); + const auto K_Jp = linear_operator(tangent_matrix.block(J_dof, p_dof)); + const auto K_JJ = linear_operator(tangent_matrix.block(J_dof, J_dof)); + PreconditionSelector< SparseMatrix, Vector > + preconditioner_K_Jp_inv ("jacobi"); + preconditioner_K_Jp_inv.use_matrix(tangent_matrix.block(J_dof, p_dof)); + ReductionControl solver_control_K_Jp_inv (tangent_matrix.block(J_dof, p_dof).m() * parameters.max_iterations_lin, + 1.0e-30, parameters.tol_lin); + SolverSelector< Vector > solver_K_Jp_inv; + solver_K_Jp_inv.select("cg"); + solver_K_Jp_inv.set_control(solver_control_K_Jp_inv); + const auto K_Jp_inv = inverse_operator(K_Jp, + solver_K_Jp_inv, + preconditioner_K_Jp_inv); + const auto K_pJ_inv = transpose_operator(K_Jp_inv); + const auto K_pp_bar = K_Jp_inv * K_JJ * K_pJ_inv; + const auto K_uu_bar_bar = K_up * K_pp_bar * K_pu; + const auto K_uu_con = K_uu + K_uu_bar_bar; + PreconditionSelector< SparseMatrix, Vector > + preconditioner_K_con_inv (parameters.preconditioner_type, + parameters.preconditioner_relaxation); + preconditioner_K_con_inv.use_matrix(tangent_matrix.block(u_dof, u_dof)); + ReductionControl solver_control_K_con_inv (tangent_matrix.block(u_dof, u_dof).m() * parameters.max_iterations_lin, + 1.0e-30, parameters.tol_lin); + SolverSelector< Vector > solver_K_con_inv; + solver_K_con_inv.select("cg"); + solver_K_con_inv.set_control(solver_control_K_con_inv); + const auto K_uu_con_inv = inverse_operator(K_uu_con, + solver_K_con_inv, + preconditioner_K_con_inv); + d_u = K_uu_con_inv*(f_u - K_up*(K_Jp_inv*f_J - K_pp_bar*f_p)); + timer.leave_subsection(); + timer.enter_subsection("Linear solver postprocessing"); + pcout << " PP " << std::flush; + d_J = K_pJ_inv*(f_p - K_pu*d_u); + d_p = K_Jp_inv*(f_J - K_JJ*d_J); + lin_it = solver_control_K_con_inv.last_step(); + lin_res = solver_control_K_con_inv.last_value(); + } + else if (parameters.type_lin == "Direct") + { + SparseDirectUMFPACK A_direct; + A_direct.initialize(tangent_matrix); + A_direct.vmult(newton_update, system_rhs); + lin_it = 1; + lin_res = 0.0; + pcout << " -- " << std::flush; + } + else + Assert (false, ExcMessage("Linear solver type not implemented")); + timer.leave_subsection(); + constraints.distribute(newton_update); + } + return std::make_pair(lin_it, lin_res); + } + template + void Solid::output_results() const + { + DataOut data_out; + std::vector + data_component_interpretation(dim, + DataComponentInterpretation::component_is_part_of_vector); + data_component_interpretation.push_back(DataComponentInterpretation::component_is_scalar); + data_component_interpretation.push_back(DataComponentInterpretation::component_is_scalar); + std::vector solution_name(dim, "displacement"); + solution_name.push_back("pressure"); + solution_name.push_back("dilatation"); + data_out.attach_dof_handler(dof_handler_ref); + data_out.add_data_vector(solution_n, + solution_name, + DataOut::type_dof_data, + data_component_interpretation); + Vector soln(solution_n.size()); + for (unsigned int i = 0; i < soln.size(); ++i) + soln(i) = solution_n(i); + MappingQEulerian q_mapping(degree, dof_handler_ref, soln); + data_out.build_patches(q_mapping, degree); + std::ostringstream filename; + filename << "solution-" << dim << "d-" << time.get_timestep() << ".vtk"; + std::ofstream output(filename.str().c_str()); + data_out.write_vtk(output); + } +} +int main (int argc,char **argv) +{ + std::ofstream logfile("output"); + deallog.attach(logfile); + deallog.depth_file(0); + deallog.threshold_double(1.e-10); + + Utilities::MPI::MPI_InitFinalize mpi_initialization (argc, argv, testing_max_num_threads()); + + using namespace dealii; + using namespace Step44; + try + { + const unsigned int dim = 3; + Solid solid(SOURCE_DIR "/prm/parameters-step-44.prm"); + solid.run(); + } + catch (std::exception &exc) + { + std::cerr << std::endl << std::endl + << "----------------------------------------------------" + << std::endl; + std::cerr << "Exception on processing: " << std::endl << exc.what() + << std::endl << "Aborting!" << std::endl + << "----------------------------------------------------" + << std::endl; + return 1; + } + catch (...) + { + std::cerr << std::endl << std::endl + << "----------------------------------------------------" + << std::endl; + std::cerr << "Unknown exception!" << std::endl << "Aborting!" + << std::endl + << "----------------------------------------------------" + << std::endl; + return 1; + } + return 0; +} diff --git a/tests/physics/step-44.output b/tests/physics/step-44.output new file mode 100644 index 0000000000..a5bd04fc20 --- /dev/null +++ b/tests/physics/step-44.output @@ -0,0 +1,167 @@ + +Grid: + Reference volume: 1.00000e-09 +Triangulation: + Number of active cells: 64 + Number of degrees of freedom: 503 + Setting up quadrature point data... + +Timestep 1 @ 0.100000s +___________________________________________________________________________________________________________________________________________________________ + SOLVER STEP | LIN_IT LIN_RES RES_NORM RES_U RES_P RES_J NU_NORM NU_U NU_P NU_J +___________________________________________________________________________________________________________________________________________________________ + 0 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 134 1.879e-06 1.000e+00 1.000e+00 0.000e+00 0.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 + 1 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 96 9.785e-04 8.085e-02 8.085e-02 7.076e-13 3.053e-08 9.397e-02 3.598e-02 9.397e-02 9.399e-02 + 2 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 119 4.017e-06 8.826e-04 8.826e-04 2.254e-15 1.998e-10 8.493e-04 1.975e-04 8.493e-04 8.494e-04 + 3 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 149 7.738e-11 1.069e-06 1.069e-06 4.212e-20 2.171e-14 9.915e-07 2.729e-07 9.915e-07 9.915e-07 + 4 ASM_R CONVERGED! +___________________________________________________________________________________________________________________________________________________________ +Relative errors: +Displacement: 2.729e-07 +Force: 2.063e-11 +Dilatation: 3.484e-07 +v / V_0: 1.000e-09 / 1.000e-09 = 1.000e+00 + +Timestep 2 @ 2.000e-01s +___________________________________________________________________________________________________________________________________________________________ + SOLVER STEP | LIN_IT LIN_RES RES_NORM RES_U RES_P RES_J NU_NORM NU_U NU_P NU_J +___________________________________________________________________________________________________________________________________________________________ + 0 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 131 3.051e-06 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 + 1 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 92 1.172e-03 8.472e-02 8.472e-02 8.757e+12 5.853e+06 1.096e-01 4.023e-02 1.096e-01 1.097e-01 + 2 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 111 5.758e-06 9.375e-04 9.375e-04 3.433e+10 5.674e+04 1.112e-03 3.103e-04 1.112e-03 1.112e-03 + 3 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 151 1.003e-10 1.537e-06 1.537e-06 8.734e+05 6.606e+00 1.426e-06 7.544e-07 1.426e-06 1.426e-06 + 4 ASM_R CONVERGED! +___________________________________________________________________________________________________________________________________________________________ +Relative errors: +Displacement: 7.544e-07 +Force: 2.675e-11 +Dilatation: 7.035e-07 +v / V_0: 1.000e-09 / 1.000e-09 = 1.000e+00 + +Timestep 3 @ 3.000e-01s +___________________________________________________________________________________________________________________________________________________________ + SOLVER STEP | LIN_IT LIN_RES RES_NORM RES_U RES_P RES_J NU_NORM NU_U NU_P NU_J +___________________________________________________________________________________________________________________________________________________________ + 0 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 127 2.879e-06 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 + 1 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 91 1.498e-03 9.356e-02 9.356e-02 1.684e+12 4.976e+06 1.131e-01 4.961e-02 1.131e-01 1.131e-01 + 2 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 107 6.289e-06 9.500e-04 9.500e-04 8.139e+09 5.059e+04 1.448e-03 4.916e-04 1.448e-03 1.448e-03 + 3 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 147 2.200e-10 1.687e-06 1.687e-06 4.346e+05 8.460e+00 1.502e-06 5.180e-07 1.502e-06 1.502e-06 + 4 ASM_R CONVERGED! +___________________________________________________________________________________________________________________________________________________________ +Relative errors: +Displacement: 5.180e-07 +Force: 5.866e-11 +Dilatation: 1.059e-06 +v / V_0: 1.000e-09 / 1.000e-09 = 1.000e+00 + +Timestep 4 @ 4.000e-01s +___________________________________________________________________________________________________________________________________________________________ + SOLVER STEP | LIN_IT LIN_RES RES_NORM RES_U RES_P RES_J NU_NORM NU_U NU_P NU_J +___________________________________________________________________________________________________________________________________________________________ + 0 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 130 1.876e-06 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 + 1 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 91 1.124e-03 1.069e-01 1.069e-01 2.260e+12 4.315e+06 9.763e-02 6.072e-02 9.763e-02 9.764e-02 + 2 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 110 6.459e-06 1.409e-03 1.409e-03 1.222e+10 2.736e+04 1.896e-03 8.054e-04 1.896e-03 1.896e-03 + 3 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 144 7.557e-10 1.771e-06 1.771e-06 1.831e+06 1.301e+01 1.957e-06 7.733e-07 1.957e-06 1.957e-06 + 4 ASM_R CONVERGED! +___________________________________________________________________________________________________________________________________________________________ +Relative errors: +Displacement: 7.733e-07 +Force: 2.015e-10 +Dilatation: 1.407e-06 +v / V_0: 1.000e-09 / 1.000e-09 = 1.000e+00 + +Timestep 5 @ 5.000e-01s +___________________________________________________________________________________________________________________________________________________________ + SOLVER STEP | LIN_IT LIN_RES RES_NORM RES_U RES_P RES_J NU_NORM NU_U NU_P NU_J +___________________________________________________________________________________________________________________________________________________________ + 0 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 133 1.921e-06 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 + 1 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 94 7.758e-04 1.179e-01 1.179e-01 1.270e+12 3.762e+06 7.329e-02 6.923e-02 7.329e-02 7.330e-02 + 2 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 114 6.837e-06 2.265e-03 2.265e-03 7.113e+09 9.735e+03 2.289e-03 1.160e-03 2.289e-03 2.289e-03 + 3 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 134 2.491e-09 2.033e-06 2.033e-06 2.460e+06 1.721e+01 2.811e-06 5.735e-07 2.811e-06 2.811e-06 + 4 ASM_R CONVERGED! +___________________________________________________________________________________________________________________________________________________________ +Relative errors: +Displacement: 5.735e-07 +Force: 6.642e-10 +Dilatation: 1.742e-06 +v / V_0: 1.000e-09 / 1.000e-09 = 1.000e+00 + +Timestep 6 @ 6.000e-01s +___________________________________________________________________________________________________________________________________________________________ + SOLVER STEP | LIN_IT LIN_RES RES_NORM RES_U RES_P RES_J NU_NORM NU_U NU_P NU_J +___________________________________________________________________________________________________________________________________________________________ + 0 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 132 1.570e-06 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 + 1 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 93 8.254e-04 1.230e-01 1.230e-01 2.574e+12 3.411e+06 5.485e-02 7.377e-02 5.485e-02 5.486e-02 + 2 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 118 6.328e-06 2.737e-03 2.737e-03 1.393e+10 3.815e+03 2.295e-03 1.409e-03 2.295e-03 2.295e-03 + 3 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 141 1.786e-09 2.421e-06 2.421e-06 7.040e+06 1.550e+01 2.731e-06 6.528e-07 2.731e-06 2.731e-06 + 4 ASM_R CONVERGED! +___________________________________________________________________________________________________________________________________________________________ +Relative errors: +Displacement: 6.528e-07 +Force: 4.763e-10 +Dilatation: 2.057e-06 +v / V_0: 1.000e-09 / 1.000e-09 = 1.000e+00 + +Timestep 7 @ 7.000e-01s +___________________________________________________________________________________________________________________________________________________________ + SOLVER STEP | LIN_IT LIN_RES RES_NORM RES_U RES_P RES_J NU_NORM NU_U NU_P NU_J +___________________________________________________________________________________________________________________________________________________________ + 0 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 132 2.942e-06 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 + 1 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 93 7.359e-04 1.234e-01 1.234e-01 1.412e+12 3.061e+06 4.450e-02 7.478e-02 4.450e-02 4.452e-02 + 2 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 120 3.420e-06 2.699e-03 2.699e-03 7.451e+09 2.142e+03 2.079e-03 1.491e-03 2.079e-03 2.079e-03 + 3 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 148 1.688e-09 1.625e-06 1.625e-06 4.062e+06 1.135e+01 2.104e-06 6.589e-07 2.104e-06 2.105e-06 + 4 ASM_R CONVERGED! +___________________________________________________________________________________________________________________________________________________________ +Relative errors: +Displacement: 6.589e-07 +Force: 4.502e-10 +Dilatation: 2.353e-06 +v / V_0: 1.000e-09 / 1.000e-09 = 1.000e+00 + +Timestep 8 @ 8.000e-01s +___________________________________________________________________________________________________________________________________________________________ + SOLVER STEP | LIN_IT LIN_RES RES_NORM RES_U RES_P RES_J NU_NORM NU_U NU_P NU_J +___________________________________________________________________________________________________________________________________________________________ + 0 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 137 2.965e-06 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 + 1 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 96 5.552e-04 1.207e-01 1.207e-01 1.543e+12 3.613e+06 3.817e-02 7.299e-02 3.817e-02 3.818e-02 + 2 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 124 1.818e-06 2.512e-03 2.512e-03 8.134e+09 2.018e+03 1.745e-03 1.428e-03 1.745e-03 1.746e-03 + 3 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 151 1.101e-09 1.149e-06 1.149e-06 4.014e+06 9.162e+00 9.495e-07 6.011e-07 9.495e-07 9.496e-07 + 4 ASM_R CONVERGED! +___________________________________________________________________________________________________________________________________________________________ +Relative errors: +Displacement: 6.011e-07 +Force: 2.936e-10 +Dilatation: 2.632e-06 +v / V_0: 1.000e-09 / 1.000e-09 = 1.000e+00 + +Timestep 9 @ 9.000e-01s +___________________________________________________________________________________________________________________________________________________________ + SOLVER STEP | LIN_IT LIN_RES RES_NORM RES_U RES_P RES_J NU_NORM NU_U NU_P NU_J +___________________________________________________________________________________________________________________________________________________________ + 0 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 134 3.726e-06 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 + 1 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 96 3.272e-04 1.155e-01 1.155e-01 1.793e+12 3.058e+06 3.352e-02 6.924e-02 3.352e-02 3.354e-02 + 2 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 129 1.004e-06 2.232e-03 2.232e-03 9.116e+09 1.519e+03 1.335e-03 1.247e-03 1.335e-03 1.335e-03 + 3 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 153 9.268e-10 8.594e-07 8.594e-07 3.613e+06 4.382e+00 6.229e-07 4.688e-07 6.229e-07 6.230e-07 + 4 ASM_R CONVERGED! +___________________________________________________________________________________________________________________________________________________________ +Relative errors: +Displacement: 4.688e-07 +Force: 2.472e-10 +Dilatation: 2.899e-06 +v / V_0: 1.000e-09 / 1.000e-09 = 1.000e+00 + +Timestep 10 @ 1.000e+00s +___________________________________________________________________________________________________________________________________________________________ + SOLVER STEP | LIN_IT LIN_RES RES_NORM RES_U RES_P RES_J NU_NORM NU_U NU_P NU_J +___________________________________________________________________________________________________________________________________________________________ + 0 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 134 3.218e-06 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 + 1 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 95 3.148e-04 1.085e-01 1.085e-01 2.377e+12 3.129e+06 3.002e-02 6.447e-02 3.002e-02 3.004e-02 + 2 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 132 9.070e-07 1.905e-03 1.905e-03 1.109e+10 1.319e+03 9.672e-04 1.008e-03 9.672e-04 9.672e-04 + 3 ASM_R ASM_K CST ASM_SC SLV PP UQPH | 156 5.143e-10 6.087e-07 6.087e-07 3.174e+06 2.465e+00 4.277e-07 3.161e-07 4.277e-07 4.278e-07 + 4 ASM_R CONVERGED! +___________________________________________________________________________________________________________________________________________________________ +Relative errors: +Displacement: 3.161e-07 +Force: 1.372e-10 +Dilatation: 3.157e-06 +v / V_0: 1.000e-09 / 1.000e-09 = 1.000e+00 -- 2.39.5