--- /dev/null
+// ---------------------------------------------------------------------
+//
+// 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.
+ *
+ * <h3>Notation</h3>
+ *
+ * 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 <i>kind</i> 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.
+ *
+ * <h3>Notation</h3>
+ *
+ * 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
+ {
+ }
+
+}
ALIASES += dealiiExceptionMessage{1}="@note The message that will be printed by this exception reads: <div class='doxygen-generated-exception-message'> \1 </div> "
+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
#---------------------------------------------------------------------------
<ol>
+ <li> 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.
+ <br>
+ (Jean-Paul Pelteret, Andrew McBride, 2016/12/05)
+ </li>
+
+ <li> 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.
+ <br>
+ (Jean-Paul Pelteret, Andrew McBride, 2016/12/05)
+ </li>
+
+ <li> 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.
+ <br>
+ (Jean-Paul Pelteret, 2016/12/05)
+ </li>
+
<li> 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.
--- /dev/null
+// ---------------------------------------------------------------------
+//
+// 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 <deal.II/base/symmetric_tensor.h>
+#include <deal.II/base/tensor.h>
+#include <deal.II/physics/elasticity/standard_tensors.h>
+
+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 <int dim, typename Number>
+ 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 <int dim, typename Number>
+ 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 <int dim, typename Number>
+ 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 <int dim, typename Number>
+ 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 <int dim, typename Number>
+ 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 <int dim, typename Number>
+ 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 <int dim, typename Number>
+ 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 <int dim, typename Number>
+ 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 <int dim, typename Number>
+ 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 <int dim, typename Number>
+ 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 <int dim, typename Number>
+ Tensor<2, dim, Number>
+ w (const Tensor<2, dim, Number> &F,
+ const Tensor<2, dim, Number> &dF_dt);
+
+//@}
+ };
+
+ }
+}
+
+
+
+#ifndef DOXYGEN
+
+// ------------------------- inline functions ------------------------
+
+
+
+template <int dim, typename Number>
+inline
+Tensor<2, dim, Number>
+Physics::Elasticity::Kinematics::F (const Tensor<2, dim, Number> &Grad_u)
+{
+ return StandardTensors<dim>::I + Grad_u;
+}
+
+
+
+template <int dim, typename Number>
+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 <int dim, typename Number>
+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<dim>());
+}
+
+
+
+template <int dim, typename Number>
+inline
+SymmetricTensor<2, dim, Number>
+Physics::Elasticity::Kinematics::C (const Tensor<2, dim, Number> &F)
+{
+ return symmetrize(transpose(F)*F);
+}
+
+
+
+template <int dim, typename Number>
+inline
+SymmetricTensor<2, dim, Number>
+Physics::Elasticity::Kinematics::b (const Tensor<2, dim, Number> &F)
+{
+ return symmetrize(F*transpose(F));
+}
+
+
+
+template <int dim, typename Number>
+inline
+SymmetricTensor<2, dim, Number>
+Physics::Elasticity::Kinematics::E (const Tensor<2, dim, Number> &F)
+{
+ return Number(0.5)*(C(F) - static_cast<SymmetricTensor<2,dim,Number> >(StandardTensors<dim>::I));
+}
+
+
+
+template <int dim, typename Number>
+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 <int dim, typename Number>
+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<SymmetricTensor<2,dim,Number> >(StandardTensors<dim>::I) - transpose(F_inv)*F_inv);
+}
+
+
+
+template <int dim, typename Number>
+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 <int dim, typename Number>
+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 <int dim, typename Number>
+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
--- /dev/null
+// ---------------------------------------------------------------------
+//
+// 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 <deal.II/base/symmetric_tensor.h>
+#include <deal.II/base/tensor.h>
+
+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 <int dim>
+ 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 <typename Number>
+ 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 <typename Number>
+ 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 <typename Number>
+ 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 <typename Number>
+ static SymmetricTensor<4, dim, Number>
+ dC_inv_dC (const Tensor<2, dim, Number> &F);
+
+//@}
+ };
+
+ }
+}
+
+
+
+#ifndef DOXYGEN
+
+// ------------------------- inline functions ------------------------
+
+
+template <int dim>
+template <typename Number>
+inline
+SymmetricTensor<4, dim, Number>
+Physics::Elasticity::StandardTensors<dim>::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 <int dim>
+template <typename Number>
+inline
+SymmetricTensor<4, dim, Number>
+Physics::Elasticity::StandardTensors<dim>::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 <int dim>
+template <typename Number>
+inline
+SymmetricTensor<2, dim, Number>
+Physics::Elasticity::StandardTensors<dim>::ddet_F_dC (const Tensor<2, dim, Number> &F)
+{
+ return Number(0.5)*determinant(F)*symmetrize(invert(transpose(F)*F));
+}
+
+
+
+template <int dim>
+template <typename Number>
+inline
+SymmetricTensor<4, dim, Number>
+Physics::Elasticity::StandardTensors<dim>::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<dim; ++A)
+ for (unsigned int B=A; B<dim; ++B)
+ for (unsigned int C=0; C<dim; ++C)
+ for (unsigned int D=C; D<dim; ++D)
+ dC_inv_dC[A][B][C][D] -= 0.5*(C_inv[A][C] * C_inv[B][D] + C_inv[A][D] * C_inv[B][C] );
+
+ return dC_inv_dC;
+}
+
+#endif // DOXYGEN
+
+DEAL_II_NAMESPACE_CLOSE
+
+#endif
--- /dev/null
+// ---------------------------------------------------------------------
+//
+// 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__transformations_h
+#define dealii__transformations_h
+
+#include <deal.II/base/tensor.h>
+#include <deal.II/base/symmetric_tensor.h>
+
+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 <int dim, typename Number>
+ 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 <int dim, typename Number>
+ 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 <int dim, typename Number>
+ 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 <int dim, typename Number>
+ 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 <int dim, typename Number>
+ 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 <int dim, typename Number>
+ 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 <int dim, typename Number>
+ 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 <int dim, typename Number>
+ 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 <int dim, typename Number>
+ 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 <int dim, typename Number>
+ 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 <int dim, typename Number>
+ 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 <int dim, typename Number>
+ 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 <int dim, typename Number>
+ 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 <int dim, typename Number>
+ 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 <int dim, typename Number>
+ 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 <int dim, typename Number>
+ 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 <int dim, typename Number>
+ 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 <int dim, typename Number>
+ 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 <int dim, typename Number>
+ 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 <int dim, typename Number>
+ 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 <int dim, typename Number>
+ 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 <int dim, typename Number>
+ 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 <int dim, typename Number>
+ 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 <int dim, typename Number>
+ 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 <int dim, typename Number>
+ 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 <int dim, typename Number>
+ 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 <int dim, typename Number>
+ 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 <int dim, typename Number>
+ 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 <int dim, typename Number>
+ 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 <int dim, typename Number>
+ 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<int dim, typename Number>
+ 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 <int dim, typename Number>
+ 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 <int dim, typename Number>
+ 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 <int dim, typename Number>
+ 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<dim; ++i)
+ for (unsigned int J=0; J<dim; ++J)
+ for (unsigned int I=0; I<dim; ++I)
+ tmp_1[i][J] += F[i][I] * T[I][J];
+
+ dealii::SymmetricTensor<2,dim,Number> out;
+ for (unsigned int i=0; i<dim; ++i)
+ for (unsigned int j=i; j<dim; ++j)
+ for (unsigned int J=0; J<dim; ++J)
+ out[i][j] += F[j][J] * tmp_1[i][J];
+
+ return out;
+ }
+
+
+
+ template <int dim, typename Number>
+ 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 <int dim, typename Number>
+ 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<dim; ++i)
+ for (unsigned int J=0; J<dim; ++J)
+ for (unsigned int K=0; K<dim; ++K)
+ for (unsigned int L=0; L<dim; ++L)
+ for (unsigned int I=0; I<dim; ++I)
+ tmp_1[i][J][K][L] += F[i][I] * H[I][J][K][L];
+
+ Tensor<4,dim,Number> tmp_2;
+ for (unsigned int i=0; i<dim; ++i)
+ for (unsigned int j=0; j<dim; ++j)
+ for (unsigned int K=0; K<dim; ++K)
+ for (unsigned int L=0; L<dim; ++L)
+ for (unsigned int J=0; J<dim; ++J)
+ tmp_2[i][j][K][L] += F[j][J] * tmp_1[i][J][K][L];
+
+ tmp_1 = 0.0;
+ for (unsigned int i=0; i<dim; ++i)
+ for (unsigned int j=0; j<dim; ++j)
+ for (unsigned int k=0; k<dim; ++k)
+ for (unsigned int L=0; L<dim; ++L)
+ for (unsigned int K=0; K<dim; ++K)
+ tmp_1[i][j][k][L] += F[k][K] * tmp_2[i][j][K][L];
+
+ dealii::SymmetricTensor<4,dim,Number> out;
+ for (unsigned int i=0; i<dim; ++i)
+ for (unsigned int j=i; j<dim; ++j)
+ for (unsigned int k=0; k<dim; ++k)
+ for (unsigned int l=k; l<dim; ++l)
+ for (unsigned int L=0; L<dim; ++L)
+ out[i][j][k][l] += F[l][L] * tmp_1[i][j][k][L];
+
+ return out;
+ }
+ }
+ }
+}
+
+
+
+template <int dim, typename Number>
+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 <int dim, typename Number>
+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 <int dim, typename Number>
+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 <int dim, typename Number>
+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 <int dim, typename Number>
+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 <int dim, typename Number>
+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 <int dim, typename Number>
+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 <int dim, typename Number>
+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 <int dim, typename Number>
+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 <int dim, typename Number>
+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 <int dim, typename Number>
+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 <int dim, typename Number>
+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 <int dim, typename Number>
+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 <int dim, typename Number>
+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 <int dim, typename Number>
+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 <int dim, typename Number>
+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 <int dim, typename Number>
+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 <int dim, typename Number>
+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 <int dim, typename Number>
+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 <int dim, typename Number>
+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 <int dim, typename Number>
+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 <int dim, typename Number>
+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 <int dim, typename Number>
+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 <int dim, typename Number>
+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 <int dim, typename Number>
+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 <int dim, typename Number>
+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 <int dim, typename Number>
+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 <int dim, typename Number>
+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 <int dim, typename Number>
+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 <int dim, typename Number>
+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<int dim, typename Number>
+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
ADD_SUBDIRECTORY(matrix_free)
ADD_SUBDIRECTORY(meshworker)
ADD_SUBDIRECTORY(opencascade)
+ADD_SUBDIRECTORY(physics)
FOREACH(build ${DEAL_II_BUILD_TYPES})
STRING(TOLOWER ${build} build_lowercase)
--- /dev/null
+## ---------------------------------------------------------------------
+##
+## 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}")
--- /dev/null
+## ---------------------------------------------------------------------
+##
+## 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}")
--- /dev/null
+// ---------------------------------------------------------------------
+//
+// 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/physics/elasticity/kinematics.h>
+
+DEAL_II_NAMESPACE_OPEN
+
+// explicit instantiations
+#include "kinematics.inst"
+
+DEAL_II_NAMESPACE_CLOSE
--- /dev/null
+// ---------------------------------------------------------------------
+//
+// 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<deal_II_dimension,number>(const Tensor<2,deal_II_dimension,number>&);
+
+ template
+ Tensor<2,deal_II_dimension,number>
+ F_iso<deal_II_dimension,number>(const Tensor<2,deal_II_dimension,number>&);
+
+ template
+ SymmetricTensor<2,deal_II_dimension,number>
+ F_vol<deal_II_dimension,number>(const Tensor<2,deal_II_dimension,number>&);
+
+ template
+ SymmetricTensor<2,deal_II_dimension,number>
+ C<deal_II_dimension,number>(const Tensor<2,deal_II_dimension,number>&);
+
+ template
+ SymmetricTensor<2,deal_II_dimension,number>
+ b<deal_II_dimension,number>(const Tensor<2,deal_II_dimension,number>&);
+
+ template
+ SymmetricTensor<2,deal_II_dimension,number>
+ E<deal_II_dimension,number>(const Tensor<2,deal_II_dimension,number>&);
+
+ template
+ SymmetricTensor<2,deal_II_dimension,number>
+ epsilon<deal_II_dimension,number>(const Tensor<2,deal_II_dimension,number>&);
+
+ template
+ SymmetricTensor<2,deal_II_dimension,number>
+ e<deal_II_dimension,number>(const Tensor<2,deal_II_dimension,number>&);
+
+ template
+ Tensor<2,deal_II_dimension,number>
+ l<deal_II_dimension,number>(
+ const Tensor<2,deal_II_dimension,number>&,
+ const Tensor<2,deal_II_dimension,number>&);
+
+ template
+ SymmetricTensor<2,deal_II_dimension,number>
+ d<deal_II_dimension,number>(
+ const Tensor<2,deal_II_dimension,number>&,
+ const Tensor<2,deal_II_dimension,number>&);
+
+ template
+ Tensor<2,deal_II_dimension,number>
+ w<deal_II_dimension,number>(
+ const Tensor<2,deal_II_dimension,number>&,
+ const Tensor<2,deal_II_dimension,number>&);
+ \}
+ \}
+ \}
+}
--- /dev/null
+// ---------------------------------------------------------------------
+//
+// 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/base/symmetric_tensor.h>
+#include <deal.II/physics/elasticity/standard_tensors.h>
+
+DEAL_II_NAMESPACE_OPEN
+
+
+template <int dim>
+const SymmetricTensor<2, dim>
+Physics::Elasticity::StandardTensors<dim>::I = unit_symmetric_tensor<dim>();
+
+
+
+template <int dim>
+const SymmetricTensor<4, dim>
+Physics::Elasticity::StandardTensors<dim>::S = identity_tensor<dim>();
+
+
+
+template <int dim>
+const SymmetricTensor<4, dim>
+Physics::Elasticity::StandardTensors<dim>::IxI = outer_product(unit_symmetric_tensor<dim>(),
+ unit_symmetric_tensor<dim>());
+
+
+
+template <int dim>
+const SymmetricTensor<4, dim>
+Physics::Elasticity::StandardTensors<dim>::dev_P = deviator_tensor<dim>();
+
+
+// explicit instantiations
+#include "standard_tensors.inst"
+
+DEAL_II_NAMESPACE_CLOSE
--- /dev/null
+// ---------------------------------------------------------------------
+//
+// 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<deal_II_dimension>;
+ \}
+ \}
+}
+
+
+for (deal_II_dimension : DIMENSIONS; number : REAL_SCALARS)
+{
+ namespace Physics
+ \{
+ namespace Elasticity
+ \{
+ template
+ SymmetricTensor<4,deal_II_dimension,number>
+ StandardTensors<deal_II_dimension>::Dev_P<number>(const Tensor<2,deal_II_dimension,number> &);
+
+ template
+ SymmetricTensor<4,deal_II_dimension,number>
+ StandardTensors<deal_II_dimension>::Dev_P_T<number>(const Tensor<2,deal_II_dimension,number> &);
+
+ template
+ SymmetricTensor<2,deal_II_dimension,number>
+ StandardTensors<deal_II_dimension>::ddet_F_dC<number>(const Tensor<2,deal_II_dimension,number> &);
+
+ template
+ SymmetricTensor<4,deal_II_dimension,number>
+ StandardTensors<deal_II_dimension>::dC_inv_dC<number>(const Tensor<2,deal_II_dimension,number> &);
+ \}
+ \}
+}
--- /dev/null
+// ---------------------------------------------------------------------
+//
+// 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/physics/transformations.h>
+
+DEAL_II_NAMESPACE_OPEN
+
+// explicit instantiations
+#include "transformations.inst"
+
+DEAL_II_NAMESPACE_CLOSE
--- /dev/null
+// ---------------------------------------------------------------------
+//
+// 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> &);
+ \}
+
+ \}
+ \}
+}
--- /dev/null
+CMAKE_MINIMUM_REQUIRED(VERSION 2.8.9)
+INCLUDE(../setup_testsubproject.cmake)
+PROJECT(testsuite CXX)
+DEAL_II_PICKUP_TESTS()
--- /dev/null
+// ---------------------------------------------------------------------
+//
+// 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 <deal.II/base/logstream.h>
+
+#include <deal.II/base/quadrature_lib.h>
+#include <deal.II/base/symmetric_tensor.h>
+#include <deal.II/base/tensor.h>
+#include <deal.II/dofs/dof_handler.h>
+#include <deal.II/dofs/dof_accessor.h>
+#include <deal.II/fe/mapping_q_eulerian.h>
+#include <deal.II/fe/fe_q.h>
+#include <deal.II/fe/fe_system.h>
+#include <deal.II/fe/fe_values.h>
+#include <deal.II/fe/fe_values_extractors.h>
+#include <deal.II/grid/tria.h>
+#include <deal.II/grid/tria_accessor.h>
+#include <deal.II/grid/tria_iterator.h>
+#include <deal.II/grid/grid_generator.h>
+#include <deal.II/lac/vector.h>
+
+#include <deal.II/physics/elasticity/kinematics.h>
+#include <deal.II/physics/transformations.h>
+
+#include <fstream>
+#include <iomanip>
+
+using namespace dealii;
+using namespace dealii::Physics;
+using namespace dealii::Physics::Elasticity;
+
+template<int dim>
+void
+test_kinematic_tensors ()
+{
+ const FESystem<dim> fe (FE_Q<dim>(1), dim);
+ const QGauss<dim> qf (2);
+ Triangulation<dim> tria;
+ GridGenerator::hyper_cube(tria, -1, 1);
+ DoFHandler<dim> dof_handler (tria);
+ dof_handler.distribute_dofs(fe);
+
+ Vector<double> soln_t (dof_handler.n_dofs());
+ Vector<double> soln_t1 (dof_handler.n_dofs());
+
+ for (typename DoFHandler<dim>::active_cell_iterator
+ cell = dof_handler.begin_active();
+ cell != dof_handler.end(); ++cell)
+ {
+ for (unsigned int v=0; v<GeometryInfo<dim>::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<double> 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<dim> fe_values (fe, qf, update_gradients);
+ MappingQEulerian<dim> q1_mapping(1, dof_handler, soln_t);
+ FEValues<dim> fe_values_mapped (q1_mapping, fe, qf, update_gradients);
+
+ for (typename DoFHandler<dim>::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<n_q_points; ++q_point)
+ {
+ static const double tol = 1e-12;
+
+ // Material gradients
+ const Tensor<2,dim> &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<dim>()).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<dim>()) + 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;
+}
--- /dev/null
+
+DEAL::OK
--- /dev/null
+// ---------------------------------------------------------------------
+//
+// 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 <deal.II/base/symmetric_tensor.h>
+#include <deal.II/base/tensor.h>
+#include <deal.II/base/logstream.h>
+#include <deal.II/physics/elasticity/standard_tensors.h>
+#include <fstream>
+#include <iomanip>
+
+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<int dim>
+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<dim>::I
+ + 2.0*c01*(I1*StandardTensors<dim>::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<int dim>
+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<dim>::I
+ + 2.0*c01*(I1*StandardTensors<dim>::I - b);
+ return symmetrize(static_cast< Tensor<2,dim> >(tmp)*static_cast< Tensor<2,dim> >(b));
+}
+
+template<int dim>
+void
+test_standard_tensors ()
+{
+ SymmetricTensor<2,dim> t;
+ for (unsigned int i=0; i<dim; ++i)
+ for (unsigned int j=i; j<dim; ++j)
+ t[i][j] = dim*i+j+1.0;
+
+ // Check second-order identity tensor I:
+ AssertThrow (std::fabs (StandardTensors<dim>::I*t - trace(t)) < 1e-14,
+ ExcInternalError());
+ AssertThrow (std::fabs (t*StandardTensors<dim>::I - trace(t)) < 1e-14,
+ ExcInternalError());
+
+ // Check fourth-order identity tensor II:
+ AssertThrow (std::fabs ((StandardTensors<dim>::S*t - t).norm()) < 1e-14,
+ ExcInternalError());
+ AssertThrow (std::fabs ((t*StandardTensors<dim>::S - t).norm()) < 1e-14,
+ ExcInternalError());
+
+ // Check fourth-order tensor IxI:
+ AssertThrow (std::fabs ((StandardTensors<dim>::IxI*t - trace(t)*unit_symmetric_tensor<dim>()).norm()) < 1e-14,
+ ExcInternalError());
+ AssertThrow (std::fabs ((t*StandardTensors<dim>::IxI - trace(t)*unit_symmetric_tensor<dim>()).norm()) < 1e-14,
+ ExcInternalError());
+
+ // Check spatial deviatoric tensor dev_P:
+ AssertThrow (std::fabs ((StandardTensors<dim>::dev_P*t - (t - (trace(t)/dim)*unit_symmetric_tensor<dim>())).norm()) < 1e-14,
+ ExcInternalError());
+ AssertThrow (std::fabs ((t*StandardTensors<dim>::dev_P - (t - (trace(t)/dim)*unit_symmetric_tensor<dim>())).norm()) < 1e-14,
+ ExcInternalError());
+
+ // Check referential deviatoric tensor Dev_P:
+ Tensor<2,dim> F (unit_symmetric_tensor<dim>());
+ 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<dim>::Dev_P_T(F)*s;
+ const SymmetricTensor<2,dim> s_x_Dev_P = s*StandardTensors<dim>::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<dim>::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<dim>::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<dim>::Dev_P(F);
+ const SymmetricTensor<2,dim> tau_iso = StandardTensors<dim>::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;
+}
--- /dev/null
+
+DEAL::OK
--- /dev/null
+# 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
--- /dev/null
+// ---------------------------------------------------------------------
+//
+// 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 <deal.II/base/conditional_ostream.h>
+#include <deal.II/base/function.h>
+#include <deal.II/base/parameter_handler.h>
+#include <deal.II/base/point.h>
+#include <deal.II/base/quadrature_lib.h>
+#include <deal.II/base/quadrature_point_data.h>
+#include <deal.II/base/symmetric_tensor.h>
+#include <deal.II/base/tensor.h>
+#include <deal.II/base/timer.h>
+#include <deal.II/base/work_stream.h>
+#include <deal.II/dofs/dof_renumbering.h>
+#include <deal.II/dofs/dof_tools.h>
+#include <deal.II/grid/grid_generator.h>
+#include <deal.II/grid/grid_tools.h>
+#include <deal.II/grid/grid_in.h>
+#include <deal.II/grid/tria.h>
+#include <deal.II/grid/tria_boundary_lib.h>
+#include <deal.II/fe/fe_dgp_monomial.h>
+#include <deal.II/fe/fe_q.h>
+#include <deal.II/fe/fe_system.h>
+#include <deal.II/fe/fe_tools.h>
+#include <deal.II/fe/fe_values.h>
+#include <deal.II/fe/mapping_q_eulerian.h>
+#include <deal.II/lac/block_sparse_matrix.h>
+#include <deal.II/lac/block_vector.h>
+#include <deal.II/lac/dynamic_sparsity_pattern.h>
+#include <deal.II/lac/full_matrix.h>
+#include <deal.II/lac/precondition_selector.h>
+#include <deal.II/lac/solver_cg.h>
+#include <deal.II/lac/sparse_direct.h>
+#include <deal.II/lac/constraint_matrix.h>
+#include <deal.II/lac/linear_operator.h>
+#include <deal.II/lac/packaged_operation.h>
+#include <deal.II/lac/iterative_inverse.h>
+#include <deal.II/numerics/data_out.h>
+#include <deal.II/numerics/vector_tools.h>
+
+#include <deal.II/physics/transformations.h>
+#include <deal.II/physics/elasticity/kinematics.h>
+#include <deal.II/physics/elasticity/standard_tensors.h>
+
+#include <iostream>
+#include <fstream>
+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 <int dim>
+ 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<dim>::I),
+ C_inv(Physics::Elasticity::StandardTensors<dim>::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<dim>::Dev_P(F);
+ }
+ SymmetricTensor<2, dim> get_S_bar() const
+ {
+ // Derived from energy function
+ return 2.0 * c_1 * Physics::Elasticity::StandardTensors<dim>::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<dim>::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<dim>::dC_inv_dC(F))
+ - (2.0 / dim) * (S_iso_x_C_inv + C_inv_x_S_iso)
+ + Physics::Elasticity::StandardTensors<dim>::Dev_P_T(F) * H_bar
+ * Physics::Elasticity::StandardTensors<dim>::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<dim>::I;
+ }
+ SymmetricTensor<2, dim> get_tau_iso() const
+ {
+ return Physics::Elasticity::StandardTensors<dim>::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<dim>::IxI
+ - (2.0 * Physics::Elasticity::StandardTensors<dim>::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<dim>::I);
+ const SymmetricTensor<4, dim> I_x_tau_iso
+ = outer_product(Physics::Elasticity::StandardTensors<dim>::I,
+ tau_iso);
+ const SymmetricTensor<4, dim> c_bar = get_c_bar();
+ return (2.0 / dim) * trace(tau_bar)
+ * Physics::Elasticity::StandardTensors<dim>::dev_P
+ - (2.0 / dim) * (tau_iso_x_I + I_x_tau_iso)
+ + Physics::Elasticity::StandardTensors<dim>::dev_P * c_bar
+ * Physics::Elasticity::StandardTensors<dim>::dev_P;
+ }
+ SymmetricTensor<4, dim> get_c_bar() const
+ {
+ return SymmetricTensor<4, dim>();
+ }
+ };
+ template <int dim>
+ class PointHistory
+ {
+ public:
+ PointHistory()
+ :
+ F_inv(Physics::Elasticity::StandardTensors<dim>::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<dim>(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<dim> > material;
+ Tensor<2, dim> F_inv;
+ SymmetricTensor<2, dim> tau;
+ double d2Psi_vol_dJ2;
+ double dPsi_vol_dJ;
+ SymmetricTensor<4, dim> Jc;
+ };
+ template <int dim>
+ 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<dim>::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<dim>::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<dim>::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<double> &solution_delta);
+ void
+ update_qph_incremental_one_cell(const typename DoFHandler<dim>::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<double> &solution_delta);
+ std::pair<unsigned int, double>
+ solve_linear_system(BlockVector<double> &newton_update);
+ BlockVector<double>
+ get_total_solution(const BlockVector<double> &solution_delta) const;
+ void
+ output_results() const;
+ Parameters::AllParameters parameters;
+ double vol_reference;
+ Triangulation<dim> triangulation;
+ Time time;
+ mutable TimerOutput timer;
+ CellDataStorage<typename Triangulation<dim>::cell_iterator,
+ PointHistory<dim> > quadrature_point_history;
+ const unsigned int degree;
+ const FESystem<dim> fe;
+ DoFHandler<dim> 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<types::global_dof_index> dofs_per_block;
+ std::vector<types::global_dof_index> element_indices_u;
+ std::vector<types::global_dof_index> element_indices_p;
+ std::vector<types::global_dof_index> element_indices_J;
+ const QGauss<dim> qf_cell;
+ const QGauss<dim - 1> qf_face;
+ const unsigned int n_q_points;
+ const unsigned int n_q_points_f;
+ ConstraintMatrix constraints;
+ BlockSparsityPattern sparsity_pattern;
+ BlockSparseMatrix<double> tangent_matrix;
+ BlockVector<double> system_rhs;
+ BlockVector<double> 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<double> &newton_update,
+ Errors &error_update);
+ std::pair<double, double>
+ get_error_dilation() const;
+ double
+ compute_vol_current () const;
+ void
+ print_conv_header();
+ void
+ print_conv_footer();
+ };
+ template <int dim>
+ Solid<dim>::Solid(const std::string &input_file)
+ :
+ parameters(input_file),
+ triangulation(Triangulation<dim>::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<dim>(parameters.poly_degree), dim, // displacement
+ FE_DGPMonomial<dim>(parameters.poly_degree - 1), 1, // pressure
+ FE_DGPMonomial<dim>(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 <int dim>
+ Solid<dim>::~Solid()
+ {
+ dof_handler_ref.clear();
+ }
+ template <int dim>
+ void Solid<dim>::run()
+ {
+ make_grid();
+ system_setup();
+ {
+ ConstraintMatrix constraints;
+ constraints.close();
+ const ComponentSelectFunction<dim>
+ J_mask (J_component, n_components);
+ VectorTools::project (dof_handler_ref,
+ constraints,
+ QGauss<dim>(degree+2),
+ J_mask,
+ solution_n);
+ }
+ output_results();
+ time.increment();
+ BlockVector<double> 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 <int dim>
+ struct Solid<dim>::PerTaskData_K
+ {
+ FullMatrix<double> cell_matrix;
+ std::vector<types::global_dof_index> 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 <int dim>
+ struct Solid<dim>::ScratchData_K
+ {
+ FEValues<dim> fe_values_ref;
+ std::vector<std::vector<double> > Nx;
+ std::vector<std::vector<Tensor<2, dim> > > grad_Nx;
+ std::vector<std::vector<SymmetricTensor<2, dim> > > symm_grad_Nx;
+ ScratchData_K(const FiniteElement<dim> &fe_cell,
+ const QGauss<dim> &qf_cell,
+ const UpdateFlags uf_cell)
+ :
+ fe_values_ref(fe_cell, qf_cell, uf_cell),
+ Nx(qf_cell.size(),
+ std::vector<double>(fe_cell.dofs_per_cell)),
+ grad_Nx(qf_cell.size(),
+ std::vector<Tensor<2, dim> >(fe_cell.dofs_per_cell)),
+ symm_grad_Nx(qf_cell.size(),
+ std::vector<SymmetricTensor<2, dim> >
+ (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 <int dim>
+ struct Solid<dim>::PerTaskData_RHS
+ {
+ Vector<double> cell_rhs;
+ std::vector<types::global_dof_index> 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 <int dim>
+ struct Solid<dim>::ScratchData_RHS
+ {
+ FEValues<dim> fe_values_ref;
+ FEFaceValues<dim> fe_face_values_ref;
+ std::vector<std::vector<double> > Nx;
+ std::vector<std::vector<SymmetricTensor<2, dim> > > symm_grad_Nx;
+ ScratchData_RHS(const FiniteElement<dim> &fe_cell,
+ const QGauss<dim> &qf_cell, const UpdateFlags uf_cell,
+ const QGauss<dim - 1> & 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<double>(fe_cell.dofs_per_cell)),
+ symm_grad_Nx(qf_cell.size(),
+ std::vector<SymmetricTensor<2, dim> >
+ (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 <int dim>
+ struct Solid<dim>::PerTaskData_SC
+ {
+ FullMatrix<double> cell_matrix;
+ std::vector<types::global_dof_index> local_dof_indices;
+ FullMatrix<double> k_orig;
+ FullMatrix<double> k_pu;
+ FullMatrix<double> k_pJ;
+ FullMatrix<double> k_JJ;
+ FullMatrix<double> k_pJ_inv;
+ FullMatrix<double> k_bbar;
+ FullMatrix<double> A;
+ FullMatrix<double> B;
+ FullMatrix<double> 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 <int dim>
+ struct Solid<dim>::ScratchData_SC
+ {
+ void reset()
+ {}
+ };
+ template <int dim>
+ struct Solid<dim>::PerTaskData_UQPH
+ {
+ void reset()
+ {}
+ };
+ template <int dim>
+ struct Solid<dim>::ScratchData_UQPH
+ {
+ const BlockVector<double> &solution_total;
+ std::vector<Tensor<2, dim> > solution_grads_u_total;
+ std::vector<double> solution_values_p_total;
+ std::vector<double> solution_values_J_total;
+ FEValues<dim> fe_values_ref;
+ ScratchData_UQPH(const FiniteElement<dim> &fe_cell,
+ const QGauss<dim> &qf_cell,
+ const UpdateFlags uf_cell,
+ const BlockVector<double> &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 <int dim>
+ void Solid<dim>::make_grid()
+ {
+ GridGenerator::hyper_rectangle(triangulation,
+ (dim==3 ? Point<dim>(0.0, 0.0, 0.0) : Point<dim>(0.0, 0.0)),
+ (dim==3 ? Point<dim>(1.0, 1.0, 1.0) : Point<dim>(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<dim>::active_cell_iterator cell =
+ triangulation.begin_active(), endc = triangulation.end();
+ for (; cell != endc; ++cell)
+ for (unsigned int face = 0;
+ face < GeometryInfo<dim>::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 <int dim>
+ void Solid<dim>::system_setup()
+ {
+ timer.enter_subsection("Setup system");
+ std::vector<unsigned int> 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 <int dim>
+ void
+ Solid<dim>::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 <int dim>
+ void Solid<dim>::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<dim>::active_cell_iterator cell =
+ triangulation.begin_active(); cell != triangulation.end(); ++cell)
+ {
+ const std::vector<std::shared_ptr<PointHistory<dim> > > 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 <int dim>
+ void Solid<dim>::update_qph_incremental(const BlockVector<double> &solution_delta)
+ {
+ timer.enter_subsection("Update QPH data");
+ pcout << " UQPH " << std::flush;
+ const BlockVector<double> 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 <int dim>
+ void
+ Solid<dim>::update_qph_incremental_one_cell(const typename DoFHandler<dim>::active_cell_iterator &cell,
+ ScratchData_UQPH &scratch,
+ PerTaskData_UQPH &/*data*/)
+ {
+ const std::vector<std::shared_ptr<PointHistory<dim> > > 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 <int dim>
+ void
+ Solid<dim>::solve_nonlinear_timestep(BlockVector<double> &solution_delta)
+ {
+ pcout << std::endl << "Timestep " << time.get_timestep() << " @ "
+ << time.current() << "s" << std::endl;
+ BlockVector<double> 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<unsigned int, double>
+ 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 <int dim>
+ void Solid<dim>::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 <int dim>
+ void Solid<dim>::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<double,double> 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 <int dim>
+ double
+ Solid<dim>::compute_vol_current() const
+ {
+ double vol_current = 0.0;
+ FEValues<dim> fe_values_ref(fe, qf_cell, update_JxW_values);
+ for (typename Triangulation<dim>::active_cell_iterator
+ cell = triangulation.begin_active();
+ cell != triangulation.end(); ++cell)
+ {
+ fe_values_ref.reinit(cell);
+ const std::vector<std::shared_ptr<const PointHistory<dim> > > 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 <int dim>
+ std::pair<double, double>
+ Solid<dim>::get_error_dilation() const
+ {
+ double dil_L2_error = 0.0;
+ FEValues<dim> fe_values_ref(fe, qf_cell, update_JxW_values);
+ for (typename Triangulation<dim>::active_cell_iterator
+ cell = triangulation.begin_active();
+ cell != triangulation.end(); ++cell)
+ {
+ fe_values_ref.reinit(cell);
+ const std::vector<std::shared_ptr<const PointHistory<dim> > > 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 <int dim>
+ void Solid<dim>::get_error_residual(Errors &error_residual)
+ {
+ BlockVector<double> 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 <int dim>
+ void Solid<dim>::get_error_update(const BlockVector<double> &newton_update,
+ Errors &error_update)
+ {
+ BlockVector<double> 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 <int dim>
+ BlockVector<double>
+ Solid<dim>::get_total_solution(const BlockVector<double> &solution_delta) const
+ {
+ BlockVector<double> solution_total(solution_n);
+ solution_total += solution_delta;
+ return solution_total;
+ }
+ template <int dim>
+ void Solid<dim>::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<dim>::assemble_system_tangent_one_cell,
+ this,
+ std_cxx11::_1,
+ std_cxx11::_2,
+ std_cxx11::_3),
+ std_cxx11::bind(&Solid<dim>::copy_local_to_global_K,
+ this,
+ std_cxx11::_1),
+ scratch_data,
+ per_task_data);
+ timer.leave_subsection();
+ }
+ template <int dim>
+ void Solid<dim>::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 <int dim>
+ void
+ Solid<dim>::assemble_system_tangent_one_cell(const typename DoFHandler<dim>::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<std::shared_ptr<const PointHistory<dim> > > 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<double>
+ &N = scratch.Nx[q_point];
+ const std::vector<SymmetricTensor<2, dim> >
+ &symm_grad_Nx = scratch.symm_grad_Nx[q_point];
+ const std::vector<Tensor<2, dim> >
+ &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<dim>::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 <int dim>
+ void Solid<dim>::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<dim>::assemble_system_rhs_one_cell,
+ this,
+ std_cxx11::_1,
+ std_cxx11::_2,
+ std_cxx11::_3),
+ std_cxx11::bind(&Solid<dim>::copy_local_to_global_rhs,
+ this,
+ std_cxx11::_1),
+ scratch_data,
+ per_task_data);
+ timer.leave_subsection();
+ }
+ template <int dim>
+ void Solid<dim>::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 <int dim>
+ void
+ Solid<dim>::assemble_system_rhs_one_cell(const typename DoFHandler<dim>::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<std::shared_ptr<const PointHistory<dim> > > 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<double>
+ &N = scratch.Nx[q_point];
+ const std::vector<SymmetricTensor<2, dim> >
+ &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<dim>::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 <int dim>
+ void Solid<dim>::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<dim>(n_components),
+ constraints,
+ fe.component_mask(x_displacement));
+ else
+ VectorTools::interpolate_boundary_values(dof_handler_ref,
+ boundary_id,
+ ZeroFunction<dim>(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<dim>(n_components),
+ constraints,
+ fe.component_mask(y_displacement));
+ else
+ VectorTools::interpolate_boundary_values(dof_handler_ref,
+ boundary_id,
+ ZeroFunction<dim>(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<dim>(n_components),
+ constraints,
+ (fe.component_mask(x_displacement)
+ |
+ fe.component_mask(z_displacement)));
+ else
+ VectorTools::interpolate_boundary_values(dof_handler_ref,
+ boundary_id,
+ ZeroFunction<dim>(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<dim>(n_components),
+ constraints,
+ fe.component_mask(z_displacement));
+ else
+ VectorTools::interpolate_boundary_values(dof_handler_ref,
+ boundary_id,
+ ZeroFunction<dim>(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<dim>(n_components),
+ constraints,
+ (fe.component_mask(x_displacement)
+ |
+ fe.component_mask(z_displacement)));
+ else
+ VectorTools::interpolate_boundary_values(dof_handler_ref,
+ boundary_id,
+ ZeroFunction<dim>(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<dim>(n_components),
+ constraints,
+ (fe.component_mask(x_displacement)));
+ else
+ VectorTools::interpolate_boundary_values(dof_handler_ref,
+ boundary_id,
+ ZeroFunction<dim>(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<dim>(n_components),
+ constraints,
+ (fe.component_mask(x_displacement)));
+ else
+ VectorTools::interpolate_boundary_values(dof_handler_ref,
+ boundary_id,
+ ZeroFunction<dim>(n_components),
+ constraints,
+ (fe.component_mask(x_displacement)));
+ }
+ }
+ constraints.close();
+ }
+ template <int dim>
+ void Solid<dim>::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 <int dim>
+ void Solid<dim>::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 <int dim>
+ void
+ Solid<dim>::assemble_sc_one_cell(const typename DoFHandler<dim>::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 <int dim>
+ std::pair<unsigned int, double>
+ Solid<dim>::solve_linear_system(BlockVector<double> &newton_update)
+ {
+ unsigned int lin_it = 0;
+ double lin_res = 0.0;
+ if (parameters.use_static_condensation == true)
+ {
+ BlockVector<double> A(dofs_per_block);
+ BlockVector<double> 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<Vector<double> > GVM;
+ SolverCG<Vector<double> > solver_CG(solver_control, GVM);
+ PreconditionSelector<SparseMatrix<double>, Vector<double> >
+ 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<double> &f_u = system_rhs.block(u_dof);
+ const Vector<double> &f_p = system_rhs.block(p_dof);
+ const Vector<double> &f_J = system_rhs.block(J_dof);
+ Vector<double> &d_u = newton_update.block(u_dof);
+ Vector<double> &d_p = newton_update.block(p_dof);
+ Vector<double> &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<double>, Vector<double> >
+ 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<double> > 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<double>, Vector<double> >
+ 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<double> > 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 <int dim>
+ void Solid<dim>::output_results() const
+ {
+ DataOut<dim> data_out;
+ std::vector<DataComponentInterpretation::DataComponentInterpretation>
+ 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<std::string> 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<dim>::type_dof_data,
+ data_component_interpretation);
+ Vector<double> soln(solution_n.size());
+ for (unsigned int i = 0; i < soln.size(); ++i)
+ soln(i) = solution_n(i);
+ MappingQEulerian<dim> 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<dim> 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;
+}
--- /dev/null
+
+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
--- /dev/null
+// ---------------------------------------------------------------------
+//
+// 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 <deal.II/base/conditional_ostream.h>
+#include <deal.II/base/function.h>
+#include <deal.II/base/parameter_handler.h>
+#include <deal.II/base/point.h>
+#include <deal.II/base/quadrature_lib.h>
+#include <deal.II/base/quadrature_point_data.h>
+#include <deal.II/base/symmetric_tensor.h>
+#include <deal.II/base/tensor.h>
+#include <deal.II/base/timer.h>
+#include <deal.II/base/work_stream.h>
+#include <deal.II/dofs/dof_renumbering.h>
+#include <deal.II/dofs/dof_tools.h>
+#include <deal.II/grid/grid_generator.h>
+#include <deal.II/grid/grid_tools.h>
+#include <deal.II/grid/grid_in.h>
+#include <deal.II/grid/tria.h>
+#include <deal.II/grid/tria_boundary_lib.h>
+#include <deal.II/fe/fe_dgp_monomial.h>
+#include <deal.II/fe/fe_q.h>
+#include <deal.II/fe/fe_system.h>
+#include <deal.II/fe/fe_tools.h>
+#include <deal.II/fe/fe_values.h>
+#include <deal.II/fe/mapping_q_eulerian.h>
+#include <deal.II/lac/block_sparse_matrix.h>
+#include <deal.II/lac/block_vector.h>
+#include <deal.II/lac/dynamic_sparsity_pattern.h>
+#include <deal.II/lac/full_matrix.h>
+#include <deal.II/lac/precondition_selector.h>
+#include <deal.II/lac/solver_cg.h>
+#include <deal.II/lac/sparse_direct.h>
+#include <deal.II/lac/constraint_matrix.h>
+#include <deal.II/lac/linear_operator.h>
+#include <deal.II/lac/packaged_operation.h>
+#include <deal.II/lac/iterative_inverse.h>
+#include <deal.II/numerics/data_out.h>
+#include <deal.II/numerics/vector_tools.h>
+
+#include <deal.II/physics/transformations.h>
+#include <deal.II/physics/elasticity/kinematics.h>
+#include <deal.II/physics/elasticity/standard_tensors.h>
+
+#include <iostream>
+#include <fstream>
+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 <int dim>
+ 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<dim>::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<dim>::I;
+ }
+ SymmetricTensor<2, dim> get_tau_iso() const
+ {
+ return Physics::Elasticity::StandardTensors<dim>::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<dim>::IxI
+ - (2.0 * Physics::Elasticity::StandardTensors<dim>::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<dim>::I);
+ const SymmetricTensor<4, dim> I_x_tau_iso
+ = outer_product(Physics::Elasticity::StandardTensors<dim>::I,
+ tau_iso);
+ const SymmetricTensor<4, dim> c_bar = get_c_bar();
+ return (2.0 / dim) * trace(tau_bar)
+ * Physics::Elasticity::StandardTensors<dim>::dev_P
+ - (2.0 / dim) * (tau_iso_x_I + I_x_tau_iso)
+ + Physics::Elasticity::StandardTensors<dim>::dev_P * c_bar
+ * Physics::Elasticity::StandardTensors<dim>::dev_P;
+ }
+ SymmetricTensor<4, dim> get_c_bar() const
+ {
+ return SymmetricTensor<4, dim>();
+ }
+ };
+ template <int dim>
+ class PointHistory
+ {
+ public:
+ PointHistory()
+ :
+ F_inv(Physics::Elasticity::StandardTensors<dim>::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<dim>(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<dim> > material;
+ Tensor<2, dim> F_inv;
+ SymmetricTensor<2, dim> tau;
+ double d2Psi_vol_dJ2;
+ double dPsi_vol_dJ;
+ SymmetricTensor<4, dim> Jc;
+ };
+ template <int dim>
+ 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<dim>::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<dim>::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<dim>::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<double> &solution_delta);
+ void
+ update_qph_incremental_one_cell(const typename DoFHandler<dim>::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<double> &solution_delta);
+ std::pair<unsigned int, double>
+ solve_linear_system(BlockVector<double> &newton_update);
+ BlockVector<double>
+ get_total_solution(const BlockVector<double> &solution_delta) const;
+ void
+ output_results() const;
+ Parameters::AllParameters parameters;
+ double vol_reference;
+ Triangulation<dim> triangulation;
+ Time time;
+ mutable TimerOutput timer;
+ CellDataStorage<typename Triangulation<dim>::cell_iterator,
+ PointHistory<dim> > quadrature_point_history;
+ const unsigned int degree;
+ const FESystem<dim> fe;
+ DoFHandler<dim> 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<types::global_dof_index> dofs_per_block;
+ std::vector<types::global_dof_index> element_indices_u;
+ std::vector<types::global_dof_index> element_indices_p;
+ std::vector<types::global_dof_index> element_indices_J;
+ const QGauss<dim> qf_cell;
+ const QGauss<dim - 1> qf_face;
+ const unsigned int n_q_points;
+ const unsigned int n_q_points_f;
+ ConstraintMatrix constraints;
+ BlockSparsityPattern sparsity_pattern;
+ BlockSparseMatrix<double> tangent_matrix;
+ BlockVector<double> system_rhs;
+ BlockVector<double> 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<double> &newton_update,
+ Errors &error_update);
+ std::pair<double, double>
+ get_error_dilation() const;
+ double
+ compute_vol_current () const;
+ void
+ print_conv_header();
+ void
+ print_conv_footer();
+ };
+ template <int dim>
+ Solid<dim>::Solid(const std::string &input_file)
+ :
+ parameters(input_file),
+ triangulation(Triangulation<dim>::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<dim>(parameters.poly_degree), dim, // displacement
+ FE_DGPMonomial<dim>(parameters.poly_degree - 1), 1, // pressure
+ FE_DGPMonomial<dim>(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 <int dim>
+ Solid<dim>::~Solid()
+ {
+ dof_handler_ref.clear();
+ }
+ template <int dim>
+ void Solid<dim>::run()
+ {
+ make_grid();
+ system_setup();
+ {
+ ConstraintMatrix constraints;
+ constraints.close();
+ const ComponentSelectFunction<dim>
+ J_mask (J_component, n_components);
+ VectorTools::project (dof_handler_ref,
+ constraints,
+ QGauss<dim>(degree+2),
+ J_mask,
+ solution_n);
+ }
+ output_results();
+ time.increment();
+ BlockVector<double> 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 <int dim>
+ struct Solid<dim>::PerTaskData_K
+ {
+ FullMatrix<double> cell_matrix;
+ std::vector<types::global_dof_index> 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 <int dim>
+ struct Solid<dim>::ScratchData_K
+ {
+ FEValues<dim> fe_values_ref;
+ std::vector<std::vector<double> > Nx;
+ std::vector<std::vector<Tensor<2, dim> > > grad_Nx;
+ std::vector<std::vector<SymmetricTensor<2, dim> > > symm_grad_Nx;
+ ScratchData_K(const FiniteElement<dim> &fe_cell,
+ const QGauss<dim> &qf_cell,
+ const UpdateFlags uf_cell)
+ :
+ fe_values_ref(fe_cell, qf_cell, uf_cell),
+ Nx(qf_cell.size(),
+ std::vector<double>(fe_cell.dofs_per_cell)),
+ grad_Nx(qf_cell.size(),
+ std::vector<Tensor<2, dim> >(fe_cell.dofs_per_cell)),
+ symm_grad_Nx(qf_cell.size(),
+ std::vector<SymmetricTensor<2, dim> >
+ (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 <int dim>
+ struct Solid<dim>::PerTaskData_RHS
+ {
+ Vector<double> cell_rhs;
+ std::vector<types::global_dof_index> 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 <int dim>
+ struct Solid<dim>::ScratchData_RHS
+ {
+ FEValues<dim> fe_values_ref;
+ FEFaceValues<dim> fe_face_values_ref;
+ std::vector<std::vector<double> > Nx;
+ std::vector<std::vector<SymmetricTensor<2, dim> > > symm_grad_Nx;
+ ScratchData_RHS(const FiniteElement<dim> &fe_cell,
+ const QGauss<dim> &qf_cell, const UpdateFlags uf_cell,
+ const QGauss<dim - 1> & 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<double>(fe_cell.dofs_per_cell)),
+ symm_grad_Nx(qf_cell.size(),
+ std::vector<SymmetricTensor<2, dim> >
+ (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 <int dim>
+ struct Solid<dim>::PerTaskData_SC
+ {
+ FullMatrix<double> cell_matrix;
+ std::vector<types::global_dof_index> local_dof_indices;
+ FullMatrix<double> k_orig;
+ FullMatrix<double> k_pu;
+ FullMatrix<double> k_pJ;
+ FullMatrix<double> k_JJ;
+ FullMatrix<double> k_pJ_inv;
+ FullMatrix<double> k_bbar;
+ FullMatrix<double> A;
+ FullMatrix<double> B;
+ FullMatrix<double> 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 <int dim>
+ struct Solid<dim>::ScratchData_SC
+ {
+ void reset()
+ {}
+ };
+ template <int dim>
+ struct Solid<dim>::PerTaskData_UQPH
+ {
+ void reset()
+ {}
+ };
+ template <int dim>
+ struct Solid<dim>::ScratchData_UQPH
+ {
+ const BlockVector<double> &solution_total;
+ std::vector<Tensor<2, dim> > solution_grads_u_total;
+ std::vector<double> solution_values_p_total;
+ std::vector<double> solution_values_J_total;
+ FEValues<dim> fe_values_ref;
+ ScratchData_UQPH(const FiniteElement<dim> &fe_cell,
+ const QGauss<dim> &qf_cell,
+ const UpdateFlags uf_cell,
+ const BlockVector<double> &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 <int dim>
+ void Solid<dim>::make_grid()
+ {
+ GridGenerator::hyper_rectangle(triangulation,
+ (dim==3 ? Point<dim>(0.0, 0.0, 0.0) : Point<dim>(0.0, 0.0)),
+ (dim==3 ? Point<dim>(1.0, 1.0, 1.0) : Point<dim>(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<dim>::active_cell_iterator cell =
+ triangulation.begin_active(), endc = triangulation.end();
+ for (; cell != endc; ++cell)
+ for (unsigned int face = 0;
+ face < GeometryInfo<dim>::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 <int dim>
+ void Solid<dim>::system_setup()
+ {
+ timer.enter_subsection("Setup system");
+ std::vector<unsigned int> 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 <int dim>
+ void
+ Solid<dim>::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 <int dim>
+ void Solid<dim>::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<dim>::active_cell_iterator cell =
+ triangulation.begin_active(); cell != triangulation.end(); ++cell)
+ {
+ const std::vector<std::shared_ptr<PointHistory<dim> > > 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 <int dim>
+ void Solid<dim>::update_qph_incremental(const BlockVector<double> &solution_delta)
+ {
+ timer.enter_subsection("Update QPH data");
+ pcout << " UQPH " << std::flush;
+ const BlockVector<double> 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 <int dim>
+ void
+ Solid<dim>::update_qph_incremental_one_cell(const typename DoFHandler<dim>::active_cell_iterator &cell,
+ ScratchData_UQPH &scratch,
+ PerTaskData_UQPH &/*data*/)
+ {
+ const std::vector<std::shared_ptr<PointHistory<dim> > > 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 <int dim>
+ void
+ Solid<dim>::solve_nonlinear_timestep(BlockVector<double> &solution_delta)
+ {
+ pcout << std::endl << "Timestep " << time.get_timestep() << " @ "
+ << time.current() << "s" << std::endl;
+ BlockVector<double> 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<unsigned int, double>
+ 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 <int dim>
+ void Solid<dim>::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 <int dim>
+ void Solid<dim>::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<double,double> 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 <int dim>
+ double
+ Solid<dim>::compute_vol_current() const
+ {
+ double vol_current = 0.0;
+ FEValues<dim> fe_values_ref(fe, qf_cell, update_JxW_values);
+ for (typename Triangulation<dim>::active_cell_iterator
+ cell = triangulation.begin_active();
+ cell != triangulation.end(); ++cell)
+ {
+ fe_values_ref.reinit(cell);
+ const std::vector<std::shared_ptr<const PointHistory<dim> > > 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 <int dim>
+ std::pair<double, double>
+ Solid<dim>::get_error_dilation() const
+ {
+ double dil_L2_error = 0.0;
+ FEValues<dim> fe_values_ref(fe, qf_cell, update_JxW_values);
+ for (typename Triangulation<dim>::active_cell_iterator
+ cell = triangulation.begin_active();
+ cell != triangulation.end(); ++cell)
+ {
+ fe_values_ref.reinit(cell);
+ const std::vector<std::shared_ptr<const PointHistory<dim> > > 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 <int dim>
+ void Solid<dim>::get_error_residual(Errors &error_residual)
+ {
+ BlockVector<double> 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 <int dim>
+ void Solid<dim>::get_error_update(const BlockVector<double> &newton_update,
+ Errors &error_update)
+ {
+ BlockVector<double> 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 <int dim>
+ BlockVector<double>
+ Solid<dim>::get_total_solution(const BlockVector<double> &solution_delta) const
+ {
+ BlockVector<double> solution_total(solution_n);
+ solution_total += solution_delta;
+ return solution_total;
+ }
+ template <int dim>
+ void Solid<dim>::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<dim>::assemble_system_tangent_one_cell,
+ this,
+ std_cxx11::_1,
+ std_cxx11::_2,
+ std_cxx11::_3),
+ std_cxx11::bind(&Solid<dim>::copy_local_to_global_K,
+ this,
+ std_cxx11::_1),
+ scratch_data,
+ per_task_data);
+ timer.leave_subsection();
+ }
+ template <int dim>
+ void Solid<dim>::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 <int dim>
+ void
+ Solid<dim>::assemble_system_tangent_one_cell(const typename DoFHandler<dim>::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<std::shared_ptr<const PointHistory<dim> > > 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<double>
+ &N = scratch.Nx[q_point];
+ const std::vector<SymmetricTensor<2, dim> >
+ &symm_grad_Nx = scratch.symm_grad_Nx[q_point];
+ const std::vector<Tensor<2, dim> >
+ &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<dim>::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 <int dim>
+ void Solid<dim>::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<dim>::assemble_system_rhs_one_cell,
+ this,
+ std_cxx11::_1,
+ std_cxx11::_2,
+ std_cxx11::_3),
+ std_cxx11::bind(&Solid<dim>::copy_local_to_global_rhs,
+ this,
+ std_cxx11::_1),
+ scratch_data,
+ per_task_data);
+ timer.leave_subsection();
+ }
+ template <int dim>
+ void Solid<dim>::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 <int dim>
+ void
+ Solid<dim>::assemble_system_rhs_one_cell(const typename DoFHandler<dim>::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<std::shared_ptr<const PointHistory<dim> > > 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<double>
+ &N = scratch.Nx[q_point];
+ const std::vector<SymmetricTensor<2, dim> >
+ &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<dim>::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 <int dim>
+ void Solid<dim>::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<dim>(n_components),
+ constraints,
+ fe.component_mask(x_displacement));
+ else
+ VectorTools::interpolate_boundary_values(dof_handler_ref,
+ boundary_id,
+ ZeroFunction<dim>(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<dim>(n_components),
+ constraints,
+ fe.component_mask(y_displacement));
+ else
+ VectorTools::interpolate_boundary_values(dof_handler_ref,
+ boundary_id,
+ ZeroFunction<dim>(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<dim>(n_components),
+ constraints,
+ (fe.component_mask(x_displacement)
+ |
+ fe.component_mask(z_displacement)));
+ else
+ VectorTools::interpolate_boundary_values(dof_handler_ref,
+ boundary_id,
+ ZeroFunction<dim>(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<dim>(n_components),
+ constraints,
+ fe.component_mask(z_displacement));
+ else
+ VectorTools::interpolate_boundary_values(dof_handler_ref,
+ boundary_id,
+ ZeroFunction<dim>(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<dim>(n_components),
+ constraints,
+ (fe.component_mask(x_displacement)
+ |
+ fe.component_mask(z_displacement)));
+ else
+ VectorTools::interpolate_boundary_values(dof_handler_ref,
+ boundary_id,
+ ZeroFunction<dim>(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<dim>(n_components),
+ constraints,
+ (fe.component_mask(x_displacement)));
+ else
+ VectorTools::interpolate_boundary_values(dof_handler_ref,
+ boundary_id,
+ ZeroFunction<dim>(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<dim>(n_components),
+ constraints,
+ (fe.component_mask(x_displacement)));
+ else
+ VectorTools::interpolate_boundary_values(dof_handler_ref,
+ boundary_id,
+ ZeroFunction<dim>(n_components),
+ constraints,
+ (fe.component_mask(x_displacement)));
+ }
+ }
+ constraints.close();
+ }
+ template <int dim>
+ void Solid<dim>::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 <int dim>
+ void Solid<dim>::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 <int dim>
+ void
+ Solid<dim>::assemble_sc_one_cell(const typename DoFHandler<dim>::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 <int dim>
+ std::pair<unsigned int, double>
+ Solid<dim>::solve_linear_system(BlockVector<double> &newton_update)
+ {
+ unsigned int lin_it = 0;
+ double lin_res = 0.0;
+ if (parameters.use_static_condensation == true)
+ {
+ BlockVector<double> A(dofs_per_block);
+ BlockVector<double> 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<Vector<double> > GVM;
+ SolverCG<Vector<double> > solver_CG(solver_control, GVM);
+ PreconditionSelector<SparseMatrix<double>, Vector<double> >
+ 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<double> &f_u = system_rhs.block(u_dof);
+ const Vector<double> &f_p = system_rhs.block(p_dof);
+ const Vector<double> &f_J = system_rhs.block(J_dof);
+ Vector<double> &d_u = newton_update.block(u_dof);
+ Vector<double> &d_p = newton_update.block(p_dof);
+ Vector<double> &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<double>, Vector<double> >
+ 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<double> > 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<double>, Vector<double> >
+ 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<double> > 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 <int dim>
+ void Solid<dim>::output_results() const
+ {
+ DataOut<dim> data_out;
+ std::vector<DataComponentInterpretation::DataComponentInterpretation>
+ 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<std::string> 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<dim>::type_dof_data,
+ data_component_interpretation);
+ Vector<double> soln(solution_n.size());
+ for (unsigned int i = 0; i < soln.size(); ++i)
+ soln(i) = solution_n(i);
+ MappingQEulerian<dim> 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<dim> 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;
+}
--- /dev/null
+
+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
--- /dev/null
+// ---------------------------------------------------------------------
+//
+// 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 <deal.II/base/conditional_ostream.h>
+#include <deal.II/base/function.h>
+#include <deal.II/base/parameter_handler.h>
+#include <deal.II/base/point.h>
+#include <deal.II/base/quadrature_lib.h>
+#include <deal.II/base/symmetric_tensor.h>
+#include <deal.II/base/tensor.h>
+#include <deal.II/base/timer.h>
+#include <deal.II/base/work_stream.h>
+#include <deal.II/dofs/dof_renumbering.h>
+#include <deal.II/dofs/dof_tools.h>
+#include <deal.II/base/quadrature_point_data.h>
+#include <deal.II/grid/grid_generator.h>
+#include <deal.II/grid/grid_tools.h>
+#include <deal.II/grid/grid_in.h>
+#include <deal.II/grid/tria.h>
+#include <deal.II/grid/tria_boundary_lib.h>
+#include <deal.II/fe/fe_dgp_monomial.h>
+#include <deal.II/fe/fe_q.h>
+#include <deal.II/fe/fe_system.h>
+#include <deal.II/fe/fe_tools.h>
+#include <deal.II/fe/fe_values.h>
+#include <deal.II/fe/mapping_q_eulerian.h>
+#include <deal.II/lac/block_sparse_matrix.h>
+#include <deal.II/lac/block_vector.h>
+#include <deal.II/lac/dynamic_sparsity_pattern.h>
+#include <deal.II/lac/full_matrix.h>
+#include <deal.II/lac/precondition_selector.h>
+#include <deal.II/lac/solver_cg.h>
+#include <deal.II/lac/sparse_direct.h>
+#include <deal.II/lac/constraint_matrix.h>
+#include <deal.II/lac/linear_operator.h>
+#include <deal.II/lac/packaged_operation.h>
+#include <deal.II/lac/iterative_inverse.h>
+#include <deal.II/numerics/data_out.h>
+#include <deal.II/numerics/vector_tools.h>
+#include <iostream>
+#include <fstream>
+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 <int dim>
+ 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 <int dim>
+ const SymmetricTensor<2, dim>
+ StandardTensors<dim>::I = unit_symmetric_tensor<dim>();
+ template <int dim>
+ const SymmetricTensor<4, dim>
+ StandardTensors<dim>::IxI = outer_product(I, I);
+ template <int dim>
+ const SymmetricTensor<4, dim>
+ StandardTensors<dim>::II = identity_tensor<dim>();
+ template <int dim>
+ const SymmetricTensor<4, dim>
+ StandardTensors<dim>::dev_P = deviator_tensor<dim>();
+ 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 <int dim>
+ 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<dim>::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<dim>::I;
+ }
+ SymmetricTensor<2, dim> get_tau_iso() const
+ {
+ return StandardTensors<dim>::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<dim>::IxI
+ - (2.0 * StandardTensors<dim>::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<dim>::I);
+ const SymmetricTensor<4, dim> I_x_tau_iso
+ = outer_product(StandardTensors<dim>::I,
+ tau_iso);
+ const SymmetricTensor<4, dim> c_bar = get_c_bar();
+ return (2.0 / dim) * trace(tau_bar)
+ * StandardTensors<dim>::dev_P
+ - (2.0 / dim) * (tau_iso_x_I + I_x_tau_iso)
+ + StandardTensors<dim>::dev_P * c_bar
+ * StandardTensors<dim>::dev_P;
+ }
+ SymmetricTensor<4, dim> get_c_bar() const
+ {
+ return SymmetricTensor<4, dim>();
+ }
+ };
+ template <int dim>
+ class PointHistory
+ {
+ public:
+ PointHistory()
+ :
+ F_inv(StandardTensors<dim>::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<dim>(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<dim>::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<dim> > material;
+ Tensor<2, dim> F_inv;
+ SymmetricTensor<2, dim> tau;
+ double d2Psi_vol_dJ2;
+ double dPsi_vol_dJ;
+ SymmetricTensor<4, dim> Jc;
+ };
+ template <int dim>
+ 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<dim>::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<dim>::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<dim>::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<double> &solution_delta);
+ void
+ update_qph_incremental_one_cell(const typename DoFHandler<dim>::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<double> &solution_delta);
+ std::pair<unsigned int, double>
+ solve_linear_system(BlockVector<double> &newton_update);
+ BlockVector<double>
+ get_total_solution(const BlockVector<double> &solution_delta) const;
+ void
+ output_results() const;
+ Parameters::AllParameters parameters;
+ double vol_reference;
+ Triangulation<dim> triangulation;
+ Time time;
+ mutable TimerOutput timer;
+ CellDataStorage<typename Triangulation<dim>::cell_iterator,
+ PointHistory<dim> > quadrature_point_history;
+ const unsigned int degree;
+ const FESystem<dim> fe;
+ DoFHandler<dim> 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<types::global_dof_index> dofs_per_block;
+ std::vector<types::global_dof_index> element_indices_u;
+ std::vector<types::global_dof_index> element_indices_p;
+ std::vector<types::global_dof_index> element_indices_J;
+ const QGauss<dim> qf_cell;
+ const QGauss<dim - 1> qf_face;
+ const unsigned int n_q_points;
+ const unsigned int n_q_points_f;
+ ConstraintMatrix constraints;
+ BlockSparsityPattern sparsity_pattern;
+ BlockSparseMatrix<double> tangent_matrix;
+ BlockVector<double> system_rhs;
+ BlockVector<double> 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<double> &newton_update,
+ Errors &error_update);
+ std::pair<double, double>
+ get_error_dilation() const;
+ double
+ compute_vol_current () const;
+ void
+ print_conv_header();
+ void
+ print_conv_footer();
+ };
+ template <int dim>
+ Solid<dim>::Solid(const std::string &input_file)
+ :
+ parameters(input_file),
+ triangulation(Triangulation<dim>::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<dim>(parameters.poly_degree), dim, // displacement
+ FE_DGPMonomial<dim>(parameters.poly_degree - 1), 1, // pressure
+ FE_DGPMonomial<dim>(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 <int dim>
+ Solid<dim>::~Solid()
+ {
+ dof_handler_ref.clear();
+ }
+ template <int dim>
+ void Solid<dim>::run()
+ {
+ make_grid();
+ system_setup();
+ {
+ ConstraintMatrix constraints;
+ constraints.close();
+ const ComponentSelectFunction<dim>
+ J_mask (J_component, n_components);
+ VectorTools::project (dof_handler_ref,
+ constraints,
+ QGauss<dim>(degree+2),
+ J_mask,
+ solution_n);
+ }
+ output_results();
+ time.increment();
+ BlockVector<double> 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 <int dim>
+ struct Solid<dim>::PerTaskData_K
+ {
+ FullMatrix<double> cell_matrix;
+ std::vector<types::global_dof_index> 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 <int dim>
+ struct Solid<dim>::ScratchData_K
+ {
+ FEValues<dim> fe_values_ref;
+ std::vector<std::vector<double> > Nx;
+ std::vector<std::vector<Tensor<2, dim> > > grad_Nx;
+ std::vector<std::vector<SymmetricTensor<2, dim> > > symm_grad_Nx;
+ ScratchData_K(const FiniteElement<dim> &fe_cell,
+ const QGauss<dim> &qf_cell,
+ const UpdateFlags uf_cell)
+ :
+ fe_values_ref(fe_cell, qf_cell, uf_cell),
+ Nx(qf_cell.size(),
+ std::vector<double>(fe_cell.dofs_per_cell)),
+ grad_Nx(qf_cell.size(),
+ std::vector<Tensor<2, dim> >(fe_cell.dofs_per_cell)),
+ symm_grad_Nx(qf_cell.size(),
+ std::vector<SymmetricTensor<2, dim> >
+ (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 <int dim>
+ struct Solid<dim>::PerTaskData_RHS
+ {
+ Vector<double> cell_rhs;
+ std::vector<types::global_dof_index> 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 <int dim>
+ struct Solid<dim>::ScratchData_RHS
+ {
+ FEValues<dim> fe_values_ref;
+ FEFaceValues<dim> fe_face_values_ref;
+ std::vector<std::vector<double> > Nx;
+ std::vector<std::vector<SymmetricTensor<2, dim> > > symm_grad_Nx;
+ ScratchData_RHS(const FiniteElement<dim> &fe_cell,
+ const QGauss<dim> &qf_cell, const UpdateFlags uf_cell,
+ const QGauss<dim - 1> & 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<double>(fe_cell.dofs_per_cell)),
+ symm_grad_Nx(qf_cell.size(),
+ std::vector<SymmetricTensor<2, dim> >
+ (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 <int dim>
+ struct Solid<dim>::PerTaskData_SC
+ {
+ FullMatrix<double> cell_matrix;
+ std::vector<types::global_dof_index> local_dof_indices;
+ FullMatrix<double> k_orig;
+ FullMatrix<double> k_pu;
+ FullMatrix<double> k_pJ;
+ FullMatrix<double> k_JJ;
+ FullMatrix<double> k_pJ_inv;
+ FullMatrix<double> k_bbar;
+ FullMatrix<double> A;
+ FullMatrix<double> B;
+ FullMatrix<double> 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 <int dim>
+ struct Solid<dim>::ScratchData_SC
+ {
+ void reset()
+ {}
+ };
+ template <int dim>
+ struct Solid<dim>::PerTaskData_UQPH
+ {
+ void reset()
+ {}
+ };
+ template <int dim>
+ struct Solid<dim>::ScratchData_UQPH
+ {
+ const BlockVector<double> &solution_total;
+ std::vector<Tensor<2, dim> > solution_grads_u_total;
+ std::vector<double> solution_values_p_total;
+ std::vector<double> solution_values_J_total;
+ FEValues<dim> fe_values_ref;
+ ScratchData_UQPH(const FiniteElement<dim> &fe_cell,
+ const QGauss<dim> &qf_cell,
+ const UpdateFlags uf_cell,
+ const BlockVector<double> &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 <int dim>
+ void Solid<dim>::make_grid()
+ {
+ GridGenerator::hyper_rectangle(triangulation,
+ (dim==3 ? Point<dim>(0.0, 0.0, 0.0) : Point<dim>(0.0, 0.0)),
+ (dim==3 ? Point<dim>(1.0, 1.0, 1.0) : Point<dim>(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<dim>::active_cell_iterator cell =
+ triangulation.begin_active(), endc = triangulation.end();
+ for (; cell != endc; ++cell)
+ for (unsigned int face = 0;
+ face < GeometryInfo<dim>::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 <int dim>
+ void Solid<dim>::system_setup()
+ {
+ timer.enter_subsection("Setup system");
+ std::vector<unsigned int> 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 <int dim>
+ void
+ Solid<dim>::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 <int dim>
+ void Solid<dim>::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<dim>::active_cell_iterator cell =
+ triangulation.begin_active(); cell != triangulation.end(); ++cell)
+ {
+ const std::vector<std::shared_ptr<PointHistory<dim> > > 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 <int dim>
+ void Solid<dim>::update_qph_incremental(const BlockVector<double> &solution_delta)
+ {
+ timer.enter_subsection("Update QPH data");
+ pcout << " UQPH " << std::flush;
+ const BlockVector<double> 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 <int dim>
+ void
+ Solid<dim>::update_qph_incremental_one_cell(const typename DoFHandler<dim>::active_cell_iterator &cell,
+ ScratchData_UQPH &scratch,
+ PerTaskData_UQPH &/*data*/)
+ {
+ const std::vector<std::shared_ptr<PointHistory<dim> > > 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 <int dim>
+ void
+ Solid<dim>::solve_nonlinear_timestep(BlockVector<double> &solution_delta)
+ {
+ pcout << std::endl << "Timestep " << time.get_timestep() << " @ "
+ << time.current() << "s" << std::endl;
+ BlockVector<double> 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<unsigned int, double>
+ 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 <int dim>
+ void Solid<dim>::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 <int dim>
+ void Solid<dim>::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<double,double> 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 <int dim>
+ double
+ Solid<dim>::compute_vol_current() const
+ {
+ double vol_current = 0.0;
+ FEValues<dim> fe_values_ref(fe, qf_cell, update_JxW_values);
+ for (typename Triangulation<dim>::active_cell_iterator
+ cell = triangulation.begin_active();
+ cell != triangulation.end(); ++cell)
+ {
+ fe_values_ref.reinit(cell);
+ const std::vector<std::shared_ptr<const PointHistory<dim> > > 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 <int dim>
+ std::pair<double, double>
+ Solid<dim>::get_error_dilation() const
+ {
+ double dil_L2_error = 0.0;
+ FEValues<dim> fe_values_ref(fe, qf_cell, update_JxW_values);
+ for (typename Triangulation<dim>::active_cell_iterator
+ cell = triangulation.begin_active();
+ cell != triangulation.end(); ++cell)
+ {
+ fe_values_ref.reinit(cell);
+ const std::vector<std::shared_ptr<const PointHistory<dim> > > 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 <int dim>
+ void Solid<dim>::get_error_residual(Errors &error_residual)
+ {
+ BlockVector<double> 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 <int dim>
+ void Solid<dim>::get_error_update(const BlockVector<double> &newton_update,
+ Errors &error_update)
+ {
+ BlockVector<double> 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 <int dim>
+ BlockVector<double>
+ Solid<dim>::get_total_solution(const BlockVector<double> &solution_delta) const
+ {
+ BlockVector<double> solution_total(solution_n);
+ solution_total += solution_delta;
+ return solution_total;
+ }
+ template <int dim>
+ void Solid<dim>::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<dim>::assemble_system_tangent_one_cell,
+ this,
+ std_cxx11::_1,
+ std_cxx11::_2,
+ std_cxx11::_3),
+ std_cxx11::bind(&Solid<dim>::copy_local_to_global_K,
+ this,
+ std_cxx11::_1),
+ scratch_data,
+ per_task_data);
+ timer.leave_subsection();
+ }
+ template <int dim>
+ void Solid<dim>::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 <int dim>
+ void
+ Solid<dim>::assemble_system_tangent_one_cell(const typename DoFHandler<dim>::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<std::shared_ptr<const PointHistory<dim> > > 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<double>
+ &N = scratch.Nx[q_point];
+ const std::vector<SymmetricTensor<2, dim> >
+ &symm_grad_Nx = scratch.symm_grad_Nx[q_point];
+ const std::vector<Tensor<2, dim> >
+ &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<dim>::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 <int dim>
+ void Solid<dim>::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<dim>::assemble_system_rhs_one_cell,
+ this,
+ std_cxx11::_1,
+ std_cxx11::_2,
+ std_cxx11::_3),
+ std_cxx11::bind(&Solid<dim>::copy_local_to_global_rhs,
+ this,
+ std_cxx11::_1),
+ scratch_data,
+ per_task_data);
+ timer.leave_subsection();
+ }
+ template <int dim>
+ void Solid<dim>::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 <int dim>
+ void
+ Solid<dim>::assemble_system_rhs_one_cell(const typename DoFHandler<dim>::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<std::shared_ptr<const PointHistory<dim> > > 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<double>
+ &N = scratch.Nx[q_point];
+ const std::vector<SymmetricTensor<2, dim> >
+ &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<dim>::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 <int dim>
+ void Solid<dim>::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<dim>(n_components),
+ constraints,
+ fe.component_mask(x_displacement));
+ else
+ VectorTools::interpolate_boundary_values(dof_handler_ref,
+ boundary_id,
+ ZeroFunction<dim>(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<dim>(n_components),
+ constraints,
+ fe.component_mask(y_displacement));
+ else
+ VectorTools::interpolate_boundary_values(dof_handler_ref,
+ boundary_id,
+ ZeroFunction<dim>(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<dim>(n_components),
+ constraints,
+ (fe.component_mask(x_displacement)
+ |
+ fe.component_mask(z_displacement)));
+ else
+ VectorTools::interpolate_boundary_values(dof_handler_ref,
+ boundary_id,
+ ZeroFunction<dim>(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<dim>(n_components),
+ constraints,
+ fe.component_mask(z_displacement));
+ else
+ VectorTools::interpolate_boundary_values(dof_handler_ref,
+ boundary_id,
+ ZeroFunction<dim>(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<dim>(n_components),
+ constraints,
+ (fe.component_mask(x_displacement)
+ |
+ fe.component_mask(z_displacement)));
+ else
+ VectorTools::interpolate_boundary_values(dof_handler_ref,
+ boundary_id,
+ ZeroFunction<dim>(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<dim>(n_components),
+ constraints,
+ (fe.component_mask(x_displacement)));
+ else
+ VectorTools::interpolate_boundary_values(dof_handler_ref,
+ boundary_id,
+ ZeroFunction<dim>(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<dim>(n_components),
+ constraints,
+ (fe.component_mask(x_displacement)));
+ else
+ VectorTools::interpolate_boundary_values(dof_handler_ref,
+ boundary_id,
+ ZeroFunction<dim>(n_components),
+ constraints,
+ (fe.component_mask(x_displacement)));
+ }
+ }
+ constraints.close();
+ }
+ template <int dim>
+ void Solid<dim>::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 <int dim>
+ void Solid<dim>::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 <int dim>
+ void
+ Solid<dim>::assemble_sc_one_cell(const typename DoFHandler<dim>::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 <int dim>
+ std::pair<unsigned int, double>
+ Solid<dim>::solve_linear_system(BlockVector<double> &newton_update)
+ {
+ unsigned int lin_it = 0;
+ double lin_res = 0.0;
+ if (parameters.use_static_condensation == true)
+ {
+ BlockVector<double> A(dofs_per_block);
+ BlockVector<double> 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<Vector<double> > GVM;
+ SolverCG<Vector<double> > solver_CG(solver_control, GVM);
+ PreconditionSelector<SparseMatrix<double>, Vector<double> >
+ 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<double> &f_u = system_rhs.block(u_dof);
+ const Vector<double> &f_p = system_rhs.block(p_dof);
+ const Vector<double> &f_J = system_rhs.block(J_dof);
+ Vector<double> &d_u = newton_update.block(u_dof);
+ Vector<double> &d_p = newton_update.block(p_dof);
+ Vector<double> &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<double>, Vector<double> >
+ 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<double> > 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<double>, Vector<double> >
+ 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<double> > 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 <int dim>
+ void Solid<dim>::output_results() const
+ {
+ DataOut<dim> data_out;
+ std::vector<DataComponentInterpretation::DataComponentInterpretation>
+ 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<std::string> 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<dim>::type_dof_data,
+ data_component_interpretation);
+ Vector<double> soln(solution_n.size());
+ for (unsigned int i = 0; i < soln.size(); ++i)
+ soln(i) = solution_n(i);
+ MappingQEulerian<dim> 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<dim> 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;
+}
--- /dev/null
+
+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