]> https://gitweb.dealii.org/ - code-gallery.git/commitdiff
Change line endings of a .cc file from DOS to Unix. 134/head
authorWolfgang Bangerth <bangerth@colostate.edu>
Tue, 11 Apr 2023 17:56:35 +0000 (11:56 -0600)
committerWolfgang Bangerth <bangerth@colostate.edu>
Tue, 11 Apr 2023 17:56:35 +0000 (11:56 -0600)
Nonlinear_PoroViscoelasticity/nonlinear-poro-viscoelasticity.cc

index fbcb4fe26583ef589ae82918c60b24af2f5d514e..522abd2e675b925644ea8c59a5f5508853684ebe 100644 (file)
-/* ---------------------------------------------------------------------\r
- *\r
- * Copyright (C) 2010 - 2020 by the deal.II authors and\r
- *                              Ester Comellas and Jean-Paul Pelteret\r
- *\r
- * This file is part of the deal.II library.\r
- *\r
- * The deal.II library is free software; you can use it, redistribute\r
- * it, and/or modify it under the terms of the GNU Lesser General\r
- * Public License as published by the Free Software Foundation; either\r
- * version 2.1 of the License, or (at your option) any later version.\r
- * The full text of the license can be found in the file LICENSE at\r
- * the top level of the deal.II distribution.\r
- *\r
- * ---------------------------------------------------------------------\r
- */\r
-\r
-/*   Authors: Ester Comellas and Jean-Paul Pelteret,\r
- *           University of Erlangen-Nuremberg, 2018\r
- */\r
-\r
-// We start by including all the necessary deal.II header files and some C++\r
-// related ones. They have been discussed in detail in previous tutorial\r
-// programs, so you need only refer to past tutorials for details.\r
-\r
-#include <deal.II/base/function.h>\r
-#include <deal.II/base/parameter_handler.h>\r
-#include <deal.II/base/point.h>\r
-#include <deal.II/base/quadrature_lib.h>\r
-#include <deal.II/base/symmetric_tensor.h>\r
-#include <deal.II/base/tensor.h>\r
-#include <deal.II/base/timer.h>\r
-#include <deal.II/base/work_stream.h>\r
-#include <deal.II/base/mpi.h>\r
-#include <deal.II/base/quadrature_point_data.h>\r
-\r
-#include <deal.II/differentiation/ad.h>\r
-\r
-#include <deal.II/distributed/shared_tria.h>\r
-\r
-#include <deal.II/dofs/dof_renumbering.h>\r
-#include <deal.II/dofs/dof_tools.h>\r
-#include <deal.II/dofs/dof_accessor.h>\r
-\r
-#include <deal.II/grid/filtered_iterator.h>\r
-#include <deal.II/grid/grid_generator.h>\r
-#include <deal.II/grid/grid_tools.h>\r
-#include <deal.II/grid/grid_in.h>\r
-#include <deal.II/grid/grid_out.h>\r
-#include <deal.II/grid/manifold_lib.h>\r
-#include <deal.II/grid/tria_accessor.h>\r
-#include <deal.II/grid/tria_iterator.h>\r
-\r
-#include <deal.II/fe/fe_dgp_monomial.h>\r
-#include <deal.II/fe/fe_q.h>\r
-#include <deal.II/fe/fe_system.h>\r
-#include <deal.II/fe/fe_tools.h>\r
-#include <deal.II/fe/fe_values.h>\r
-\r
-#include <deal.II/lac/block_sparsity_pattern.h>\r
-#include <deal.II/lac/affine_constraints.h>\r
-#include <deal.II/lac/dynamic_sparsity_pattern.h>\r
-#include <deal.II/lac/full_matrix.h>\r
-#include <deal.II/lac/linear_operator.h>\r
-#include <deal.II/lac/packaged_operation.h>\r
-\r
-#include <deal.II/lac/trilinos_block_sparse_matrix.h>\r
-#include <deal.II/lac/trilinos_linear_operator.h>\r
-#include <deal.II/lac/trilinos_parallel_block_vector.h>\r
-#include <deal.II/lac/trilinos_precondition.h>\r
-#include <deal.II/lac/trilinos_sparse_matrix.h>\r
-#include <deal.II/lac/trilinos_sparsity_pattern.h>\r
-#include <deal.II/lac/trilinos_solver.h>\r
-#include <deal.II/lac/trilinos_vector.h>\r
-\r
-#include <deal.II/lac/block_vector.h>\r
-#include <deal.II/lac/vector.h>\r
-\r
-#include <deal.II/numerics/data_postprocessor.h>\r
-#include <deal.II/numerics/data_out.h>\r
-#include <deal.II/numerics/data_out_faces.h>\r
-#include <deal.II/numerics/fe_field_function.h>\r
-#include <deal.II/numerics/vector_tools.h>\r
-\r
-#include <deal.II/physics/transformations.h>\r
-#include <deal.II/physics/elasticity/kinematics.h>\r
-#include <deal.II/physics/elasticity/standard_tensors.h>\r
-\r
-#include <iostream>\r
-#include <fstream>\r
-#include <numeric>\r
-#include <iomanip>\r
-\r
-\r
-// We create a namespace for everything that relates to\r
-// the nonlinear poro-viscoelastic formulation,\r
-// and import all the deal.II function and class names into it:\r
-namespace NonLinearPoroViscoElasticity\r
-{\r
-    using namespace dealii;\r
-\r
-// @sect3{Run-time parameters}\r
-//\r
-// Set up a ParameterHandler object to read in the parameter choices at run-time\r
-// introduced by the user through the file "parameters.prm"\r
-    namespace Parameters\r
-    {\r
-// @sect4{Finite Element system}\r
-// Here we specify the polynomial order used to approximate the solution,\r
-// both for the displacements and pressure unknowns.\r
-// The quadrature order should be adjusted accordingly.\r
-      struct FESystem\r
-      {\r
-        unsigned int poly_degree_displ;\r
-        unsigned int poly_degree_pore;\r
-        unsigned int quad_order;\r
-\r
-        static void\r
-        declare_parameters(ParameterHandler &prm);\r
-\r
-        void\r
-        parse_parameters(ParameterHandler &prm);\r
-      };\r
-\r
-      void FESystem::declare_parameters(ParameterHandler &prm)\r
-      {\r
-        prm.enter_subsection("Finite element system");\r
-        {\r
-          prm.declare_entry("Polynomial degree displ", "2",\r
-                            Patterns::Integer(0),\r
-                            "Displacement system polynomial order");\r
-\r
-          prm.declare_entry("Polynomial degree pore", "1",\r
-                            Patterns::Integer(0),\r
-                            "Pore pressure system polynomial order");\r
-\r
-          prm.declare_entry("Quadrature order", "3",\r
-                            Patterns::Integer(0),\r
-                            "Gauss quadrature order");\r
-        }\r
-        prm.leave_subsection();\r
-      }\r
-\r
-      void FESystem::parse_parameters(ParameterHandler &prm)\r
-      {\r
-        prm.enter_subsection("Finite element system");\r
-        {\r
-          poly_degree_displ = prm.get_integer("Polynomial degree displ");\r
-          poly_degree_pore = prm.get_integer("Polynomial degree pore");\r
-          quad_order = prm.get_integer("Quadrature order");\r
-        }\r
-        prm.leave_subsection();\r
-      }\r
-\r
-// @sect4{Geometry}\r
-// These parameters are related to the geometry definition and mesh generation.\r
-// We select the type of problem to solve and introduce the desired load values.\r
-      struct Geometry\r
-      {\r
-        std::string  geom_type;\r
-        unsigned int global_refinement;\r
-        double       scale;\r
-        std::string  load_type;\r
-        double       load;\r
-        unsigned int num_cycle_sets;\r
-        double       fluid_flow;\r
-        double       drained_pressure;\r
-\r
-        static void\r
-        declare_parameters(ParameterHandler &prm);\r
-\r
-        void\r
-        parse_parameters(ParameterHandler &prm);\r
-      };\r
-\r
-      void Geometry::declare_parameters(ParameterHandler &prm)\r
-      {\r
-        prm.enter_subsection("Geometry");\r
-        {\r
-          prm.declare_entry("Geometry type", "Ehlers_tube_step_load",\r
-                             Patterns::Selection("Ehlers_tube_step_load"\r
-                                                 "|Ehlers_tube_increase_load"\r
-                                                 "|Ehlers_cube_consolidation"\r
-                                                 "|Franceschini_consolidation"\r
-                                                 "|Budday_cube_tension_compression"\r
-                                                 "|Budday_cube_tension_compression_fully_fixed"\r
-                                                 "|Budday_cube_shear_fully_fixed"),\r
-                                "Type of geometry used. "\r
-                                "For Ehlers verification examples see Ehlers and Eipper (1999). "\r
-                                "For Franceschini brain consolidation see Franceschini et al. (2006)"\r
-                                "For Budday brain examples see Budday et al. (2017)");\r
-\r
-          prm.declare_entry("Global refinement", "1",\r
-                            Patterns::Integer(0),\r
-                            "Global refinement level");\r
-\r
-          prm.declare_entry("Grid scale", "1.0",\r
-                            Patterns::Double(0.0),\r
-                            "Global grid scaling factor");\r
-\r
-          prm.declare_entry("Load type", "pressure",\r
-                            Patterns::Selection("pressure|displacement|none"),\r
-                            "Type of loading");\r
-\r
-          prm.declare_entry("Load value", "-7.5e+6",\r
-                            Patterns::Double(),\r
-                            "Loading value");\r
-\r
-          prm.declare_entry("Number of cycle sets", "1",\r
-                            Patterns::Integer(1,2),\r
-                            "Number of times each set of 3 cycles is repeated, only for "\r
-                            "Budday_cube_tension_compression and Budday_cube_tension_compression_fully_fixed. "\r
-                            "Load value is doubled in second set, load rate is kept constant."\r
-                            "Final time indicates end of second cycle set.");\r
-\r
-          prm.declare_entry("Fluid flow value", "0.0",\r
-                            Patterns::Double(),\r
-                            "Prescribed fluid flow. Not implemented in any example yet.");\r
-\r
-          prm.declare_entry("Drained pressure", "0.0",\r
-                            Patterns::Double(),\r
-                            "Increase of pressure value at drained boundary w.r.t the atmospheric pressure.");\r
-        }\r
-        prm.leave_subsection();\r
-      }\r
-\r
-      void Geometry::parse_parameters(ParameterHandler &prm)\r
-      {\r
-        prm.enter_subsection("Geometry");\r
-        {\r
-          geom_type = prm.get("Geometry type");\r
-          global_refinement = prm.get_integer("Global refinement");\r
-          scale = prm.get_double("Grid scale");\r
-          load_type = prm.get("Load type");\r
-          load = prm.get_double("Load value");\r
-          num_cycle_sets = prm.get_integer("Number of cycle sets");\r
-          fluid_flow = prm.get_double("Fluid flow value");\r
-          drained_pressure = prm.get_double("Drained pressure");\r
-        }\r
-        prm.leave_subsection();\r
-      }\r
-\r
-// @sect4{Materials}\r
-\r
-// Here we select the type of material for the solid component\r
-// and define the corresponding material parameters.\r
-// Then we define he fluid data, including the type of\r
-// seepage velocity definition to use.\r
-      struct Materials\r
-      {\r
-        std::string  mat_type;\r
-        double lambda;\r
-        double mu;\r
-        double mu1_infty;\r
-        double mu2_infty;\r
-        double mu3_infty;\r
-        double alpha1_infty;\r
-        double alpha2_infty;\r
-        double alpha3_infty;\r
-        double mu1_mode_1;\r
-        double mu2_mode_1;\r
-        double mu3_mode_1;\r
-        double alpha1_mode_1;\r
-        double alpha2_mode_1;\r
-        double alpha3_mode_1;\r
-        double viscosity_mode_1;\r
-        std::string  fluid_type;\r
-        double solid_vol_frac;\r
-        double kappa_darcy;\r
-        double init_intrinsic_perm;\r
-        double viscosity_FR;\r
-        double init_darcy_coef;\r
-        double weight_FR;\r
-        bool gravity_term;\r
-        int gravity_direction;\r
-        double gravity_value;\r
-        double density_FR;\r
-        double density_SR;\r
-        enum SymmetricTensorEigenvectorMethod eigen_solver;\r
-\r
-        static void\r
-        declare_parameters(ParameterHandler &prm);\r
-\r
-        void\r
-        parse_parameters(ParameterHandler &prm);\r
-      };\r
-\r
-      void Materials::declare_parameters(ParameterHandler &prm)\r
-      {\r
-        prm.enter_subsection("Material properties");\r
-        {\r
-          prm.declare_entry("material", "Neo-Hooke",\r
-                            Patterns::Selection("Neo-Hooke|Ogden|visco-Ogden"),\r
-                            "Type of material used in the problem");\r
-\r
-          prm.declare_entry("lambda", "8.375e6",\r
-                            Patterns::Double(0,1e100),\r
-                            "First Lamé parameter for extension function related to compactation point in solid material [Pa].");\r
-\r
-          prm.declare_entry("shear modulus", "5.583e6",\r
-                            Patterns::Double(0,1e100),\r
-                            "shear modulus for Neo-Hooke materials [Pa].");\r
-\r
-          prm.declare_entry("eigen solver", "QL Implicit Shifts",\r
-                            Patterns::Selection("QL Implicit Shifts|Jacobi"),\r
-                            "The type of eigen solver to be used for Ogden and visco-Ogden models.");\r
-\r
-          prm.declare_entry("mu1", "0.0",\r
-                            Patterns::Double(),\r
-                            "Shear material parameter 'mu1' for Ogden material [Pa].");\r
-\r
-          prm.declare_entry("mu2", "0.0",\r
-                            Patterns::Double(),\r
-                            "Shear material parameter 'mu2' for Ogden material [Pa].");\r
-\r
-          prm.declare_entry("mu3", "0.0",\r
-                            Patterns::Double(),\r
-                            "Shear material parameter 'mu1' for Ogden material [Pa].");\r
-\r
-          prm.declare_entry("alpha1", "1.0",\r
-                            Patterns::Double(),\r
-                            "Stiffness material parameter 'alpha1' for Ogden material [-].");\r
-\r
-          prm.declare_entry("alpha2", "1.0",\r
-                            Patterns::Double(),\r
-                            "Stiffness material parameter 'alpha2' for Ogden material [-].");\r
-\r
-          prm.declare_entry("alpha3", "1.0",\r
-                            Patterns::Double(),\r
-                            "Stiffness material parameter 'alpha3' for Ogden material [-].");\r
-\r
-          prm.declare_entry("mu1_1", "0.0",\r
-                            Patterns::Double(),\r
-                            "Shear material parameter 'mu1' for first viscous mode in Ogden material [Pa].");\r
-\r
-          prm.declare_entry("mu2_1", "0.0",\r
-                            Patterns::Double(),\r
-                            "Shear material parameter 'mu2' for first viscous mode in Ogden material [Pa].");\r
-\r
-          prm.declare_entry("mu3_1", "0.0",\r
-                            Patterns::Double(),\r
-                            "Shear material parameter 'mu1' for first viscous mode in Ogden material [Pa].");\r
-\r
-          prm.declare_entry("alpha1_1", "1.0",\r
-                            Patterns::Double(),\r
-                            "Stiffness material parameter 'alpha1' for first viscous mode in Ogden material [-].");\r
-\r
-          prm.declare_entry("alpha2_1", "1.0",\r
-                            Patterns::Double(),\r
-                            "Stiffness material parameter 'alpha2' for first viscous mode in Ogden material [-].");\r
-\r
-          prm.declare_entry("alpha3_1", "1.0",\r
-                            Patterns::Double(),\r
-                            "Stiffness material parameter 'alpha3' for first viscous mode in Ogden material [-].");\r
-\r
-          prm.declare_entry("viscosity_1", "1e-10",\r
-                            Patterns::Double(1e-10,1e100),\r
-                            "Deformation-independent viscosity parameter 'eta_1' for first viscous mode in Ogden material [-].");\r
-\r
-          prm.declare_entry("seepage definition", "Ehlers",\r
-                            Patterns::Selection("Markert|Ehlers"),\r
-                            "Type of formulation used to define the seepage velocity in the problem. "\r
-                            "Choose between Markert formulation of deformation-dependent intrinsic permeability "\r
-                            "and Ehlers formulation of deformation-dependent Darcy flow coefficient.");\r
-\r
-          prm.declare_entry("initial solid volume fraction", "0.67",\r
-                            Patterns::Double(0.001,0.999),\r
-                            "Initial porosity (solid volume fraction, 0 < n_0s < 1)");\r
-\r
-          prm.declare_entry("kappa", "0.0",\r
-                            Patterns::Double(0,100),\r
-                            "Deformation-dependency control parameter for specific permeability (kappa >= 0)");\r
-\r
-          prm.declare_entry("initial intrinsic permeability", "0.0",\r
-                            Patterns::Double(0,1e100),\r
-                            "Initial intrinsic permeability parameter [m^2] (isotropic permeability). To be used with Markert formulation.");\r
-\r
-          prm.declare_entry("fluid viscosity", "0.0",\r
-                            Patterns::Double(0, 1e100),\r
-                            "Effective shear viscosity parameter of the fluid [Pa·s, (N·s)/m^2]. To be used with Markert formulation.");\r
-\r
-          prm.declare_entry("initial Darcy coefficient", "1.0e-4",\r
-                            Patterns::Double(0,1e100),\r
-                            "Initial Darcy flow coefficient [m/s] (isotropic permeability). To be used with Ehlers formulation.");\r
-\r
-          prm.declare_entry("fluid weight", "1.0e4",\r
-                            Patterns::Double(0, 1e100),\r
-                            "Effective weight of the fluid [N/m^3]. To be used with Ehlers formulation.");\r
-\r
-          prm.declare_entry("gravity term", "false",\r
-                            Patterns::Bool(),\r
-                            "Gravity term considered (true) or neglected (false)");\r
-\r
-          prm.declare_entry("fluid density", "1.0",\r
-                            Patterns::Double(0,1e100),\r
-                            "Real (or effective) density of the fluid");\r
-\r
-          prm.declare_entry("solid density", "1.0",\r
-                            Patterns::Double(0,1e100),\r
-                            "Real (or effective) density of the solid");\r
-\r
-          prm.declare_entry("gravity direction", "2",\r
-                            Patterns::Integer(0,2),\r
-                            "Direction of gravity (unit vector 0 for x, 1 for y, 2 for z)");\r
-\r
-          prm.declare_entry("gravity value", "-9.81",\r
-                            Patterns::Double(),\r
-                            "Value of gravity (be careful to have consistent units!)");\r
-        }\r
-        prm.leave_subsection();\r
-      }\r
-\r
-      void Materials::parse_parameters(ParameterHandler &prm)\r
-      {\r
-        prm.enter_subsection("Material properties");\r
-        {\r
-          //Solid\r
-          mat_type = prm.get("material");\r
-          lambda = prm.get_double("lambda");\r
-          mu = prm.get_double("shear modulus");\r
-          mu1_infty = prm.get_double("mu1");\r
-          mu2_infty = prm.get_double("mu2");\r
-          mu3_infty = prm.get_double("mu3");\r
-          alpha1_infty = prm.get_double("alpha1");\r
-          alpha2_infty = prm.get_double("alpha2");\r
-          alpha3_infty = prm.get_double("alpha3");\r
-          mu1_mode_1 = prm.get_double("mu1_1");\r
-          mu2_mode_1 = prm.get_double("mu2_1");\r
-          mu3_mode_1 = prm.get_double("mu3_1");\r
-          alpha1_mode_1 = prm.get_double("alpha1_1");\r
-          alpha2_mode_1 = prm.get_double("alpha2_1");\r
-          alpha3_mode_1 = prm.get_double("alpha3_1");\r
-          viscosity_mode_1 = prm.get_double("viscosity_1");\r
-          //Fluid\r
-          fluid_type = prm.get("seepage definition");\r
-          solid_vol_frac = prm.get_double("initial solid volume fraction");\r
-          kappa_darcy = prm.get_double("kappa");\r
-          init_intrinsic_perm = prm.get_double("initial intrinsic permeability");\r
-          viscosity_FR = prm.get_double("fluid viscosity");\r
-          init_darcy_coef = prm.get_double("initial Darcy coefficient");\r
-          weight_FR = prm.get_double("fluid weight");\r
-          //Gravity effects\r
-          gravity_term = prm.get_bool("gravity term");\r
-          density_FR = prm.get_double("fluid density");\r
-          density_SR = prm.get_double("solid density");\r
-          gravity_direction = prm.get_integer("gravity direction");\r
-          gravity_value = prm.get_double("gravity value");\r
-\r
-          if ( (fluid_type == "Markert") && ((init_intrinsic_perm == 0.0) || (viscosity_FR == 0.0)) )\r
-              AssertThrow(false, ExcMessage("Markert seepage velocity formulation requires the definition of "\r
-                                            "'initial intrinsic permeability' and 'fluid viscosity' greater than 0.0."));\r
-\r
-          if ( (fluid_type == "Ehlers") && ((init_darcy_coef == 0.0) || (weight_FR == 0.0)) )\r
-              AssertThrow(false, ExcMessage("Ehler seepage velocity formulation requires the definition of "\r
-                                            "'initial Darcy coefficient' and 'fluid weight' greater than 0.0."));\r
-\r
-          const std::string eigen_solver_type = prm.get("eigen solver");\r
-          if (eigen_solver_type == "QL Implicit Shifts")\r
-            eigen_solver = SymmetricTensorEigenvectorMethod::ql_implicit_shifts;\r
-          else if (eigen_solver_type == "Jacobi")\r
-            eigen_solver = SymmetricTensorEigenvectorMethod::jacobi;\r
-          else\r
-          {\r
-            AssertThrow(false, ExcMessage("Unknown eigen solver selected."));\r
-          }\r
-        }\r
-        prm.leave_subsection();\r
-      }\r
-\r
-// @sect4{Nonlinear solver}\r
-\r
-// We now define the tolerances and the maximum number of iterations for the\r
-// Newton-Raphson scheme used to solve the nonlinear system of governing equations.\r
-      struct NonlinearSolver\r
-      {\r
-        unsigned int max_iterations_NR;\r
-        double       tol_f;\r
-        double       tol_u;\r
-        double       tol_p_fluid;\r
-\r
-        static void\r
-        declare_parameters(ParameterHandler &prm);\r
-\r
-        void\r
-        parse_parameters(ParameterHandler &prm);\r
-      };\r
-\r
-      void NonlinearSolver::declare_parameters(ParameterHandler &prm)\r
-      {\r
-        prm.enter_subsection("Nonlinear solver");\r
-        {\r
-          prm.declare_entry("Max iterations Newton-Raphson", "15",\r
-                            Patterns::Integer(0),\r
-                            "Number of Newton-Raphson iterations allowed");\r
-\r
-          prm.declare_entry("Tolerance force", "1.0e-8",\r
-                            Patterns::Double(0.0),\r
-                            "Force residual tolerance");\r
-\r
-          prm.declare_entry("Tolerance displacement", "1.0e-6",\r
-                            Patterns::Double(0.0),\r
-                            "Displacement error tolerance");\r
-\r
-          prm.declare_entry("Tolerance pore pressure", "1.0e-6",\r
-                            Patterns::Double(0.0),\r
-                            "Pore pressure error tolerance");\r
-        }\r
-        prm.leave_subsection();\r
-      }\r
-\r
-      void NonlinearSolver::parse_parameters(ParameterHandler &prm)\r
-      {\r
-        prm.enter_subsection("Nonlinear solver");\r
-        {\r
-          max_iterations_NR = prm.get_integer("Max iterations Newton-Raphson");\r
-          tol_f = prm.get_double("Tolerance force");\r
-          tol_u = prm.get_double("Tolerance displacement");\r
-          tol_p_fluid =  prm.get_double("Tolerance pore pressure");\r
-        }\r
-        prm.leave_subsection();\r
-      }\r
-\r
-// @sect4{Time}\r
-// Here we set the timestep size $ \varDelta t $ and the simulation end-time.\r
-      struct Time\r
-      {\r
-        double end_time;\r
-        double delta_t;\r
-        static void\r
-        declare_parameters(ParameterHandler &prm);\r
-\r
-        void\r
-        parse_parameters(ParameterHandler &prm);\r
-      };\r
-\r
-      void Time::declare_parameters(ParameterHandler &prm)\r
-      {\r
-        prm.enter_subsection("Time");\r
-        {\r
-          prm.declare_entry("End time", "10.0",\r
-                            Patterns::Double(),\r
-                            "End time");\r
-\r
-          prm.declare_entry("Time step size", "0.002",\r
-                            Patterns::Double(1.0e-6),\r
-                            "Time step size. The value must be larger than the displacement error tolerance defined.");\r
-        }\r
-        prm.leave_subsection();\r
-      }\r
-\r
-      void Time::parse_parameters(ParameterHandler &prm)\r
-      {\r
-        prm.enter_subsection("Time");\r
-        {\r
-          end_time = prm.get_double("End time");\r
-          delta_t = prm.get_double("Time step size");\r
-        }\r
-        prm.leave_subsection();\r
-      }\r
-\r
-\r
-// @sect4{Output}\r
-// We can choose the frequency of the data for the output files.\r
-      struct OutputParam\r
-      {\r
-\r
-        std::string  outfiles_requested;\r
-        unsigned int timestep_output;\r
-        std::string  outtype;\r
-\r
-        static void\r
-        declare_parameters(ParameterHandler &prm);\r
-\r
-        void\r
-        parse_parameters(ParameterHandler &prm);\r
-      };\r
-\r
-      void OutputParam::declare_parameters(ParameterHandler &prm)\r
-      {\r
-        prm.enter_subsection("Output parameters");\r
-        {\r
-          prm.declare_entry("Output files", "true",\r
-                            Patterns::Selection("true|false"),\r
-                            "Paraview output files to generate.");\r
-          prm.declare_entry("Time step number output", "1",\r
-                            Patterns::Integer(0),\r
-                            "Output data for time steps multiple of the given "\r
-                            "integer value.");\r
-          prm.declare_entry("Averaged results", "nodes",\r
-                             Patterns::Selection("elements|nodes"),\r
-                             "Output data associated with integration point values"\r
-                             " averaged on elements or on nodes.");\r
-        }\r
-        prm.leave_subsection();\r
-      }\r
-\r
-      void OutputParam::parse_parameters(ParameterHandler &prm)\r
-      {\r
-        prm.enter_subsection("Output parameters");\r
-        {\r
-          outfiles_requested = prm.get("Output files");\r
-          timestep_output = prm.get_integer("Time step number output");\r
-          outtype = prm.get("Averaged results");\r
-        }\r
-        prm.leave_subsection();\r
-      }\r
-\r
-// @sect4{All parameters}\r
-// We finally consolidate all of the above structures into a single container that holds all the run-time selections.\r
-      struct AllParameters : public FESystem,\r
-                             public Geometry,\r
-                             public Materials,\r
-                             public NonlinearSolver,\r
-                             public Time,\r
-                             public OutputParam\r
-      {\r
-        AllParameters(const std::string &input_file);\r
-\r
-        static void\r
-        declare_parameters(ParameterHandler &prm);\r
-\r
-        void\r
-        parse_parameters(ParameterHandler &prm);\r
-      };\r
-\r
-      AllParameters::AllParameters(const std::string &input_file)\r
-      {\r
-        ParameterHandler prm;\r
-        declare_parameters(prm);\r
-        prm.parse_input(input_file);\r
-        parse_parameters(prm);\r
-      }\r
-\r
-      void AllParameters::declare_parameters(ParameterHandler &prm)\r
-      {\r
-        FESystem::declare_parameters(prm);\r
-        Geometry::declare_parameters(prm);\r
-        Materials::declare_parameters(prm);\r
-        NonlinearSolver::declare_parameters(prm);\r
-        Time::declare_parameters(prm);\r
-        OutputParam::declare_parameters(prm);\r
-      }\r
-\r
-      void AllParameters::parse_parameters(ParameterHandler &prm)\r
-      {\r
-        FESystem::parse_parameters(prm);\r
-        Geometry::parse_parameters(prm);\r
-        Materials::parse_parameters(prm);\r
-        NonlinearSolver::parse_parameters(prm);\r
-        Time::parse_parameters(prm);\r
-        OutputParam::parse_parameters(prm);\r
-      }\r
-    }\r
-\r
-// @sect3{Time class}\r
-// A simple class to store time data.\r
-// For simplicity we assume a constant time step size.\r
-    class Time\r
-    {\r
-        public:\r
-          Time (const double time_end,\r
-                const double delta_t)\r
-            :\r
-            timestep(0),\r
-            time_current(0.0),\r
-            time_end(time_end),\r
-            delta_t(delta_t)\r
-          {}\r
-\r
-          virtual ~Time()\r
-          {}\r
-\r
-          double get_current() const\r
-          {\r
-            return time_current;\r
-          }\r
-          double get_end() const\r
-          {\r
-            return time_end;\r
-          }\r
-          double get_delta_t() const\r
-          {\r
-            return delta_t;\r
-          }\r
-          unsigned int get_timestep() const\r
-          {\r
-            return timestep;\r
-          }\r
-          void increment_time ()\r
-          {\r
-            time_current += delta_t;\r
-            ++timestep;\r
-          }\r
-\r
-        private:\r
-          unsigned int timestep;\r
-          double time_current;\r
-          double time_end;\r
-          const double delta_t;\r
-    };\r
-\r
-// @sect3{Constitutive equation for the solid component of the biphasic material}\r
-\r
-//@sect4{Base class: generic hyperelastic material}\r
-// The ``extra" Kirchhoff stress in the solid component is the sum of isochoric\r
-// and a volumetric part.\r
-// $\mathbf{\tau} = \mathbf{\tau}_E^{(\bullet)} + \mathbf{\tau}^{\textrm{vol}}$\r
-// The deviatoric part changes depending on the type of material model selected:\r
-// Neo-Hooken hyperelasticity, Ogden hyperelasticiy,\r
-// or a single-mode finite viscoelasticity based on the Ogden hyperelastic model.\r
-// In this base class we declare  it as a virtual function,\r
-// and it will be defined for each model type in the corresponding derived class.\r
-// We define here the volumetric component, which depends on the\r
-// extension function $U(J_S)$ selected, and in this case is the same for all models.\r
-// We use the function proposed by\r
-// Ehlers & Eipper 1999 doi:10.1023/A:1006565509095\r
-// We also define some public functions to access and update the internal variables.\r
-    template <int dim, typename NumberType = Sacado::Fad::DFad<double> >\r
-    class Material_Hyperelastic\r
-    {\r
-        public:\r
-          Material_Hyperelastic(const Parameters::AllParameters &parameters,\r
-                                const Time                      &time)\r
-            :\r
-            n_OS (parameters.solid_vol_frac),\r
-            lambda (parameters.lambda),\r
-            time(time),\r
-            det_F (1.0),\r
-            det_F_converged (1.0),\r
-            eigen_solver (parameters.eigen_solver)\r
-           {}\r
-          ~Material_Hyperelastic()\r
-          {}\r
-\r
-          SymmetricTensor<2, dim, NumberType>\r
-          get_tau_E(const Tensor<2,dim, NumberType> &F) const\r
-          {\r
-            return ( get_tau_E_base(F) + get_tau_E_ext_func(F) );\r
-          }\r
-\r
-          SymmetricTensor<2, dim, NumberType>\r
-          get_Cauchy_E(const Tensor<2, dim, NumberType> &F) const\r
-          {\r
-              const NumberType det_F = determinant(F);\r
-              Assert(det_F > 0, ExcInternalError());\r
-              return get_tau_E(F)*NumberType(1/det_F);\r
-          }\r
-\r
-          double\r
-          get_converged_det_F() const\r
-          {\r
-              return  det_F_converged;\r
-          }\r
-\r
-          virtual void\r
-          update_end_timestep()\r
-          {\r
-              det_F_converged = det_F;\r
-          }\r
-\r
-          virtual void\r
-          update_internal_equilibrium( const Tensor<2, dim, NumberType> &F )\r
-          {\r
-              det_F = Tensor<0,dim,double>(determinant(F));\r
-          }\r
-\r
-          virtual double\r
-          get_viscous_dissipation( ) const = 0;\r
-\r
-          const double n_OS;\r
-          const double lambda;\r
-          const Time  &time;\r
-          double det_F;\r
-          double det_F_converged;\r
-          const enum SymmetricTensorEigenvectorMethod eigen_solver;\r
-\r
-        protected:\r
-          SymmetricTensor<2, dim, NumberType>\r
-          get_tau_E_ext_func(const Tensor<2,dim, NumberType> &F) const\r
-          {\r
-              const NumberType det_F = determinant(F);\r
-              Assert(det_F > 0, ExcInternalError());\r
-\r
-              static const SymmetricTensor< 2, dim, double>\r
-                    I (Physics::Elasticity::StandardTensors<dim>::I);\r
-              return  ( NumberType(lambda * (1.0-n_OS)*(1.0-n_OS)\r
-                         * (det_F/(1.0-n_OS) - det_F/(det_F-n_OS))) * I );\r
-          }\r
-\r
-          virtual SymmetricTensor<2, dim, NumberType>\r
-           get_tau_E_base(const Tensor<2,dim, NumberType> &F) const = 0;\r
-    };\r
-\r
-//@sect4{Derived class: Neo-Hookean hyperelastic material}\r
-    template <int dim, typename NumberType = Sacado::Fad::DFad<double> >\r
-    class NeoHooke : public Material_Hyperelastic < dim, NumberType >\r
-    {\r
-        public:\r
-            NeoHooke(const Parameters::AllParameters &parameters,\r
-                     const Time                      &time)\r
-            :\r
-            Material_Hyperelastic< dim, NumberType > (parameters,time),\r
-            mu(parameters.mu)\r
-           {}\r
-          virtual ~NeoHooke()\r
-          {}\r
-\r
-           double\r
-           get_viscous_dissipation() const override\r
-           {\r
-               return 0.0;\r
-           }\r
-\r
-        protected:\r
-          const double mu;\r
-\r
-          SymmetricTensor<2, dim, NumberType>\r
-          get_tau_E_base(const Tensor<2,dim, NumberType> &F) const override\r
-          {\r
-             static const SymmetricTensor< 2, dim, double>\r
-                I (Physics::Elasticity::StandardTensors<dim>::I);\r
-\r
-             const bool use_standard_model = true;\r
-\r
-             if (use_standard_model)\r
-             {\r
-               // Standard Neo-Hooke\r
-               return ( mu * ( symmetrize(F * transpose(F)) - I ) );\r
-             }\r
-             else\r
-             {\r
-               // Neo-Hooke in terms of principal stretches\r
-               const SymmetricTensor<2, dim, NumberType>\r
-                B = symmetrize(F * transpose(F));\r
-               const std::array< std::pair< NumberType, Tensor< 1, dim, NumberType > >, dim >\r
-                eigen_B = eigenvectors(B, this->eigen_solver);\r
-\r
-               SymmetricTensor<2, dim, NumberType> B_ev;\r
-               for (unsigned int d=0; d<dim; ++d)\r
-                 B_ev += eigen_B[d].first*symmetrize(outer_product(eigen_B[d].second,eigen_B[d].second));\r
-\r
-                return ( mu*(B_ev-I) );\r
-             }\r
-          }\r
-    };\r
-\r
-//@sect4{Derived class: Ogden hyperelastic material}\r
-    template <int dim, typename NumberType = Sacado::Fad::DFad<double> >\r
-    class Ogden : public Material_Hyperelastic < dim, NumberType >\r
-    {\r
-        public:\r
-          Ogden(const Parameters::AllParameters &parameters,\r
-                const Time                      &time)\r
-          :\r
-          Material_Hyperelastic< dim, NumberType > (parameters,time),\r
-          mu({parameters.mu1_infty,\r
-              parameters.mu2_infty,\r
-              parameters.mu3_infty}),\r
-          alpha({parameters.alpha1_infty,\r
-                 parameters.alpha2_infty,\r
-                 parameters.alpha3_infty})\r
-           {}\r
-          virtual ~Ogden()\r
-          {}\r
-\r
-           double\r
-           get_viscous_dissipation() const override\r
-           {\r
-               return 0.0;\r
-           }\r
-\r
-        protected:\r
-          std::vector<double> mu;\r
-          std::vector<double> alpha;\r
-\r
-          SymmetricTensor<2, dim, NumberType>\r
-          get_tau_E_base(const Tensor<2,dim, NumberType> &F) const override\r
-          {\r
-            const SymmetricTensor<2, dim, NumberType>\r
-             B = symmetrize(F * transpose(F));\r
-\r
-            const std::array< std::pair< NumberType, Tensor< 1, dim, NumberType > >, dim >\r
-             eigen_B = eigenvectors(B, this->eigen_solver);\r
-\r
-            SymmetricTensor<2, dim, NumberType>  tau;\r
-            static const SymmetricTensor< 2, dim, double>\r
-              I (Physics::Elasticity::StandardTensors<dim>::I);\r
-\r
-            for (unsigned int i = 0; i < 3; ++i)\r
-            {\r
-                for (unsigned int A = 0; A < dim; ++A)\r
-                {\r
-                    SymmetricTensor<2, dim, NumberType>  tau_aux1 = symmetrize(\r
-                            outer_product(eigen_B[A].second,eigen_B[A].second));\r
-                    tau_aux1 *= mu[i]*std::pow(eigen_B[A].first, (alpha[i]/2.) );\r
-                    tau += tau_aux1;\r
-                }\r
-                SymmetricTensor<2, dim, NumberType>  tau_aux2 (I);\r
-                tau_aux2 *= mu[i];\r
-                tau -= tau_aux2;\r
-            }\r
-            return tau;\r
-          }\r
-    };\r
-\r
-//@sect4{Derived class: Single-mode Ogden viscoelastic material}\r
-// We use the finite viscoelastic model described in\r
-// Reese & Govindjee (1998) doi:10.1016/S0020-7683(97)00217-5\r
-// The algorithm for the implicit exponential time integration is given in\r
-// Budday et al. (2017) doi: 10.1016/j.actbio.2017.06.024\r
-    template <int dim, typename NumberType = Sacado::Fad::DFad<double> >\r
-    class visco_Ogden : public Material_Hyperelastic < dim, NumberType >\r
-    {\r
-        public:\r
-            visco_Ogden(const Parameters::AllParameters &parameters,\r
-                        const Time                      &time)\r
-            :\r
-            Material_Hyperelastic< dim, NumberType > (parameters,time),\r
-            mu_infty({parameters.mu1_infty,\r
-                      parameters.mu2_infty,\r
-                      parameters.mu3_infty}),\r
-            alpha_infty({parameters.alpha1_infty,\r
-                         parameters.alpha2_infty,\r
-                         parameters.alpha3_infty}),\r
-            mu_mode_1({parameters.mu1_mode_1,\r
-                       parameters.mu2_mode_1,\r
-                       parameters.mu3_mode_1}),\r
-            alpha_mode_1({parameters.alpha1_mode_1,\r
-                          parameters.alpha2_mode_1,\r
-                          parameters.alpha3_mode_1}),\r
-            viscosity_mode_1(parameters.viscosity_mode_1),\r
-            Cinv_v_1(Physics::Elasticity::StandardTensors<dim>::I),\r
-            Cinv_v_1_converged(Physics::Elasticity::StandardTensors<dim>::I)\r
-            {}\r
-            virtual ~visco_Ogden()\r
-            {}\r
-\r
-          void\r
-          update_internal_equilibrium( const Tensor<2, dim, NumberType> &F ) override\r
-          {\r
-              Material_Hyperelastic < dim, NumberType >::update_internal_equilibrium(F);\r
-\r
-              this->Cinv_v_1 = this->Cinv_v_1_converged;\r
-              SymmetricTensor<2, dim, NumberType> B_e_1_tr = symmetrize(F * this->Cinv_v_1 * transpose(F));\r
-\r
-              const std::array< std::pair< NumberType, Tensor< 1, dim, NumberType > >, dim >\r
-                eigen_B_e_1_tr = eigenvectors(B_e_1_tr, this->eigen_solver);\r
-\r
-              Tensor< 1, dim, NumberType > lambdas_e_1_tr;\r
-              Tensor< 1, dim, NumberType > epsilon_e_1_tr;\r
-              for (int a = 0; a < dim; ++a)\r
-              {\r
-                  lambdas_e_1_tr[a] = std::sqrt(eigen_B_e_1_tr[a].first);\r
-                  epsilon_e_1_tr[a] = std::log(lambdas_e_1_tr[a]);\r
-              }\r
-\r
-             const double tolerance = 1e-8;\r
-             double residual_check = tolerance*10.0;\r
-             Tensor< 1, dim, NumberType > residual;\r
-             Tensor< 2, dim, NumberType > tangent;\r
-             static const SymmetricTensor< 2, dim, double> I(Physics::Elasticity::StandardTensors<dim>::I);\r
-             NumberType J_e_1 = std::sqrt(determinant(B_e_1_tr));\r
-\r
-             std::vector<NumberType> lambdas_e_1_iso(dim);\r
-             SymmetricTensor<2, dim, NumberType> B_e_1;\r
-             int iteration = 0;\r
-\r
-             Tensor< 1, dim, NumberType > lambdas_e_1;\r
-             Tensor< 1, dim, NumberType > epsilon_e_1;\r
-             epsilon_e_1 = epsilon_e_1_tr;\r
-\r
-              while(residual_check > tolerance)\r
-              {\r
-                  NumberType aux_J_e_1 = 1.0;\r
-                  for (unsigned int a = 0; a < dim; ++a)\r
-                  {\r
-                      lambdas_e_1[a] = std::exp(epsilon_e_1[a]);\r
-                      aux_J_e_1 *= lambdas_e_1[a];\r
-                  }\r
-\r
-                  J_e_1 = aux_J_e_1;\r
-\r
-                  for (unsigned int a = 0; a < dim; ++a)\r
-                      lambdas_e_1_iso[a] = lambdas_e_1[a]*std::pow(J_e_1,-1.0/dim);\r
-\r
-                  for (unsigned int a = 0; a < dim; ++a)\r
-                  {\r
-                      residual[a] = get_beta_mode_1(lambdas_e_1_iso, a);\r
-                      residual[a] *= this->time.get_delta_t()/(2.0*viscosity_mode_1);\r
-                      residual[a] += epsilon_e_1[a];\r
-                      residual[a] -= epsilon_e_1_tr[a];\r
-\r
-                      for (unsigned int b = 0; b < dim; ++b)\r
-                      {\r
-                          tangent[a][b]  = get_gamma_mode_1(lambdas_e_1_iso, a, b);\r
-                          tangent[a][b] *= this->time.get_delta_t()/(2.0*viscosity_mode_1);\r
-                          tangent[a][b] += I[a][b];\r
-                      }\r
-\r
-                  }\r
-                  epsilon_e_1 -= invert(tangent)*residual;\r
-\r
-                  residual_check = 0.0;\r
-                  for (unsigned int a = 0; a < dim; ++a)\r
-                  {\r
-                      if ( std::abs(residual[a]) > residual_check)\r
-                          residual_check = std::abs(Tensor<0,dim,double>(residual[a]));\r
-                  }\r
-                  iteration += 1;\r
-                  if (iteration > 15 )\r
-                      AssertThrow(false, ExcMessage("No convergence in local Newton iteration for the "\r
-                                                    "viscoelastic exponential time integration algorithm."));\r
-              }\r
-\r
-              NumberType aux_J_e_1 = 1.0;\r
-              for (unsigned int a = 0; a < dim; ++a)\r
-              {\r
-                  lambdas_e_1[a] = std::exp(epsilon_e_1[a]);\r
-                  aux_J_e_1 *= lambdas_e_1[a];\r
-              }\r
-              J_e_1 = aux_J_e_1;\r
-\r
-              for (unsigned int a = 0; a < dim; ++a)\r
-                  lambdas_e_1_iso[a] = lambdas_e_1[a]*std::pow(J_e_1,-1.0/dim);\r
-\r
-              for (unsigned int a = 0; a < dim; ++a)\r
-              {\r
-                  SymmetricTensor<2, dim, NumberType>\r
-                  B_e_1_aux = symmetrize(outer_product(eigen_B_e_1_tr[a].second,eigen_B_e_1_tr[a].second));\r
-                  B_e_1_aux *= lambdas_e_1[a] * lambdas_e_1[a];\r
-                  B_e_1 += B_e_1_aux;\r
-              }\r
-\r
-              Tensor<2, dim, NumberType>Cinv_v_1_AD = symmetrize(invert(F) * B_e_1 * invert(transpose(F)));\r
-\r
-              this->tau_neq_1 = 0;\r
-              for (unsigned int a = 0; a < dim; ++a)\r
-              {\r
-                  SymmetricTensor<2, dim, NumberType>\r
-                  tau_neq_1_aux = symmetrize(outer_product(eigen_B_e_1_tr[a].second,eigen_B_e_1_tr[a].second));\r
-                  tau_neq_1_aux *=  get_beta_mode_1(lambdas_e_1_iso, a);\r
-                  this->tau_neq_1 += tau_neq_1_aux;\r
-              }\r
-\r
-              // Store history\r
-              for (unsigned int a = 0; a < dim; ++a)\r
-                  for (unsigned int b = 0; b < dim; ++b)\r
-                      this->Cinv_v_1[a][b]= Tensor<0,dim,double>(Cinv_v_1_AD[a][b]);\r
-          }\r
-\r
-          void update_end_timestep() override\r
-          {\r
-              Material_Hyperelastic < dim, NumberType >::update_end_timestep();\r
-              this->Cinv_v_1_converged = this->Cinv_v_1;\r
-          }\r
-\r
-           double get_viscous_dissipation() const override\r
-           {\r
-               NumberType dissipation_term = get_tau_E_neq() * get_tau_E_neq(); //Double contract the two SymmetricTensor\r
-               dissipation_term /= (2*viscosity_mode_1);\r
-\r
-               return dissipation_term.val();\r
-           }\r
-\r
-        protected:\r
-          std::vector<double> mu_infty;\r
-          std::vector<double> alpha_infty;\r
-          std::vector<double> mu_mode_1;\r
-          std::vector<double> alpha_mode_1;\r
-          double viscosity_mode_1;\r
-          SymmetricTensor<2, dim, double> Cinv_v_1;\r
-          SymmetricTensor<2, dim, double> Cinv_v_1_converged;\r
-          SymmetricTensor<2, dim, NumberType> tau_neq_1;\r
-\r
-          SymmetricTensor<2, dim, NumberType>\r
-          get_tau_E_base(const Tensor<2,dim, NumberType> &F) const override\r
-          {\r
-              return ( get_tau_E_neq() + get_tau_E_eq(F) );\r
-          }\r
-\r
-          SymmetricTensor<2, dim, NumberType>\r
-          get_tau_E_eq(const Tensor<2,dim, NumberType> &F) const\r
-          {\r
-            const SymmetricTensor<2, dim, NumberType> B = symmetrize(F * transpose(F));\r
-\r
-            std::array< std::pair< NumberType, Tensor< 1, dim, NumberType > >, dim > eigen_B;\r
-            eigen_B = eigenvectors(B, this->eigen_solver);\r
-\r
-            SymmetricTensor<2, dim, NumberType>  tau;\r
-            static const SymmetricTensor< 2, dim, double>\r
-              I (Physics::Elasticity::StandardTensors<dim>::I);\r
-\r
-            for (unsigned int i = 0; i < 3; ++i)\r
-            {\r
-                for (unsigned int A = 0; A < dim; ++A)\r
-                {\r
-                    SymmetricTensor<2, dim, NumberType>  tau_aux1 = symmetrize(\r
-                          outer_product(eigen_B[A].second,eigen_B[A].second));\r
-                    tau_aux1 *= mu_infty[i]*std::pow(eigen_B[A].first, (alpha_infty[i]/2.) );\r
-                    tau += tau_aux1;\r
-                }\r
-                SymmetricTensor<2, dim, NumberType>  tau_aux2 (I);\r
-                tau_aux2 *= mu_infty[i];\r
-                tau -= tau_aux2;\r
-            }\r
-            return tau;\r
-          }\r
-\r
-          SymmetricTensor<2, dim, NumberType>\r
-          get_tau_E_neq() const\r
-          {\r
-              return tau_neq_1;\r
-          }\r
-\r
-          NumberType\r
-          get_beta_mode_1(std::vector< NumberType > &lambda, const int &A) const\r
-          {\r
-              NumberType beta = 0.0;\r
-\r
-              for (unsigned int i = 0; i < 3; ++i) //3rd-order Ogden model\r
-              {\r
-\r
-                  NumberType aux = 0.0;\r
-                  for (int p = 0; p < dim; ++p)\r
-                      aux += std::pow(lambda[p],alpha_mode_1[i]);\r
-\r
-                  aux *= -1.0/dim;\r
-                  aux += std::pow(lambda[A], alpha_mode_1[i]);\r
-                  aux *= mu_mode_1[i];\r
-\r
-                  beta  += aux;\r
-              }\r
-              return beta;\r
-          }\r
-\r
-          NumberType\r
-          get_gamma_mode_1(std::vector< NumberType > &lambda,\r
-                           const int                 &A,\r
-                           const int                 &B       ) const\r
-          {\r
-              NumberType gamma = 0.0;\r
-\r
-              if (A==B)\r
-              {\r
-                  for (unsigned int i = 0; i < 3; ++i)\r
-                  {\r
-                      NumberType aux = 0.0;\r
-                      for (int p = 0; p < dim; ++p)\r
-                          aux += std::pow(lambda[p],alpha_mode_1[i]);\r
-\r
-                      aux *= 1.0/(dim*dim);\r
-                      aux += 1.0/dim * std::pow(lambda[A], alpha_mode_1[i]);\r
-                      aux *= mu_mode_1[i]*alpha_mode_1[i];\r
-\r
-                      gamma += aux;\r
-                  }\r
-              }\r
-              else\r
-              {\r
-                  for (unsigned int i = 0; i < 3; ++i)\r
-                  {\r
-                      NumberType aux = 0.0;\r
-                      for (int p = 0; p < dim; ++p)\r
-                          aux += std::pow(lambda[p],alpha_mode_1[i]);\r
-\r
-                      aux *= 1.0/(dim*dim);\r
-                      aux -= 1.0/dim * std::pow(lambda[A], alpha_mode_1[i]);\r
-                      aux -= 1.0/dim * std::pow(lambda[B], alpha_mode_1[i]);\r
-                      aux *= mu_mode_1[i]*alpha_mode_1[i];\r
-\r
-                      gamma += aux;\r
-                  }\r
-              }\r
-\r
-              return gamma;\r
-          }\r
-    };\r
-\r
-\r
-// @sect3{Constitutive equation for the fluid component of the biphasic material}\r
-// We consider two slightly different definitions to define the seepage velocity with a Darcy-like law.\r
-// Ehlers & Eipper 1999, doi:10.1023/A:1006565509095\r
-// Markert 2007, doi:10.1007/s11242-007-9107-6\r
-// The selection of one or another is made by the user via the parameters file.\r
-    template <int dim, typename NumberType = Sacado::Fad::DFad<double> >\r
-    class Material_Darcy_Fluid\r
-    {\r
-       public:\r
-         Material_Darcy_Fluid(const Parameters::AllParameters &parameters)\r
-         :\r
-         fluid_type(parameters.fluid_type),\r
-         n_OS(parameters.solid_vol_frac),\r
-         initial_intrinsic_permeability(parameters.init_intrinsic_perm),\r
-         viscosity_FR(parameters.viscosity_FR),\r
-         initial_darcy_coefficient(parameters.init_darcy_coef),\r
-         weight_FR(parameters.weight_FR),\r
-         kappa_darcy(parameters.kappa_darcy),\r
-         gravity_term(parameters.gravity_term),\r
-         density_FR(parameters.density_FR),\r
-         gravity_direction(parameters.gravity_direction),\r
-         gravity_value(parameters.gravity_value)\r
-         {\r
-           Assert(kappa_darcy >= 0, ExcInternalError());\r
-         }\r
-         ~Material_Darcy_Fluid()\r
-         {}\r
-\r
-         Tensor<1, dim, NumberType> get_seepage_velocity_current\r
-                             (const Tensor<2,dim, NumberType> &F,\r
-                              const Tensor<1,dim, NumberType> &grad_p_fluid) const\r
-         {\r
-             const NumberType det_F = determinant(F);\r
-             Assert(det_F > 0.0, ExcInternalError());\r
-\r
-             Tensor<2, dim, NumberType> permeability_term;\r
-\r
-             if (fluid_type == "Markert")\r
-                 permeability_term = get_instrinsic_permeability_current(F) / viscosity_FR;\r
-\r
-             else if (fluid_type == "Ehlers")\r
-                 permeability_term = get_darcy_flow_current(F) / weight_FR;\r
-\r
-             else\r
-                 AssertThrow(false, ExcMessage(\r
-                   "Material_Darcy_Fluid --> Only Markert "\r
-                   "and Ehlers formulations have been implemented."));\r
-\r
-             return ( -1.0 * permeability_term * det_F\r
-                      * (grad_p_fluid - get_body_force_FR_current()) );\r
-         }\r
-\r
-         double get_porous_dissipation(const Tensor<2,dim, NumberType> &F,\r
-                                       const Tensor<1,dim, NumberType> &grad_p_fluid) const\r
-         {\r
-             NumberType dissipation_term;\r
-             Tensor<1, dim, NumberType> seepage_velocity;\r
-             Tensor<2, dim, NumberType> permeability_term;\r
-\r
-             const NumberType det_F = determinant(F);\r
-             Assert(det_F > 0.0, ExcInternalError());\r
-\r
-             if (fluid_type == "Markert")\r
-             {\r
-                 permeability_term = get_instrinsic_permeability_current(F) / viscosity_FR;\r
-                 seepage_velocity = get_seepage_velocity_current(F,grad_p_fluid);\r
-             }\r
-             else if (fluid_type == "Ehlers")\r
-             {\r
-                 permeability_term = get_darcy_flow_current(F) / weight_FR;\r
-                 seepage_velocity = get_seepage_velocity_current(F,grad_p_fluid);\r
-             }\r
-             else\r
-                 AssertThrow(false, ExcMessage(\r
-                   "Material_Darcy_Fluid --> Only Markert and Ehlers "\r
-                   "formulations have been implemented."));\r
-\r
-             dissipation_term = ( invert(permeability_term) * seepage_velocity ) * seepage_velocity;\r
-             dissipation_term *= 1.0/(det_F*det_F);\r
-             return Tensor<0,dim,double>(dissipation_term);\r
-         }\r
-\r
-       protected:\r
-         const std::string  fluid_type;\r
-         const double n_OS;\r
-         const double initial_intrinsic_permeability;\r
-         const double viscosity_FR;\r
-         const double initial_darcy_coefficient;\r
-         const double weight_FR;\r
-         const double kappa_darcy;\r
-         const bool   gravity_term;\r
-         const double density_FR;\r
-         const int    gravity_direction;\r
-         const double    gravity_value;\r
-\r
-         Tensor<2, dim, NumberType>\r
-         get_instrinsic_permeability_current(const Tensor<2,dim, NumberType> &F) const\r
-         {\r
-           static const SymmetricTensor< 2, dim, double>\r
-               I (Physics::Elasticity::StandardTensors<dim>::I);\r
-           const Tensor<2, dim, NumberType> initial_instrinsic_permeability_tensor\r
-               = Tensor<2, dim, double>(initial_intrinsic_permeability * I);\r
-\r
-           const NumberType det_F = determinant(F);\r
-           Assert(det_F > 0.0, ExcInternalError());\r
-\r
-           const NumberType fraction = (det_F - n_OS)/(1 - n_OS);\r
-           return ( NumberType (std::pow(fraction, kappa_darcy))\r
-                     * initial_instrinsic_permeability_tensor );\r
-         }\r
-\r
-         Tensor<2, dim, NumberType>\r
-         get_darcy_flow_current(const Tensor<2,dim, NumberType> &F) const\r
-         {\r
-           static const SymmetricTensor< 2, dim, double>\r
-              I (Physics::Elasticity::StandardTensors<dim>::I);\r
-           const Tensor<2, dim, NumberType> initial_darcy_flow_tensor\r
-              = Tensor<2, dim, double>(initial_darcy_coefficient * I);\r
-\r
-           const NumberType det_F = determinant(F);\r
-           Assert(det_F > 0.0, ExcInternalError());\r
-\r
-           const NumberType fraction = (1.0 - (n_OS / det_F) )/(1.0 - n_OS);\r
-           return ( NumberType (std::pow(fraction, kappa_darcy))\r
-                     * initial_darcy_flow_tensor);\r
-         }\r
-\r
-        Tensor<1, dim, NumberType>\r
-        get_body_force_FR_current() const\r
-        {\r
-            Tensor<1, dim, NumberType> body_force_FR_current;\r
-\r
-            if (gravity_term == true)\r
-            {\r
-               Tensor<1, dim, NumberType> gravity_vector;\r
-               gravity_vector[gravity_direction] = gravity_value;\r
-               body_force_FR_current = density_FR * gravity_vector;\r
-            }\r
-            return body_force_FR_current;\r
-        }\r
-    };\r
-\r
-// @sect3{Quadrature point history}\r
-// As seen in step-18, the <code> PointHistory </code> class offers a method\r
-// for storing data at the quadrature points.  Here each quadrature point\r
-// holds a pointer to a material description.  Thus, different material models\r
-// can be used in different regions of the domain.  Among other data, we\r
-// choose to store the ``extra" Kirchhoff stress $\boldsymbol{\tau}_E$ and\r
-// the dissipation values $\mathcal{D}_p$ and $\mathcal{D}_v$.\r
-    template <int dim, typename NumberType = Sacado::Fad::DFad<double> > //double>\r
-    class PointHistory\r
-    {\r
-        public:\r
-            PointHistory()\r
-            {}\r
-\r
-            virtual ~PointHistory()\r
-            {}\r
-\r
-            void setup_lqp (const Parameters::AllParameters &parameters,\r
-                            const Time                      &time)\r
-            {\r
-                if (parameters.mat_type == "Neo-Hooke")\r
-                    solid_material.reset(new NeoHooke<dim,NumberType>(parameters,time));\r
-                else if (parameters.mat_type == "Ogden")\r
-                    solid_material.reset(new Ogden<dim,NumberType>(parameters,time));\r
-                else if (parameters.mat_type == "visco-Ogden")\r
-                    solid_material.reset(new visco_Ogden<dim,NumberType>(parameters,time));\r
-                else\r
-                    Assert (false, ExcMessage("Material type not implemented"));\r
-\r
-                fluid_material.reset(new Material_Darcy_Fluid<dim,NumberType>(parameters));\r
-            }\r
-\r
-            SymmetricTensor<2, dim, NumberType>\r
-            get_tau_E(const Tensor<2, dim, NumberType> &F) const\r
-            {\r
-                return solid_material->get_tau_E(F);\r
-            }\r
-\r
-            SymmetricTensor<2, dim, NumberType>\r
-            get_Cauchy_E(const Tensor<2, dim, NumberType> &F) const\r
-            {\r
-                return solid_material->get_Cauchy_E(F);\r
-            }\r
-\r
-            double\r
-            get_converged_det_F() const\r
-            {\r
-              return  solid_material->get_converged_det_F();\r
-            }\r
-\r
-            void\r
-            update_end_timestep()\r
-            {\r
-                solid_material->update_end_timestep();\r
-            }\r
-\r
-            void\r
-            update_internal_equilibrium(const Tensor<2, dim, NumberType> &F )\r
-            {\r
-                solid_material->update_internal_equilibrium(F);\r
-            }\r
-\r
-            double\r
-            get_viscous_dissipation() const\r
-            {\r
-                return solid_material->get_viscous_dissipation();\r
-            }\r
-\r
-            Tensor<1,dim, NumberType>\r
-            get_seepage_velocity_current (const Tensor<2,dim, NumberType> &F,\r
-                                          const Tensor<1,dim, NumberType> &grad_p_fluid) const\r
-             {\r
-                 return fluid_material->get_seepage_velocity_current(F, grad_p_fluid);\r
-             }\r
-\r
-            double\r
-            get_porous_dissipation(const Tensor<2,dim, NumberType> &F,\r
-                                   const Tensor<1,dim, NumberType> &grad_p_fluid) const\r
-            {\r
-                return fluid_material->get_porous_dissipation(F, grad_p_fluid);\r
-            }\r
-\r
-            Tensor<1, dim, NumberType>\r
-            get_overall_body_force (const Tensor<2,dim, NumberType> &F,\r
-                                    const Parameters::AllParameters &parameters) const\r
-            {\r
-                Tensor<1, dim, NumberType> body_force;\r
-\r
-                if (parameters.gravity_term == true)\r
-                {\r
-                    const NumberType det_F_AD = determinant(F);\r
-                    Assert(det_F_AD > 0.0, ExcInternalError());\r
-\r
-                    const NumberType overall_density_ref\r
-                        = parameters.density_SR * parameters.solid_vol_frac\r
-                          + parameters.density_FR\r
-                          * (det_F_AD - parameters.solid_vol_frac);\r
-\r
-                   Tensor<1, dim, NumberType> gravity_vector;\r
-                   gravity_vector[parameters.gravity_direction] = parameters.gravity_value;\r
-                   body_force = overall_density_ref * gravity_vector;\r
-                }\r
-\r
-                return body_force;\r
-            }\r
-        private:\r
-            std::shared_ptr< Material_Hyperelastic<dim, NumberType> > solid_material;\r
-            std::shared_ptr< Material_Darcy_Fluid<dim, NumberType> > fluid_material;\r
-    };\r
-\r
-// @sect3{Nonlinear poro-viscoelastic solid}\r
-// The Solid class is the central class as it represents the problem at hand:\r
-// the nonlinear poro-viscoelastic solid\r
-    template <int dim>\r
-    class Solid\r
-    {\r
-          public:\r
-            Solid(const Parameters::AllParameters &parameters);\r
-            virtual ~Solid();\r
-            void run();\r
-\r
-          protected:\r
-            using ADNumberType = Sacado::Fad::DFad<double>;\r
-\r
-            std::ofstream outfile;\r
-            std::ofstream pointfile;\r
-\r
-            struct PerTaskData_ASM;\r
-            template<typename NumberType = double> struct ScratchData_ASM;\r
-\r
-            //Generate mesh\r
-            virtual void make_grid() = 0;\r
-\r
-            //Define points for post-processing\r
-            virtual void define_tracked_vertices(std::vector<Point<dim> > &tracked_vertices) = 0;\r
-\r
-            //Set up the finite element system to be solved:\r
-            void system_setup(TrilinosWrappers::MPI::BlockVector &solution_delta_OUT);\r
-\r
-            //Extract sub-blocks from the global matrix\r
-            void determine_component_extractors();\r
-\r
-            // Several functions to assemble the system and right hand side matrices using multithreading.\r
-            void assemble_system\r
-                  (const TrilinosWrappers::MPI::BlockVector &solution_delta_OUT );\r
-            void assemble_system_one_cell\r
-                  (const typename DoFHandler<dim>::active_cell_iterator &cell,\r
-                   ScratchData_ASM<ADNumberType> &scratch,\r
-                   PerTaskData_ASM &data) const;\r
-            void copy_local_to_global_system(const PerTaskData_ASM &data);\r
-\r
-            // Define boundary conditions\r
-            virtual void make_constraints(const int &it_nr);\r
-            virtual void make_dirichlet_constraints(AffineConstraints<double> &constraints) = 0;\r
-            virtual Tensor<1,dim> get_neumann_traction\r
-                   (const types::boundary_id &boundary_id,\r
-                    const Point<dim>         &pt,\r
-                    const Tensor<1,dim>      &N) const = 0;\r
-            virtual double get_prescribed_fluid_flow\r
-                   (const types::boundary_id &boundary_id,\r
-                    const Point<dim>         &pt) const = 0;\r
-            virtual types::boundary_id\r
-                     get_reaction_boundary_id_for_output () const = 0;\r
-            virtual std::pair<types::boundary_id,types::boundary_id>\r
-                     get_drained_boundary_id_for_output () const = 0;\r
-            virtual std::vector<double> get_dirichlet_load\r
-                    (const types::boundary_id   &boundary_id,\r
-                     const int                  &direction) const = 0;\r
-\r
-            // Create and update the quadrature points.\r
-            void setup_qph();\r
-\r
-            //Solve non-linear system using a Newton-Raphson scheme\r
-            void solve_nonlinear_timestep(TrilinosWrappers::MPI::BlockVector &solution_delta_OUT);\r
-\r
-            //Solve the linearized equations using a direct solver\r
-            void solve_linear_system ( TrilinosWrappers::MPI::BlockVector &newton_update_OUT);\r
-\r
-            //Retrieve the  solution\r
-            TrilinosWrappers::MPI::BlockVector\r
-            get_total_solution(const TrilinosWrappers::MPI::BlockVector &solution_delta_IN) const;\r
-\r
-            // Store the converged values of the internal variables at the end of each timestep\r
-            void update_end_timestep();\r
-\r
-            //Post-processing and writing data to files\r
-            void output_results_to_vtu(const unsigned int timestep,\r
-                                       const double current_time,\r
-                                       TrilinosWrappers::MPI::BlockVector solution) const;\r
-            void output_results_to_plot(const unsigned int timestep,\r
-                                        const double current_time,\r
-                                        TrilinosWrappers::MPI::BlockVector solution,\r
-                                        std::vector<Point<dim> > &tracked_vertices,\r
-                                        std::ofstream &pointfile) const;\r
-\r
-            // Headers and footer for the output files\r
-            void print_console_file_header( std::ofstream &outfile) const;\r
-            void print_plot_file_header(std::vector<Point<dim> > &tracked_vertices,\r
-                                        std::ofstream &pointfile) const;\r
-            void print_console_file_footer(std::ofstream &outfile) const;\r
-            void print_plot_file_footer( std::ofstream &pointfile) const;\r
-\r
-            // For parallel communication\r
-            MPI_Comm                         mpi_communicator;\r
-            const unsigned int               n_mpi_processes;\r
-            const unsigned int               this_mpi_process;\r
-            mutable ConditionalOStream       pcout;\r
-\r
-            // A collection of the parameters used to describe the problem setup\r
-            const Parameters::AllParameters &parameters;\r
-\r
-            // Declare an instance of dealii Triangulation class (mesh)\r
-            parallel::shared::Triangulation<dim>  triangulation;\r
-\r
-            // Keep track of the current time and the time spent evaluating certain functions\r
-            Time          time;\r
-            TimerOutput   timerconsole;\r
-            TimerOutput   timerfile;\r
-\r
-            // A storage object for quadrature point information.\r
-            CellDataStorage<typename Triangulation<dim>::cell_iterator, PointHistory<dim,ADNumberType> > quadrature_point_history;\r
-\r
-            //Integers to store polynomial degree (needed for output)\r
-            const unsigned int  degree_displ;\r
-            const unsigned int  degree_pore;\r
-\r
-            //Declare an instance of dealii FESystem class (finite element definition)\r
-            const FESystem<dim> fe;\r
-\r
-            //Declare an instance of dealii DoFHandler class (assign DoFs to mesh)\r
-            DoFHandler<dim>     dof_handler_ref;\r
-\r
-            //Integer to store DoFs per element (this value will be used often)\r
-            const unsigned int  dofs_per_cell;\r
-\r
-            //Declare an instance of dealii Extractor objects used to retrieve information from the solution vectors\r
-            //We will use "u_fe" and "p_fluid_fe"as subscript in operator [] expressions on FEValues and FEFaceValues\r
-            //objects to extract the components of the displacement vector and fluid pressure, respectively.\r
-            const FEValuesExtractors::Vector u_fe;\r
-            const FEValuesExtractors::Scalar p_fluid_fe;\r
-\r
-            // Description of how the block-system is arranged. There are 3 blocks:\r
-            //   0 - vector DOF displacements u\r
-            //   1 - scalar DOF fluid pressure p_fluid\r
-            static const unsigned int  n_blocks = 2;\r
-            static const unsigned int  n_components = dim+1;\r
-            static const unsigned int  first_u_component = 0;\r
-            static const unsigned int  p_fluid_component = dim;\r
-\r
-            enum\r
-            {\r
-              u_block = 0,\r
-              p_fluid_block = 1\r
-            };\r
-\r
-            // Extractors\r
-            const FEValuesExtractors::Scalar x_displacement;\r
-            const FEValuesExtractors::Scalar y_displacement;\r
-            const FEValuesExtractors::Scalar z_displacement;\r
-            const FEValuesExtractors::Scalar pressure;\r
-\r
-            // Block data\r
-            std::vector<unsigned int> block_component;\r
-\r
-            // DoF index data\r
-            std::vector<IndexSet> all_locally_owned_dofs;\r
-            IndexSet locally_owned_dofs;\r
-            IndexSet locally_relevant_dofs;\r
-            std::vector<IndexSet> locally_owned_partitioning;\r
-            std::vector<IndexSet> locally_relevant_partitioning;\r
-\r
-            std::vector<types::global_dof_index>   dofs_per_block;\r
-            std::vector<types::global_dof_index>   element_indices_u;\r
-            std::vector<types::global_dof_index>   element_indices_p_fluid;\r
-\r
-            //Declare an instance of dealii QGauss class (The Gauss-Legendre family of quadrature rules for numerical integration)\r
-            //Gauss Points in element, with n quadrature points (in each space direction <dim> )\r
-            const QGauss<dim>                qf_cell;\r
-            //Gauss Points on element faces (used for definition of BCs)\r
-            const QGauss<dim - 1>            qf_face;\r
-            //Integer to store num GPs per element (this value will be used often)\r
-            const unsigned int               n_q_points;\r
-            //Integer to store num GPs per face (this value will be used often)\r
-            const unsigned int               n_q_points_f;\r
-\r
-            //Declare an instance of dealii AffineConstraints class (linear constraints on DoFs due to hanging nodes or BCs)\r
-            AffineConstraints<double>        constraints;\r
-\r
-            //Declare an instance of dealii classes necessary for FE system set-up and assembly\r
-            //Store elements of tangent matrix (indicated by SparsityPattern class) as sparse matrix (more efficient)\r
-            TrilinosWrappers::BlockSparseMatrix tangent_matrix;\r
-            TrilinosWrappers::BlockSparseMatrix tangent_matrix_preconditioner;\r
-            //Right hand side vector of forces\r
-            TrilinosWrappers::MPI::BlockVector  system_rhs;\r
-            //Total displacement values + pressure (accumulated solution to FE system)\r
-            TrilinosWrappers::MPI::BlockVector  solution_n;\r
-\r
-            // Non-block system for the direct solver. We will copy the block system into these to solve the linearized system of equations.\r
-            TrilinosWrappers::SparseMatrix tangent_matrix_nb;\r
-            TrilinosWrappers::MPI::Vector  system_rhs_nb;\r
-\r
-            //We define variables to store norms and update norms and normalisation factors.\r
-            struct Errors\r
-            {\r
-              Errors()\r
-                :\r
-                norm(1.0), u(1.0), p_fluid(1.0)\r
-              {}\r
-\r
-              void reset()\r
-              {\r
-                norm = 1.0;\r
-                u = 1.0;\r
-                p_fluid = 1.0;\r
-              }\r
-              void normalise(const Errors &rhs)\r
-              {\r
-                if (rhs.norm != 0.0)\r
-                  norm /= rhs.norm;\r
-                if (rhs.u != 0.0)\r
-                  u /= rhs.u;\r
-                if (rhs.p_fluid != 0.0)\r
-                  p_fluid /= rhs.p_fluid;\r
-              }\r
-\r
-              double norm, u, p_fluid;\r
-            };\r
-\r
-            //Declare several instances of the "Error" structure\r
-            Errors error_residual, error_residual_0, error_residual_norm, error_update,\r
-                   error_update_0, error_update_norm;\r
-\r
-            // Methods to calculate error measures\r
-            void get_error_residual(Errors &error_residual_OUT);\r
-            void get_error_update\r
-                 (const TrilinosWrappers::MPI::BlockVector &newton_update_IN,\r
-                  Errors                                   &error_update_OUT);\r
-\r
-            // Print information to screen\r
-            void print_conv_header();\r
-            void print_conv_footer();\r
-\r
-//NOTE: In all functions, we pass by reference (&), so these functions work on the original copy (not a clone copy),\r
-//      modifying the input variables inside the functions will change them outside the function.\r
-    };\r
-\r
-// @sect3{Implementation of the <code>Solid</code> class}\r
-// @sect4{Public interface}\r
-// We initialise the Solid class using data extracted from the parameter file.\r
-    template <int dim>\r
-    Solid<dim>::Solid(const Parameters::AllParameters &parameters)\r
-        :\r
-        mpi_communicator(MPI_COMM_WORLD),\r
-        n_mpi_processes (Utilities::MPI::n_mpi_processes(mpi_communicator)),\r
-        this_mpi_process (Utilities::MPI::this_mpi_process(mpi_communicator)),\r
-        pcout(std::cout, this_mpi_process == 0),\r
-        parameters(parameters),\r
-        triangulation(mpi_communicator,Triangulation<dim>::maximum_smoothing),\r
-        time(parameters.end_time, parameters.delta_t),\r
-        timerconsole( mpi_communicator,\r
-                      pcout,\r
-                      TimerOutput::summary,\r
-                      TimerOutput::wall_times),\r
-        timerfile( mpi_communicator,\r
-                   outfile,\r
-                   TimerOutput::summary,\r
-                   TimerOutput::wall_times),\r
-        degree_displ(parameters.poly_degree_displ),\r
-        degree_pore(parameters.poly_degree_pore),\r
-        fe( FE_Q<dim>(parameters.poly_degree_displ), dim,\r
-            FE_Q<dim>(parameters.poly_degree_pore), 1 ),\r
-        dof_handler_ref(triangulation),\r
-        dofs_per_cell (fe.dofs_per_cell),\r
-        u_fe(first_u_component),\r
-        p_fluid_fe(p_fluid_component),\r
-        x_displacement(first_u_component),\r
-        y_displacement(first_u_component+1),\r
-        z_displacement(first_u_component+2),\r
-        pressure(p_fluid_component),\r
-        dofs_per_block(n_blocks),\r
-        qf_cell(parameters.quad_order),\r
-        qf_face(parameters.quad_order),\r
-        n_q_points (qf_cell.size()),\r
-        n_q_points_f (qf_face.size())\r
-        {\r
-         Assert(dim==3, ExcMessage("This problem only works in 3 space dimensions."));\r
-         determine_component_extractors();\r
-        }\r
-\r
-    //The class destructor simply clears the data held by the DOFHandler\r
-    template <int dim>\r
-    Solid<dim>::~Solid()\r
-    {\r
-        dof_handler_ref.clear();\r
-    }\r
-\r
-//Runs the 3D solid problem\r
-    template <int dim>\r
-    void Solid<dim>::run()\r
-    {\r
-          //The current solution increment is defined as a block vector to reflect the structure\r
-          //of the PDE system, with multiple solution components\r
-          TrilinosWrappers::MPI::BlockVector solution_delta;\r
-\r
-          //Open file\r
-          if (this_mpi_process == 0)\r
-          {\r
-              outfile.open("console-output.sol");\r
-              print_console_file_header(outfile);\r
-          }\r
-\r
-          //Generate mesh\r
-          make_grid();\r
-\r
-          //Assign DOFs and create the stiffness and right-hand-side force vector\r
-          system_setup(solution_delta);\r
-\r
-          //Define points for post-processing\r
-          std::vector<Point<dim> > tracked_vertices (2);\r
-          define_tracked_vertices(tracked_vertices);\r
-          std::vector<Point<dim>> reaction_force;\r
-\r
-          if (this_mpi_process == 0)\r
-          {\r
-              pointfile.open("data-for-gnuplot.sol");\r
-              print_plot_file_header(tracked_vertices, pointfile);\r
-          }\r
-\r
-          //Print results to output file\r
-          if (parameters.outfiles_requested == "true")\r
-          {\r
-                output_results_to_vtu(time.get_timestep(),\r
-                                      time.get_current(),\r
-                                      solution_n           );\r
-          }\r
-\r
-          output_results_to_plot(time.get_timestep(),\r
-                                 time.get_current(),\r
-                                 solution_n,\r
-                                 tracked_vertices,\r
-                                 pointfile);\r
-\r
-          //Increment time step (=load step)\r
-          //NOTE: In solving the quasi-static problem, the time becomes a loading parameter,\r
-          //i.e. we increase the loading linearly with time, making the two concepts interchangeable.\r
-          time.increment_time();\r
-\r
-          //Print information on screen\r
-          pcout << "\nSolver:";\r
-          pcout << "\n  CST     = make constraints";\r
-          pcout << "\n  ASM_SYS = assemble system";\r
-          pcout << "\n  SLV     = linear solver \n";\r
-\r
-          //Print information on file\r
-          outfile << "\nSolver:";\r
-          outfile << "\n  CST     = make constraints";\r
-          outfile << "\n  ASM_SYS = assemble system";\r
-          outfile << "\n  SLV     = linear solver \n";\r
-\r
-          while ( (time.get_end() - time.get_current()) > -1.0*parameters.tol_u )\r
-            {\r
-              //Initialize the current solution increment to zero\r
-              solution_delta = 0.0;\r
-\r
-              //Solve the non-linear system using a Newton-Rapshon scheme\r
-              solve_nonlinear_timestep(solution_delta);\r
-\r
-              //Add the computed solution increment to total solution\r
-              solution_n += solution_delta;\r
-\r
-              //Store the converged values of the internal variables\r
-              update_end_timestep();\r
-\r
-              //Output results\r
-              if (( (time.get_timestep()%parameters.timestep_output) == 0 )\r
-                   && (parameters.outfiles_requested == "true") )\r
-              {\r
-                      output_results_to_vtu(time.get_timestep(),\r
-                                            time.get_current(),\r
-                                            solution_n           );\r
-              }\r
-\r
-              output_results_to_plot(time.get_timestep(),\r
-                                     time.get_current(),\r
-                                     solution_n,\r
-                                     tracked_vertices,\r
-                                     pointfile);\r
-\r
-              //Increment the time step (=load step)\r
-              time.increment_time();\r
-            }\r
-\r
-          //Print the footers and close files\r
-          if (this_mpi_process == 0)\r
-          {\r
-              print_plot_file_footer(pointfile);\r
-              pointfile.close ();\r
-              print_console_file_footer(outfile);\r
-\r
-              //NOTE: ideally, we should close the outfile here [ >> outfile.close (); ]\r
-              //But if we do, then the timer output will not be printed. That is why we leave it open.\r
-          }\r
-    }\r
-\r
-// @sect4{Private interface}\r
-// We define the structures needed for parallelization with Threading Building Blocks (TBB)\r
-// Tangent matrix and right-hand side force vector assembly structures.\r
-// PerTaskData_ASM stores local contributions\r
-    template <int dim>\r
-    struct Solid<dim>::PerTaskData_ASM\r
-    {\r
-        FullMatrix<double>        cell_matrix;\r
-        Vector<double>            cell_rhs;\r
-        std::vector<types::global_dof_index> local_dof_indices;\r
-\r
-        PerTaskData_ASM(const unsigned int dofs_per_cell)\r
-          :\r
-          cell_matrix(dofs_per_cell, dofs_per_cell),\r
-          cell_rhs(dofs_per_cell),\r
-          local_dof_indices(dofs_per_cell)\r
-        {}\r
-\r
-        void reset()\r
-        {\r
-          cell_matrix = 0.0;\r
-          cell_rhs = 0.0;\r
-        }\r
-    };\r
-\r
-    // ScratchData_ASM stores larger objects used during the assembly\r
-    template <int dim>\r
-    template <typename NumberType>\r
-    struct Solid<dim>::ScratchData_ASM\r
-    {\r
-        const TrilinosWrappers::MPI::BlockVector &solution_total;\r
-\r
-        //Integration helper\r
-        FEValues<dim>     fe_values_ref;\r
-        FEFaceValues<dim> fe_face_values_ref;\r
-\r
-        // Quadrature point solution\r
-        std::vector<NumberType>                  local_dof_values;\r
-        std::vector<Tensor<2, dim, NumberType> > solution_grads_u_total;\r
-        std::vector<NumberType>                  solution_values_p_fluid_total;\r
-        std::vector<Tensor<1, dim, NumberType> > solution_grads_p_fluid_total;\r
-        std::vector<Tensor<1, dim, NumberType> > solution_grads_face_p_fluid_total;\r
-\r
-        //shape function values\r
-        std::vector<std::vector<Tensor<1,dim>>>          Nx;\r
-        std::vector<std::vector<double>>                 Nx_p_fluid;\r
-        //shape function gradients\r
-        std::vector<std::vector<Tensor<2,dim, NumberType>>>          grad_Nx;\r
-        std::vector<std::vector<SymmetricTensor<2,dim, NumberType>>> symm_grad_Nx;\r
-        std::vector<std::vector<Tensor<1,dim, NumberType>>>          grad_Nx_p_fluid;\r
-\r
-        ScratchData_ASM(const FiniteElement<dim> &fe_cell,\r
-                        const QGauss<dim> &qf_cell, const UpdateFlags uf_cell,\r
-                        const QGauss<dim - 1> & qf_face, const UpdateFlags uf_face,\r
-                        const TrilinosWrappers::MPI::BlockVector &solution_total    )\r
-          :\r
-          solution_total (solution_total),\r
-          fe_values_ref(fe_cell, qf_cell, uf_cell),\r
-          fe_face_values_ref(fe_cell, qf_face, uf_face),\r
-          local_dof_values(fe_cell.dofs_per_cell),\r
-          solution_grads_u_total(qf_cell.size()),\r
-          solution_values_p_fluid_total(qf_cell.size()),\r
-          solution_grads_p_fluid_total(qf_cell.size()),\r
-          solution_grads_face_p_fluid_total(qf_face.size()),\r
-          Nx(qf_cell.size(), std::vector<Tensor<1,dim>>(fe_cell.dofs_per_cell)),\r
-          Nx_p_fluid(qf_cell.size(), std::vector<double>(fe_cell.dofs_per_cell)),\r
-          grad_Nx(qf_cell.size(), std::vector<Tensor<2, dim, NumberType>>(fe_cell.dofs_per_cell)),\r
-          symm_grad_Nx(qf_cell.size(), std::vector<SymmetricTensor<2, dim, NumberType>> (fe_cell.dofs_per_cell)),\r
-          grad_Nx_p_fluid(qf_cell.size(), std::vector<Tensor<1, dim, NumberType>>(fe_cell.dofs_per_cell))\r
-        {}\r
-\r
-        ScratchData_ASM(const ScratchData_ASM &rhs)\r
-          :\r
-          solution_total (rhs.solution_total),\r
-          fe_values_ref(rhs.fe_values_ref.get_fe(),\r
-                        rhs.fe_values_ref.get_quadrature(),\r
-                        rhs.fe_values_ref.get_update_flags()),\r
-          fe_face_values_ref(rhs.fe_face_values_ref.get_fe(),\r
-                             rhs.fe_face_values_ref.get_quadrature(),\r
-                             rhs.fe_face_values_ref.get_update_flags()),\r
-          local_dof_values(rhs.local_dof_values),\r
-          solution_grads_u_total(rhs.solution_grads_u_total),\r
-          solution_values_p_fluid_total(rhs.solution_values_p_fluid_total),\r
-          solution_grads_p_fluid_total(rhs.solution_grads_p_fluid_total),\r
-          solution_grads_face_p_fluid_total(rhs.solution_grads_face_p_fluid_total),\r
-          Nx(rhs.Nx),\r
-          Nx_p_fluid(rhs.Nx_p_fluid),\r
-          grad_Nx(rhs.grad_Nx),\r
-          symm_grad_Nx(rhs.symm_grad_Nx),\r
-          grad_Nx_p_fluid(rhs.grad_Nx_p_fluid)\r
-        {}\r
-\r
-        void reset()\r
-        {\r
-          const unsigned int n_q_points = Nx_p_fluid.size();\r
-          const unsigned int n_dofs_per_cell = Nx_p_fluid[0].size();\r
-\r
-          Assert(local_dof_values.size() == n_dofs_per_cell, ExcInternalError());\r
-\r
-          for (unsigned int k = 0; k < n_dofs_per_cell; ++k)\r
-            {\r
-              local_dof_values[k] = 0.0;\r
-            }\r
-\r
-          Assert(solution_grads_u_total.size() == n_q_points, ExcInternalError());\r
-          Assert(solution_values_p_fluid_total.size() == n_q_points, ExcInternalError());\r
-          Assert(solution_grads_p_fluid_total.size() == n_q_points, ExcInternalError());\r
-\r
-          Assert(Nx.size() == n_q_points, ExcInternalError());\r
-          Assert(grad_Nx.size() == n_q_points, ExcInternalError());\r
-          Assert(symm_grad_Nx.size() == n_q_points, ExcInternalError());\r
-\r
-          for (unsigned int q_point = 0; q_point < n_q_points; ++q_point)\r
-            {\r
-              Assert( Nx[q_point].size() == n_dofs_per_cell, ExcInternalError());\r
-              Assert( grad_Nx[q_point].size() == n_dofs_per_cell, ExcInternalError());\r
-              Assert( symm_grad_Nx[q_point].size() == n_dofs_per_cell, ExcInternalError());\r
-\r
-              solution_grads_u_total[q_point] = 0.0;\r
-              solution_values_p_fluid_total[q_point] = 0.0;\r
-              solution_grads_p_fluid_total[q_point] = 0.0;\r
-\r
-              for (unsigned int k = 0; k < n_dofs_per_cell; ++k)\r
-                {\r
-                  Nx[q_point][k] = 0.0;\r
-                  Nx_p_fluid[q_point][k] = 0.0;\r
-                  grad_Nx[q_point][k] = 0.0;\r
-                  symm_grad_Nx[q_point][k] = 0.0;\r
-                  grad_Nx_p_fluid[q_point][k] = 0.0;\r
-                }\r
-            }\r
-\r
-          const unsigned int n_f_q_points = solution_grads_face_p_fluid_total.size();\r
-          Assert(solution_grads_face_p_fluid_total.size() == n_f_q_points, ExcInternalError());\r
-\r
-          for (unsigned int f_q_point = 0; f_q_point < n_f_q_points; ++f_q_point)\r
-              solution_grads_face_p_fluid_total[f_q_point] = 0.0;\r
-        }\r
-    };\r
-\r
-    //Define the boundary conditions on the mesh\r
-    template <int dim>\r
-    void Solid<dim>::make_constraints(const int &it_nr_IN)\r
-    {\r
-        pcout     << " CST " << std::flush;\r
-        outfile   << " CST " << std::flush;\r
-\r
-        if (it_nr_IN > 1) return;\r
-\r
-        const bool apply_dirichlet_bc = (it_nr_IN == 0);\r
-\r
-        if (apply_dirichlet_bc)\r
-        {\r
-          constraints.clear();\r
-          make_dirichlet_constraints(constraints);\r
-        }\r
-        else\r
-        {\r
-          for (unsigned int i=0; i<dof_handler_ref.n_dofs(); ++i)\r
-            if (constraints.is_inhomogeneously_constrained(i) == true)\r
-              constraints.set_inhomogeneity(i,0.0);\r
-        }\r
-        constraints.close();\r
-    }\r
-\r
-    //Set-up the FE system\r
-    template <int dim>\r
-    void Solid<dim>::system_setup(TrilinosWrappers::MPI::BlockVector &solution_delta_OUT)\r
-    {\r
-        timerconsole.enter_subsection("Setup system");\r
-        timerfile.enter_subsection("Setup system");\r
-\r
-        //Determine number of components per block\r
-        std::vector<unsigned int> block_component(n_components, u_block);\r
-        block_component[p_fluid_component] = p_fluid_block;\r
-\r
-        // The DOF handler is initialised and we renumber the grid in an efficient manner.\r
-        dof_handler_ref.distribute_dofs(fe);\r
-        DoFRenumbering::Cuthill_McKee(dof_handler_ref);\r
-        DoFRenumbering::component_wise(dof_handler_ref, block_component);\r
-\r
-        // Count the number of DoFs in each block\r
-        dofs_per_block = DoFTools::count_dofs_per_fe_block(dof_handler_ref, block_component);\r
-\r
-        // Setup the sparsity pattern and tangent matrix\r
-        all_locally_owned_dofs = DoFTools::locally_owned_dofs_per_subdomain (dof_handler_ref);\r
-        std::vector<IndexSet> all_locally_relevant_dofs\r
-        = DoFTools::locally_relevant_dofs_per_subdomain (dof_handler_ref);\r
-\r
-        locally_owned_dofs.clear();\r
-        locally_owned_partitioning.clear();\r
-        Assert(all_locally_owned_dofs.size() > this_mpi_process, ExcInternalError());\r
-        locally_owned_dofs = all_locally_owned_dofs[this_mpi_process];\r
-\r
-        locally_relevant_dofs.clear();\r
-        locally_relevant_partitioning.clear();\r
-        Assert(all_locally_relevant_dofs.size() > this_mpi_process, ExcInternalError());\r
-        locally_relevant_dofs = all_locally_relevant_dofs[this_mpi_process];\r
-\r
-        locally_owned_partitioning.reserve(n_blocks);\r
-        locally_relevant_partitioning.reserve(n_blocks);\r
-\r
-        for (unsigned int b=0; b<n_blocks; ++b)\r
-          {\r
-            const types::global_dof_index idx_begin\r
-            = std::accumulate(dofs_per_block.begin(),\r
-                              std::next(dofs_per_block.begin(),b), 0);\r
-            const types::global_dof_index idx_end\r
-            = std::accumulate(dofs_per_block.begin(),\r
-                              std::next(dofs_per_block.begin(),b+1), 0);\r
-            locally_owned_partitioning.push_back(locally_owned_dofs.get_view(idx_begin, idx_end));\r
-            locally_relevant_partitioning.push_back(locally_relevant_dofs.get_view(idx_begin, idx_end));\r
-          }\r
-\r
-        //Print information on screen\r
-        pcout  << "\nTriangulation:\n"\r
-               << "  Number of active cells: "\r
-               << triangulation.n_active_cells()\r
-               << " (by partition:";\r
-        for (unsigned int p=0; p<n_mpi_processes; ++p)\r
-          pcout  << (p==0 ? ' ' : '+')\r
-                 << (GridTools::count_cells_with_subdomain_association (triangulation,p));\r
-        pcout << ")"\r
-              << std::endl;\r
-        pcout << "  Number of degrees of freedom: "\r
-              << dof_handler_ref.n_dofs()\r
-              << " (by partition:";\r
-        for (unsigned int p=0; p<n_mpi_processes; ++p)\r
-          pcout  << (p==0 ? ' ' : '+')\r
-                 << (DoFTools::count_dofs_with_subdomain_association (dof_handler_ref,p));\r
-        pcout << ")"\r
-              << std::endl;\r
-        pcout   << "  Number of degrees of freedom per block: "\r
-            << "[n_u, n_p_fluid] = ["\r
-            << dofs_per_block[u_block]\r
-            << ", "\r
-            << dofs_per_block[p_fluid_block]\r
-            << "]"\r
-            << std::endl;\r
-\r
-        //Print information to file\r
-        outfile  << "\nTriangulation:\n"\r
-                 <<  "  Number of active cells: "\r
-                << triangulation.n_active_cells()\r
-                << " (by partition:";\r
-        for (unsigned int p=0; p<n_mpi_processes; ++p)\r
-          outfile << (p==0 ? ' ' : '+')\r
-                  << (GridTools::count_cells_with_subdomain_association (triangulation,p));\r
-        outfile << ")"\r
-                << std::endl;\r
-        outfile << "  Number of degrees of freedom: "\r
-                << dof_handler_ref.n_dofs()\r
-                << " (by partition:";\r
-        for (unsigned int p=0; p<n_mpi_processes; ++p)\r
-          outfile  << (p==0 ? ' ' : '+')\r
-                   << (DoFTools::count_dofs_with_subdomain_association (dof_handler_ref,p));\r
-        outfile << ")"\r
-                << std::endl;\r
-        outfile << "  Number of degrees of freedom per block: "\r
-            << "[n_u, n_p_fluid] = ["\r
-            << dofs_per_block[u_block]\r
-            << ", "\r
-            << dofs_per_block[p_fluid_block]\r
-            << "]"\r
-            << std::endl;\r
-\r
-        // We optimise the sparsity pattern to reflect this structure and prevent\r
-        // unnecessary data creation for the right-diagonal block components.\r
-        Table<2, DoFTools::Coupling> coupling(n_components, n_components);\r
-        for (unsigned int ii = 0; ii < n_components; ++ii)\r
-          for (unsigned int jj = 0; jj < n_components; ++jj)\r
-\r
-            //Identify "zero" matrix components of FE-system (The two components do not couple)\r
-            if (((ii == p_fluid_component) && (jj < p_fluid_component))\r
-                || ((ii < p_fluid_component) && (jj == p_fluid_component)) )\r
-              coupling[ii][jj] = DoFTools::none;\r
-\r
-            //The rest of components always couple\r
-            else\r
-              coupling[ii][jj] = DoFTools::always;\r
-\r
-        TrilinosWrappers::BlockSparsityPattern bsp (locally_owned_partitioning,\r
-                                                    mpi_communicator);\r
-\r
-        DoFTools::make_sparsity_pattern (dof_handler_ref, bsp, constraints,\r
-                                         false, this_mpi_process);\r
-        bsp.compress();\r
-\r
-        //Reinitialize the (sparse) tangent matrix with the given sparsity pattern.\r
-        tangent_matrix.reinit (bsp);\r
-\r
-        //Initialize the right hand side and solution vectors with number of DoFs\r
-        system_rhs.reinit(locally_owned_partitioning, mpi_communicator);\r
-        solution_n.reinit(locally_owned_partitioning, mpi_communicator);\r
-        solution_delta_OUT.reinit(locally_owned_partitioning, mpi_communicator);\r
-\r
-        // Non-block system\r
-        TrilinosWrappers::SparsityPattern sp (locally_owned_dofs,\r
-                                              mpi_communicator);\r
-        DoFTools::make_sparsity_pattern (dof_handler_ref, sp, constraints,\r
-                                         false, this_mpi_process);\r
-        sp.compress();\r
-        tangent_matrix_nb.reinit (sp);\r
-        system_rhs_nb.reinit(locally_owned_dofs, mpi_communicator);\r
-\r
-        //Set up the quadrature point history\r
-        setup_qph();\r
-\r
-        timerconsole.leave_subsection();\r
-        timerfile.leave_subsection();\r
-    }\r
-\r
-    //Component extractors: used to extract sub-blocks from the global matrix\r
-    //Description of which local element DOFs are attached to which block component\r
-    template <int dim>\r
-    void Solid<dim>::determine_component_extractors()\r
-    {\r
-        element_indices_u.clear();\r
-        element_indices_p_fluid.clear();\r
-\r
-        for (unsigned int k = 0; k < fe.dofs_per_cell; ++k)\r
-          {\r
-            const unsigned int k_group = fe.system_to_base_index(k).first.first;\r
-            if (k_group == u_block)\r
-              element_indices_u.push_back(k);\r
-            else if (k_group == p_fluid_block)\r
-              element_indices_p_fluid.push_back(k);\r
-            else\r
-              {\r
-                Assert(k_group <= p_fluid_block, ExcInternalError());\r
-              }\r
-          }\r
-    }\r
-\r
-    //Set-up quadrature point history (QPH) data objects\r
-    template <int dim>\r
-    void Solid<dim>::setup_qph()\r
-    {\r
-        pcout     << "\nSetting up quadrature point data..." << std::endl;\r
-        outfile   << "\nSetting up quadrature point data..." << std::endl;\r
-\r
-        //Create QPH data objects.\r
-        quadrature_point_history.initialize(triangulation.begin_active(),\r
-                                            triangulation.end(), n_q_points);\r
-\r
-        //Setup the initial quadrature point data using the info stored in parameters\r
-        FilteredIterator<typename DoFHandler<dim>::active_cell_iterator>\r
-        cell (IteratorFilters::LocallyOwnedCell(),\r
-              dof_handler_ref.begin_active()),\r
-        endc (IteratorFilters::LocallyOwnedCell(),\r
-              dof_handler_ref.end());\r
-        for (; cell!=endc; ++cell)\r
-          {\r
-            Assert(cell->is_locally_owned(), ExcInternalError());\r
-            Assert(cell->subdomain_id() == this_mpi_process, ExcInternalError());\r
-\r
-            const std::vector<std::shared_ptr<PointHistory<dim, ADNumberType> > >\r
-                lqph = quadrature_point_history.get_data(cell);\r
-            Assert(lqph.size() == n_q_points, ExcInternalError());\r
-\r
-            for (unsigned int q_point = 0; q_point < n_q_points; ++q_point)\r
-              lqph[q_point]->setup_lqp(parameters, time);\r
-          }\r
-    }\r
-\r
-    //Solve the non-linear system using a Newton-Raphson scheme\r
-    template <int dim>\r
-    void Solid<dim>::solve_nonlinear_timestep(TrilinosWrappers::MPI::BlockVector &solution_delta_OUT)\r
-    {\r
-        //Print the load step\r
-        pcout  << std::endl\r
-               << "\nTimestep "\r
-               << time.get_timestep()\r
-               << " @ "\r
-               << time.get_current()\r
-               << "s"\r
-               << std::endl;\r
-        outfile  << std::endl\r
-                 << "\nTimestep "\r
-                 << time.get_timestep()\r
-                 << " @ "\r
-                 << time.get_current()\r
-                 << "s"\r
-                 << std::endl;\r
-\r
-        //Declare newton_update vector (solution of a Newton iteration),\r
-        //which must have as many positions as global DoFs.\r
-        TrilinosWrappers::MPI::BlockVector newton_update\r
-            (locally_owned_partitioning, mpi_communicator);\r
-\r
-        //Reset the error storage objects\r
-        error_residual.reset();\r
-        error_residual_0.reset();\r
-        error_residual_norm.reset();\r
-        error_update.reset();\r
-        error_update_0.reset();\r
-        error_update_norm.reset();\r
-\r
-        print_conv_header();\r
-\r
-        //Declare and initialize iterator for the Newton-Raphson algorithm steps\r
-        unsigned int newton_iteration = 0;\r
-\r
-        //Iterate until error is below tolerance or max number iterations are reached\r
-        while(newton_iteration < parameters.max_iterations_NR)\r
-          {\r
-            pcout     << " " << std::setw(2) << newton_iteration << " " << std::flush;\r
-            outfile   << " " << std::setw(2) << newton_iteration << " " << std::flush;\r
-\r
-            //Initialize global stiffness matrix and global force vector to zero\r
-            tangent_matrix = 0.0;\r
-            system_rhs = 0.0;\r
-\r
-            tangent_matrix_nb = 0.0;\r
-            system_rhs_nb = 0.0;\r
-\r
-            //Apply boundary conditions\r
-            make_constraints(newton_iteration);\r
-            assemble_system(solution_delta_OUT);\r
-\r
-            //Compute the rhs residual (error between external and internal forces in FE system)\r
-            get_error_residual(error_residual);\r
-\r
-            //error_residual in first iteration is stored to normalize posterior error measures\r
-            if (newton_iteration == 0)\r
-              error_residual_0 = error_residual;\r
-\r
-            // Determine the normalised residual error\r
-            error_residual_norm = error_residual;\r
-            error_residual_norm.normalise(error_residual_0);\r
-\r
-            //If both errors are below the tolerances, exit the loop.\r
-            // We need to check the residual vector directly for convergence\r
-            // in the load steps where no external forces or displacements are imposed.\r
-            if (  ((newton_iteration > 0)\r
-                && (error_update_norm.u <= parameters.tol_u)\r
-                && (error_update_norm.p_fluid <= parameters.tol_p_fluid)\r
-                && (error_residual_norm.u <= parameters.tol_f)\r
-                && (error_residual_norm.p_fluid  <= parameters.tol_f))\r
-                || ( (newton_iteration > 0)\r
-                    && system_rhs.l2_norm() <= parameters.tol_f) )\r
-              {\r
-                pcout   << "\n ***** CONVERGED! *****     "\r
-                        << system_rhs.l2_norm() << "      "\r
-                        << "  " << error_residual_norm.norm\r
-                        << "  " << error_residual_norm.u\r
-                        << "  " << error_residual_norm.p_fluid\r
-                        << "        " << error_update_norm.norm\r
-                        << "  " << error_update_norm.u\r
-                        << "  " << error_update_norm.p_fluid\r
-                        << "  " << std::endl;\r
-                outfile   << "\n ***** CONVERGED! *****     "\r
-                        << system_rhs.l2_norm() << "      "\r
-                        << "  " << error_residual_norm.norm\r
-                        << "  " << error_residual_norm.u\r
-                        << "  " << error_residual_norm.p_fluid\r
-                        << "        " << error_update_norm.norm\r
-                        << "  " << error_update_norm.u\r
-                        << "  " << error_update_norm.p_fluid\r
-                        << "  " << std::endl;\r
-                print_conv_footer();\r
-\r
-                break;\r
-              }\r
-\r
-            //Solve the linearized system\r
-            solve_linear_system(newton_update);\r
-            constraints.distribute(newton_update);\r
-\r
-            //Compute the displacement error\r
-            get_error_update(newton_update, error_update);\r
-\r
-            //error_update in first iteration is stored to normalize posterior error measures\r
-            if (newton_iteration == 0)\r
-              error_update_0 = error_update;\r
-\r
-            // Determine the normalised Newton update error\r
-            error_update_norm = error_update;\r
-            error_update_norm.normalise(error_update_0);\r
-\r
-            // Determine the normalised residual error\r
-            error_residual_norm = error_residual;\r
-            error_residual_norm.normalise(error_residual_0);\r
-\r
-            //Print error values\r
-            pcout    << " |   " << std::fixed << std::setprecision(3)\r
-            << std::setw(7) << std::scientific\r
-            << system_rhs.l2_norm()\r
-            << "        " << error_residual_norm.norm\r
-            << "  " << error_residual_norm.u\r
-            << "  " << error_residual_norm.p_fluid\r
-            << "        " << error_update_norm.norm\r
-            << "  " << error_update_norm.u\r
-            << "  " << error_update_norm.p_fluid\r
-            << "  " << std::endl;\r
-\r
-            outfile  << " |   " << std::fixed << std::setprecision(3)\r
-            << std::setw(7) << std::scientific\r
-            << system_rhs.l2_norm()\r
-            << "        " << error_residual_norm.norm\r
-            << "  " << error_residual_norm.u\r
-            << "  " << error_residual_norm.p_fluid\r
-            << "        " << error_update_norm.norm\r
-            << "  " << error_update_norm.u\r
-            << "  " << error_update_norm.p_fluid\r
-            << "  " << std::endl;\r
-\r
-            // Update\r
-            solution_delta_OUT += newton_update;\r
-            newton_update = 0.0;\r
-            newton_iteration++;\r
-          }\r
-\r
-        //If maximum allowed number of iterations for Newton algorithm are reached, print non-convergence message and abort program\r
-        AssertThrow (newton_iteration < parameters.max_iterations_NR, ExcMessage("No convergence in nonlinear solver!"));\r
-    }\r
-\r
-    //Prints the header for convergence info on console\r
-    template <int dim>\r
-    void Solid<dim>::print_conv_header()\r
-    {\r
-        static const unsigned int l_width = 120;\r
-\r
-        for (unsigned int i = 0; i < l_width; ++i)\r
-          {\r
-            pcout     << "_";\r
-            outfile   << "_";\r
-          }\r
-\r
-        pcout     << std::endl;\r
-        outfile   << std::endl;\r
-\r
-        pcout   << "\n       SOLVER STEP      |    SYS_RES         "\r
-                << "RES_NORM     RES_U      RES_P           "\r
-                << "NU_NORM     NU_U       NU_P " << std::endl;\r
-        outfile << "\n       SOLVER STEP      |    SYS_RES         "\r
-                << "RES_NORM     RES_U      RES_P           "\r
-                << "NU_NORM     NU_U       NU_P " << std::endl;\r
-\r
-        for (unsigned int i = 0; i < l_width; ++i)\r
-          {\r
-            pcout     << "_";\r
-            outfile   << "_";\r
-          }\r
-        pcout     << std::endl << std::endl;\r
-        outfile   << std::endl << std::endl;\r
-    }\r
-\r
-    //Prints the footer for convergence info on console\r
-    template <int dim>\r
-    void Solid<dim>::print_conv_footer()\r
-    {\r
-        static const unsigned int l_width = 120;\r
-\r
-        for (unsigned int i = 0; i < l_width; ++i)\r
-          {\r
-            pcout     << "_";\r
-            outfile   << "_";\r
-          }\r
-        pcout     << std::endl << std::endl;\r
-        outfile   << std::endl << std::endl;\r
-\r
-        pcout << "Relative errors:" << std::endl\r
-              << "Displacement:  "\r
-              << error_update.u / error_update_0.u << std::endl\r
-              << "Force (displ): "\r
-              << error_residual.u / error_residual_0.u << std::endl\r
-              << "Pore pressure: "\r
-              << error_update.p_fluid / error_update_0.p_fluid << std::endl\r
-              << "Force (pore):  "\r
-              << error_residual.p_fluid / error_residual_0.p_fluid << std::endl;\r
-        outfile << "Relative errors:" << std::endl\r
-                << "Displacement:  "\r
-                << error_update.u / error_update_0.u << std::endl\r
-                << "Force (displ): "\r
-                << error_residual.u / error_residual_0.u << std::endl\r
-                << "Pore pressure: "\r
-                << error_update.p_fluid / error_update_0.p_fluid << std::endl\r
-                << "Force (pore):  "\r
-                << error_residual.p_fluid / error_residual_0.p_fluid << std::endl;\r
-    }\r
-\r
-    //Determine the true residual error for the problem\r
-    template <int dim>\r
-    void Solid<dim>::get_error_residual(Errors &error_residual_OUT)\r
-    {\r
-        TrilinosWrappers::MPI::BlockVector error_res(system_rhs);\r
-        constraints.set_zero(error_res);\r
-\r
-        error_residual_OUT.norm = error_res.l2_norm();\r
-        error_residual_OUT.u = error_res.block(u_block).l2_norm();\r
-        error_residual_OUT.p_fluid = error_res.block(p_fluid_block).l2_norm();\r
-    }\r
-\r
-    //Determine the true Newton update error for the problem\r
-    template <int dim>\r
-    void Solid<dim>::get_error_update\r
-               (const TrilinosWrappers::MPI::BlockVector &newton_update_IN,\r
-                Errors                                   &error_update_OUT)\r
-    {\r
-        TrilinosWrappers::MPI::BlockVector error_ud(newton_update_IN);\r
-        constraints.set_zero(error_ud);\r
-\r
-        error_update_OUT.norm = error_ud.l2_norm();\r
-        error_update_OUT.u = error_ud.block(u_block).l2_norm();\r
-        error_update_OUT.p_fluid = error_ud.block(p_fluid_block).l2_norm();\r
-    }\r
-\r
-    //Compute the total solution, which is valid at any Newton step. This is required as, to reduce\r
-    //computational error, the total solution is only updated at the end of the timestep.\r
-    template <int dim>\r
-    TrilinosWrappers::MPI::BlockVector\r
-    Solid<dim>::get_total_solution(const TrilinosWrappers::MPI::BlockVector &solution_delta_IN) const\r
-    {\r
-        // Cell interpolation -> Ghosted vector\r
-        TrilinosWrappers::MPI::BlockVector\r
-             solution_total (locally_owned_partitioning,\r
-                             locally_relevant_partitioning,\r
-                             mpi_communicator,\r
-                             /*vector_writable = */ false);\r
-        TrilinosWrappers::MPI::BlockVector tmp (solution_total);\r
-        solution_total = solution_n;\r
-        tmp = solution_delta_IN;\r
-        solution_total += tmp;\r
-        return solution_total;\r
-    }\r
-\r
-    //Compute elemental stiffness tensor and right-hand side force vector, and assemble into global ones\r
-    template <int dim>\r
-    void Solid<dim>::assemble_system( const TrilinosWrappers::MPI::BlockVector &solution_delta )\r
-    {\r
-        timerconsole.enter_subsection("Assemble system");\r
-        timerfile.enter_subsection("Assemble system");\r
-        pcout     << " ASM_SYS " << std::flush;\r
-        outfile   << " ASM_SYS " << std::flush;\r
-\r
-        const TrilinosWrappers::MPI::BlockVector solution_total(get_total_solution(solution_delta));\r
-\r
-        //Info given to FEValues and FEFaceValues constructors, to indicate which data will be needed at each element.\r
-        const UpdateFlags uf_cell(update_values |\r
-                                  update_gradients |\r
-                                  update_JxW_values);\r
-        const UpdateFlags uf_face(update_values |\r
-                                  update_gradients |\r
-                                  update_normal_vectors |\r
-                                  update_quadrature_points |\r
-                                  update_JxW_values );\r
-\r
-        //Setup a copy of the data structures required for the process and pass them, along with the\r
-        //memory addresses of the assembly functions to the WorkStream object for processing\r
-        PerTaskData_ASM per_task_data(dofs_per_cell);\r
-        ScratchData_ASM<ADNumberType> scratch_data(fe, qf_cell, uf_cell,\r
-                                                   qf_face, uf_face,\r
-                                                   solution_total);\r
-\r
-        FilteredIterator<typename DoFHandler<dim>::active_cell_iterator>\r
-        cell (IteratorFilters::LocallyOwnedCell(),\r
-              dof_handler_ref.begin_active()),\r
-        endc (IteratorFilters::LocallyOwnedCell(),\r
-              dof_handler_ref.end());\r
-        for (; cell != endc; ++cell)\r
-          {\r
-            Assert(cell->is_locally_owned(), ExcInternalError());\r
-            Assert(cell->subdomain_id() == this_mpi_process, ExcInternalError());\r
-\r
-            assemble_system_one_cell(cell, scratch_data, per_task_data);\r
-            copy_local_to_global_system(per_task_data);\r
-          }\r
-        tangent_matrix.compress(VectorOperation::add);\r
-        system_rhs.compress(VectorOperation::add);\r
-\r
-        tangent_matrix_nb.compress(VectorOperation::add);\r
-        system_rhs_nb.compress(VectorOperation::add);\r
-\r
-        timerconsole.leave_subsection();\r
-        timerfile.leave_subsection();\r
-    }\r
-\r
-    //Add the local elemental contribution to the global stiffness tensor\r
-    // We do it twice, for the block and the non-block systems\r
-    template <int dim>\r
-    void Solid<dim>::copy_local_to_global_system (const PerTaskData_ASM &data)\r
-    {\r
-        constraints.distribute_local_to_global(data.cell_matrix,\r
-            data.cell_rhs,\r
-            data.local_dof_indices,\r
-            tangent_matrix,\r
-            system_rhs);\r
-\r
-        constraints.distribute_local_to_global(data.cell_matrix,\r
-            data.cell_rhs,\r
-            data.local_dof_indices,\r
-            tangent_matrix_nb,\r
-            system_rhs_nb);\r
-    }\r
-\r
-    //Compute stiffness matrix and corresponding rhs for one element\r
-    template <int dim>\r
-    void Solid<dim>::assemble_system_one_cell\r
-             (const typename DoFHandler<dim>::active_cell_iterator &cell,\r
-              ScratchData_ASM<ADNumberType>                        &scratch,\r
-              PerTaskData_ASM                                      &data) const\r
-    {\r
-        Assert(cell->is_locally_owned(), ExcInternalError());\r
-\r
-        data.reset();\r
-        scratch.reset();\r
-        scratch.fe_values_ref.reinit(cell);\r
-        cell->get_dof_indices(data.local_dof_indices);\r
-\r
-        // Setup automatic differentiation\r
-        for (unsigned int k = 0; k < dofs_per_cell; ++k)\r
-          {\r
-            // Initialise the dofs for the cell using the current solution.\r
-            scratch.local_dof_values[k] = scratch.solution_total[data.local_dof_indices[k]];\r
-            // Mark this cell DoF as an independent variable\r
-            scratch.local_dof_values[k].diff(k, dofs_per_cell);\r
-          }\r
-\r
-        // Update the quadrature point solution\r
-        // Compute the values and gradients of the solution in terms of the AD variables\r
-        for (unsigned int q = 0; q < n_q_points; ++q)\r
-          {\r
-            for (unsigned int k = 0; k < dofs_per_cell; ++k)\r
-              {\r
-                const unsigned int k_group = fe.system_to_base_index(k).first.first;\r
-                if (k_group == u_block)\r
-                  {\r
-                    const Tensor<2, dim> Grad_Nx_u =\r
-                           scratch.fe_values_ref[u_fe].gradient(k, q);\r
-                    for (unsigned int dd = 0; dd < dim; ++dd)\r
-                      {\r
-                        for (unsigned int ee = 0; ee < dim; ++ee)\r
-                          {\r
-                            scratch.solution_grads_u_total[q][dd][ee]\r
-                             += scratch.local_dof_values[k] * Grad_Nx_u[dd][ee];\r
-                          }\r
-                      }\r
-                  }\r
-                else if  (k_group == p_fluid_block)\r
-                  {\r
-                    const double Nx_p = scratch.fe_values_ref[p_fluid_fe].value(k, q);\r
-                    const Tensor<1, dim> Grad_Nx_p =\r
-                              scratch.fe_values_ref[p_fluid_fe].gradient(k, q);\r
-\r
-                    scratch.solution_values_p_fluid_total[q]\r
-                             += scratch.local_dof_values[k] * Nx_p;\r
-                    for (unsigned int dd = 0; dd < dim; ++dd)\r
-                      {\r
-                        scratch.solution_grads_p_fluid_total[q][dd]\r
-                            += scratch.local_dof_values[k] * Grad_Nx_p[dd];\r
-                      }\r
-                  }\r
-                else\r
-                  Assert(k_group <= p_fluid_block, ExcInternalError());\r
-              }\r
-          }\r
-\r
-        //Set up pointer "lgph" to the PointHistory object of this element\r
-        const std::vector<std::shared_ptr<const PointHistory<dim, ADNumberType> > >\r
-            lqph = quadrature_point_history.get_data(cell);\r
-        Assert(lqph.size() == n_q_points, ExcInternalError());\r
-\r
-\r
-        //Precalculate the element shape function values and gradients\r
-        for (unsigned int q_point = 0; q_point < n_q_points; ++q_point)\r
-          {\r
-            Tensor<2, dim, ADNumberType> F_AD = scratch.solution_grads_u_total[q_point];\r
-            F_AD += Tensor<2, dim, double>(Physics::Elasticity::StandardTensors<dim>::I);\r
-            Assert(determinant(F_AD) > 0, ExcMessage("Invalid deformation map"));\r
-            const Tensor<2, dim, ADNumberType> F_inv_AD = invert(F_AD);\r
-\r
-            for (unsigned int i = 0; i < dofs_per_cell; ++i)\r
-              {\r
-                const unsigned int i_group = fe.system_to_base_index(i).first.first;\r
-\r
-                if (i_group == u_block)\r
-                  {\r
-                    scratch.Nx[q_point][i] =\r
-                        scratch.fe_values_ref[u_fe].value(i, q_point);\r
-                    scratch.grad_Nx[q_point][i] =\r
-                        scratch.fe_values_ref[u_fe].gradient(i, q_point)*F_inv_AD;\r
-                    scratch.symm_grad_Nx[q_point][i] =\r
-                        symmetrize(scratch.grad_Nx[q_point][i]);\r
-                  }\r
-                else if  (i_group == p_fluid_block)\r
-                  {\r
-                    scratch.Nx_p_fluid[q_point][i] =\r
-                        scratch.fe_values_ref[p_fluid_fe].value(i, q_point);\r
-                    scratch.grad_Nx_p_fluid[q_point][i] =\r
-                        scratch.fe_values_ref[p_fluid_fe].gradient(i, q_point)*F_inv_AD;\r
-                  }\r
-                else\r
-                  Assert(i_group <= p_fluid_block, ExcInternalError());\r
-              }\r
-          }\r
-\r
-        //Assemble the stiffness matrix and rhs vector\r
-        std::vector<ADNumberType> residual_ad (dofs_per_cell, ADNumberType(0.0));\r
-        for (unsigned int q_point = 0; q_point < n_q_points; ++q_point)\r
-          {\r
-            Tensor<2, dim, ADNumberType> F_AD = scratch.solution_grads_u_total[q_point];\r
-            F_AD += Tensor<2, dim,double>(Physics::Elasticity::StandardTensors<dim>::I);\r
-            const ADNumberType det_F_AD = determinant(F_AD);\r
-\r
-            Assert(det_F_AD > 0, ExcInternalError());\r
-            const Tensor<2, dim, ADNumberType> F_inv_AD = invert(F_AD); //inverse of def. gradient tensor\r
-\r
-            const ADNumberType p_fluid = scratch.solution_values_p_fluid_total[q_point];\r
-\r
-            {\r
-              PointHistory<dim, ADNumberType> *lqph_q_point_nc =\r
-                 const_cast<PointHistory<dim, ADNumberType>*>(lqph[q_point].get());\r
-              lqph_q_point_nc->update_internal_equilibrium(F_AD);\r
-            }\r
-\r
-            //Get some info from constitutive model of solid\r
-            static const SymmetricTensor< 2, dim, double>\r
-                I (Physics::Elasticity::StandardTensors<dim>::I);\r
-            const SymmetricTensor<2, dim, ADNumberType>\r
-                tau_E = lqph[q_point]->get_tau_E(F_AD);\r
-            SymmetricTensor<2, dim, ADNumberType> tau_fluid_vol (I);\r
-            tau_fluid_vol *= -1.0 * p_fluid * det_F_AD;\r
-\r
-            //Get some info from constitutive model of fluid\r
-            const ADNumberType det_F_aux =  lqph[q_point]->get_converged_det_F();\r
-            const double det_F_converged = Tensor<0,dim,double>(det_F_aux); //Needs to be double, not AD number\r
-            const Tensor<1, dim, ADNumberType> overall_body_force\r
-                = lqph[q_point]->get_overall_body_force(F_AD, parameters);\r
-\r
-            // Define some aliases to make the assembly process easier to follow\r
-            const std::vector<Tensor<1,dim>> &Nu = scratch.Nx[q_point];\r
-            const std::vector<SymmetricTensor<2, dim, ADNumberType>>\r
-                &symm_grad_Nu = scratch.symm_grad_Nx[q_point];\r
-            const std::vector<double> &Np = scratch.Nx_p_fluid[q_point];\r
-            const std::vector<Tensor<1, dim, ADNumberType> > &grad_Np\r
-                = scratch.grad_Nx_p_fluid[q_point];\r
-            const Tensor<1, dim, ADNumberType> grad_p\r
-                = scratch.solution_grads_p_fluid_total[q_point]*F_inv_AD;\r
-            const double JxW = scratch.fe_values_ref.JxW(q_point);\r
-\r
-            for (unsigned int i = 0; i < dofs_per_cell; ++i)\r
-              {\r
-                const unsigned int i_group = fe.system_to_base_index(i).first.first;\r
-\r
-                if (i_group == u_block)\r
-                  {\r
-                    residual_ad[i] += symm_grad_Nu[i] * ( tau_E + tau_fluid_vol ) * JxW;\r
-                    residual_ad[i] -= Nu[i] * overall_body_force * JxW;\r
-                  }\r
-                else if (i_group == p_fluid_block)\r
-                  {\r
-                    const Tensor<1, dim, ADNumberType> seepage_vel_current\r
-                        = lqph[q_point]->get_seepage_velocity_current(F_AD, grad_p);\r
-                    residual_ad[i] += Np[i] * (det_F_AD - det_F_converged) * JxW;\r
-                    residual_ad[i] -= time.get_delta_t() * grad_Np[i]\r
-                                      * seepage_vel_current * JxW;\r
-                  }\r
-                else\r
-                  Assert(i_group <= p_fluid_block, ExcInternalError());\r
-              }\r
-          }\r
-\r
-          // Assemble the Neumann contribution (external force contribution).\r
-          for (unsigned int face = 0; face < GeometryInfo<dim>::faces_per_cell; ++face) //Loop over faces in element\r
-            {\r
-              if (cell->face(face)->at_boundary() == true)\r
-                {\r
-                  scratch.fe_face_values_ref.reinit(cell, face);\r
-\r
-                  for (unsigned int f_q_point = 0; f_q_point < n_q_points_f; ++f_q_point)\r
-                    {\r
-                      const Tensor<1, dim> &N\r
-                          = scratch.fe_face_values_ref.normal_vector(f_q_point);\r
-                      const Point<dim>     &pt\r
-                          = scratch.fe_face_values_ref.quadrature_point(f_q_point);\r
-                      const Tensor<1, dim> traction\r
-                          = get_neumann_traction(cell->face(face)->boundary_id(), pt, N);\r
-                      const double flow\r
-                          = get_prescribed_fluid_flow(cell->face(face)->boundary_id(), pt);\r
-\r
-                      if ( (traction.norm() < 1e-12) && (std::abs(flow) < 1e-12) ) continue;\r
-\r
-                      const double JxW_f = scratch.fe_face_values_ref.JxW(f_q_point);\r
-\r
-                      for (unsigned int i = 0; i < dofs_per_cell; ++i)\r
-                        {\r
-                          const unsigned int i_group = fe.system_to_base_index(i).first.first;\r
-\r
-                          if ((i_group == u_block) && (traction.norm() > 1e-12))\r
-                          {\r
-                              const unsigned int component_i\r
-                                = fe.system_to_component_index(i).first;\r
-                              const double Nu_f\r
-                                = scratch.fe_face_values_ref.shape_value(i, f_q_point);\r
-                              residual_ad[i] -= (Nu_f * traction[component_i]) * JxW_f;\r
-                          }\r
-                          if ((i_group == p_fluid_block) && (std::abs(flow) > 1e-12))\r
-                          {\r
-                              const double Nu_p\r
-                                = scratch.fe_face_values_ref.shape_value(i, f_q_point);\r
-                              residual_ad[i] -= (Nu_p * flow) * JxW_f;\r
-                          }\r
-                        }\r
-                    }\r
-                }\r
-            }\r
-\r
-        // Linearise the residual\r
-        for (unsigned int i = 0; i < dofs_per_cell; ++i)\r
-          {\r
-            const ADNumberType &R_i = residual_ad[i];\r
-\r
-            data.cell_rhs(i) -= R_i.val();\r
-            for (unsigned int j=0; j<dofs_per_cell; ++j)\r
-              data.cell_matrix(i,j) += R_i.fastAccessDx(j);\r
-          }\r
-    }\r
-\r
-    //Store the converged values of the internal variables\r
-    template <int dim>\r
-    void Solid<dim>::update_end_timestep()\r
-    {\r
-          FilteredIterator<typename DoFHandler<dim>::active_cell_iterator>\r
-          cell (IteratorFilters::LocallyOwnedCell(),\r
-                dof_handler_ref.begin_active()),\r
-          endc (IteratorFilters::LocallyOwnedCell(),\r
-                dof_handler_ref.end());\r
-          for (; cell!=endc; ++cell)\r
-          {\r
-            Assert(cell->is_locally_owned(), ExcInternalError());\r
-            Assert(cell->subdomain_id() == this_mpi_process, ExcInternalError());\r
-\r
-            const std::vector<std::shared_ptr<PointHistory<dim, ADNumberType> > >\r
-                lqph = quadrature_point_history.get_data(cell);\r
-            Assert(lqph.size() == n_q_points, ExcInternalError());\r
-            for (unsigned int q_point = 0; q_point < n_q_points; ++q_point)\r
-              lqph[q_point]->update_end_timestep();\r
-          }\r
-    }\r
-\r
-\r
-     //Solve the linearized equations\r
-     template <int dim>\r
-     void Solid<dim>::solve_linear_system( TrilinosWrappers::MPI::BlockVector &newton_update_OUT)\r
-     {\r
-\r
-           timerconsole.enter_subsection("Linear solver");\r
-           timerfile.enter_subsection("Linear solver");\r
-           pcout     << " SLV " << std::flush;\r
-           outfile   << " SLV " << std::flush;\r
-\r
-           TrilinosWrappers::MPI::Vector newton_update_nb;\r
-           newton_update_nb.reinit(locally_owned_dofs, mpi_communicator);\r
-\r
-           SolverControl solver_control (tangent_matrix_nb.m(),\r
-                                         1.0e-6 * system_rhs_nb.l2_norm());\r
-           TrilinosWrappers::SolverDirect solver (solver_control);\r
-           solver.solve(tangent_matrix_nb, newton_update_nb, system_rhs_nb);\r
-\r
-           // Copy the non-block solution back to block system\r
-           for (unsigned int i=0; i<locally_owned_dofs.n_elements(); ++i)\r
-             {\r
-               const types::global_dof_index idx_i\r
-                              = locally_owned_dofs.nth_index_in_set(i);\r
-               newton_update_OUT(idx_i) = newton_update_nb(idx_i);\r
-             }\r
-           newton_update_OUT.compress(VectorOperation::insert);\r
-\r
-           timerconsole.leave_subsection();\r
-           timerfile.leave_subsection();\r
-     }\r
-\r
-    //Class to compute gradient of the pressure\r
-    template <int dim>\r
-    class GradientPostprocessor : public DataPostprocessorVector<dim>\r
-    {\r
-        public:\r
-          GradientPostprocessor (const unsigned int p_fluid_component)\r
-            :\r
-            DataPostprocessorVector<dim> ("grad_p",\r
-                                          update_gradients),\r
-            p_fluid_component (p_fluid_component)\r
-          {}\r
-\r
-          virtual ~GradientPostprocessor(){}\r
-\r
-          virtual void\r
-          evaluate_vector_field\r
-               (const DataPostprocessorInputs::Vector<dim> &input_data,\r
-                std::vector<Vector<double> >               &computed_quantities) const override\r
-          {\r
-            AssertDimension (input_data.solution_gradients.size(),\r
-                             computed_quantities.size());\r
-            for (unsigned int p=0; p<input_data.solution_gradients.size(); ++p)\r
-              {\r
-                AssertDimension (computed_quantities[p].size(), dim);\r
-                for (unsigned int d=0; d<dim; ++d)\r
-                  computed_quantities[p][d]\r
-                    = input_data.solution_gradients[p][p_fluid_component][d];\r
-              }\r
-          }\r
-\r
-        private:\r
-          const unsigned int  p_fluid_component;\r
-    };\r
-\r
-\r
-      //Print results to vtu file\r
-      template <int dim> void Solid<dim>::output_results_to_vtu\r
-                            (const unsigned int timestep,\r
-                             const double current_time,\r
-                             TrilinosWrappers::MPI::BlockVector solution_IN) const\r
-      {\r
-        TrilinosWrappers::MPI::BlockVector solution_total(locally_owned_partitioning,\r
-                                                          locally_relevant_partitioning,\r
-                                                          mpi_communicator,\r
-                                                          false);\r
-        solution_total = solution_IN;\r
-        Vector<double> material_id;\r
-        material_id.reinit(triangulation.n_active_cells());\r
-        std::vector<types::subdomain_id> partition_int(triangulation.n_active_cells());\r
-        GradientPostprocessor<dim> gradient_postprocessor(p_fluid_component);\r
-\r
-         //Declare local variables with number of stress components\r
-         //& assign value according to "dim" value\r
-         unsigned int num_comp_symm_tensor = 6;\r
-\r
-        //Declare local vectors to store values\r
-        // OUTPUT AVERAGED ON ELEMENTS -------------------------------------------\r
-        std::vector<Vector<double>>cauchy_stresses_total_elements\r
-                             (num_comp_symm_tensor,\r
-                              Vector<double> (triangulation.n_active_cells()));\r
-        std::vector<Vector<double>>cauchy_stresses_E_elements\r
-                             (num_comp_symm_tensor,\r
-                              Vector<double> (triangulation.n_active_cells()));\r
-        std::vector<Vector<double>>stretches_elements\r
-                             (dim,\r
-                              Vector<double> (triangulation.n_active_cells()));\r
-        std::vector<Vector<double>>seepage_velocity_elements\r
-                              (dim,\r
-                               Vector<double> (triangulation.n_active_cells()));\r
-        Vector<double> porous_dissipation_elements\r
-                              (triangulation.n_active_cells());\r
-        Vector<double> viscous_dissipation_elements\r
-                              (triangulation.n_active_cells());\r
-        Vector<double> solid_vol_fraction_elements\r
-                              (triangulation.n_active_cells());\r
-\r
-        // OUTPUT AVERAGED ON NODES ----------------------------------------------\r
-        // We need to create a new FE space with a single dof per node to avoid\r
-        // duplication of the output on nodes for our problem with dim+1 dofs.\r
-        FE_Q<dim> fe_vertex(1);\r
-        DoFHandler<dim> vertex_handler_ref(triangulation);\r
-        vertex_handler_ref.distribute_dofs(fe_vertex);\r
-        AssertThrow(vertex_handler_ref.n_dofs() == triangulation.n_vertices(),\r
-          ExcDimensionMismatch(vertex_handler_ref.n_dofs(),\r
-                               triangulation.n_vertices()));\r
-\r
-        Vector<double> counter_on_vertices_mpi\r
-                        (vertex_handler_ref.n_dofs());\r
-        Vector<double> sum_counter_on_vertices\r
-                        (vertex_handler_ref.n_dofs());\r
-\r
-        std::vector<Vector<double>>cauchy_stresses_total_vertex_mpi\r
-                                  (num_comp_symm_tensor,\r
-                                   Vector<double>(vertex_handler_ref.n_dofs()));\r
-        std::vector<Vector<double>>sum_cauchy_stresses_total_vertex\r
-                                  (num_comp_symm_tensor,\r
-                                   Vector<double>(vertex_handler_ref.n_dofs()));\r
-        std::vector<Vector<double>>cauchy_stresses_E_vertex_mpi\r
-                                  (num_comp_symm_tensor,\r
-                                   Vector<double>(vertex_handler_ref.n_dofs()));\r
-        std::vector<Vector<double>>sum_cauchy_stresses_E_vertex\r
-                                  (num_comp_symm_tensor,\r
-                                   Vector<double>(vertex_handler_ref.n_dofs()));\r
-        std::vector<Vector<double>>stretches_vertex_mpi\r
-                                  (dim,\r
-                                   Vector<double>(vertex_handler_ref.n_dofs()));\r
-        std::vector<Vector<double>>sum_stretches_vertex\r
-                                  (dim,\r
-                                   Vector<double>(vertex_handler_ref.n_dofs()));\r
-        Vector<double> porous_dissipation_vertex_mpi(vertex_handler_ref.n_dofs());\r
-        Vector<double> sum_porous_dissipation_vertex(vertex_handler_ref.n_dofs());\r
-        Vector<double> viscous_dissipation_vertex_mpi(vertex_handler_ref.n_dofs());\r
-        Vector<double> sum_viscous_dissipation_vertex(vertex_handler_ref.n_dofs());\r
-        Vector<double> solid_vol_fraction_vertex_mpi(vertex_handler_ref.n_dofs());\r
-        Vector<double> sum_solid_vol_fraction_vertex(vertex_handler_ref.n_dofs());\r
-\r
-        // We need to create a new FE space with a dim dof per node to\r
-        // be able to ouput data on nodes in vector form\r
-        FESystem<dim> fe_vertex_vec(FE_Q<dim>(1),dim);\r
-        DoFHandler<dim> vertex_vec_handler_ref(triangulation);\r
-        vertex_vec_handler_ref.distribute_dofs(fe_vertex_vec);\r
-        AssertThrow(vertex_vec_handler_ref.n_dofs() == (dim*triangulation.n_vertices()),\r
-          ExcDimensionMismatch(vertex_vec_handler_ref.n_dofs(),\r
-                               (dim*triangulation.n_vertices())));\r
-\r
-        Vector<double> seepage_velocity_vertex_vec_mpi(vertex_vec_handler_ref.n_dofs());\r
-        Vector<double> sum_seepage_velocity_vertex_vec(vertex_vec_handler_ref.n_dofs());\r
-        Vector<double> counter_on_vertices_vec_mpi(vertex_vec_handler_ref.n_dofs());\r
-        Vector<double> sum_counter_on_vertices_vec(vertex_vec_handler_ref.n_dofs());\r
-        // -----------------------------------------------------------------------\r
-\r
-        //Declare and initialize local unit vectors (to construct tensor basis)\r
-        std::vector<Tensor<1,dim>> basis_vectors (dim, Tensor<1,dim>() );\r
-        for (unsigned int i=0; i<dim; ++i)\r
-            basis_vectors[i][i] = 1;\r
-\r
-        //Declare an instance of the material class object\r
-        if (parameters.mat_type == "Neo-Hooke")\r
-            NeoHooke<dim,ADNumberType> material(parameters,time);\r
-        else if (parameters.mat_type == "Ogden")\r
-            Ogden<dim,ADNumberType> material(parameters,time);\r
-        else if (parameters.mat_type == "visco-Ogden")\r
-            visco_Ogden <dim,ADNumberType>material(parameters,time);\r
-        else\r
-            Assert (false, ExcMessage("Material type not implemented"));\r
-\r
-        //Define a local instance of FEValues to compute updated values required\r
-        //to calculate stresses\r
-        const UpdateFlags uf_cell(update_values | update_gradients |\r
-                                  update_JxW_values);\r
-        FEValues<dim> fe_values_ref (fe, qf_cell, uf_cell);\r
-\r
-        //Iterate through elements (cells) and Gauss Points\r
-        FilteredIterator<typename DoFHandler<dim>::active_cell_iterator>\r
-          cell(IteratorFilters::LocallyOwnedCell(),\r
-               dof_handler_ref.begin_active()),\r
-          endc(IteratorFilters::LocallyOwnedCell(),\r
-               dof_handler_ref.end()),\r
-          cell_v(IteratorFilters::LocallyOwnedCell(),\r
-                 vertex_handler_ref.begin_active()),\r
-          cell_v_vec(IteratorFilters::LocallyOwnedCell(),\r
-                     vertex_vec_handler_ref.begin_active());\r
-        //start cell loop\r
-        for (; cell!=endc; ++cell, ++cell_v, ++cell_v_vec)\r
-        {\r
-            Assert(cell->is_locally_owned(), ExcInternalError());\r
-            Assert(cell->subdomain_id() == this_mpi_process, ExcInternalError());\r
-\r
-            material_id(cell->active_cell_index())=\r
-              static_cast<int>(cell->material_id());\r
-\r
-            fe_values_ref.reinit(cell);\r
-\r
-            std::vector<Tensor<2,dim>> solution_grads_u(n_q_points);\r
-            fe_values_ref[u_fe].get_function_gradients(solution_total,\r
-                                                       solution_grads_u);\r
-\r
-            std::vector<double> solution_values_p_fluid_total(n_q_points);\r
-            fe_values_ref[p_fluid_fe].get_function_values(solution_total,\r
-                                                          solution_values_p_fluid_total);\r
-\r
-            std::vector<Tensor<1,dim>> solution_grads_p_fluid_AD (n_q_points);\r
-            fe_values_ref[p_fluid_fe].get_function_gradients(solution_total,\r
-                                                             solution_grads_p_fluid_AD);\r
-\r
-            //start gauss point loop\r
-            for (unsigned int q_point=0; q_point<n_q_points; ++q_point)\r
-            {\r
-                const Tensor<2,dim,ADNumberType>\r
-                  F_AD = Physics::Elasticity::Kinematics::F(solution_grads_u[q_point]);\r
-                ADNumberType det_F_AD = determinant(F_AD);\r
-                const double det_F = Tensor<0,dim,double>(det_F_AD);\r
-\r
-                const std::vector<std::shared_ptr<const PointHistory<dim,ADNumberType>>>\r
-                    lqph = quadrature_point_history.get_data(cell);\r
-                Assert(lqph.size() == n_q_points, ExcInternalError());\r
-\r
-                const double p_fluid = solution_values_p_fluid_total[q_point];\r
-\r
-                //Cauchy stress\r
-                static const SymmetricTensor<2,dim,double>\r
-                  I (Physics::Elasticity::StandardTensors<dim>::I);\r
-                SymmetricTensor<2,dim> sigma_E;\r
-                const SymmetricTensor<2,dim,ADNumberType> sigma_E_AD =\r
-                  lqph[q_point]->get_Cauchy_E(F_AD);\r
-\r
-                for (unsigned int i=0; i<dim; ++i)\r
-                    for (unsigned int j=0; j<dim; ++j)\r
-                       sigma_E[i][j] = Tensor<0,dim,double>(sigma_E_AD[i][j]);\r
-\r
-                SymmetricTensor<2,dim> sigma_fluid_vol (I);\r
-                sigma_fluid_vol *= -p_fluid;\r
-                const SymmetricTensor<2,dim> sigma = sigma_E + sigma_fluid_vol;\r
-\r
-                //Volumes\r
-                const double solid_vol_fraction = (parameters.solid_vol_frac)/det_F;\r
-\r
-                //Green-Lagrange strain\r
-                const Tensor<2,dim> E_strain = 0.5*(transpose(F_AD)*F_AD - I);\r
-\r
-                //Seepage velocity\r
-                const Tensor<2,dim,ADNumberType> F_inv = invert(F_AD);\r
-                const Tensor<1,dim,ADNumberType> grad_p_fluid_AD =\r
-                                          solution_grads_p_fluid_AD[q_point]*F_inv;\r
-                const Tensor<1,dim,ADNumberType> seepage_vel_AD =\r
-                 lqph[q_point]->get_seepage_velocity_current(F_AD, grad_p_fluid_AD);\r
-\r
-                //Dissipations\r
-                const double porous_dissipation =\r
-                  lqph[q_point]->get_porous_dissipation(F_AD, grad_p_fluid_AD);\r
-                const double viscous_dissipation =\r
-                  lqph[q_point]->get_viscous_dissipation();\r
-\r
-                // OUTPUT AVERAGED ON ELEMENTS -------------------------------------------\r
-                // Both average on elements and on nodes is NOT weighted with the\r
-                // integration point volume, i.e., we assume equal contribution of each\r
-                // integration point to the average. Ideally, it should be weighted,\r
-                // but I haven't invested time in getting it to work properly.\r
-                if (parameters.outtype == "elements")\r
-                {\r
-                    for (unsigned int j=0; j<dim; ++j)\r
-                    {\r
-                        cauchy_stresses_total_elements[j](cell->active_cell_index())\r
-                          += ((sigma*basis_vectors[j])*basis_vectors[j])/n_q_points;\r
-                        cauchy_stresses_E_elements[j](cell->active_cell_index())\r
-                          += ((sigma_E*basis_vectors[j])*basis_vectors[j])/n_q_points;\r
-                        stretches_elements[j](cell->active_cell_index())\r
-                          += std::sqrt(1.0+2.0*Tensor<0,dim,double>(E_strain[j][j]))\r
-                             /n_q_points;\r
-                        seepage_velocity_elements[j](cell->active_cell_index())\r
-                          +=  Tensor<0,dim,double>(seepage_vel_AD[j])/n_q_points;\r
-                    }\r
-\r
-                    porous_dissipation_elements(cell->active_cell_index())\r
-                      +=  porous_dissipation/n_q_points;\r
-                    viscous_dissipation_elements(cell->active_cell_index())\r
-                      +=  viscous_dissipation/n_q_points;\r
-                    solid_vol_fraction_elements(cell->active_cell_index())\r
-                      +=  solid_vol_fraction/n_q_points;\r
-\r
-                    cauchy_stresses_total_elements[3](cell->active_cell_index())\r
-                      += ((sigma*basis_vectors[0])*basis_vectors[1])/n_q_points; //sig_xy\r
-                    cauchy_stresses_total_elements[4](cell->active_cell_index())\r
-                      += ((sigma*basis_vectors[0])*basis_vectors[2])/n_q_points;//sig_xz\r
-                    cauchy_stresses_total_elements[5](cell->active_cell_index())\r
-                      += ((sigma*basis_vectors[1])*basis_vectors[2])/n_q_points;//sig_yz\r
-\r
-                    cauchy_stresses_E_elements[3](cell->active_cell_index())\r
-                      += ((sigma_E*basis_vectors[0])* basis_vectors[1])/n_q_points; //sig_xy\r
-                    cauchy_stresses_E_elements[4](cell->active_cell_index())\r
-                      += ((sigma_E*basis_vectors[0])* basis_vectors[2])/n_q_points;//sig_xz\r
-                    cauchy_stresses_E_elements[5](cell->active_cell_index())\r
-                      += ((sigma_E*basis_vectors[1])* basis_vectors[2])/n_q_points;//sig_yz\r
-\r
-                }\r
-                // OUTPUT AVERAGED ON NODES -------------------------------------------\r
-                else if (parameters.outtype == "nodes")\r
-                {\r
-                  for (unsigned int v=0; v<(GeometryInfo<dim>::vertices_per_cell); ++v)\r
-                  {\r
-                      types::global_dof_index local_vertex_indices =\r
-                                                    cell_v->vertex_dof_index(v, 0);\r
-                      counter_on_vertices_mpi(local_vertex_indices) += 1;\r
-                      for (unsigned int k=0; k<dim; ++k)\r
-                      {\r
-                          cauchy_stresses_total_vertex_mpi[k](local_vertex_indices)\r
-                            += (sigma*basis_vectors[k])*basis_vectors[k];\r
-                          cauchy_stresses_E_vertex_mpi[k](local_vertex_indices)\r
-                            += (sigma_E*basis_vectors[k])*basis_vectors[k];\r
-                          stretches_vertex_mpi[k](local_vertex_indices)\r
-                            += std::sqrt(1.0+2.0*Tensor<0,dim,double>(E_strain[k][k]));\r
-\r
-                          types::global_dof_index local_vertex_vec_indices =\r
-                                                cell_v_vec->vertex_dof_index(v, k);\r
-                          counter_on_vertices_vec_mpi(local_vertex_vec_indices) += 1;\r
-                          seepage_velocity_vertex_vec_mpi(local_vertex_vec_indices)\r
-                            += Tensor<0,dim,double>(seepage_vel_AD[k]);\r
-                      }\r
-\r
-                      porous_dissipation_vertex_mpi(local_vertex_indices)\r
-                        += porous_dissipation;\r
-                      viscous_dissipation_vertex_mpi(local_vertex_indices)\r
-                        += viscous_dissipation;\r
-                      solid_vol_fraction_vertex_mpi(local_vertex_indices)\r
-                        += solid_vol_fraction;\r
-\r
-                      cauchy_stresses_total_vertex_mpi[3](local_vertex_indices)\r
-                        += (sigma*basis_vectors[0])*basis_vectors[1]; //sig_xy\r
-                      cauchy_stresses_total_vertex_mpi[4](local_vertex_indices)\r
-                        += (sigma*basis_vectors[0])*basis_vectors[2];//sig_xz\r
-                      cauchy_stresses_total_vertex_mpi[5](local_vertex_indices)\r
-                        += (sigma*basis_vectors[1])*basis_vectors[2]; //sig_yz\r
-\r
-                      cauchy_stresses_E_vertex_mpi[3](local_vertex_indices)\r
-                        += (sigma_E*basis_vectors[0])*basis_vectors[1]; //sig_xy\r
-                      cauchy_stresses_E_vertex_mpi[4](local_vertex_indices)\r
-                        += (sigma_E*basis_vectors[0])*basis_vectors[2];//sig_xz\r
-                      cauchy_stresses_E_vertex_mpi[5](local_vertex_indices)\r
-                        += (sigma_E*basis_vectors[1])*basis_vectors[2]; //sig_yz\r
-                    }\r
-              }\r
-              //---------------------------------------------------------------\r
-            } //end gauss point loop\r
-        }//end cell loop\r
-\r
-        // Different nodes might have different amount of contributions, e.g.,\r
-        // corner nodes have less integration points contributing to the averaged.\r
-        // This is why we need a counter and divide at the end, outside the cell loop.\r
-        if (parameters.outtype == "nodes")\r
-        {\r
-          for (unsigned int d=0; d<(vertex_handler_ref.n_dofs()); ++d)\r
-          {\r
-            sum_counter_on_vertices[d] =\r
-              Utilities::MPI::sum(counter_on_vertices_mpi[d],\r
-                                  mpi_communicator);\r
-            sum_porous_dissipation_vertex[d] =\r
-              Utilities::MPI::sum(porous_dissipation_vertex_mpi[d],\r
-                                  mpi_communicator);\r
-            sum_viscous_dissipation_vertex[d] =\r
-              Utilities::MPI::sum(viscous_dissipation_vertex_mpi[d],\r
-                                  mpi_communicator);\r
-            sum_solid_vol_fraction_vertex[d] =\r
-              Utilities::MPI::sum(solid_vol_fraction_vertex_mpi[d],\r
-                                  mpi_communicator);\r
-\r
-            for (unsigned int k=0; k<num_comp_symm_tensor; ++k)\r
-            {\r
-              sum_cauchy_stresses_total_vertex[k][d] =\r
-                  Utilities::MPI::sum(cauchy_stresses_total_vertex_mpi[k][d],\r
-                                      mpi_communicator);\r
-              sum_cauchy_stresses_E_vertex[k][d] =\r
-                  Utilities::MPI::sum(cauchy_stresses_E_vertex_mpi[k][d],\r
-                                      mpi_communicator);\r
-            }\r
-            for (unsigned int k=0; k<dim; ++k)\r
-            {\r
-              sum_stretches_vertex[k][d] =\r
-                  Utilities::MPI::sum(stretches_vertex_mpi[k][d],\r
-                                      mpi_communicator);\r
-            }\r
-          }\r
-\r
-          for (unsigned int d=0; d<(vertex_vec_handler_ref.n_dofs()); ++d)\r
-          {\r
-              sum_counter_on_vertices_vec[d] =\r
-                  Utilities::MPI::sum(counter_on_vertices_vec_mpi[d],\r
-                                      mpi_communicator);\r
-              sum_seepage_velocity_vertex_vec[d] =\r
-                  Utilities::MPI::sum(seepage_velocity_vertex_vec_mpi[d],\r
-                                      mpi_communicator);\r
-          }\r
-\r
-          for (unsigned int d=0; d<(vertex_handler_ref.n_dofs()); ++d)\r
-          {\r
-            if (sum_counter_on_vertices[d]>0)\r
-            {\r
-              for (unsigned int i=0; i<num_comp_symm_tensor; ++i)\r
-              {\r
-                  sum_cauchy_stresses_total_vertex[i][d] /= sum_counter_on_vertices[d];\r
-                  sum_cauchy_stresses_E_vertex[i][d] /= sum_counter_on_vertices[d];\r
-              }\r
-              for (unsigned int i=0; i<dim; ++i)\r
-              {\r
-                  sum_stretches_vertex[i][d] /= sum_counter_on_vertices[d];\r
-              }\r
-              sum_porous_dissipation_vertex[d] /= sum_counter_on_vertices[d];\r
-              sum_viscous_dissipation_vertex[d] /= sum_counter_on_vertices[d];\r
-              sum_solid_vol_fraction_vertex[d] /= sum_counter_on_vertices[d];\r
-            }\r
-          }\r
-\r
-          for (unsigned int d=0; d<(vertex_vec_handler_ref.n_dofs()); ++d)\r
-          {\r
-            if (sum_counter_on_vertices_vec[d]>0)\r
-            {\r
-              sum_seepage_velocity_vertex_vec[d] /= sum_counter_on_vertices_vec[d];\r
-            }\r
-          }\r
-\r
-        }\r
-\r
-        // Add the results to the solution to create the output file for Paraview\r
-        DataOut<dim> data_out;\r
-        std::vector<DataComponentInterpretation::DataComponentInterpretation>\r
-          comp_type(dim,\r
-                    DataComponentInterpretation::component_is_part_of_vector);\r
-        comp_type.push_back(DataComponentInterpretation::component_is_scalar);\r
-\r
-        GridTools::get_subdomain_association(triangulation, partition_int);\r
-\r
-        std::vector<std::string> solution_name(dim, "displacement");\r
-        solution_name.push_back("pore_pressure");\r
-\r
-        data_out.attach_dof_handler(dof_handler_ref);\r
-        data_out.add_data_vector(solution_total,\r
-                                 solution_name,\r
-                                 DataOut<dim>::type_dof_data,\r
-                                 comp_type);\r
-\r
-        data_out.add_data_vector(solution_total,\r
-                                 gradient_postprocessor);\r
-\r
-        const Vector<double> partitioning(partition_int.begin(),\r
-                                          partition_int.end());\r
-\r
-        data_out.add_data_vector(partitioning, "partitioning");\r
-        data_out.add_data_vector(material_id, "material_id");\r
-\r
-        // Integration point results -----------------------------------------------------------\r
-        if (parameters.outtype == "elements")\r
-        {\r
-          data_out.add_data_vector(cauchy_stresses_total_elements[0], "cauchy_xx");\r
-          data_out.add_data_vector(cauchy_stresses_total_elements[1], "cauchy_yy");\r
-          data_out.add_data_vector(cauchy_stresses_total_elements[2], "cauchy_zz");\r
-          data_out.add_data_vector(cauchy_stresses_total_elements[3], "cauchy_xy");\r
-          data_out.add_data_vector(cauchy_stresses_total_elements[4], "cauchy_xz");\r
-          data_out.add_data_vector(cauchy_stresses_total_elements[5], "cauchy_yz");\r
-\r
-          data_out.add_data_vector(cauchy_stresses_E_elements[0], "cauchy_E_xx");\r
-          data_out.add_data_vector(cauchy_stresses_E_elements[1], "cauchy_E_yy");\r
-          data_out.add_data_vector(cauchy_stresses_E_elements[2], "cauchy_E_zz");\r
-          data_out.add_data_vector(cauchy_stresses_E_elements[3], "cauchy_E_xy");\r
-          data_out.add_data_vector(cauchy_stresses_E_elements[4], "cauchy_E_xz");\r
-          data_out.add_data_vector(cauchy_stresses_E_elements[5], "cauchy_E_yz");\r
-\r
-          data_out.add_data_vector(stretches_elements[0], "stretch_xx");\r
-          data_out.add_data_vector(stretches_elements[1], "stretch_yy");\r
-          data_out.add_data_vector(stretches_elements[2], "stretch_zz");\r
-\r
-          data_out.add_data_vector(seepage_velocity_elements[0], "seepage_vel_x");\r
-          data_out.add_data_vector(seepage_velocity_elements[1], "seepage_vel_y");\r
-          data_out.add_data_vector(seepage_velocity_elements[2], "seepage_vel_z");\r
-\r
-          data_out.add_data_vector(porous_dissipation_elements, "dissipation_porous");\r
-          data_out.add_data_vector(viscous_dissipation_elements, "dissipation_viscous");\r
-          data_out.add_data_vector(solid_vol_fraction_elements, "solid_vol_fraction");\r
-        }\r
-        else if  (parameters.outtype == "nodes")\r
-        {\r
-          data_out.add_data_vector(vertex_handler_ref,\r
-                                   sum_cauchy_stresses_total_vertex[0],\r
-                                   "cauchy_xx");\r
-          data_out.add_data_vector(vertex_handler_ref,\r
-                                   sum_cauchy_stresses_total_vertex[1],\r
-                                   "cauchy_yy");\r
-          data_out.add_data_vector(vertex_handler_ref,\r
-                                   sum_cauchy_stresses_total_vertex[2],\r
-                                   "cauchy_zz");\r
-          data_out.add_data_vector(vertex_handler_ref,\r
-                                   sum_cauchy_stresses_total_vertex[3],\r
-                                   "cauchy_xy");\r
-          data_out.add_data_vector(vertex_handler_ref,\r
-                                   sum_cauchy_stresses_total_vertex[4],\r
-                                   "cauchy_xz");\r
-          data_out.add_data_vector(vertex_handler_ref,\r
-                                   sum_cauchy_stresses_total_vertex[5],\r
-                                   "cauchy_yz");\r
-\r
-          data_out.add_data_vector(vertex_handler_ref,\r
-                                   sum_cauchy_stresses_E_vertex[0],\r
-                                   "cauchy_E_xx");\r
-          data_out.add_data_vector(vertex_handler_ref,\r
-                                   sum_cauchy_stresses_E_vertex[1],\r
-                                   "cauchy_E_yy");\r
-          data_out.add_data_vector(vertex_handler_ref,\r
-                                   sum_cauchy_stresses_E_vertex[2],\r
-                                   "cauchy_E_zz");\r
-          data_out.add_data_vector(vertex_handler_ref,\r
-                                   sum_cauchy_stresses_E_vertex[3],\r
-                                   "cauchy_E_xy");\r
-          data_out.add_data_vector(vertex_handler_ref,\r
-                                   sum_cauchy_stresses_E_vertex[4],\r
-                                   "cauchy_E_xz");\r
-          data_out.add_data_vector(vertex_handler_ref,\r
-                                   sum_cauchy_stresses_E_vertex[5],\r
-                                   "cauchy_E_yz");\r
-\r
-          data_out.add_data_vector(vertex_handler_ref,\r
-                                   sum_stretches_vertex[0],\r
-                                   "stretch_xx");\r
-          data_out.add_data_vector(vertex_handler_ref,\r
-                                   sum_stretches_vertex[1],\r
-                                   "stretch_yy");\r
-          data_out.add_data_vector(vertex_handler_ref,\r
-                                   sum_stretches_vertex[2],\r
-                                   "stretch_zz");\r
-\r
-          std::vector<DataComponentInterpretation::DataComponentInterpretation>\r
-           comp_type_vec(dim,\r
-                         DataComponentInterpretation::component_is_part_of_vector);\r
-          std::vector<std::string> solution_name_vec(dim,"seepage_velocity");\r
-\r
-          data_out.add_data_vector(vertex_vec_handler_ref,\r
-                                   sum_seepage_velocity_vertex_vec,\r
-                                   solution_name_vec,\r
-                                   comp_type_vec);\r
-\r
-          data_out.add_data_vector(vertex_handler_ref,\r
-                                   sum_porous_dissipation_vertex,\r
-                                   "dissipation_porous");\r
-          data_out.add_data_vector(vertex_handler_ref,\r
-                                   sum_viscous_dissipation_vertex,\r
-                                   "dissipation_viscous");\r
-          data_out.add_data_vector(vertex_handler_ref,\r
-                                   sum_solid_vol_fraction_vertex,\r
-                                   "solid_vol_fraction");\r
-        }\r
-      //---------------------------------------------------------------------\r
-\r
-        data_out.build_patches(degree_displ);\r
-\r
-        struct Filename\r
-        {\r
-          static std::string get_filename_vtu(unsigned int process,\r
-                                              unsigned int timestep,\r
-                                              const unsigned int n_digits = 5)\r
-          {\r
-            std::ostringstream filename_vtu;\r
-            filename_vtu\r
-            << "solution."\r
-            << Utilities::int_to_string(process, n_digits)\r
-            << "."\r
-            << Utilities::int_to_string(timestep, n_digits)\r
-            << ".vtu";\r
-            return filename_vtu.str();\r
-          }\r
-\r
-          static std::string get_filename_pvtu(unsigned int timestep,\r
-                                               const unsigned int n_digits = 5)\r
-          {\r
-            std::ostringstream filename_vtu;\r
-            filename_vtu\r
-            << "solution."\r
-            << Utilities::int_to_string(timestep, n_digits)\r
-            << ".pvtu";\r
-            return filename_vtu.str();\r
-          }\r
-\r
-          static std::string get_filename_pvd (void)\r
-          {\r
-            std::ostringstream filename_vtu;\r
-            filename_vtu\r
-            << "solution.pvd";\r
-            return filename_vtu.str();\r
-          }\r
-        };\r
-\r
-        const std::string filename_vtu = Filename::get_filename_vtu(this_mpi_process,\r
-                                                                    timestep);\r
-        std::ofstream output(filename_vtu.c_str());\r
-        data_out.write_vtu(output);\r
-\r
-        // We have a collection of files written in parallel\r
-        // This next set of steps should only be performed by master process\r
-        if (this_mpi_process == 0)\r
-        {\r
-          // List of all files written out at this timestep by all processors\r
-          std::vector<std::string> parallel_filenames_vtu;\r
-          for (unsigned int p=0; p<n_mpi_processes; ++p)\r
-          {\r
-            parallel_filenames_vtu.push_back(Filename::get_filename_vtu(p, timestep));\r
-          }\r
-\r
-          const std::string filename_pvtu(Filename::get_filename_pvtu(timestep));\r
-          std::ofstream pvtu_master(filename_pvtu.c_str());\r
-          data_out.write_pvtu_record(pvtu_master,\r
-                                     parallel_filenames_vtu);\r
-\r
-          // Time dependent data master file\r
-          static std::vector<std::pair<double,std::string>> time_and_name_history;\r
-          time_and_name_history.push_back(std::make_pair(current_time,\r
-                                                          filename_pvtu));\r
-          const std::string filename_pvd(Filename::get_filename_pvd());\r
-          std::ofstream pvd_output(filename_pvd.c_str());\r
-          DataOutBase::write_pvd_record(pvd_output, time_and_name_history);\r
-        }\r
-      }\r
-\r
-\r
-      //Print results to plotting file\r
-      template <int dim>\r
-      void Solid<dim>::output_results_to_plot(\r
-                                const unsigned int timestep,\r
-                                const double current_time,\r
-                                TrilinosWrappers::MPI::BlockVector solution_IN,\r
-                                std::vector<Point<dim> > &tracked_vertices_IN,\r
-                                std::ofstream &plotpointfile) const\r
-      {\r
-        TrilinosWrappers::MPI::BlockVector solution_total(locally_owned_partitioning,\r
-                                                          locally_relevant_partitioning,\r
-                                                          mpi_communicator,\r
-                                                          false);\r
-\r
-        (void) timestep;\r
-        solution_total = solution_IN;\r
-\r
-        //Variables needed to print the solution file for plotting\r
-        Point<dim> reaction_force;\r
-        Point<dim> reaction_force_pressure;\r
-        Point<dim> reaction_force_extra;\r
-        double total_fluid_flow = 0.0;\r
-        double total_porous_dissipation = 0.0;\r
-        double total_viscous_dissipation = 0.0;\r
-        double total_solid_vol = 0.0;\r
-        double total_vol_current = 0.0;\r
-        double total_vol_reference = 0.0;\r
-        std::vector<Point<dim+1>> solution_vertices(tracked_vertices_IN.size());\r
-\r
-        //Auxiliar variables needed for mpi processing\r
-        Tensor<1,dim> sum_reaction_mpi;\r
-        Tensor<1,dim> sum_reaction_pressure_mpi;\r
-        Tensor<1,dim> sum_reaction_extra_mpi;\r
-        sum_reaction_mpi = 0.0;\r
-        sum_reaction_pressure_mpi = 0.0;\r
-        sum_reaction_extra_mpi = 0.0;\r
-        double sum_total_flow_mpi = 0.0;\r
-        double sum_porous_dissipation_mpi = 0.0;\r
-        double sum_viscous_dissipation_mpi = 0.0;\r
-        double sum_solid_vol_mpi = 0.0;\r
-        double sum_vol_current_mpi = 0.0;\r
-        double sum_vol_reference_mpi = 0.0;\r
-\r
-        //Declare an instance of the material class object\r
-        if (parameters.mat_type == "Neo-Hooke")\r
-            NeoHooke<dim,ADNumberType> material(parameters,time);\r
-        else if (parameters.mat_type == "Ogden")\r
-            Ogden<dim,ADNumberType> material(parameters, time);\r
-        else if (parameters.mat_type == "visco-Ogden")\r
-            visco_Ogden <dim,ADNumberType>material(parameters,time);\r
-        else\r
-        Assert (false, ExcMessage("Material type not implemented"));\r
-\r
-        //Define a local instance of FEValues to compute updated values required\r
-        //to calculate stresses\r
-        const UpdateFlags uf_cell(update_values | update_gradients |\r
-                                  update_JxW_values);\r
-        FEValues<dim> fe_values_ref (fe, qf_cell, uf_cell);\r
-\r
-        //Iterate through elements (cells) and Gauss Points\r
-        FilteredIterator<typename DoFHandler<dim>::active_cell_iterator>\r
-          cell(IteratorFilters::LocallyOwnedCell(),\r
-               dof_handler_ref.begin_active()),\r
-          endc(IteratorFilters::LocallyOwnedCell(),\r
-               dof_handler_ref.end());\r
-        //start cell loop\r
-        for (; cell!=endc; ++cell)\r
-        {\r
-            Assert(cell->is_locally_owned(), ExcInternalError());\r
-            Assert(cell->subdomain_id() == this_mpi_process, ExcInternalError());\r
-\r
-            fe_values_ref.reinit(cell);\r
-\r
-            std::vector<Tensor<2,dim>> solution_grads_u(n_q_points);\r
-            fe_values_ref[u_fe].get_function_gradients(solution_total,\r
-                                                       solution_grads_u);\r
-\r
-            std::vector<double> solution_values_p_fluid_total(n_q_points);\r
-            fe_values_ref[p_fluid_fe].get_function_values(solution_total,\r
-                                                          solution_values_p_fluid_total);\r
-\r
-            std::vector<Tensor<1,dim >> solution_grads_p_fluid_AD(n_q_points);\r
-            fe_values_ref[p_fluid_fe].get_function_gradients(solution_total,\r
-                                                             solution_grads_p_fluid_AD);\r
-\r
-            //start gauss point loop\r
-            for (unsigned int q_point=0; q_point<n_q_points; ++q_point)\r
-            {\r
-                const Tensor<2,dim,ADNumberType>\r
-                  F_AD = Physics::Elasticity::Kinematics::F(solution_grads_u[q_point]);\r
-                ADNumberType det_F_AD = determinant(F_AD);\r
-                const double det_F = Tensor<0,dim,double>(det_F_AD);\r
-\r
-                const std::vector<std::shared_ptr<const PointHistory<dim,ADNumberType>>>\r
-                    lqph = quadrature_point_history.get_data(cell);\r
-                Assert(lqph.size() == n_q_points, ExcInternalError());\r
-\r
-                double JxW = fe_values_ref.JxW(q_point);\r
-\r
-                //Volumes\r
-                sum_vol_current_mpi  += det_F * JxW;\r
-                sum_vol_reference_mpi += JxW;\r
-                sum_solid_vol_mpi += parameters.solid_vol_frac * JxW * det_F;\r
-\r
-                //Seepage velocity\r
-                const Tensor<2,dim,ADNumberType> F_inv = invert(F_AD);\r
-                const Tensor<1,dim,ADNumberType>\r
-                  grad_p_fluid_AD =  solution_grads_p_fluid_AD[q_point]*F_inv;\r
-                const Tensor<1,dim,ADNumberType> seepage_vel_AD\r
-                = lqph[q_point]->get_seepage_velocity_current(F_AD, grad_p_fluid_AD);\r
-\r
-                //Dissipations\r
-                const double porous_dissipation =\r
-                  lqph[q_point]->get_porous_dissipation(F_AD, grad_p_fluid_AD);\r
-                sum_porous_dissipation_mpi += porous_dissipation * det_F * JxW;\r
-\r
-                const double viscous_dissipation = lqph[q_point]->get_viscous_dissipation();\r
-                sum_viscous_dissipation_mpi += viscous_dissipation * det_F * JxW;\r
-\r
-              //---------------------------------------------------------------\r
-            } //end gauss point loop\r
-\r
-            // Compute reaction force on load boundary & total fluid flow across\r
-            // drained boundary.\r
-            // Define a local instance of FEFaceValues to compute values required\r
-            // to calculate reaction force\r
-            const UpdateFlags uf_face( update_values | update_gradients |\r
-                                       update_normal_vectors | update_JxW_values );\r
-            FEFaceValues<dim> fe_face_values_ref(fe, qf_face, uf_face);\r
-\r
-            //start face loop\r
-            for (unsigned int face=0; face<GeometryInfo<dim>::faces_per_cell; ++face)\r
-            {\r
-                //Reaction force\r
-                if (cell->face(face)->at_boundary() == true &&\r
-                    cell->face(face)->boundary_id() == get_reaction_boundary_id_for_output() )\r
-                {\r
-                    fe_face_values_ref.reinit(cell, face);\r
-\r
-                    //Get displacement gradients for current face\r
-                    std::vector<Tensor<2,dim> > solution_grads_u_f(n_q_points_f);\r
-                    fe_face_values_ref[u_fe].get_function_gradients\r
-                                                         (solution_total,\r
-                                                          solution_grads_u_f);\r
-\r
-                    //Get pressure for current element\r
-                    std::vector< double > solution_values_p_fluid_total_f(n_q_points_f);\r
-                    fe_face_values_ref[p_fluid_fe].get_function_values\r
-                                               (solution_total,\r
-                                                solution_values_p_fluid_total_f);\r
-\r
-                    //start gauss points on faces loop\r
-                    for (unsigned int f_q_point=0; f_q_point<n_q_points_f; ++f_q_point)\r
-                    {\r
-                        const Tensor<1,dim> &N = fe_face_values_ref.normal_vector(f_q_point);\r
-                        const double JxW_f = fe_face_values_ref.JxW(f_q_point);\r
-\r
-                        //Compute deformation gradient from displacements gradient\r
-                        //(present configuration)\r
-                        const Tensor<2,dim,ADNumberType> F_AD =\r
-                          Physics::Elasticity::Kinematics::F(solution_grads_u_f[f_q_point]);\r
-\r
-                        const std::vector<std::shared_ptr<const PointHistory<dim,ADNumberType>>>\r
-                            lqph = quadrature_point_history.get_data(cell);\r
-                        Assert(lqph.size() == n_q_points, ExcInternalError());\r
-\r
-                        const double p_fluid = solution_values_p_fluid_total[f_q_point];\r
-\r
-                        //Cauchy stress\r
-                        static const SymmetricTensor<2,dim,double>\r
-                          I (Physics::Elasticity::StandardTensors<dim>::I);\r
-                        SymmetricTensor<2,dim> sigma_E;\r
-                        const SymmetricTensor<2,dim,ADNumberType> sigma_E_AD =\r
-                          lqph[f_q_point]->get_Cauchy_E(F_AD);\r
-\r
-                        for (unsigned int i=0; i<dim; ++i)\r
-                            for (unsigned int j=0; j<dim; ++j)\r
-                               sigma_E[i][j] = Tensor<0,dim,double>(sigma_E_AD[i][j]);\r
-\r
-                        SymmetricTensor<2,dim> sigma_fluid_vol(I);\r
-                        sigma_fluid_vol *= -1.0*p_fluid;\r
-                        const SymmetricTensor<2,dim> sigma = sigma_E+sigma_fluid_vol;\r
-                        sum_reaction_mpi += sigma * N * JxW_f;\r
-                        sum_reaction_pressure_mpi += sigma_fluid_vol * N * JxW_f;\r
-                        sum_reaction_extra_mpi += sigma_E * N * JxW_f;\r
-                    }//end gauss points on faces loop\r
-                }\r
-\r
-                //Fluid flow\r
-                if (cell->face(face)->at_boundary() == true &&\r
-                   (cell->face(face)->boundary_id() ==\r
-                      get_drained_boundary_id_for_output().first ||\r
-                    cell->face(face)->boundary_id() ==\r
-                      get_drained_boundary_id_for_output().second ) )\r
-                {\r
-                    fe_face_values_ref.reinit(cell, face);\r
-\r
-                    //Get displacement gradients for current face\r
-                    std::vector<Tensor<2,dim>> solution_grads_u_f(n_q_points_f);\r
-                    fe_face_values_ref[u_fe].get_function_gradients\r
-                                                            (solution_total,\r
-                                                             solution_grads_u_f);\r
-\r
-                    //Get pressure gradients for current face\r
-                    std::vector<Tensor<1,dim>> solution_grads_p_f(n_q_points_f);\r
-                    fe_face_values_ref[p_fluid_fe].get_function_gradients\r
-                                                             (solution_total,\r
-                                                              solution_grads_p_f);\r
-\r
-                    //start gauss points on faces loop\r
-                    for (unsigned int f_q_point=0; f_q_point<n_q_points_f; ++f_q_point)\r
-                    {\r
-                        const Tensor<1,dim> &N =\r
-                                  fe_face_values_ref.normal_vector(f_q_point);\r
-                        const double JxW_f = fe_face_values_ref.JxW(f_q_point);\r
-\r
-                        //Deformation gradient and inverse from displacements gradient\r
-                        //(present configuration)\r
-                        const Tensor<2,dim,ADNumberType> F_AD\r
-                            = Physics::Elasticity::Kinematics::F(solution_grads_u_f[f_q_point]);\r
-\r
-                        const Tensor<2,dim,ADNumberType> F_inv_AD = invert(F_AD);\r
-                        ADNumberType det_F_AD = determinant(F_AD);\r
-\r
-                        const std::vector<std::shared_ptr<const PointHistory<dim,ADNumberType>>>\r
-                            lqph = quadrature_point_history.get_data(cell);\r
-                        Assert(lqph.size() == n_q_points, ExcInternalError());\r
-\r
-                        //Seepage velocity\r
-                        Tensor<1,dim> seepage;\r
-                        double det_F = Tensor<0,dim,double>(det_F_AD);\r
-                        const Tensor<1,dim,ADNumberType> grad_p\r
-                                          = solution_grads_p_f[f_q_point]*F_inv_AD;\r
-                        const Tensor<1,dim,ADNumberType> seepage_AD\r
-                          = lqph[f_q_point]->get_seepage_velocity_current(F_AD, grad_p);\r
-\r
-                        for (unsigned int i=0; i<dim; ++i)\r
-                            seepage[i] = Tensor<0,dim,double>(seepage_AD[i]);\r
-\r
-                        sum_total_flow_mpi += (seepage/det_F) * N * JxW_f;\r
-                    }//end gauss points on faces loop\r
-                }\r
-            }//end face loop\r
-        }//end cell loop\r
-\r
-        //Sum the results from different MPI process and then add to the reaction_force vector\r
-        //In theory, the solution on each surface (each cell) only exists in one MPI process\r
-        //so, we add all MPI process, one will have the solution and the others will be zero\r
-        for (unsigned int d=0; d<dim; ++d)\r
-        {\r
-            reaction_force[d] = Utilities::MPI::sum(sum_reaction_mpi[d],\r
-                                                    mpi_communicator);\r
-            reaction_force_pressure[d] = Utilities::MPI::sum(sum_reaction_pressure_mpi[d],\r
-                                                             mpi_communicator);\r
-            reaction_force_extra[d] = Utilities::MPI::sum(sum_reaction_extra_mpi[d],\r
-                                                          mpi_communicator);\r
-        }\r
-\r
-        //Same for total fluid flow, and for porous and viscous dissipations\r
-        total_fluid_flow = Utilities::MPI::sum(sum_total_flow_mpi,\r
-                                               mpi_communicator);\r
-        total_porous_dissipation = Utilities::MPI::sum(sum_porous_dissipation_mpi,\r
-                                                       mpi_communicator);\r
-        total_viscous_dissipation = Utilities::MPI::sum(sum_viscous_dissipation_mpi,\r
-                                                        mpi_communicator);\r
-        total_solid_vol = Utilities::MPI::sum(sum_solid_vol_mpi,\r
-                                              mpi_communicator);\r
-        total_vol_current = Utilities::MPI::sum(sum_vol_current_mpi,\r
-                                                mpi_communicator);\r
-        total_vol_reference = Utilities::MPI::sum(sum_vol_reference_mpi,\r
-                                                  mpi_communicator);\r
-\r
-      //  Extract solution for tracked vectors\r
-      // Copying an MPI::BlockVector into MPI::Vector is not possible,\r
-      // so we copy each block of MPI::BlockVector into an MPI::Vector\r
-      // And then we copy the MPI::Vector into "normal" Vectors\r
-        TrilinosWrappers::MPI::Vector solution_vector_u_MPI(solution_total.block(u_block));\r
-        TrilinosWrappers::MPI::Vector solution_vector_p_MPI(solution_total.block(p_fluid_block));\r
-        Vector<double> solution_u_vector(solution_vector_u_MPI);\r
-        Vector<double> solution_p_vector(solution_vector_p_MPI);\r
-\r
-        if (this_mpi_process == 0)\r
-        {\r
-            //Append the pressure solution vector to the displacement solution vector,\r
-            //creating a single solution vector equivalent to the original BlockVector\r
-            //so FEFieldFunction will work with the dof_handler_ref.\r
-            Vector<double> solution_vector(solution_p_vector.size()\r
-                                           +solution_u_vector.size());\r
-\r
-            for (unsigned int d=0; d<(solution_u_vector.size()); ++d)\r
-                solution_vector[d] = solution_u_vector[d];\r
-\r
-            for (unsigned int d=0; d<(solution_p_vector.size()); ++d)\r
-                solution_vector[solution_u_vector.size()+d] = solution_p_vector[d];\r
-\r
-            Functions::FEFieldFunction<dim,Vector<double>>\r
-            find_solution(dof_handler_ref, solution_vector);\r
-\r
-            for (unsigned int p=0; p<tracked_vertices_IN.size(); ++p)\r
-            {\r
-                Vector<double> update(dim+1);\r
-                Point<dim> pt_ref;\r
-\r
-                pt_ref[0]= tracked_vertices_IN[p][0];\r
-                pt_ref[1]= tracked_vertices_IN[p][1];\r
-                pt_ref[2]= tracked_vertices_IN[p][2];\r
-\r
-               find_solution.vector_value(pt_ref, update);\r
-\r
-               for (unsigned int d=0; d<(dim+1); ++d)\r
-               {\r
-                   //For values close to zero, set to 0.0\r
-                   if (abs(update[d])<1.5*parameters.tol_u)\r
-                       update[d] = 0.0;\r
-                   solution_vertices[p][d] = update[d];\r
-               }\r
-            }\r
-      // Write the results to the plotting file.\r
-      // Add two blank lines between cycles in the cyclic loading examples so GNUPLOT can detect each cycle as a different block\r
-            if (( (parameters.geom_type == "Budday_cube_tension_compression_fully_fixed")||\r
-                  (parameters.geom_type == "Budday_cube_tension_compression")||\r
-                  (parameters.geom_type == "Budday_cube_shear_fully_fixed")                ) &&\r
-                ( (abs(current_time - parameters.end_time/3.)   <0.9*parameters.delta_t)||\r
-                  (abs(current_time - 2.*parameters.end_time/3.)<0.9*parameters.delta_t)   ) &&\r
-                  parameters.num_cycle_sets == 1 )\r
-            {\r
-                plotpointfile << std::endl<< std::endl;\r
-            }\r
-            if (( (parameters.geom_type == "Budday_cube_tension_compression_fully_fixed")||\r
-                  (parameters.geom_type == "Budday_cube_tension_compression")||\r
-                  (parameters.geom_type == "Budday_cube_shear_fully_fixed")             ) &&\r
-                ( (abs(current_time - parameters.end_time/9.)   <0.9*parameters.delta_t)||\r
-                  (abs(current_time - 2.*parameters.end_time/9.)<0.9*parameters.delta_t)||\r
-                  (abs(current_time - 3.*parameters.end_time/9.)<0.9*parameters.delta_t)||\r
-                  (abs(current_time - 5.*parameters.end_time/9.)<0.9*parameters.delta_t)||\r
-                  (abs(current_time - 7.*parameters.end_time/9.)<0.9*parameters.delta_t) ) &&\r
-                  parameters.num_cycle_sets == 2 )\r
-            {\r
-                plotpointfile << std::endl<< std::endl;\r
-            }\r
-\r
-            plotpointfile <<  std::setprecision(6) << std::scientific;\r
-            plotpointfile << std::setw(16) << current_time        << ","\r
-                          << std::setw(15) << total_vol_reference << ","\r
-                          << std::setw(15) << total_vol_current   << ","\r
-                          << std::setw(15) << total_solid_vol     << ",";\r
-\r
-            if (current_time == 0.0)\r
-            {\r
-                for (unsigned int p=0; p<tracked_vertices_IN.size(); ++p)\r
-                {\r
-                    for (unsigned int d=0; d<dim; ++d)\r
-                        plotpointfile << std::setw(15) << 0.0 << ",";\r
-\r
-                    plotpointfile << std::setw(15) << parameters.drained_pressure << ",";\r
-                }\r
-                for (unsigned int d=0; d<(3*dim+2); ++d)\r
-                    plotpointfile << std::setw(15) << 0.0 << ",";\r
-\r
-                plotpointfile << std::setw(15) << 0.0;\r
-            }\r
-            else\r
-            {\r
-                for (unsigned int p=0; p<tracked_vertices_IN.size(); ++p)\r
-                    for (unsigned int d=0; d<(dim+1); ++d)\r
-                        plotpointfile << std::setw(15) << solution_vertices[p][d]<< ",";\r
-\r
-                for (unsigned int d=0; d<dim; ++d)\r
-                    plotpointfile << std::setw(15) << reaction_force[d] << ",";\r
-\r
-                for (unsigned int d=0; d<dim; ++d)\r
-                    plotpointfile << std::setw(15) << reaction_force_pressure[d] << ",";\r
-\r
-                for (unsigned int d=0; d<dim; ++d)\r
-                    plotpointfile << std::setw(15) << reaction_force_extra[d] << ",";\r
-\r
-                plotpointfile << std::setw(15) << total_fluid_flow << ","\r
-                              << std::setw(15) << total_porous_dissipation<< ","\r
-                              << std::setw(15) << total_viscous_dissipation;\r
-            }\r
-            plotpointfile << std::endl;\r
-        }\r
-      }\r
-\r
-    //Header for console output file\r
-    template <int dim>\r
-    void Solid<dim>::print_console_file_header(std::ofstream &outputfile) const\r
-    {\r
-            outputfile << "/*-----------------------------------------------------------------------------------------";\r
-            outputfile << "\n\n  Poro-viscoelastic formulation to solve nonlinear solid mechanics problems using deal.ii";\r
-            outputfile << "\n\n  Problem setup by E Comellas and J-P Pelteret, University of Erlangen-Nuremberg, 2018";\r
-            outputfile << "\n\n/*-----------------------------------------------------------------------------------------";\r
-            outputfile << "\n\nCONSOLE OUTPUT: \n\n";\r
-    }\r
-\r
-    //Header for plotting output file\r
-    template <int dim>\r
-    void Solid<dim>::print_plot_file_header(std::vector<Point<dim> > &tracked_vertices,\r
-                                            std::ofstream &plotpointfile) const\r
-    {\r
-            plotpointfile << "#\n# *** Solution history for tracked vertices -- DOF: 0 = Ux,  1 = Uy,  2 = Uz,  3 = P ***"\r
-                          << std::endl;\r
-\r
-            for  (unsigned int p=0; p<tracked_vertices.size(); ++p)\r
-            {\r
-                plotpointfile << "#        Point " << p << " coordinates:  ";\r
-                for (unsigned int d=0; d<dim; ++d)\r
-                  {\r
-                    plotpointfile << tracked_vertices[p][d];\r
-                    if (!( (p == tracked_vertices.size()-1) && (d == dim-1) ))\r
-                        plotpointfile << ",        ";\r
-                  }\r
-                plotpointfile << std::endl;\r
-            }\r
-            plotpointfile << "#    The reaction force is the integral over the loaded surfaces in the "\r
-                          << "undeformed configuration of the Cauchy stress times the normal surface unit vector.\n"\r
-                          << "#    reac(p) corresponds to the volumetric part of the Cauchy stress due to the pore fluid pressure"\r
-                          << " and reac(E) corresponds to the extra part of the Cauchy stress due to the solid contribution."\r
-                          << std::endl\r
-                          << "#    The fluid flow is the integral over the drained surfaces in the "\r
-                          << "undeformed configuration of the seepage velocity times the normal surface unit vector."\r
-                          << std::endl\r
-                          << "# Column number:"\r
-                          << std::endl\r
-                          << "#";\r
-\r
-          unsigned int columns = 24;\r
-          for (unsigned int d=1; d<columns; ++d)\r
-              plotpointfile << std::setw(15)<< d <<",";\r
-\r
-            plotpointfile << std::setw(15)<< columns\r
-                          << std::endl\r
-                          << "#"\r
-                          << std::right << std::setw(16) << "Time,"\r
-                          << std::right << std::setw(16) << "ref vol,"\r
-                          << std::right << std::setw(16) << "def vol,"\r
-                          << std::right << std::setw(16) << "solid vol,";\r
-            for (unsigned int p=0; p<tracked_vertices.size(); ++p)\r
-                for (unsigned int d=0; d<(dim+1); ++d)\r
-                    plotpointfile << std::right<< std::setw(11)\r
-                                  <<"P" << p << "[" << d << "],";\r
-\r
-            for (unsigned int d=0; d<dim; ++d)\r
-                plotpointfile << std::right<< std::setw(13)\r
-                              << "reaction [" << d << "],";\r
-\r
-            for (unsigned int d=0; d<dim; ++d)\r
-                plotpointfile << std::right<< std::setw(13)\r
-                              << "reac(p) [" << d << "],";\r
-\r
-            for (unsigned int d=0; d<dim; ++d)\r
-                plotpointfile << std::right<< std::setw(13)\r
-                              << "reac(E) [" << d << "],";\r
-\r
-            plotpointfile << std::right<< std::setw(16)<< "fluid flow,"\r
-                          << std::right<< std::setw(16)<< "porous dissip,"\r
-                          << std::right<< std::setw(15)<< "viscous dissip"\r
-                          << std::endl;\r
-    }\r
-\r
-    //Footer for console output file\r
-    template <int dim>\r
-    void Solid<dim>::print_console_file_footer(std::ofstream &outputfile) const\r
-    {\r
-           //Copy "parameters" file at end of output file.\r
-           std::ifstream infile("parameters.prm");\r
-           std::string content = "";\r
-           int i;\r
-\r
-           for(i=0 ; infile.eof()!=true ; i++)\r
-           {\r
-               char aux = infile.get();\r
-               content += aux;\r
-               if(aux=='\n') content += '#';\r
-           }\r
-\r
-           i--;\r
-           content.erase(content.end()-1);\r
-           infile.close();\r
-\r
-           outputfile << "\n\n\n\n PARAMETERS FILE USED IN THIS COMPUTATION: \n#"\r
-                      << std::endl\r
-                      << content;\r
-    }\r
-\r
-    //Footer for plotting output file\r
-    template <int dim>\r
-    void Solid<dim>::print_plot_file_footer(std::ofstream &plotpointfile) const\r
-    {\r
-           //Copy "parameters" file at end of output file.\r
-           std::ifstream infile("parameters.prm");\r
-           std::string content = "";\r
-           int i;\r
-\r
-           for(i=0 ; infile.eof()!=true ; i++)\r
-           {\r
-               char aux = infile.get();\r
-               content += aux;\r
-               if(aux=='\n') content += '#';\r
-           }\r
-\r
-           i--;\r
-           content.erase(content.end()-1);\r
-           infile.close();\r
-\r
-           plotpointfile << "#"<< std::endl\r
-                         << "#"<< std::endl\r
-                         << "# PARAMETERS FILE USED IN THIS COMPUTATION:" << std::endl\r
-                         << "#"<< std::endl\r
-                         << content;\r
-    }\r
-\r
-\r
-    // @sect3{Verification examples from Ehlers and Eipper 1999}\r
-    // We group the definition of the geometry, boundary and loading conditions specific to\r
-    // the verification examples from Ehlers and Eipper 1999 into specific classes.\r
-\r
-    //@sect4{Base class: Tube geometry and boundary conditions}\r
-    template <int dim>\r
-    class VerificationEhlers1999TubeBase\r
-          : public Solid<dim>\r
-    {\r
-        public:\r
-          VerificationEhlers1999TubeBase (const Parameters::AllParameters &parameters)\r
-            : Solid<dim> (parameters)\r
-          {}\r
-\r
-          virtual ~VerificationEhlers1999TubeBase () {}\r
-\r
-        private:\r
-          virtual void make_grid() override\r
-          {\r
-            GridGenerator::cylinder( this->triangulation,\r
-                                     0.1,\r
-                                     0.5);\r
-\r
-            const double rot_angle = 3.0*numbers::PI/2.0;\r
-            GridTools::rotate( Point<3>::unit_vector(1), rot_angle, this->triangulation);\r
-\r
-            this->triangulation.reset_manifold(0);\r
-            static const CylindricalManifold<dim> manifold_description_3d(2);\r
-            this->triangulation.set_manifold (0, manifold_description_3d);\r
-            GridTools::scale(this->parameters.scale, this->triangulation);\r
-            this->triangulation.refine_global(std::max (1U, this->parameters.global_refinement));\r
-            this->triangulation.reset_manifold(0);\r
-          }\r
-\r
-          virtual void define_tracked_vertices(std::vector<Point<dim> > &tracked_vertices) override\r
-          {\r
-            tracked_vertices[0][0] = 0.0*this->parameters.scale;\r
-            tracked_vertices[0][1] = 0.0*this->parameters.scale;\r
-            tracked_vertices[0][2] = 0.5*this->parameters.scale;\r
-\r
-            tracked_vertices[1][0] = 0.0*this->parameters.scale;\r
-            tracked_vertices[1][1] = 0.0*this->parameters.scale;\r
-            tracked_vertices[1][2] = -0.5*this->parameters.scale;\r
-          }\r
-\r
-          virtual void make_dirichlet_constraints(AffineConstraints<double> &constraints) override\r
-          {\r
-            if (this->time.get_timestep() < 2)\r
-            {\r
-              VectorTools::interpolate_boundary_values(this->dof_handler_ref,\r
-                                                       2,\r
-                                                       Functions::ConstantFunction<dim>(this->parameters.drained_pressure,this->n_components),\r
-                                                       constraints,\r
-                                                       (this->fe.component_mask(this->pressure)));\r
-            }\r
-            else\r
-            {\r
-              VectorTools::interpolate_boundary_values(this->dof_handler_ref,\r
-                                                       2,\r
-                                                       Functions::ZeroFunction<dim>(this->n_components),\r
-                                                       constraints,\r
-                                                       (this->fe.component_mask(this->pressure)));\r
-            }\r
-\r
-            VectorTools::interpolate_boundary_values( this->dof_handler_ref,\r
-                                                      0,\r
-                                                      Functions::ZeroFunction<dim>(this->n_components),\r
-                                                      constraints,\r
-                                                      (this->fe.component_mask(this->x_displacement)|\r
-                                                       this->fe.component_mask(this->y_displacement)  ) );\r
-\r
-            VectorTools::interpolate_boundary_values( this->dof_handler_ref,\r
-                                                      1,\r
-                                                      Functions::ZeroFunction<dim>(this->n_components),\r
-                                                      constraints,\r
-                                                      (this->fe.component_mask(this->x_displacement) |\r
-                                                       this->fe.component_mask(this->y_displacement) |\r
-                                                       this->fe.component_mask(this->z_displacement) ));\r
-          }\r
-\r
-          virtual double\r
-          get_prescribed_fluid_flow (const types::boundary_id &boundary_id,\r
-                                     const Point<dim>         &pt) const override\r
-          {\r
-              (void)pt;\r
-              (void)boundary_id;\r
-              return 0.0;\r
-          }\r
-\r
-          virtual types::boundary_id\r
-          get_reaction_boundary_id_for_output() const override\r
-          {\r
-              return 2;\r
-          }\r
-\r
-          virtual  std::pair<types::boundary_id,types::boundary_id>\r
-          get_drained_boundary_id_for_output() const override\r
-          {\r
-              return std::make_pair(2,2);\r
-          }\r
-\r
-          virtual std::vector<double>\r
-          get_dirichlet_load(const types::boundary_id   &boundary_id,\r
-                             const int                  &direction) const override\r
-          {\r
-              std::vector<double> displ_incr(dim, 0.0);\r
-              (void)boundary_id;\r
-              (void)direction;\r
-              AssertThrow(false, ExcMessage("Displacement loading not implemented for Ehlers verification examples."));\r
-\r
-              return displ_incr;\r
-          }\r
-    };\r
-\r
-    //@sect4{Derived class: Step load example}\r
-    template <int dim>\r
-    class VerificationEhlers1999StepLoad\r
-          : public VerificationEhlers1999TubeBase<dim>\r
-    {\r
-        public:\r
-          VerificationEhlers1999StepLoad (const Parameters::AllParameters &parameters)\r
-            : VerificationEhlers1999TubeBase<dim> (parameters)\r
-          {}\r
-\r
-          virtual ~VerificationEhlers1999StepLoad () {}\r
-\r
-        private:\r
-            virtual Tensor<1,dim>\r
-            get_neumann_traction (const types::boundary_id &boundary_id,\r
-                                  const Point<dim>         &pt,\r
-                                  const Tensor<1,dim>      &N) const override\r
-            {\r
-              if (this->parameters.load_type == "pressure")\r
-              {\r
-                if (boundary_id == 2)\r
-                {\r
-                  return this->parameters.load * N;\r
-                }\r
-              }\r
-\r
-              (void)pt;\r
-\r
-              return Tensor<1,dim>();\r
-            }\r
-    };\r
-\r
-    //@sect4{Derived class: Load increasing example}\r
-    template <int dim>\r
-    class VerificationEhlers1999IncreaseLoad\r
-          : public VerificationEhlers1999TubeBase<dim>\r
-    {\r
-        public:\r
-          VerificationEhlers1999IncreaseLoad (const Parameters::AllParameters &parameters)\r
-            : VerificationEhlers1999TubeBase<dim> (parameters)\r
-          {}\r
-\r
-          virtual ~VerificationEhlers1999IncreaseLoad () {}\r
-\r
-        private:\r
-            virtual Tensor<1,dim>\r
-            get_neumann_traction (const types::boundary_id &boundary_id,\r
-                                  const Point<dim>         &pt,\r
-                                  const Tensor<1,dim>      &N) const override\r
-            {\r
-              if (this->parameters.load_type == "pressure")\r
-              {\r
-                if (boundary_id == 2)\r
-                {\r
-                  const double initial_load = this->parameters.load;\r
-                  const double final_load = 20.0*initial_load;\r
-                  const double initial_time = this->time.get_delta_t();\r
-                  const double final_time = this->time.get_end();\r
-                  const double current_time = this->time.get_current();\r
-                  const double load = initial_load + (final_load-initial_load)*(current_time-initial_time)/(final_time-initial_time);\r
-                  return load * N;\r
-                }\r
-              }\r
-\r
-              (void)pt;\r
-\r
-              return Tensor<1,dim>();\r
-            }\r
-    };\r
-\r
-    //@sect4{Class: Consolidation cube}\r
-    template <int dim>\r
-    class VerificationEhlers1999CubeConsolidation\r
-          : public Solid<dim>\r
-    {\r
-        public:\r
-          VerificationEhlers1999CubeConsolidation (const Parameters::AllParameters &parameters)\r
-            : Solid<dim> (parameters)\r
-          {}\r
-\r
-          virtual ~VerificationEhlers1999CubeConsolidation () {}\r
-\r
-        private:\r
-          virtual void\r
-          make_grid() override\r
-          {\r
-             GridGenerator::hyper_rectangle(this->triangulation,\r
-                                            Point<dim>(0.0, 0.0, 0.0),\r
-                                            Point<dim>(1.0, 1.0, 1.0),\r
-                                            true);\r
-\r
-             GridTools::scale(this->parameters.scale, this->triangulation);\r
-             this->triangulation.refine_global(std::max (1U, this->parameters.global_refinement));\r
-\r
-             typename Triangulation<dim>::active_cell_iterator cell =\r
-                     this->triangulation.begin_active(), endc = this->triangulation.end();\r
-             for (; cell != endc; ++cell)\r
-             {\r
-               for (unsigned int face = 0; face < GeometryInfo<dim>::faces_per_cell; ++face)\r
-                 if (cell->face(face)->at_boundary() == true  &&\r
-                     cell->face(face)->center()[2] == 1.0 * this->parameters.scale)\r
-                 {\r
-                   if (cell->face(face)->center()[0] < 0.5 * this->parameters.scale  &&\r
-                       cell->face(face)->center()[1] < 0.5 * this->parameters.scale)\r
-                       cell->face(face)->set_boundary_id(100);\r
-                   else\r
-                       cell->face(face)->set_boundary_id(101);\r
-                 }\r
-             }\r
-          }\r
-\r
-          virtual void\r
-          define_tracked_vertices(std::vector<Point<dim> > &tracked_vertices) override\r
-          {\r
-            tracked_vertices[0][0] = 0.0*this->parameters.scale;\r
-            tracked_vertices[0][1] = 0.0*this->parameters.scale;\r
-            tracked_vertices[0][2] = 1.0*this->parameters.scale;\r
-\r
-            tracked_vertices[1][0] = 0.0*this->parameters.scale;\r
-            tracked_vertices[1][1] = 0.0*this->parameters.scale;\r
-            tracked_vertices[1][2] = 0.0*this->parameters.scale;\r
-          }\r
-\r
-          virtual void\r
-          make_dirichlet_constraints(AffineConstraints<double> &constraints) override\r
-          {\r
-            if (this->time.get_timestep() < 2)\r
-            {\r
-              VectorTools::interpolate_boundary_values(this->dof_handler_ref,\r
-                                                       101,\r
-                                                       Functions::ConstantFunction<dim>(this->parameters.drained_pressure,this->n_components),\r
-                                                       constraints,\r
-                                                       (this->fe.component_mask(this->pressure)));\r
-            }\r
-            else\r
-            {\r
-              VectorTools::interpolate_boundary_values(this->dof_handler_ref,\r
-                                                       101,\r
-                                                       Functions::ZeroFunction<dim>(this->n_components),\r
-                                                       constraints,\r
-                                                       (this->fe.component_mask(this->pressure)));\r
-            }\r
-\r
-            VectorTools::interpolate_boundary_values( this->dof_handler_ref,\r
-                                                      0,\r
-                                                      Functions::ZeroFunction<dim>(this->n_components),\r
-                                                      constraints,\r
-                                                      this->fe.component_mask(this->x_displacement));\r
-\r
-            VectorTools::interpolate_boundary_values( this->dof_handler_ref,\r
-                                                      1,\r
-                                                      Functions::ZeroFunction<dim>(this->n_components),\r
-                                                      constraints,\r
-                                                      this->fe.component_mask(this->x_displacement));\r
-\r
-            VectorTools::interpolate_boundary_values( this->dof_handler_ref,\r
-                                                      2,\r
-                                                      Functions::ZeroFunction<dim>(this->n_components),\r
-                                                      constraints,\r
-                                                      this->fe.component_mask(this->y_displacement));\r
-\r
-            VectorTools::interpolate_boundary_values( this->dof_handler_ref,\r
-                                                      3,\r
-                                                      Functions::ZeroFunction<dim>(this->n_components),\r
-                                                      constraints,\r
-                                                      this->fe.component_mask(this->y_displacement));\r
-\r
-            VectorTools::interpolate_boundary_values( this->dof_handler_ref,\r
-                                                      4,\r
-                                                      Functions::ZeroFunction<dim>(this->n_components),\r
-                                                      constraints,\r
-                                                      ( this->fe.component_mask(this->x_displacement) |\r
-                                                        this->fe.component_mask(this->y_displacement) |\r
-                                                        this->fe.component_mask(this->z_displacement) ));\r
-          }\r
-\r
-          virtual Tensor<1,dim>\r
-          get_neumann_traction (const types::boundary_id &boundary_id,\r
-                                const Point<dim>         &pt,\r
-                                const Tensor<1,dim>      &N) const override\r
-          {\r
-            if (this->parameters.load_type == "pressure")\r
-            {\r
-              if (boundary_id == 100)\r
-              {\r
-                return this->parameters.load * N;\r
-              }\r
-            }\r
-\r
-            (void)pt;\r
-\r
-            return Tensor<1,dim>();\r
-          }\r
-\r
-          virtual double\r
-          get_prescribed_fluid_flow (const types::boundary_id &boundary_id,\r
-                                     const Point<dim>         &pt) const override\r
-          {\r
-              (void)pt;\r
-              (void)boundary_id;\r
-              return 0.0;\r
-          }\r
-\r
-          virtual types::boundary_id\r
-          get_reaction_boundary_id_for_output() const override\r
-          {\r
-              return 100;\r
-          }\r
-\r
-          virtual  std::pair<types::boundary_id,types::boundary_id>\r
-          get_drained_boundary_id_for_output() const override\r
-          {\r
-              return std::make_pair(101,101);\r
-          }\r
-\r
-          virtual std::vector<double>\r
-          get_dirichlet_load(const types::boundary_id   &boundary_id,\r
-                             const int                  &direction) const override\r
-          {\r
-              std::vector<double> displ_incr(dim, 0.0);\r
-              (void)boundary_id;\r
-              (void)direction;\r
-              AssertThrow(false, ExcMessage("Displacement loading not implemented for Ehlers verification examples."));\r
-\r
-              return displ_incr;\r
-          }\r
-    };\r
-\r
-    //@sect4{Franceschini experiments}\r
-    template <int dim>\r
-    class Franceschini2006Consolidation\r
-          : public Solid<dim>\r
-    {\r
-        public:\r
-        Franceschini2006Consolidation (const Parameters::AllParameters &parameters)\r
-            : Solid<dim> (parameters)\r
-          {}\r
-\r
-          virtual ~Franceschini2006Consolidation () {}\r
-\r
-        private:\r
-          virtual void make_grid() override\r
-          {\r
-            const Point<dim-1> mesh_center(0.0, 0.0);\r
-            const double radius = 0.5;\r
-            //const double height = 0.27;  //8.1 mm for 30 mm radius\r
-            const double height = 0.23;  //6.9 mm for 30 mm radius\r
-            Triangulation<dim-1> triangulation_in;\r
-            GridGenerator::hyper_ball( triangulation_in,\r
-                                       mesh_center,\r
-                                       radius);\r
-\r
-            GridGenerator::extrude_triangulation(triangulation_in,\r
-                                                  2,\r
-                                                  height,\r
-                                                  this->triangulation);\r
-\r
-            const CylindricalManifold<dim> cylinder_3d(2);\r
-            const types::manifold_id cylinder_id = 0;\r
-\r
-\r
-            this->triangulation.set_manifold(cylinder_id, cylinder_3d);\r
-\r
-            for (auto cell : this->triangulation.active_cell_iterators())\r
-            {\r
-              for (unsigned int face = 0; face < GeometryInfo<dim>::faces_per_cell; ++face)\r
-              {\r
-                if (cell->face(face)->at_boundary() == true)\r
-                {\r
-                  if (cell->face(face)->center()[2] == 0.0)\r
-                      cell->face(face)->set_boundary_id(1);\r
-\r
-                  else if (cell->face(face)->center()[2] == height)\r
-                      cell->face(face)->set_boundary_id(2);\r
-\r
-                  else\r
-                  {\r
-                      cell->face(face)->set_boundary_id(0);\r
-                      cell->face(face)->set_all_manifold_ids(cylinder_id);\r
-                  }\r
-                }\r
-              }\r
-            }\r
-\r
-            GridTools::scale(this->parameters.scale, this->triangulation);\r
-            this->triangulation.refine_global(std::max (1U, this->parameters.global_refinement));\r
-          }\r
-\r
-          virtual void define_tracked_vertices(std::vector<Point<dim> > &tracked_vertices) override\r
-          {\r
-            tracked_vertices[0][0] = 0.0*this->parameters.scale;\r
-            tracked_vertices[0][1] = 0.0*this->parameters.scale;\r
-         //  tracked_vertices[0][2] = 0.27*this->parameters.scale;\r
-            tracked_vertices[0][2] = 0.23*this->parameters.scale;\r
-\r
-            tracked_vertices[1][0] = 0.0*this->parameters.scale;\r
-            tracked_vertices[1][1] = 0.0*this->parameters.scale;\r
-            tracked_vertices[1][2] = 0.0*this->parameters.scale;\r
-          }\r
-\r
-          virtual void make_dirichlet_constraints(AffineConstraints<double> &constraints) override\r
-          {\r
-            if (this->time.get_timestep() < 2)\r
-            {\r
-              VectorTools::interpolate_boundary_values(this->dof_handler_ref,\r
-                                                       1,\r
-                                                       Functions::ConstantFunction<dim>(this->parameters.drained_pressure,this->n_components),\r
-                                                       constraints,\r
-                                                       (this->fe.component_mask(this->pressure)));\r
-\r
-              VectorTools::interpolate_boundary_values(this->dof_handler_ref,\r
-                                                       2,\r
-                                                       Functions::ConstantFunction<dim>(this->parameters.drained_pressure,this->n_components),\r
-                                                       constraints,\r
-                                                       (this->fe.component_mask(this->pressure)));\r
-            }\r
-            else\r
-            {\r
-              VectorTools::interpolate_boundary_values(this->dof_handler_ref,\r
-                                                       1,\r
-                                                       Functions::ZeroFunction<dim>(this->n_components),\r
-                                                       constraints,\r
-                                                       (this->fe.component_mask(this->pressure)));\r
-\r
-              VectorTools::interpolate_boundary_values(this->dof_handler_ref,\r
-                                                       2,\r
-                                                       Functions::ZeroFunction<dim>(this->n_components),\r
-                                                       constraints,\r
-                                                       (this->fe.component_mask(this->pressure)));\r
-            }\r
-\r
-            VectorTools::interpolate_boundary_values( this->dof_handler_ref,\r
-                                                      0,\r
-                                                      Functions::ZeroFunction<dim>(this->n_components),\r
-                                                      constraints,\r
-                                                      (this->fe.component_mask(this->x_displacement)|\r
-                                                       this->fe.component_mask(this->y_displacement)  ) );\r
-\r
-            VectorTools::interpolate_boundary_values( this->dof_handler_ref,\r
-                                                      1,\r
-                                                      Functions::ZeroFunction<dim>(this->n_components),\r
-                                                      constraints,\r
-                                                      (this->fe.component_mask(this->x_displacement) |\r
-                                                       this->fe.component_mask(this->y_displacement) |\r
-                                                       this->fe.component_mask(this->z_displacement) ));\r
-\r
-            VectorTools::interpolate_boundary_values( this->dof_handler_ref,\r
-                                                      2,\r
-                                                      Functions::ZeroFunction<dim>(this->n_components),\r
-                                                      constraints,\r
-                                                      (this->fe.component_mask(this->x_displacement) |\r
-                                                       this->fe.component_mask(this->y_displacement) ));\r
-          }\r
-\r
-          virtual double\r
-          get_prescribed_fluid_flow (const types::boundary_id &boundary_id,\r
-                                     const Point<dim>         &pt) const override\r
-          {\r
-              (void)pt;\r
-              (void)boundary_id;\r
-              return 0.0;\r
-          }\r
-\r
-          virtual types::boundary_id\r
-          get_reaction_boundary_id_for_output() const override\r
-          {\r
-              return 2;\r
-          }\r
-\r
-          virtual  std::pair<types::boundary_id,types::boundary_id>\r
-          get_drained_boundary_id_for_output() const override\r
-          {\r
-              return std::make_pair(1,2);\r
-          }\r
-\r
-          virtual std::vector<double>\r
-          get_dirichlet_load(const types::boundary_id   &boundary_id,\r
-                             const int                  &direction) const override\r
-          {\r
-              std::vector<double> displ_incr(dim, 0.0);\r
-              (void)boundary_id;\r
-              (void)direction;\r
-              AssertThrow(false, ExcMessage("Displacement loading not implemented for Franceschini examples."));\r
-\r
-              return displ_incr;\r
-          }\r
-\r
-          virtual Tensor<1,dim>\r
-          get_neumann_traction (const types::boundary_id &boundary_id,\r
-                                const Point<dim>         &pt,\r
-                                const Tensor<1,dim>      &N) const override\r
-          {\r
-            if (this->parameters.load_type == "pressure")\r
-            {\r
-              if (boundary_id == 2)\r
-              {\r
-                return (this->parameters.load * N);\r
-                /*\r
-                const double final_load = this->parameters.load;\r
-                const double final_load_time = 10 * this->time.get_delta_t();\r
-                const double current_time = this->time.get_current();\r
-\r
-\r
-                const double c = final_load_time / 2.0;\r
-                const double r = 200.0 * 0.03 / c;\r
-\r
-                const double load = final_load * std::exp(r * current_time)\r
-                                    / ( std::exp(c * current_time) +  std::exp(r * current_time));\r
-                return load * N;\r
-                */\r
-              }\r
-            }\r
-\r
-            (void)pt;\r
-\r
-            return Tensor<1,dim>();\r
-          }\r
-    };\r
-\r
-    // @sect3{Examples to reproduce experiments by Budday et al. 2017}\r
-    // We group the definition of the geometry, boundary and loading conditions specific to\r
-    // the examples to reproduce experiments by Budday et al. 2017 into specific classes.\r
-\r
-    //@sect4{Base class: Cube geometry and loading pattern}\r
-    template <int dim>\r
-    class BrainBudday2017BaseCube\r
-          : public Solid<dim>\r
-    {\r
-        public:\r
-            BrainBudday2017BaseCube (const Parameters::AllParameters &parameters)\r
-            : Solid<dim> (parameters)\r
-          {}\r
-\r
-          virtual ~BrainBudday2017BaseCube () {}\r
-\r
-        private:\r
-          virtual void\r
-          make_grid() override\r
-          {\r
-            GridGenerator::hyper_cube(this->triangulation,\r
-                                      0.0,\r
-                                      1.0,\r
-                                      true);\r
-\r
-            typename Triangulation<dim>::active_cell_iterator cell =\r
-                    this->triangulation.begin_active(), endc = this->triangulation.end();\r
-            for (; cell != endc; ++cell)\r
-            {\r
-              for (unsigned int face = 0; face < GeometryInfo<dim>::faces_per_cell; ++face)\r
-                if (cell->face(face)->at_boundary() == true  &&\r
-                    ( cell->face(face)->boundary_id() == 0 ||\r
-                      cell->face(face)->boundary_id() == 1 ||\r
-                      cell->face(face)->boundary_id() == 2 ||\r
-                      cell->face(face)->boundary_id() == 3    ) )\r
-\r
-                      cell->face(face)->set_boundary_id(100);\r
-\r
-            }\r
-\r
-            GridTools::scale(this->parameters.scale, this->triangulation);\r
-            this->triangulation.refine_global(std::max (1U, this->parameters.global_refinement));\r
-          }\r
-\r
-          virtual double\r
-          get_prescribed_fluid_flow (const types::boundary_id &boundary_id,\r
-                                     const Point<dim>         &pt) const override\r
-          {\r
-              (void)pt;\r
-              (void)boundary_id;\r
-              return 0.0;\r
-          }\r
-\r
-          virtual  std::pair<types::boundary_id,types::boundary_id>\r
-          get_drained_boundary_id_for_output() const override\r
-          {\r
-              return std::make_pair(100,100);\r
-          }\r
-    };\r
-\r
-    //@sect4{Derived class: Uniaxial boundary conditions}\r
-    template <int dim>\r
-    class BrainBudday2017CubeTensionCompression\r
-          : public BrainBudday2017BaseCube<dim>\r
-    {\r
-        public:\r
-          BrainBudday2017CubeTensionCompression (const Parameters::AllParameters &parameters)\r
-            : BrainBudday2017BaseCube<dim> (parameters)\r
-          {}\r
-\r
-          virtual ~BrainBudday2017CubeTensionCompression () {}\r
-\r
-        private:\r
-          virtual void\r
-          define_tracked_vertices(std::vector<Point<dim> > &tracked_vertices) override\r
-          {\r
-            tracked_vertices[0][0] = 0.5*this->parameters.scale;\r
-            tracked_vertices[0][1] = 0.5*this->parameters.scale;\r
-            tracked_vertices[0][2] = 1.0*this->parameters.scale;\r
-\r
-            tracked_vertices[1][0] = 0.5*this->parameters.scale;\r
-            tracked_vertices[1][1] = 0.5*this->parameters.scale;\r
-            tracked_vertices[1][2] = 0.5*this->parameters.scale;\r
-          }\r
-\r
-          virtual void\r
-          make_dirichlet_constraints(AffineConstraints<double> &constraints) override\r
-          {\r
-              if (this->time.get_timestep() < 2)\r
-              {\r
-                  VectorTools::interpolate_boundary_values(this->dof_handler_ref,\r
-                                                           100,\r
-                                                           Functions::ConstantFunction<dim>(this->parameters.drained_pressure,this->n_components),\r
-                                                           constraints,\r
-                                                           (this->fe.component_mask(this->pressure)));\r
-              }\r
-              else\r
-              {\r
-                  VectorTools::interpolate_boundary_values( this->dof_handler_ref,\r
-                                                            100,\r
-                                                            Functions::ZeroFunction<dim>(this->n_components),\r
-                                                            constraints,\r
-                                                            (this->fe.component_mask(this->pressure)));\r
-              }\r
-              VectorTools::interpolate_boundary_values( this->dof_handler_ref,\r
-                                                        4,\r
-                                                        Functions::ZeroFunction<dim>(this->n_components),\r
-                                                        constraints,\r
-                                                        this->fe.component_mask(this->z_displacement) );\r
-\r
-            Point<dim> fix_node(0.5*this->parameters.scale, 0.5*this->parameters.scale, 0.0);\r
-            typename DoFHandler<dim>::active_cell_iterator\r
-            cell = this->dof_handler_ref.begin_active(), endc = this->dof_handler_ref.end();\r
-            for (; cell != endc; ++cell)\r
-              for (unsigned int node = 0; node < GeometryInfo<dim>::vertices_per_cell; ++node)\r
-              {\r
-                  if (  (abs(cell->vertex(node)[2]-fix_node[2]) < (1e-6 * this->parameters.scale))\r
-                    &&  (abs(cell->vertex(node)[0]-fix_node[0]) < (1e-6 * this->parameters.scale)))\r
-                      constraints.add_line(cell->vertex_dof_index(node, 0));\r
-\r
-                  if (  (abs(cell->vertex(node)[2]-fix_node[2]) < (1e-6 * this->parameters.scale))\r
-                    &&  (abs(cell->vertex(node)[1]-fix_node[1]) < (1e-6 * this->parameters.scale)))\r
-                    constraints.add_line(cell->vertex_dof_index(node, 1));\r
-              }\r
-\r
-            if (this->parameters.load_type == "displacement")\r
-            {\r
-                const std::vector<double> value = get_dirichlet_load(5,2);\r
-                FEValuesExtractors::Scalar direction;\r
-                direction = this->z_displacement;\r
-\r
-                VectorTools::interpolate_boundary_values( this->dof_handler_ref,\r
-                                                           5,\r
-                                                           Functions::ConstantFunction<dim>(value[2],this->n_components),\r
-                                                           constraints,\r
-                                                           this->fe.component_mask(direction));\r
-            }\r
-          }\r
-\r
-          virtual Tensor<1,dim>\r
-          get_neumann_traction (const types::boundary_id &boundary_id,\r
-                                const Point<dim>         &pt,\r
-                                const Tensor<1,dim>      &N) const override\r
-          {\r
-              if (this->parameters.load_type == "pressure")\r
-              {\r
-                if (boundary_id ==  5)\r
-                {\r
-                    const double final_load   = this->parameters.load;\r
-                    const double current_time = this->time.get_current();\r
-                    const double final_time   = this->time.get_end();\r
-                    const double num_cycles   = 3.0;\r
-\r
-                    return  final_load/2.0 * (1.0 - std::sin(numbers::PI * (2.0*num_cycles*current_time/final_time + 0.5))) * N;\r
-                }\r
-              }\r
-\r
-              (void)pt;\r
-\r
-              return Tensor<1,dim>();\r
-            }\r
-\r
-          virtual types::boundary_id\r
-          get_reaction_boundary_id_for_output() const override\r
-          {\r
-              return 5;\r
-          }\r
-\r
-          virtual std::vector<double>\r
-          get_dirichlet_load(const types::boundary_id   &boundary_id,\r
-                             const int                  &direction) const override\r
-          {\r
-                std::vector<double> displ_incr(dim,0.0);\r
-\r
-                if ( (boundary_id == 5) && (direction == 2) )\r
-                {\r
-                    const double final_displ  = this->parameters.load;\r
-                    const double current_time = this->time.get_current();\r
-                    const double final_time   = this->time.get_end();\r
-                    const double delta_time   = this->time.get_delta_t();\r
-                    const double num_cycles   = 3.0;\r
-                    double current_displ = 0.0;\r
-                    double previous_displ = 0.0;\r
-\r
-                    if (this->parameters.num_cycle_sets == 1)\r
-                    {\r
-                        current_displ  = final_displ/2.0 * (1.0\r
-                          - std::sin(numbers::PI * (2.0*num_cycles*current_time/final_time + 0.5)));\r
-                        previous_displ = final_displ/2.0 * (1.0\r
-                          - std::sin(numbers::PI * (2.0*num_cycles*(current_time-delta_time)/final_time + 0.5)));\r
-                    }\r
-                    else\r
-                    {\r
-                        if ( current_time <= (final_time*1.0/3.0) )\r
-                        {\r
-                            current_displ  = final_displ/2.0 * (1.0 - std::sin(numbers::PI *\r
-                                                 (2.0*num_cycles*current_time/(final_time*1.0/3.0) + 0.5)));\r
-                            previous_displ = final_displ/2.0 * (1.0 - std::sin(numbers::PI *\r
-                                                 (2.0*num_cycles*(current_time-delta_time)/(final_time*1.0/3.0) + 0.5)));\r
-                        }\r
-                        else\r
-                        {\r
-                            current_displ  = final_displ * (1.0 - std::sin(numbers::PI *\r
-                                                 (2.0*num_cycles*current_time / (final_time*2.0/3.0)\r
-                                                  - (num_cycles - 0.5) )));\r
-                            previous_displ = final_displ * (1.0 - std::sin(numbers::PI *\r
-                                                 (2.0*num_cycles*(current_time-delta_time) / (final_time*2.0/3.0)\r
-                                                  - (num_cycles - 0.5))));\r
-                        }\r
-                    }\r
-                    displ_incr[2] = current_displ - previous_displ;\r
-                }\r
-                return displ_incr;\r
-          }\r
-    };\r
-\r
-    //@sect4{Derived class: No lateral displacement in loading surfaces}\r
-    template <int dim>\r
-    class BrainBudday2017CubeTensionCompressionFullyFixed\r
-          : public BrainBudday2017BaseCube<dim>\r
-    {\r
-        public:\r
-          BrainBudday2017CubeTensionCompressionFullyFixed (const Parameters::AllParameters &parameters)\r
-            : BrainBudday2017BaseCube<dim> (parameters)\r
-          {}\r
-\r
-          virtual ~BrainBudday2017CubeTensionCompressionFullyFixed () {}\r
-\r
-        private:\r
-          virtual void\r
-          define_tracked_vertices(std::vector<Point<dim> > &tracked_vertices) override\r
-          {\r
-            tracked_vertices[0][0] = 0.5*this->parameters.scale;\r
-            tracked_vertices[0][1] = 0.5*this->parameters.scale;\r
-            tracked_vertices[0][2] = 1.0*this->parameters.scale;\r
-\r
-            tracked_vertices[1][0] = 0.5*this->parameters.scale;\r
-            tracked_vertices[1][1] = 0.5*this->parameters.scale;\r
-            tracked_vertices[1][2] = 0.5*this->parameters.scale;\r
-          }\r
-\r
-          virtual void\r
-          make_dirichlet_constraints(AffineConstraints<double> &constraints) override\r
-          {\r
-              if (this->time.get_timestep() < 2)\r
-              {\r
-                  VectorTools::interpolate_boundary_values(this->dof_handler_ref,\r
-                                                           100,\r
-                                                           Functions::ConstantFunction<dim>(this->parameters.drained_pressure,this->n_components),\r
-                                                           constraints,\r
-                                                           (this->fe.component_mask(this->pressure)));\r
-              }\r
-              else\r
-              {\r
-                  VectorTools::interpolate_boundary_values( this->dof_handler_ref,\r
-                                                            100,\r
-                                                            Functions::ZeroFunction<dim>(this->n_components),\r
-                                                            constraints,\r
-                                                            (this->fe.component_mask(this->pressure)));\r
-              }\r
-\r
-              VectorTools::interpolate_boundary_values( this->dof_handler_ref,\r
-                                                        4,\r
-                                                        Functions::ZeroFunction<dim>(this->n_components),\r
-                                                        constraints,\r
-                                                      (this->fe.component_mask(this->x_displacement) |\r
-                                                       this->fe.component_mask(this->y_displacement) |\r
-                                                       this->fe.component_mask(this->z_displacement) ));\r
-\r
-\r
-            if (this->parameters.load_type == "displacement")\r
-            {\r
-                const std::vector<double> value = get_dirichlet_load(5,2);\r
-                FEValuesExtractors::Scalar direction;\r
-                direction = this->z_displacement;\r
-\r
-                VectorTools::interpolate_boundary_values( this->dof_handler_ref,\r
-                                                           5,\r
-                                                           Functions::ConstantFunction<dim>(value[2],this->n_components),\r
-                                                           constraints,\r
-                                                           this->fe.component_mask(direction) );\r
-\r
-               VectorTools::interpolate_boundary_values( this->dof_handler_ref,\r
-                                                          5,\r
-                                                          Functions::ZeroFunction<dim>(this->n_components),\r
-                                                          constraints,\r
-                                                          (this->fe.component_mask(this->x_displacement) |\r
-                                                           this->fe.component_mask(this->y_displacement) ));\r
-            }\r
-          }\r
-\r
-          virtual Tensor<1,dim>\r
-          get_neumann_traction (const types::boundary_id &boundary_id,\r
-                                const Point<dim>         &pt,\r
-                                const Tensor<1,dim>      &N) const override\r
-          {\r
-              if (this->parameters.load_type == "pressure")\r
-              {\r
-                if (boundary_id ==  5)\r
-                {\r
-                    const double final_load   = this->parameters.load;\r
-                    const double current_time = this->time.get_current();\r
-                    const double final_time   = this->time.get_end();\r
-                    const double num_cycles   = 3.0;\r
-\r
-                    return  final_load/2.0 * (1.0 - std::sin(numbers::PI * (2.0*num_cycles*current_time/final_time + 0.5))) * N;\r
-                }\r
-              }\r
-\r
-              (void)pt;\r
-\r
-              return Tensor<1,dim>();\r
-            }\r
-\r
-          virtual types::boundary_id\r
-          get_reaction_boundary_id_for_output() const override\r
-          {\r
-              return 5;\r
-          }\r
-\r
-          virtual std::vector<double>\r
-          get_dirichlet_load(const types::boundary_id   &boundary_id,\r
-                             const int                  &direction) const override\r
-          {\r
-                std::vector<double> displ_incr(dim,0.0);\r
-\r
-                if ( (boundary_id == 5) && (direction == 2) )\r
-                {\r
-                    const double final_displ  = this->parameters.load;\r
-                    const double current_time = this->time.get_current();\r
-                    const double final_time   = this->time.get_end();\r
-                    const double delta_time   = this->time.get_delta_t();\r
-                    const double num_cycles   = 3.0;\r
-                    double current_displ = 0.0;\r
-                    double previous_displ = 0.0;\r
-\r
-                    if (this->parameters.num_cycle_sets == 1)\r
-                    {\r
-                        current_displ  = final_displ/2.0 * (1.0 - std::sin(numbers::PI * (2.0*num_cycles*current_time/final_time + 0.5)));\r
-                        previous_displ = final_displ/2.0 * (1.0 - std::sin(numbers::PI * (2.0*num_cycles*(current_time-delta_time)/final_time + 0.5)));\r
-                    }\r
-                    else\r
-                    {\r
-                        if ( current_time <= (final_time*1.0/3.0) )\r
-                        {\r
-                            current_displ  = final_displ/2.0 * (1.0 - std::sin(numbers::PI *\r
-                                                 (2.0*num_cycles*current_time/(final_time*1.0/3.0) + 0.5)));\r
-                            previous_displ = final_displ/2.0 * (1.0 - std::sin(numbers::PI *\r
-                                                 (2.0*num_cycles*(current_time-delta_time)/(final_time*1.0/3.0) + 0.5)));\r
-                        }\r
-                        else\r
-                        {\r
-                            current_displ  = final_displ * (1.0 - std::sin(numbers::PI *\r
-                                                 (2.0*num_cycles*current_time / (final_time*2.0/3.0)\r
-                                                  - (num_cycles - 0.5) )));\r
-                            previous_displ = final_displ * (1.0 - std::sin(numbers::PI *\r
-                                                 (2.0*num_cycles*(current_time-delta_time) / (final_time*2.0/3.0)\r
-                                                  - (num_cycles - 0.5))));\r
-                        }\r
-                    }\r
-                    displ_incr[2] = current_displ - previous_displ;\r
-                }\r
-                return displ_incr;\r
-          }\r
-    };\r
-\r
-    //@sect4{Derived class: No lateral or vertical displacement in loading surface}\r
-    template <int dim>\r
-    class BrainBudday2017CubeShearFullyFixed\r
-          : public BrainBudday2017BaseCube<dim>\r
-    {\r
-        public:\r
-          BrainBudday2017CubeShearFullyFixed (const Parameters::AllParameters &parameters)\r
-            : BrainBudday2017BaseCube<dim> (parameters)\r
-          {}\r
-\r
-          virtual ~BrainBudday2017CubeShearFullyFixed () {}\r
-\r
-        private:\r
-          virtual void\r
-          define_tracked_vertices(std::vector<Point<dim> > &tracked_vertices) override\r
-          {\r
-            tracked_vertices[0][0] = 0.75*this->parameters.scale;\r
-            tracked_vertices[0][1] = 0.5*this->parameters.scale;\r
-            tracked_vertices[0][2] = 0.0*this->parameters.scale;\r
-\r
-            tracked_vertices[1][0] = 0.25*this->parameters.scale;\r
-            tracked_vertices[1][1] = 0.5*this->parameters.scale;\r
-            tracked_vertices[1][2] = 0.0*this->parameters.scale;\r
-          }\r
-\r
-          virtual void\r
-          make_dirichlet_constraints(AffineConstraints<double> &constraints) override\r
-          {\r
-              if (this->time.get_timestep() < 2)\r
-              {\r
-                  VectorTools::interpolate_boundary_values(this->dof_handler_ref,\r
-                                                           100,\r
-                                                           Functions::ConstantFunction<dim>(this->parameters.drained_pressure,this->n_components),\r
-                                                           constraints,\r
-                                                           (this->fe.component_mask(this->pressure)));\r
-              }\r
-              else\r
-              {\r
-                  VectorTools::interpolate_boundary_values( this->dof_handler_ref,\r
-                                                            100,\r
-                                                            Functions::ZeroFunction<dim>(this->n_components),\r
-                                                            constraints,\r
-                                                            (this->fe.component_mask(this->pressure)));\r
-              }\r
-\r
-              VectorTools::interpolate_boundary_values( this->dof_handler_ref,\r
-                                                        5,\r
-                                                        Functions::ZeroFunction<dim>(this->n_components),\r
-                                                        constraints,\r
-                                                      (this->fe.component_mask(this->x_displacement) |\r
-                                                       this->fe.component_mask(this->y_displacement) |\r
-                                                       this->fe.component_mask(this->z_displacement) ));\r
-\r
-\r
-            if (this->parameters.load_type == "displacement")\r
-            {\r
-                const std::vector<double> value = get_dirichlet_load(4,0);\r
-                FEValuesExtractors::Scalar direction;\r
-                direction = this->x_displacement;\r
-\r
-                VectorTools::interpolate_boundary_values( this->dof_handler_ref,\r
-                                                           4,\r
-                                                           Functions::ConstantFunction<dim>(value[0],this->n_components),\r
-                                                           constraints,\r
-                                                           this->fe.component_mask(direction));\r
-\r
-               VectorTools::interpolate_boundary_values( this->dof_handler_ref,\r
-                                                          4,\r
-                                                          Functions::ZeroFunction<dim>(this->n_components),\r
-                                                          constraints,\r
-                                                          (this->fe.component_mask(this->y_displacement) |\r
-                                                           this->fe.component_mask(this->z_displacement) ));\r
-            }\r
-          }\r
-\r
-          virtual Tensor<1,dim>\r
-          get_neumann_traction (const types::boundary_id &boundary_id,\r
-                                const Point<dim>         &pt,\r
-                                const Tensor<1,dim>      &N) const override\r
-          {\r
-              if (this->parameters.load_type == "pressure")\r
-              {\r
-                if (boundary_id ==  4)\r
-                {\r
-                    const double final_load   = this->parameters.load;\r
-                    const double current_time = this->time.get_current();\r
-                    const double final_time   = this->time.get_end();\r
-                    const double num_cycles   = 3.0;\r
-                    const Tensor<1,3> axis ({0.0,1.0,0.0});\r
-                    const double angle = numbers::PI;\r
-                    static const Tensor< 2, dim, double> R(Physics::Transformations::Rotations::rotation_matrix_3d(axis,angle));\r
-\r
-                    return  (final_load * (std::sin(2.0*(numbers::PI)*num_cycles*current_time/final_time)) * (R * N));\r
-                }\r
-              }\r
-\r
-              (void)pt;\r
-\r
-              return Tensor<1,dim>();\r
-            }\r
-\r
-          virtual types::boundary_id\r
-          get_reaction_boundary_id_for_output() const override\r
-          {\r
-              return 4;\r
-          }\r
-\r
-          virtual std::vector<double>\r
-          get_dirichlet_load(const types::boundary_id   &boundary_id,\r
-                             const int                  &direction) const override\r
-          {\r
-                std::vector<double> displ_incr (dim, 0.0);\r
-\r
-                if ( (boundary_id == 4) && (direction == 0) )\r
-                {\r
-                    const double final_displ  = this->parameters.load;\r
-                    const double current_time = this->time.get_current();\r
-                    const double final_time   = this->time.get_end();\r
-                    const double delta_time   = this->time.get_delta_t();\r
-                    const double num_cycles   = 3.0;\r
-                    double current_displ = 0.0;\r
-                    double previous_displ = 0.0;\r
-\r
-                    if (this->parameters.num_cycle_sets == 1)\r
-                    {\r
-                        current_displ  = final_displ * (std::sin(2.0*(numbers::PI)*num_cycles*current_time/final_time));\r
-                        previous_displ = final_displ * (std::sin(2.0*(numbers::PI)*num_cycles*(current_time-delta_time)/final_time));\r
-                    }\r
-                    else\r
-                    {\r
-                        AssertThrow(false, ExcMessage("Problem type not defined. Budday shear experiments implemented only for one set of cycles."));\r
-                    }\r
-                    displ_incr[0] = current_displ - previous_displ;\r
-                }\r
-                return displ_incr;\r
-          }\r
-    };\r
-\r
-}\r
-\r
-// @sect3{Main function}\r
-// Lastly we provide the main driver function which is similar to the other tutorials.\r
-int main (int argc, char *argv[])\r
-{\r
-  using namespace dealii;\r
-  using namespace NonLinearPoroViscoElasticity;\r
-\r
-  const unsigned int n_tbb_processes = 1;\r
-  Utilities::MPI::MPI_InitFinalize mpi_initialization(argc, argv, n_tbb_processes);\r
-\r
-  try\r
-    {\r
-      Parameters::AllParameters parameters ("parameters.prm");\r
-      if (parameters.geom_type == "Ehlers_tube_step_load")\r
-      {\r
-        VerificationEhlers1999StepLoad<3> solid_3d(parameters);\r
-        solid_3d.run();\r
-      }\r
-      else if (parameters.geom_type == "Ehlers_tube_increase_load")\r
-      {\r
-        VerificationEhlers1999IncreaseLoad<3> solid_3d(parameters);\r
-        solid_3d.run();\r
-      }\r
-      else if (parameters.geom_type == "Ehlers_cube_consolidation")\r
-      {\r
-        VerificationEhlers1999CubeConsolidation<3> solid_3d(parameters);\r
-        solid_3d.run();\r
-      }\r
-      else if (parameters.geom_type == "Franceschini_consolidation")\r
-      {\r
-        Franceschini2006Consolidation<3> solid_3d(parameters);\r
-        solid_3d.run();\r
-      }\r
-      else if (parameters.geom_type == "Budday_cube_tension_compression")\r
-      {\r
-        BrainBudday2017CubeTensionCompression<3> solid_3d(parameters);\r
-        solid_3d.run();\r
-      }\r
-      else if (parameters.geom_type == "Budday_cube_tension_compression_fully_fixed")\r
-      {\r
-        BrainBudday2017CubeTensionCompressionFullyFixed<3> solid_3d(parameters);\r
-        solid_3d.run();\r
-      }\r
-      else if (parameters.geom_type == "Budday_cube_shear_fully_fixed")\r
-      {\r
-        BrainBudday2017CubeShearFullyFixed<3> solid_3d(parameters);\r
-        solid_3d.run();\r
-      }\r
-      else\r
-      {\r
-        AssertThrow(false, ExcMessage("Problem type not defined. Current setting: " + parameters.geom_type));\r
-      }\r
-\r
-    }\r
-  catch (std::exception &exc)\r
-    {\r
-      if (Utilities::MPI::this_mpi_process(MPI_COMM_WORLD) == 0)\r
-      {\r
-          std::cerr << std::endl << std::endl\r
-                    << "----------------------------------------------------"\r
-                    << std::endl;\r
-          std::cerr << "Exception on processing: " << std::endl << exc.what()\r
-                    << std::endl << "Aborting!" << std::endl\r
-                    << "----------------------------------------------------"\r
-                    << std::endl;\r
-\r
-          return 1;\r
-      }\r
-    }\r
-  catch (...)\r
-    {\r
-      if (Utilities::MPI::this_mpi_process(MPI_COMM_WORLD) == 0)\r
-      {\r
-          std::cerr << std::endl << std::endl\r
-                    << "----------------------------------------------------"\r
-                    << std::endl;\r
-          std::cerr << "Unknown exception!" << std::endl << "Aborting!"\r
-                    << std::endl\r
-                    << "----------------------------------------------------"\r
-                    << std::endl;\r
-          return 1;\r
-      }\r
-    }\r
-  return 0;\r
-}\r
+/* ---------------------------------------------------------------------
+ *
+ * Copyright (C) 2010 - 2020 by the deal.II authors and
+ *                              Ester Comellas and Jean-Paul Pelteret
+ *
+ * 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.
+ *
+ * ---------------------------------------------------------------------
+ */
+
+/*   Authors: Ester Comellas and Jean-Paul Pelteret,
+ *           University of Erlangen-Nuremberg, 2018
+ */
+
+// We start by including all the necessary deal.II header files and some C++
+// related ones. They have been discussed in detail in previous tutorial
+// programs, so you need only refer to past tutorials for details.
+
+#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/base/mpi.h>
+#include <deal.II/base/quadrature_point_data.h>
+
+#include <deal.II/differentiation/ad.h>
+
+#include <deal.II/distributed/shared_tria.h>
+
+#include <deal.II/dofs/dof_renumbering.h>
+#include <deal.II/dofs/dof_tools.h>
+#include <deal.II/dofs/dof_accessor.h>
+
+#include <deal.II/grid/filtered_iterator.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/grid_out.h>
+#include <deal.II/grid/manifold_lib.h>
+#include <deal.II/grid/tria_accessor.h>
+#include <deal.II/grid/tria_iterator.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/lac/block_sparsity_pattern.h>
+#include <deal.II/lac/affine_constraints.h>
+#include <deal.II/lac/dynamic_sparsity_pattern.h>
+#include <deal.II/lac/full_matrix.h>
+#include <deal.II/lac/linear_operator.h>
+#include <deal.II/lac/packaged_operation.h>
+
+#include <deal.II/lac/trilinos_block_sparse_matrix.h>
+#include <deal.II/lac/trilinos_linear_operator.h>
+#include <deal.II/lac/trilinos_parallel_block_vector.h>
+#include <deal.II/lac/trilinos_precondition.h>
+#include <deal.II/lac/trilinos_sparse_matrix.h>
+#include <deal.II/lac/trilinos_sparsity_pattern.h>
+#include <deal.II/lac/trilinos_solver.h>
+#include <deal.II/lac/trilinos_vector.h>
+
+#include <deal.II/lac/block_vector.h>
+#include <deal.II/lac/vector.h>
+
+#include <deal.II/numerics/data_postprocessor.h>
+#include <deal.II/numerics/data_out.h>
+#include <deal.II/numerics/data_out_faces.h>
+#include <deal.II/numerics/fe_field_function.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>
+#include <numeric>
+#include <iomanip>
+
+
+// We create a namespace for everything that relates to
+// the nonlinear poro-viscoelastic formulation,
+// and import all the deal.II function and class names into it:
+namespace NonLinearPoroViscoElasticity
+{
+    using namespace dealii;
+
+// @sect3{Run-time parameters}
+//
+// Set up a ParameterHandler object to read in the parameter choices at run-time
+// introduced by the user through the file "parameters.prm"
+    namespace Parameters
+    {
+// @sect4{Finite Element system}
+// Here we specify the polynomial order used to approximate the solution,
+// both for the displacements and pressure unknowns.
+// The quadrature order should be adjusted accordingly.
+      struct FESystem
+      {
+        unsigned int poly_degree_displ;
+        unsigned int poly_degree_pore;
+        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 displ", "2",
+                            Patterns::Integer(0),
+                            "Displacement system polynomial order");
+
+          prm.declare_entry("Polynomial degree pore", "1",
+                            Patterns::Integer(0),
+                            "Pore pressure 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_displ = prm.get_integer("Polynomial degree displ");
+          poly_degree_pore = prm.get_integer("Polynomial degree pore");
+          quad_order = prm.get_integer("Quadrature order");
+        }
+        prm.leave_subsection();
+      }
+
+// @sect4{Geometry}
+// These parameters are related to the geometry definition and mesh generation.
+// We select the type of problem to solve and introduce the desired load values.
+      struct Geometry
+      {
+        std::string  geom_type;
+        unsigned int global_refinement;
+        double       scale;
+        std::string  load_type;
+        double       load;
+        unsigned int num_cycle_sets;
+        double       fluid_flow;
+        double       drained_pressure;
+
+        static void
+        declare_parameters(ParameterHandler &prm);
+
+        void
+        parse_parameters(ParameterHandler &prm);
+      };
+
+      void Geometry::declare_parameters(ParameterHandler &prm)
+      {
+        prm.enter_subsection("Geometry");
+        {
+          prm.declare_entry("Geometry type", "Ehlers_tube_step_load",
+                             Patterns::Selection("Ehlers_tube_step_load"
+                                                 "|Ehlers_tube_increase_load"
+                                                 "|Ehlers_cube_consolidation"
+                                                 "|Franceschini_consolidation"
+                                                 "|Budday_cube_tension_compression"
+                                                 "|Budday_cube_tension_compression_fully_fixed"
+                                                 "|Budday_cube_shear_fully_fixed"),
+                                "Type of geometry used. "
+                                "For Ehlers verification examples see Ehlers and Eipper (1999). "
+                                "For Franceschini brain consolidation see Franceschini et al. (2006)"
+                                "For Budday brain examples see Budday et al. (2017)");
+
+          prm.declare_entry("Global refinement", "1",
+                            Patterns::Integer(0),
+                            "Global refinement level");
+
+          prm.declare_entry("Grid scale", "1.0",
+                            Patterns::Double(0.0),
+                            "Global grid scaling factor");
+
+          prm.declare_entry("Load type", "pressure",
+                            Patterns::Selection("pressure|displacement|none"),
+                            "Type of loading");
+
+          prm.declare_entry("Load value", "-7.5e+6",
+                            Patterns::Double(),
+                            "Loading value");
+
+          prm.declare_entry("Number of cycle sets", "1",
+                            Patterns::Integer(1,2),
+                            "Number of times each set of 3 cycles is repeated, only for "
+                            "Budday_cube_tension_compression and Budday_cube_tension_compression_fully_fixed. "
+                            "Load value is doubled in second set, load rate is kept constant."
+                            "Final time indicates end of second cycle set.");
+
+          prm.declare_entry("Fluid flow value", "0.0",
+                            Patterns::Double(),
+                            "Prescribed fluid flow. Not implemented in any example yet.");
+
+          prm.declare_entry("Drained pressure", "0.0",
+                            Patterns::Double(),
+                            "Increase of pressure value at drained boundary w.r.t the atmospheric pressure.");
+        }
+        prm.leave_subsection();
+      }
+
+      void Geometry::parse_parameters(ParameterHandler &prm)
+      {
+        prm.enter_subsection("Geometry");
+        {
+          geom_type = prm.get("Geometry type");
+          global_refinement = prm.get_integer("Global refinement");
+          scale = prm.get_double("Grid scale");
+          load_type = prm.get("Load type");
+          load = prm.get_double("Load value");
+          num_cycle_sets = prm.get_integer("Number of cycle sets");
+          fluid_flow = prm.get_double("Fluid flow value");
+          drained_pressure = prm.get_double("Drained pressure");
+        }
+        prm.leave_subsection();
+      }
+
+// @sect4{Materials}
+
+// Here we select the type of material for the solid component
+// and define the corresponding material parameters.
+// Then we define he fluid data, including the type of
+// seepage velocity definition to use.
+      struct Materials
+      {
+        std::string  mat_type;
+        double lambda;
+        double mu;
+        double mu1_infty;
+        double mu2_infty;
+        double mu3_infty;
+        double alpha1_infty;
+        double alpha2_infty;
+        double alpha3_infty;
+        double mu1_mode_1;
+        double mu2_mode_1;
+        double mu3_mode_1;
+        double alpha1_mode_1;
+        double alpha2_mode_1;
+        double alpha3_mode_1;
+        double viscosity_mode_1;
+        std::string  fluid_type;
+        double solid_vol_frac;
+        double kappa_darcy;
+        double init_intrinsic_perm;
+        double viscosity_FR;
+        double init_darcy_coef;
+        double weight_FR;
+        bool gravity_term;
+        int gravity_direction;
+        double gravity_value;
+        double density_FR;
+        double density_SR;
+        enum SymmetricTensorEigenvectorMethod eigen_solver;
+
+        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("material", "Neo-Hooke",
+                            Patterns::Selection("Neo-Hooke|Ogden|visco-Ogden"),
+                            "Type of material used in the problem");
+
+          prm.declare_entry("lambda", "8.375e6",
+                            Patterns::Double(0,1e100),
+                            "First Lamé parameter for extension function related to compactation point in solid material [Pa].");
+
+          prm.declare_entry("shear modulus", "5.583e6",
+                            Patterns::Double(0,1e100),
+                            "shear modulus for Neo-Hooke materials [Pa].");
+
+          prm.declare_entry("eigen solver", "QL Implicit Shifts",
+                            Patterns::Selection("QL Implicit Shifts|Jacobi"),
+                            "The type of eigen solver to be used for Ogden and visco-Ogden models.");
+
+          prm.declare_entry("mu1", "0.0",
+                            Patterns::Double(),
+                            "Shear material parameter 'mu1' for Ogden material [Pa].");
+
+          prm.declare_entry("mu2", "0.0",
+                            Patterns::Double(),
+                            "Shear material parameter 'mu2' for Ogden material [Pa].");
+
+          prm.declare_entry("mu3", "0.0",
+                            Patterns::Double(),
+                            "Shear material parameter 'mu1' for Ogden material [Pa].");
+
+          prm.declare_entry("alpha1", "1.0",
+                            Patterns::Double(),
+                            "Stiffness material parameter 'alpha1' for Ogden material [-].");
+
+          prm.declare_entry("alpha2", "1.0",
+                            Patterns::Double(),
+                            "Stiffness material parameter 'alpha2' for Ogden material [-].");
+
+          prm.declare_entry("alpha3", "1.0",
+                            Patterns::Double(),
+                            "Stiffness material parameter 'alpha3' for Ogden material [-].");
+
+          prm.declare_entry("mu1_1", "0.0",
+                            Patterns::Double(),
+                            "Shear material parameter 'mu1' for first viscous mode in Ogden material [Pa].");
+
+          prm.declare_entry("mu2_1", "0.0",
+                            Patterns::Double(),
+                            "Shear material parameter 'mu2' for first viscous mode in Ogden material [Pa].");
+
+          prm.declare_entry("mu3_1", "0.0",
+                            Patterns::Double(),
+                            "Shear material parameter 'mu1' for first viscous mode in Ogden material [Pa].");
+
+          prm.declare_entry("alpha1_1", "1.0",
+                            Patterns::Double(),
+                            "Stiffness material parameter 'alpha1' for first viscous mode in Ogden material [-].");
+
+          prm.declare_entry("alpha2_1", "1.0",
+                            Patterns::Double(),
+                            "Stiffness material parameter 'alpha2' for first viscous mode in Ogden material [-].");
+
+          prm.declare_entry("alpha3_1", "1.0",
+                            Patterns::Double(),
+                            "Stiffness material parameter 'alpha3' for first viscous mode in Ogden material [-].");
+
+          prm.declare_entry("viscosity_1", "1e-10",
+                            Patterns::Double(1e-10,1e100),
+                            "Deformation-independent viscosity parameter 'eta_1' for first viscous mode in Ogden material [-].");
+
+          prm.declare_entry("seepage definition", "Ehlers",
+                            Patterns::Selection("Markert|Ehlers"),
+                            "Type of formulation used to define the seepage velocity in the problem. "
+                            "Choose between Markert formulation of deformation-dependent intrinsic permeability "
+                            "and Ehlers formulation of deformation-dependent Darcy flow coefficient.");
+
+          prm.declare_entry("initial solid volume fraction", "0.67",
+                            Patterns::Double(0.001,0.999),
+                            "Initial porosity (solid volume fraction, 0 < n_0s < 1)");
+
+          prm.declare_entry("kappa", "0.0",
+                            Patterns::Double(0,100),
+                            "Deformation-dependency control parameter for specific permeability (kappa >= 0)");
+
+          prm.declare_entry("initial intrinsic permeability", "0.0",
+                            Patterns::Double(0,1e100),
+                            "Initial intrinsic permeability parameter [m^2] (isotropic permeability). To be used with Markert formulation.");
+
+          prm.declare_entry("fluid viscosity", "0.0",
+                            Patterns::Double(0, 1e100),
+                            "Effective shear viscosity parameter of the fluid [Pa·s, (N·s)/m^2]. To be used with Markert formulation.");
+
+          prm.declare_entry("initial Darcy coefficient", "1.0e-4",
+                            Patterns::Double(0,1e100),
+                            "Initial Darcy flow coefficient [m/s] (isotropic permeability). To be used with Ehlers formulation.");
+
+          prm.declare_entry("fluid weight", "1.0e4",
+                            Patterns::Double(0, 1e100),
+                            "Effective weight of the fluid [N/m^3]. To be used with Ehlers formulation.");
+
+          prm.declare_entry("gravity term", "false",
+                            Patterns::Bool(),
+                            "Gravity term considered (true) or neglected (false)");
+
+          prm.declare_entry("fluid density", "1.0",
+                            Patterns::Double(0,1e100),
+                            "Real (or effective) density of the fluid");
+
+          prm.declare_entry("solid density", "1.0",
+                            Patterns::Double(0,1e100),
+                            "Real (or effective) density of the solid");
+
+          prm.declare_entry("gravity direction", "2",
+                            Patterns::Integer(0,2),
+                            "Direction of gravity (unit vector 0 for x, 1 for y, 2 for z)");
+
+          prm.declare_entry("gravity value", "-9.81",
+                            Patterns::Double(),
+                            "Value of gravity (be careful to have consistent units!)");
+        }
+        prm.leave_subsection();
+      }
+
+      void Materials::parse_parameters(ParameterHandler &prm)
+      {
+        prm.enter_subsection("Material properties");
+        {
+          //Solid
+          mat_type = prm.get("material");
+          lambda = prm.get_double("lambda");
+          mu = prm.get_double("shear modulus");
+          mu1_infty = prm.get_double("mu1");
+          mu2_infty = prm.get_double("mu2");
+          mu3_infty = prm.get_double("mu3");
+          alpha1_infty = prm.get_double("alpha1");
+          alpha2_infty = prm.get_double("alpha2");
+          alpha3_infty = prm.get_double("alpha3");
+          mu1_mode_1 = prm.get_double("mu1_1");
+          mu2_mode_1 = prm.get_double("mu2_1");
+          mu3_mode_1 = prm.get_double("mu3_1");
+          alpha1_mode_1 = prm.get_double("alpha1_1");
+          alpha2_mode_1 = prm.get_double("alpha2_1");
+          alpha3_mode_1 = prm.get_double("alpha3_1");
+          viscosity_mode_1 = prm.get_double("viscosity_1");
+          //Fluid
+          fluid_type = prm.get("seepage definition");
+          solid_vol_frac = prm.get_double("initial solid volume fraction");
+          kappa_darcy = prm.get_double("kappa");
+          init_intrinsic_perm = prm.get_double("initial intrinsic permeability");
+          viscosity_FR = prm.get_double("fluid viscosity");
+          init_darcy_coef = prm.get_double("initial Darcy coefficient");
+          weight_FR = prm.get_double("fluid weight");
+          //Gravity effects
+          gravity_term = prm.get_bool("gravity term");
+          density_FR = prm.get_double("fluid density");
+          density_SR = prm.get_double("solid density");
+          gravity_direction = prm.get_integer("gravity direction");
+          gravity_value = prm.get_double("gravity value");
+
+          if ( (fluid_type == "Markert") && ((init_intrinsic_perm == 0.0) || (viscosity_FR == 0.0)) )
+              AssertThrow(false, ExcMessage("Markert seepage velocity formulation requires the definition of "
+                                            "'initial intrinsic permeability' and 'fluid viscosity' greater than 0.0."));
+
+          if ( (fluid_type == "Ehlers") && ((init_darcy_coef == 0.0) || (weight_FR == 0.0)) )
+              AssertThrow(false, ExcMessage("Ehler seepage velocity formulation requires the definition of "
+                                            "'initial Darcy coefficient' and 'fluid weight' greater than 0.0."));
+
+          const std::string eigen_solver_type = prm.get("eigen solver");
+          if (eigen_solver_type == "QL Implicit Shifts")
+            eigen_solver = SymmetricTensorEigenvectorMethod::ql_implicit_shifts;
+          else if (eigen_solver_type == "Jacobi")
+            eigen_solver = SymmetricTensorEigenvectorMethod::jacobi;
+          else
+          {
+            AssertThrow(false, ExcMessage("Unknown eigen solver selected."));
+          }
+        }
+        prm.leave_subsection();
+      }
+
+// @sect4{Nonlinear solver}
+
+// We now define the tolerances and the maximum number of iterations for the
+// Newton-Raphson scheme used to solve the nonlinear system of governing equations.
+      struct NonlinearSolver
+      {
+        unsigned int max_iterations_NR;
+        double       tol_f;
+        double       tol_u;
+        double       tol_p_fluid;
+
+        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", "15",
+                            Patterns::Integer(0),
+                            "Number of Newton-Raphson iterations allowed");
+
+          prm.declare_entry("Tolerance force", "1.0e-8",
+                            Patterns::Double(0.0),
+                            "Force residual tolerance");
+
+          prm.declare_entry("Tolerance displacement", "1.0e-6",
+                            Patterns::Double(0.0),
+                            "Displacement error tolerance");
+
+          prm.declare_entry("Tolerance pore pressure", "1.0e-6",
+                            Patterns::Double(0.0),
+                            "Pore pressure 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");
+          tol_p_fluid =  prm.get_double("Tolerance pore pressure");
+        }
+        prm.leave_subsection();
+      }
+
+// @sect4{Time}
+// Here we set the timestep size $ \varDelta t $ and the simulation end-time.
+      struct Time
+      {
+        double end_time;
+        double delta_t;
+        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", "10.0",
+                            Patterns::Double(),
+                            "End time");
+
+          prm.declare_entry("Time step size", "0.002",
+                            Patterns::Double(1.0e-6),
+                            "Time step size. The value must be larger than the displacement error tolerance defined.");
+        }
+        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();
+      }
+
+
+// @sect4{Output}
+// We can choose the frequency of the data for the output files.
+      struct OutputParam
+      {
+
+        std::string  outfiles_requested;
+        unsigned int timestep_output;
+        std::string  outtype;
+
+        static void
+        declare_parameters(ParameterHandler &prm);
+
+        void
+        parse_parameters(ParameterHandler &prm);
+      };
+
+      void OutputParam::declare_parameters(ParameterHandler &prm)
+      {
+        prm.enter_subsection("Output parameters");
+        {
+          prm.declare_entry("Output files", "true",
+                            Patterns::Selection("true|false"),
+                            "Paraview output files to generate.");
+          prm.declare_entry("Time step number output", "1",
+                            Patterns::Integer(0),
+                            "Output data for time steps multiple of the given "
+                            "integer value.");
+          prm.declare_entry("Averaged results", "nodes",
+                             Patterns::Selection("elements|nodes"),
+                             "Output data associated with integration point values"
+                             " averaged on elements or on nodes.");
+        }
+        prm.leave_subsection();
+      }
+
+      void OutputParam::parse_parameters(ParameterHandler &prm)
+      {
+        prm.enter_subsection("Output parameters");
+        {
+          outfiles_requested = prm.get("Output files");
+          timestep_output = prm.get_integer("Time step number output");
+          outtype = prm.get("Averaged results");
+        }
+        prm.leave_subsection();
+      }
+
+// @sect4{All parameters}
+// We finally consolidate all of the above structures into a single container that holds all the run-time selections.
+      struct AllParameters : public FESystem,
+                             public Geometry,
+                             public Materials,
+                             public NonlinearSolver,
+                             public Time,
+                             public OutputParam
+      {
+        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.parse_input(input_file);
+        parse_parameters(prm);
+      }
+
+      void AllParameters::declare_parameters(ParameterHandler &prm)
+      {
+        FESystem::declare_parameters(prm);
+        Geometry::declare_parameters(prm);
+        Materials::declare_parameters(prm);
+        NonlinearSolver::declare_parameters(prm);
+        Time::declare_parameters(prm);
+        OutputParam::declare_parameters(prm);
+      }
+
+      void AllParameters::parse_parameters(ParameterHandler &prm)
+      {
+        FESystem::parse_parameters(prm);
+        Geometry::parse_parameters(prm);
+        Materials::parse_parameters(prm);
+        NonlinearSolver::parse_parameters(prm);
+        Time::parse_parameters(prm);
+        OutputParam::parse_parameters(prm);
+      }
+    }
+
+// @sect3{Time class}
+// A simple class to store time data.
+// For simplicity we assume a constant time step size.
+    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 get_current() const
+          {
+            return time_current;
+          }
+          double get_end() const
+          {
+            return time_end;
+          }
+          double get_delta_t() const
+          {
+            return delta_t;
+          }
+          unsigned int get_timestep() const
+          {
+            return timestep;
+          }
+          void increment_time ()
+          {
+            time_current += delta_t;
+            ++timestep;
+          }
+
+        private:
+          unsigned int timestep;
+          double time_current;
+          double time_end;
+          const double delta_t;
+    };
+
+// @sect3{Constitutive equation for the solid component of the biphasic material}
+
+//@sect4{Base class: generic hyperelastic material}
+// The ``extra" Kirchhoff stress in the solid component is the sum of isochoric
+// and a volumetric part.
+// $\mathbf{\tau} = \mathbf{\tau}_E^{(\bullet)} + \mathbf{\tau}^{\textrm{vol}}$
+// The deviatoric part changes depending on the type of material model selected:
+// Neo-Hooken hyperelasticity, Ogden hyperelasticiy,
+// or a single-mode finite viscoelasticity based on the Ogden hyperelastic model.
+// In this base class we declare  it as a virtual function,
+// and it will be defined for each model type in the corresponding derived class.
+// We define here the volumetric component, which depends on the
+// extension function $U(J_S)$ selected, and in this case is the same for all models.
+// We use the function proposed by
+// Ehlers & Eipper 1999 doi:10.1023/A:1006565509095
+// We also define some public functions to access and update the internal variables.
+    template <int dim, typename NumberType = Sacado::Fad::DFad<double> >
+    class Material_Hyperelastic
+    {
+        public:
+          Material_Hyperelastic(const Parameters::AllParameters &parameters,
+                                const Time                      &time)
+            :
+            n_OS (parameters.solid_vol_frac),
+            lambda (parameters.lambda),
+            time(time),
+            det_F (1.0),
+            det_F_converged (1.0),
+            eigen_solver (parameters.eigen_solver)
+           {}
+          ~Material_Hyperelastic()
+          {}
+
+          SymmetricTensor<2, dim, NumberType>
+          get_tau_E(const Tensor<2,dim, NumberType> &F) const
+          {
+            return ( get_tau_E_base(F) + get_tau_E_ext_func(F) );
+          }
+
+          SymmetricTensor<2, dim, NumberType>
+          get_Cauchy_E(const Tensor<2, dim, NumberType> &F) const
+          {
+              const NumberType det_F = determinant(F);
+              Assert(det_F > 0, ExcInternalError());
+              return get_tau_E(F)*NumberType(1/det_F);
+          }
+
+          double
+          get_converged_det_F() const
+          {
+              return  det_F_converged;
+          }
+
+          virtual void
+          update_end_timestep()
+          {
+              det_F_converged = det_F;
+          }
+
+          virtual void
+          update_internal_equilibrium( const Tensor<2, dim, NumberType> &F )
+          {
+              det_F = Tensor<0,dim,double>(determinant(F));
+          }
+
+          virtual double
+          get_viscous_dissipation( ) const = 0;
+
+          const double n_OS;
+          const double lambda;
+          const Time  &time;
+          double det_F;
+          double det_F_converged;
+          const enum SymmetricTensorEigenvectorMethod eigen_solver;
+
+        protected:
+          SymmetricTensor<2, dim, NumberType>
+          get_tau_E_ext_func(const Tensor<2,dim, NumberType> &F) const
+          {
+              const NumberType det_F = determinant(F);
+              Assert(det_F > 0, ExcInternalError());
+
+              static const SymmetricTensor< 2, dim, double>
+                    I (Physics::Elasticity::StandardTensors<dim>::I);
+              return  ( NumberType(lambda * (1.0-n_OS)*(1.0-n_OS)
+                         * (det_F/(1.0-n_OS) - det_F/(det_F-n_OS))) * I );
+          }
+
+          virtual SymmetricTensor<2, dim, NumberType>
+           get_tau_E_base(const Tensor<2,dim, NumberType> &F) const = 0;
+    };
+
+//@sect4{Derived class: Neo-Hookean hyperelastic material}
+    template <int dim, typename NumberType = Sacado::Fad::DFad<double> >
+    class NeoHooke : public Material_Hyperelastic < dim, NumberType >
+    {
+        public:
+            NeoHooke(const Parameters::AllParameters &parameters,
+                     const Time                      &time)
+            :
+            Material_Hyperelastic< dim, NumberType > (parameters,time),
+            mu(parameters.mu)
+           {}
+          virtual ~NeoHooke()
+          {}
+
+           double
+           get_viscous_dissipation() const override
+           {
+               return 0.0;
+           }
+
+        protected:
+          const double mu;
+
+          SymmetricTensor<2, dim, NumberType>
+          get_tau_E_base(const Tensor<2,dim, NumberType> &F) const override
+          {
+             static const SymmetricTensor< 2, dim, double>
+                I (Physics::Elasticity::StandardTensors<dim>::I);
+
+             const bool use_standard_model = true;
+
+             if (use_standard_model)
+             {
+               // Standard Neo-Hooke
+               return ( mu * ( symmetrize(F * transpose(F)) - I ) );
+             }
+             else
+             {
+               // Neo-Hooke in terms of principal stretches
+               const SymmetricTensor<2, dim, NumberType>
+                B = symmetrize(F * transpose(F));
+               const std::array< std::pair< NumberType, Tensor< 1, dim, NumberType > >, dim >
+                eigen_B = eigenvectors(B, this->eigen_solver);
+
+               SymmetricTensor<2, dim, NumberType> B_ev;
+               for (unsigned int d=0; d<dim; ++d)
+                 B_ev += eigen_B[d].first*symmetrize(outer_product(eigen_B[d].second,eigen_B[d].second));
+
+                return ( mu*(B_ev-I) );
+             }
+          }
+    };
+
+//@sect4{Derived class: Ogden hyperelastic material}
+    template <int dim, typename NumberType = Sacado::Fad::DFad<double> >
+    class Ogden : public Material_Hyperelastic < dim, NumberType >
+    {
+        public:
+          Ogden(const Parameters::AllParameters &parameters,
+                const Time                      &time)
+          :
+          Material_Hyperelastic< dim, NumberType > (parameters,time),
+          mu({parameters.mu1_infty,
+              parameters.mu2_infty,
+              parameters.mu3_infty}),
+          alpha({parameters.alpha1_infty,
+                 parameters.alpha2_infty,
+                 parameters.alpha3_infty})
+           {}
+          virtual ~Ogden()
+          {}
+
+           double
+           get_viscous_dissipation() const override
+           {
+               return 0.0;
+           }
+
+        protected:
+          std::vector<double> mu;
+          std::vector<double> alpha;
+
+          SymmetricTensor<2, dim, NumberType>
+          get_tau_E_base(const Tensor<2,dim, NumberType> &F) const override
+          {
+            const SymmetricTensor<2, dim, NumberType>
+             B = symmetrize(F * transpose(F));
+
+            const std::array< std::pair< NumberType, Tensor< 1, dim, NumberType > >, dim >
+             eigen_B = eigenvectors(B, this->eigen_solver);
+
+            SymmetricTensor<2, dim, NumberType>  tau;
+            static const SymmetricTensor< 2, dim, double>
+              I (Physics::Elasticity::StandardTensors<dim>::I);
+
+            for (unsigned int i = 0; i < 3; ++i)
+            {
+                for (unsigned int A = 0; A < dim; ++A)
+                {
+                    SymmetricTensor<2, dim, NumberType>  tau_aux1 = symmetrize(
+                            outer_product(eigen_B[A].second,eigen_B[A].second));
+                    tau_aux1 *= mu[i]*std::pow(eigen_B[A].first, (alpha[i]/2.) );
+                    tau += tau_aux1;
+                }
+                SymmetricTensor<2, dim, NumberType>  tau_aux2 (I);
+                tau_aux2 *= mu[i];
+                tau -= tau_aux2;
+            }
+            return tau;
+          }
+    };
+
+//@sect4{Derived class: Single-mode Ogden viscoelastic material}
+// We use the finite viscoelastic model described in
+// Reese & Govindjee (1998) doi:10.1016/S0020-7683(97)00217-5
+// The algorithm for the implicit exponential time integration is given in
+// Budday et al. (2017) doi: 10.1016/j.actbio.2017.06.024
+    template <int dim, typename NumberType = Sacado::Fad::DFad<double> >
+    class visco_Ogden : public Material_Hyperelastic < dim, NumberType >
+    {
+        public:
+            visco_Ogden(const Parameters::AllParameters &parameters,
+                        const Time                      &time)
+            :
+            Material_Hyperelastic< dim, NumberType > (parameters,time),
+            mu_infty({parameters.mu1_infty,
+                      parameters.mu2_infty,
+                      parameters.mu3_infty}),
+            alpha_infty({parameters.alpha1_infty,
+                         parameters.alpha2_infty,
+                         parameters.alpha3_infty}),
+            mu_mode_1({parameters.mu1_mode_1,
+                       parameters.mu2_mode_1,
+                       parameters.mu3_mode_1}),
+            alpha_mode_1({parameters.alpha1_mode_1,
+                          parameters.alpha2_mode_1,
+                          parameters.alpha3_mode_1}),
+            viscosity_mode_1(parameters.viscosity_mode_1),
+            Cinv_v_1(Physics::Elasticity::StandardTensors<dim>::I),
+            Cinv_v_1_converged(Physics::Elasticity::StandardTensors<dim>::I)
+            {}
+            virtual ~visco_Ogden()
+            {}
+
+          void
+          update_internal_equilibrium( const Tensor<2, dim, NumberType> &F ) override
+          {
+              Material_Hyperelastic < dim, NumberType >::update_internal_equilibrium(F);
+
+              this->Cinv_v_1 = this->Cinv_v_1_converged;
+              SymmetricTensor<2, dim, NumberType> B_e_1_tr = symmetrize(F * this->Cinv_v_1 * transpose(F));
+
+              const std::array< std::pair< NumberType, Tensor< 1, dim, NumberType > >, dim >
+                eigen_B_e_1_tr = eigenvectors(B_e_1_tr, this->eigen_solver);
+
+              Tensor< 1, dim, NumberType > lambdas_e_1_tr;
+              Tensor< 1, dim, NumberType > epsilon_e_1_tr;
+              for (int a = 0; a < dim; ++a)
+              {
+                  lambdas_e_1_tr[a] = std::sqrt(eigen_B_e_1_tr[a].first);
+                  epsilon_e_1_tr[a] = std::log(lambdas_e_1_tr[a]);
+              }
+
+             const double tolerance = 1e-8;
+             double residual_check = tolerance*10.0;
+             Tensor< 1, dim, NumberType > residual;
+             Tensor< 2, dim, NumberType > tangent;
+             static const SymmetricTensor< 2, dim, double> I(Physics::Elasticity::StandardTensors<dim>::I);
+             NumberType J_e_1 = std::sqrt(determinant(B_e_1_tr));
+
+             std::vector<NumberType> lambdas_e_1_iso(dim);
+             SymmetricTensor<2, dim, NumberType> B_e_1;
+             int iteration = 0;
+
+             Tensor< 1, dim, NumberType > lambdas_e_1;
+             Tensor< 1, dim, NumberType > epsilon_e_1;
+             epsilon_e_1 = epsilon_e_1_tr;
+
+              while(residual_check > tolerance)
+              {
+                  NumberType aux_J_e_1 = 1.0;
+                  for (unsigned int a = 0; a < dim; ++a)
+                  {
+                      lambdas_e_1[a] = std::exp(epsilon_e_1[a]);
+                      aux_J_e_1 *= lambdas_e_1[a];
+                  }
+
+                  J_e_1 = aux_J_e_1;
+
+                  for (unsigned int a = 0; a < dim; ++a)
+                      lambdas_e_1_iso[a] = lambdas_e_1[a]*std::pow(J_e_1,-1.0/dim);
+
+                  for (unsigned int a = 0; a < dim; ++a)
+                  {
+                      residual[a] = get_beta_mode_1(lambdas_e_1_iso, a);
+                      residual[a] *= this->time.get_delta_t()/(2.0*viscosity_mode_1);
+                      residual[a] += epsilon_e_1[a];
+                      residual[a] -= epsilon_e_1_tr[a];
+
+                      for (unsigned int b = 0; b < dim; ++b)
+                      {
+                          tangent[a][b]  = get_gamma_mode_1(lambdas_e_1_iso, a, b);
+                          tangent[a][b] *= this->time.get_delta_t()/(2.0*viscosity_mode_1);
+                          tangent[a][b] += I[a][b];
+                      }
+
+                  }
+                  epsilon_e_1 -= invert(tangent)*residual;
+
+                  residual_check = 0.0;
+                  for (unsigned int a = 0; a < dim; ++a)
+                  {
+                      if ( std::abs(residual[a]) > residual_check)
+                          residual_check = std::abs(Tensor<0,dim,double>(residual[a]));
+                  }
+                  iteration += 1;
+                  if (iteration > 15 )
+                      AssertThrow(false, ExcMessage("No convergence in local Newton iteration for the "
+                                                    "viscoelastic exponential time integration algorithm."));
+              }
+
+              NumberType aux_J_e_1 = 1.0;
+              for (unsigned int a = 0; a < dim; ++a)
+              {
+                  lambdas_e_1[a] = std::exp(epsilon_e_1[a]);
+                  aux_J_e_1 *= lambdas_e_1[a];
+              }
+              J_e_1 = aux_J_e_1;
+
+              for (unsigned int a = 0; a < dim; ++a)
+                  lambdas_e_1_iso[a] = lambdas_e_1[a]*std::pow(J_e_1,-1.0/dim);
+
+              for (unsigned int a = 0; a < dim; ++a)
+              {
+                  SymmetricTensor<2, dim, NumberType>
+                  B_e_1_aux = symmetrize(outer_product(eigen_B_e_1_tr[a].second,eigen_B_e_1_tr[a].second));
+                  B_e_1_aux *= lambdas_e_1[a] * lambdas_e_1[a];
+                  B_e_1 += B_e_1_aux;
+              }
+
+              Tensor<2, dim, NumberType>Cinv_v_1_AD = symmetrize(invert(F) * B_e_1 * invert(transpose(F)));
+
+              this->tau_neq_1 = 0;
+              for (unsigned int a = 0; a < dim; ++a)
+              {
+                  SymmetricTensor<2, dim, NumberType>
+                  tau_neq_1_aux = symmetrize(outer_product(eigen_B_e_1_tr[a].second,eigen_B_e_1_tr[a].second));
+                  tau_neq_1_aux *=  get_beta_mode_1(lambdas_e_1_iso, a);
+                  this->tau_neq_1 += tau_neq_1_aux;
+              }
+
+              // Store history
+              for (unsigned int a = 0; a < dim; ++a)
+                  for (unsigned int b = 0; b < dim; ++b)
+                      this->Cinv_v_1[a][b]= Tensor<0,dim,double>(Cinv_v_1_AD[a][b]);
+          }
+
+          void update_end_timestep() override
+          {
+              Material_Hyperelastic < dim, NumberType >::update_end_timestep();
+              this->Cinv_v_1_converged = this->Cinv_v_1;
+          }
+
+           double get_viscous_dissipation() const override
+           {
+               NumberType dissipation_term = get_tau_E_neq() * get_tau_E_neq(); //Double contract the two SymmetricTensor
+               dissipation_term /= (2*viscosity_mode_1);
+
+               return dissipation_term.val();
+           }
+
+        protected:
+          std::vector<double> mu_infty;
+          std::vector<double> alpha_infty;
+          std::vector<double> mu_mode_1;
+          std::vector<double> alpha_mode_1;
+          double viscosity_mode_1;
+          SymmetricTensor<2, dim, double> Cinv_v_1;
+          SymmetricTensor<2, dim, double> Cinv_v_1_converged;
+          SymmetricTensor<2, dim, NumberType> tau_neq_1;
+
+          SymmetricTensor<2, dim, NumberType>
+          get_tau_E_base(const Tensor<2,dim, NumberType> &F) const override
+          {
+              return ( get_tau_E_neq() + get_tau_E_eq(F) );
+          }
+
+          SymmetricTensor<2, dim, NumberType>
+          get_tau_E_eq(const Tensor<2,dim, NumberType> &F) const
+          {
+            const SymmetricTensor<2, dim, NumberType> B = symmetrize(F * transpose(F));
+
+            std::array< std::pair< NumberType, Tensor< 1, dim, NumberType > >, dim > eigen_B;
+            eigen_B = eigenvectors(B, this->eigen_solver);
+
+            SymmetricTensor<2, dim, NumberType>  tau;
+            static const SymmetricTensor< 2, dim, double>
+              I (Physics::Elasticity::StandardTensors<dim>::I);
+
+            for (unsigned int i = 0; i < 3; ++i)
+            {
+                for (unsigned int A = 0; A < dim; ++A)
+                {
+                    SymmetricTensor<2, dim, NumberType>  tau_aux1 = symmetrize(
+                          outer_product(eigen_B[A].second,eigen_B[A].second));
+                    tau_aux1 *= mu_infty[i]*std::pow(eigen_B[A].first, (alpha_infty[i]/2.) );
+                    tau += tau_aux1;
+                }
+                SymmetricTensor<2, dim, NumberType>  tau_aux2 (I);
+                tau_aux2 *= mu_infty[i];
+                tau -= tau_aux2;
+            }
+            return tau;
+          }
+
+          SymmetricTensor<2, dim, NumberType>
+          get_tau_E_neq() const
+          {
+              return tau_neq_1;
+          }
+
+          NumberType
+          get_beta_mode_1(std::vector< NumberType > &lambda, const int &A) const
+          {
+              NumberType beta = 0.0;
+
+              for (unsigned int i = 0; i < 3; ++i) //3rd-order Ogden model
+              {
+
+                  NumberType aux = 0.0;
+                  for (int p = 0; p < dim; ++p)
+                      aux += std::pow(lambda[p],alpha_mode_1[i]);
+
+                  aux *= -1.0/dim;
+                  aux += std::pow(lambda[A], alpha_mode_1[i]);
+                  aux *= mu_mode_1[i];
+
+                  beta  += aux;
+              }
+              return beta;
+          }
+
+          NumberType
+          get_gamma_mode_1(std::vector< NumberType > &lambda,
+                           const int                 &A,
+                           const int                 &B       ) const
+          {
+              NumberType gamma = 0.0;
+
+              if (A==B)
+              {
+                  for (unsigned int i = 0; i < 3; ++i)
+                  {
+                      NumberType aux = 0.0;
+                      for (int p = 0; p < dim; ++p)
+                          aux += std::pow(lambda[p],alpha_mode_1[i]);
+
+                      aux *= 1.0/(dim*dim);
+                      aux += 1.0/dim * std::pow(lambda[A], alpha_mode_1[i]);
+                      aux *= mu_mode_1[i]*alpha_mode_1[i];
+
+                      gamma += aux;
+                  }
+              }
+              else
+              {
+                  for (unsigned int i = 0; i < 3; ++i)
+                  {
+                      NumberType aux = 0.0;
+                      for (int p = 0; p < dim; ++p)
+                          aux += std::pow(lambda[p],alpha_mode_1[i]);
+
+                      aux *= 1.0/(dim*dim);
+                      aux -= 1.0/dim * std::pow(lambda[A], alpha_mode_1[i]);
+                      aux -= 1.0/dim * std::pow(lambda[B], alpha_mode_1[i]);
+                      aux *= mu_mode_1[i]*alpha_mode_1[i];
+
+                      gamma += aux;
+                  }
+              }
+
+              return gamma;
+          }
+    };
+
+
+// @sect3{Constitutive equation for the fluid component of the biphasic material}
+// We consider two slightly different definitions to define the seepage velocity with a Darcy-like law.
+// Ehlers & Eipper 1999, doi:10.1023/A:1006565509095
+// Markert 2007, doi:10.1007/s11242-007-9107-6
+// The selection of one or another is made by the user via the parameters file.
+    template <int dim, typename NumberType = Sacado::Fad::DFad<double> >
+    class Material_Darcy_Fluid
+    {
+       public:
+         Material_Darcy_Fluid(const Parameters::AllParameters &parameters)
+         :
+         fluid_type(parameters.fluid_type),
+         n_OS(parameters.solid_vol_frac),
+         initial_intrinsic_permeability(parameters.init_intrinsic_perm),
+         viscosity_FR(parameters.viscosity_FR),
+         initial_darcy_coefficient(parameters.init_darcy_coef),
+         weight_FR(parameters.weight_FR),
+         kappa_darcy(parameters.kappa_darcy),
+         gravity_term(parameters.gravity_term),
+         density_FR(parameters.density_FR),
+         gravity_direction(parameters.gravity_direction),
+         gravity_value(parameters.gravity_value)
+         {
+           Assert(kappa_darcy >= 0, ExcInternalError());
+         }
+         ~Material_Darcy_Fluid()
+         {}
+
+         Tensor<1, dim, NumberType> get_seepage_velocity_current
+                             (const Tensor<2,dim, NumberType> &F,
+                              const Tensor<1,dim, NumberType> &grad_p_fluid) const
+         {
+             const NumberType det_F = determinant(F);
+             Assert(det_F > 0.0, ExcInternalError());
+
+             Tensor<2, dim, NumberType> permeability_term;
+
+             if (fluid_type == "Markert")
+                 permeability_term = get_instrinsic_permeability_current(F) / viscosity_FR;
+
+             else if (fluid_type == "Ehlers")
+                 permeability_term = get_darcy_flow_current(F) / weight_FR;
+
+             else
+                 AssertThrow(false, ExcMessage(
+                   "Material_Darcy_Fluid --> Only Markert "
+                   "and Ehlers formulations have been implemented."));
+
+             return ( -1.0 * permeability_term * det_F
+                      * (grad_p_fluid - get_body_force_FR_current()) );
+         }
+
+         double get_porous_dissipation(const Tensor<2,dim, NumberType> &F,
+                                       const Tensor<1,dim, NumberType> &grad_p_fluid) const
+         {
+             NumberType dissipation_term;
+             Tensor<1, dim, NumberType> seepage_velocity;
+             Tensor<2, dim, NumberType> permeability_term;
+
+             const NumberType det_F = determinant(F);
+             Assert(det_F > 0.0, ExcInternalError());
+
+             if (fluid_type == "Markert")
+             {
+                 permeability_term = get_instrinsic_permeability_current(F) / viscosity_FR;
+                 seepage_velocity = get_seepage_velocity_current(F,grad_p_fluid);
+             }
+             else if (fluid_type == "Ehlers")
+             {
+                 permeability_term = get_darcy_flow_current(F) / weight_FR;
+                 seepage_velocity = get_seepage_velocity_current(F,grad_p_fluid);
+             }
+             else
+                 AssertThrow(false, ExcMessage(
+                   "Material_Darcy_Fluid --> Only Markert and Ehlers "
+                   "formulations have been implemented."));
+
+             dissipation_term = ( invert(permeability_term) * seepage_velocity ) * seepage_velocity;
+             dissipation_term *= 1.0/(det_F*det_F);
+             return Tensor<0,dim,double>(dissipation_term);
+         }
+
+       protected:
+         const std::string  fluid_type;
+         const double n_OS;
+         const double initial_intrinsic_permeability;
+         const double viscosity_FR;
+         const double initial_darcy_coefficient;
+         const double weight_FR;
+         const double kappa_darcy;
+         const bool   gravity_term;
+         const double density_FR;
+         const int    gravity_direction;
+         const double    gravity_value;
+
+         Tensor<2, dim, NumberType>
+         get_instrinsic_permeability_current(const Tensor<2,dim, NumberType> &F) const
+         {
+           static const SymmetricTensor< 2, dim, double>
+               I (Physics::Elasticity::StandardTensors<dim>::I);
+           const Tensor<2, dim, NumberType> initial_instrinsic_permeability_tensor
+               = Tensor<2, dim, double>(initial_intrinsic_permeability * I);
+
+           const NumberType det_F = determinant(F);
+           Assert(det_F > 0.0, ExcInternalError());
+
+           const NumberType fraction = (det_F - n_OS)/(1 - n_OS);
+           return ( NumberType (std::pow(fraction, kappa_darcy))
+                     * initial_instrinsic_permeability_tensor );
+         }
+
+         Tensor<2, dim, NumberType>
+         get_darcy_flow_current(const Tensor<2,dim, NumberType> &F) const
+         {
+           static const SymmetricTensor< 2, dim, double>
+              I (Physics::Elasticity::StandardTensors<dim>::I);
+           const Tensor<2, dim, NumberType> initial_darcy_flow_tensor
+              = Tensor<2, dim, double>(initial_darcy_coefficient * I);
+
+           const NumberType det_F = determinant(F);
+           Assert(det_F > 0.0, ExcInternalError());
+
+           const NumberType fraction = (1.0 - (n_OS / det_F) )/(1.0 - n_OS);
+           return ( NumberType (std::pow(fraction, kappa_darcy))
+                     * initial_darcy_flow_tensor);
+         }
+
+        Tensor<1, dim, NumberType>
+        get_body_force_FR_current() const
+        {
+            Tensor<1, dim, NumberType> body_force_FR_current;
+
+            if (gravity_term == true)
+            {
+               Tensor<1, dim, NumberType> gravity_vector;
+               gravity_vector[gravity_direction] = gravity_value;
+               body_force_FR_current = density_FR * gravity_vector;
+            }
+            return body_force_FR_current;
+        }
+    };
+
+// @sect3{Quadrature point history}
+// As seen in step-18, the <code> PointHistory </code> class offers a method
+// for storing data at the quadrature points.  Here each quadrature point
+// holds a pointer to a material description.  Thus, different material models
+// can be used in different regions of the domain.  Among other data, we
+// choose to store the ``extra" Kirchhoff stress $\boldsymbol{\tau}_E$ and
+// the dissipation values $\mathcal{D}_p$ and $\mathcal{D}_v$.
+    template <int dim, typename NumberType = Sacado::Fad::DFad<double> > //double>
+    class PointHistory
+    {
+        public:
+            PointHistory()
+            {}
+
+            virtual ~PointHistory()
+            {}
+
+            void setup_lqp (const Parameters::AllParameters &parameters,
+                            const Time                      &time)
+            {
+                if (parameters.mat_type == "Neo-Hooke")
+                    solid_material.reset(new NeoHooke<dim,NumberType>(parameters,time));
+                else if (parameters.mat_type == "Ogden")
+                    solid_material.reset(new Ogden<dim,NumberType>(parameters,time));
+                else if (parameters.mat_type == "visco-Ogden")
+                    solid_material.reset(new visco_Ogden<dim,NumberType>(parameters,time));
+                else
+                    Assert (false, ExcMessage("Material type not implemented"));
+
+                fluid_material.reset(new Material_Darcy_Fluid<dim,NumberType>(parameters));
+            }
+
+            SymmetricTensor<2, dim, NumberType>
+            get_tau_E(const Tensor<2, dim, NumberType> &F) const
+            {
+                return solid_material->get_tau_E(F);
+            }
+
+            SymmetricTensor<2, dim, NumberType>
+            get_Cauchy_E(const Tensor<2, dim, NumberType> &F) const
+            {
+                return solid_material->get_Cauchy_E(F);
+            }
+
+            double
+            get_converged_det_F() const
+            {
+              return  solid_material->get_converged_det_F();
+            }
+
+            void
+            update_end_timestep()
+            {
+                solid_material->update_end_timestep();
+            }
+
+            void
+            update_internal_equilibrium(const Tensor<2, dim, NumberType> &F )
+            {
+                solid_material->update_internal_equilibrium(F);
+            }
+
+            double
+            get_viscous_dissipation() const
+            {
+                return solid_material->get_viscous_dissipation();
+            }
+
+            Tensor<1,dim, NumberType>
+            get_seepage_velocity_current (const Tensor<2,dim, NumberType> &F,
+                                          const Tensor<1,dim, NumberType> &grad_p_fluid) const
+             {
+                 return fluid_material->get_seepage_velocity_current(F, grad_p_fluid);
+             }
+
+            double
+            get_porous_dissipation(const Tensor<2,dim, NumberType> &F,
+                                   const Tensor<1,dim, NumberType> &grad_p_fluid) const
+            {
+                return fluid_material->get_porous_dissipation(F, grad_p_fluid);
+            }
+
+            Tensor<1, dim, NumberType>
+            get_overall_body_force (const Tensor<2,dim, NumberType> &F,
+                                    const Parameters::AllParameters &parameters) const
+            {
+                Tensor<1, dim, NumberType> body_force;
+
+                if (parameters.gravity_term == true)
+                {
+                    const NumberType det_F_AD = determinant(F);
+                    Assert(det_F_AD > 0.0, ExcInternalError());
+
+                    const NumberType overall_density_ref
+                        = parameters.density_SR * parameters.solid_vol_frac
+                          + parameters.density_FR
+                          * (det_F_AD - parameters.solid_vol_frac);
+
+                   Tensor<1, dim, NumberType> gravity_vector;
+                   gravity_vector[parameters.gravity_direction] = parameters.gravity_value;
+                   body_force = overall_density_ref * gravity_vector;
+                }
+
+                return body_force;
+            }
+        private:
+            std::shared_ptr< Material_Hyperelastic<dim, NumberType> > solid_material;
+            std::shared_ptr< Material_Darcy_Fluid<dim, NumberType> > fluid_material;
+    };
+
+// @sect3{Nonlinear poro-viscoelastic solid}
+// The Solid class is the central class as it represents the problem at hand:
+// the nonlinear poro-viscoelastic solid
+    template <int dim>
+    class Solid
+    {
+          public:
+            Solid(const Parameters::AllParameters &parameters);
+            virtual ~Solid();
+            void run();
+
+          protected:
+            using ADNumberType = Sacado::Fad::DFad<double>;
+
+            std::ofstream outfile;
+            std::ofstream pointfile;
+
+            struct PerTaskData_ASM;
+            template<typename NumberType = double> struct ScratchData_ASM;
+
+            //Generate mesh
+            virtual void make_grid() = 0;
+
+            //Define points for post-processing
+            virtual void define_tracked_vertices(std::vector<Point<dim> > &tracked_vertices) = 0;
+
+            //Set up the finite element system to be solved:
+            void system_setup(TrilinosWrappers::MPI::BlockVector &solution_delta_OUT);
+
+            //Extract sub-blocks from the global matrix
+            void determine_component_extractors();
+
+            // Several functions to assemble the system and right hand side matrices using multithreading.
+            void assemble_system
+                  (const TrilinosWrappers::MPI::BlockVector &solution_delta_OUT );
+            void assemble_system_one_cell
+                  (const typename DoFHandler<dim>::active_cell_iterator &cell,
+                   ScratchData_ASM<ADNumberType> &scratch,
+                   PerTaskData_ASM &data) const;
+            void copy_local_to_global_system(const PerTaskData_ASM &data);
+
+            // Define boundary conditions
+            virtual void make_constraints(const int &it_nr);
+            virtual void make_dirichlet_constraints(AffineConstraints<double> &constraints) = 0;
+            virtual Tensor<1,dim> get_neumann_traction
+                   (const types::boundary_id &boundary_id,
+                    const Point<dim>         &pt,
+                    const Tensor<1,dim>      &N) const = 0;
+            virtual double get_prescribed_fluid_flow
+                   (const types::boundary_id &boundary_id,
+                    const Point<dim>         &pt) const = 0;
+            virtual types::boundary_id
+                     get_reaction_boundary_id_for_output () const = 0;
+            virtual std::pair<types::boundary_id,types::boundary_id>
+                     get_drained_boundary_id_for_output () const = 0;
+            virtual std::vector<double> get_dirichlet_load
+                    (const types::boundary_id   &boundary_id,
+                     const int                  &direction) const = 0;
+
+            // Create and update the quadrature points.
+            void setup_qph();
+
+            //Solve non-linear system using a Newton-Raphson scheme
+            void solve_nonlinear_timestep(TrilinosWrappers::MPI::BlockVector &solution_delta_OUT);
+
+            //Solve the linearized equations using a direct solver
+            void solve_linear_system ( TrilinosWrappers::MPI::BlockVector &newton_update_OUT);
+
+            //Retrieve the  solution
+            TrilinosWrappers::MPI::BlockVector
+            get_total_solution(const TrilinosWrappers::MPI::BlockVector &solution_delta_IN) const;
+
+            // Store the converged values of the internal variables at the end of each timestep
+            void update_end_timestep();
+
+            //Post-processing and writing data to files
+            void output_results_to_vtu(const unsigned int timestep,
+                                       const double current_time,
+                                       TrilinosWrappers::MPI::BlockVector solution) const;
+            void output_results_to_plot(const unsigned int timestep,
+                                        const double current_time,
+                                        TrilinosWrappers::MPI::BlockVector solution,
+                                        std::vector<Point<dim> > &tracked_vertices,
+                                        std::ofstream &pointfile) const;
+
+            // Headers and footer for the output files
+            void print_console_file_header( std::ofstream &outfile) const;
+            void print_plot_file_header(std::vector<Point<dim> > &tracked_vertices,
+                                        std::ofstream &pointfile) const;
+            void print_console_file_footer(std::ofstream &outfile) const;
+            void print_plot_file_footer( std::ofstream &pointfile) const;
+
+            // For parallel communication
+            MPI_Comm                         mpi_communicator;
+            const unsigned int               n_mpi_processes;
+            const unsigned int               this_mpi_process;
+            mutable ConditionalOStream       pcout;
+
+            // A collection of the parameters used to describe the problem setup
+            const Parameters::AllParameters &parameters;
+
+            // Declare an instance of dealii Triangulation class (mesh)
+            parallel::shared::Triangulation<dim>  triangulation;
+
+            // Keep track of the current time and the time spent evaluating certain functions
+            Time          time;
+            TimerOutput   timerconsole;
+            TimerOutput   timerfile;
+
+            // A storage object for quadrature point information.
+            CellDataStorage<typename Triangulation<dim>::cell_iterator, PointHistory<dim,ADNumberType> > quadrature_point_history;
+
+            //Integers to store polynomial degree (needed for output)
+            const unsigned int  degree_displ;
+            const unsigned int  degree_pore;
+
+            //Declare an instance of dealii FESystem class (finite element definition)
+            const FESystem<dim> fe;
+
+            //Declare an instance of dealii DoFHandler class (assign DoFs to mesh)
+            DoFHandler<dim>     dof_handler_ref;
+
+            //Integer to store DoFs per element (this value will be used often)
+            const unsigned int  dofs_per_cell;
+
+            //Declare an instance of dealii Extractor objects used to retrieve information from the solution vectors
+            //We will use "u_fe" and "p_fluid_fe"as subscript in operator [] expressions on FEValues and FEFaceValues
+            //objects to extract the components of the displacement vector and fluid pressure, respectively.
+            const FEValuesExtractors::Vector u_fe;
+            const FEValuesExtractors::Scalar p_fluid_fe;
+
+            // Description of how the block-system is arranged. There are 3 blocks:
+            //   0 - vector DOF displacements u
+            //   1 - scalar DOF fluid pressure p_fluid
+            static const unsigned int  n_blocks = 2;
+            static const unsigned int  n_components = dim+1;
+            static const unsigned int  first_u_component = 0;
+            static const unsigned int  p_fluid_component = dim;
+
+            enum
+            {
+              u_block = 0,
+              p_fluid_block = 1
+            };
+
+            // Extractors
+            const FEValuesExtractors::Scalar x_displacement;
+            const FEValuesExtractors::Scalar y_displacement;
+            const FEValuesExtractors::Scalar z_displacement;
+            const FEValuesExtractors::Scalar pressure;
+
+            // Block data
+            std::vector<unsigned int> block_component;
+
+            // DoF index data
+            std::vector<IndexSet> all_locally_owned_dofs;
+            IndexSet locally_owned_dofs;
+            IndexSet locally_relevant_dofs;
+            std::vector<IndexSet> locally_owned_partitioning;
+            std::vector<IndexSet> locally_relevant_partitioning;
+
+            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_fluid;
+
+            //Declare an instance of dealii QGauss class (The Gauss-Legendre family of quadrature rules for numerical integration)
+            //Gauss Points in element, with n quadrature points (in each space direction <dim> )
+            const QGauss<dim>                qf_cell;
+            //Gauss Points on element faces (used for definition of BCs)
+            const QGauss<dim - 1>            qf_face;
+            //Integer to store num GPs per element (this value will be used often)
+            const unsigned int               n_q_points;
+            //Integer to store num GPs per face (this value will be used often)
+            const unsigned int               n_q_points_f;
+
+            //Declare an instance of dealii AffineConstraints class (linear constraints on DoFs due to hanging nodes or BCs)
+            AffineConstraints<double>        constraints;
+
+            //Declare an instance of dealii classes necessary for FE system set-up and assembly
+            //Store elements of tangent matrix (indicated by SparsityPattern class) as sparse matrix (more efficient)
+            TrilinosWrappers::BlockSparseMatrix tangent_matrix;
+            TrilinosWrappers::BlockSparseMatrix tangent_matrix_preconditioner;
+            //Right hand side vector of forces
+            TrilinosWrappers::MPI::BlockVector  system_rhs;
+            //Total displacement values + pressure (accumulated solution to FE system)
+            TrilinosWrappers::MPI::BlockVector  solution_n;
+
+            // Non-block system for the direct solver. We will copy the block system into these to solve the linearized system of equations.
+            TrilinosWrappers::SparseMatrix tangent_matrix_nb;
+            TrilinosWrappers::MPI::Vector  system_rhs_nb;
+
+            //We define variables to store norms and update norms and normalisation factors.
+            struct Errors
+            {
+              Errors()
+                :
+                norm(1.0), u(1.0), p_fluid(1.0)
+              {}
+
+              void reset()
+              {
+                norm = 1.0;
+                u = 1.0;
+                p_fluid = 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_fluid != 0.0)
+                  p_fluid /= rhs.p_fluid;
+              }
+
+              double norm, u, p_fluid;
+            };
+
+            //Declare several instances of the "Error" structure
+            Errors error_residual, error_residual_0, error_residual_norm, error_update,
+                   error_update_0, error_update_norm;
+
+            // Methods to calculate error measures
+            void get_error_residual(Errors &error_residual_OUT);
+            void get_error_update
+                 (const TrilinosWrappers::MPI::BlockVector &newton_update_IN,
+                  Errors                                   &error_update_OUT);
+
+            // Print information to screen
+            void print_conv_header();
+            void print_conv_footer();
+
+//NOTE: In all functions, we pass by reference (&), so these functions work on the original copy (not a clone copy),
+//      modifying the input variables inside the functions will change them outside the function.
+    };
+
+// @sect3{Implementation of the <code>Solid</code> class}
+// @sect4{Public interface}
+// We initialise the Solid class using data extracted from the parameter file.
+    template <int dim>
+    Solid<dim>::Solid(const Parameters::AllParameters &parameters)
+        :
+        mpi_communicator(MPI_COMM_WORLD),
+        n_mpi_processes (Utilities::MPI::n_mpi_processes(mpi_communicator)),
+        this_mpi_process (Utilities::MPI::this_mpi_process(mpi_communicator)),
+        pcout(std::cout, this_mpi_process == 0),
+        parameters(parameters),
+        triangulation(mpi_communicator,Triangulation<dim>::maximum_smoothing),
+        time(parameters.end_time, parameters.delta_t),
+        timerconsole( mpi_communicator,
+                      pcout,
+                      TimerOutput::summary,
+                      TimerOutput::wall_times),
+        timerfile( mpi_communicator,
+                   outfile,
+                   TimerOutput::summary,
+                   TimerOutput::wall_times),
+        degree_displ(parameters.poly_degree_displ),
+        degree_pore(parameters.poly_degree_pore),
+        fe( FE_Q<dim>(parameters.poly_degree_displ), dim,
+            FE_Q<dim>(parameters.poly_degree_pore), 1 ),
+        dof_handler_ref(triangulation),
+        dofs_per_cell (fe.dofs_per_cell),
+        u_fe(first_u_component),
+        p_fluid_fe(p_fluid_component),
+        x_displacement(first_u_component),
+        y_displacement(first_u_component+1),
+        z_displacement(first_u_component+2),
+        pressure(p_fluid_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())
+        {
+         Assert(dim==3, ExcMessage("This problem only works in 3 space dimensions."));
+         determine_component_extractors();
+        }
+
+    //The class destructor simply clears the data held by the DOFHandler
+    template <int dim>
+    Solid<dim>::~Solid()
+    {
+        dof_handler_ref.clear();
+    }
+
+//Runs the 3D solid problem
+    template <int dim>
+    void Solid<dim>::run()
+    {
+          //The current solution increment is defined as a block vector to reflect the structure
+          //of the PDE system, with multiple solution components
+          TrilinosWrappers::MPI::BlockVector solution_delta;
+
+          //Open file
+          if (this_mpi_process == 0)
+          {
+              outfile.open("console-output.sol");
+              print_console_file_header(outfile);
+          }
+
+          //Generate mesh
+          make_grid();
+
+          //Assign DOFs and create the stiffness and right-hand-side force vector
+          system_setup(solution_delta);
+
+          //Define points for post-processing
+          std::vector<Point<dim> > tracked_vertices (2);
+          define_tracked_vertices(tracked_vertices);
+          std::vector<Point<dim>> reaction_force;
+
+          if (this_mpi_process == 0)
+          {
+              pointfile.open("data-for-gnuplot.sol");
+              print_plot_file_header(tracked_vertices, pointfile);
+          }
+
+          //Print results to output file
+          if (parameters.outfiles_requested == "true")
+          {
+                output_results_to_vtu(time.get_timestep(),
+                                      time.get_current(),
+                                      solution_n           );
+          }
+
+          output_results_to_plot(time.get_timestep(),
+                                 time.get_current(),
+                                 solution_n,
+                                 tracked_vertices,
+                                 pointfile);
+
+          //Increment time step (=load step)
+          //NOTE: In solving the quasi-static problem, the time becomes a loading parameter,
+          //i.e. we increase the loading linearly with time, making the two concepts interchangeable.
+          time.increment_time();
+
+          //Print information on screen
+          pcout << "\nSolver:";
+          pcout << "\n  CST     = make constraints";
+          pcout << "\n  ASM_SYS = assemble system";
+          pcout << "\n  SLV     = linear solver \n";
+
+          //Print information on file
+          outfile << "\nSolver:";
+          outfile << "\n  CST     = make constraints";
+          outfile << "\n  ASM_SYS = assemble system";
+          outfile << "\n  SLV     = linear solver \n";
+
+          while ( (time.get_end() - time.get_current()) > -1.0*parameters.tol_u )
+            {
+              //Initialize the current solution increment to zero
+              solution_delta = 0.0;
+
+              //Solve the non-linear system using a Newton-Rapshon scheme
+              solve_nonlinear_timestep(solution_delta);
+
+              //Add the computed solution increment to total solution
+              solution_n += solution_delta;
+
+              //Store the converged values of the internal variables
+              update_end_timestep();
+
+              //Output results
+              if (( (time.get_timestep()%parameters.timestep_output) == 0 )
+                   && (parameters.outfiles_requested == "true") )
+              {
+                      output_results_to_vtu(time.get_timestep(),
+                                            time.get_current(),
+                                            solution_n           );
+              }
+
+              output_results_to_plot(time.get_timestep(),
+                                     time.get_current(),
+                                     solution_n,
+                                     tracked_vertices,
+                                     pointfile);
+
+              //Increment the time step (=load step)
+              time.increment_time();
+            }
+
+          //Print the footers and close files
+          if (this_mpi_process == 0)
+          {
+              print_plot_file_footer(pointfile);
+              pointfile.close ();
+              print_console_file_footer(outfile);
+
+              //NOTE: ideally, we should close the outfile here [ >> outfile.close (); ]
+              //But if we do, then the timer output will not be printed. That is why we leave it open.
+          }
+    }
+
+// @sect4{Private interface}
+// We define the structures needed for parallelization with Threading Building Blocks (TBB)
+// Tangent matrix and right-hand side force vector assembly structures.
+// PerTaskData_ASM stores local contributions
+    template <int dim>
+    struct Solid<dim>::PerTaskData_ASM
+    {
+        FullMatrix<double>        cell_matrix;
+        Vector<double>            cell_rhs;
+        std::vector<types::global_dof_index> local_dof_indices;
+
+        PerTaskData_ASM(const unsigned int dofs_per_cell)
+          :
+          cell_matrix(dofs_per_cell, dofs_per_cell),
+          cell_rhs(dofs_per_cell),
+          local_dof_indices(dofs_per_cell)
+        {}
+
+        void reset()
+        {
+          cell_matrix = 0.0;
+          cell_rhs = 0.0;
+        }
+    };
+
+    // ScratchData_ASM stores larger objects used during the assembly
+    template <int dim>
+    template <typename NumberType>
+    struct Solid<dim>::ScratchData_ASM
+    {
+        const TrilinosWrappers::MPI::BlockVector &solution_total;
+
+        //Integration helper
+        FEValues<dim>     fe_values_ref;
+        FEFaceValues<dim> fe_face_values_ref;
+
+        // Quadrature point solution
+        std::vector<NumberType>                  local_dof_values;
+        std::vector<Tensor<2, dim, NumberType> > solution_grads_u_total;
+        std::vector<NumberType>                  solution_values_p_fluid_total;
+        std::vector<Tensor<1, dim, NumberType> > solution_grads_p_fluid_total;
+        std::vector<Tensor<1, dim, NumberType> > solution_grads_face_p_fluid_total;
+
+        //shape function values
+        std::vector<std::vector<Tensor<1,dim>>>          Nx;
+        std::vector<std::vector<double>>                 Nx_p_fluid;
+        //shape function gradients
+        std::vector<std::vector<Tensor<2,dim, NumberType>>>          grad_Nx;
+        std::vector<std::vector<SymmetricTensor<2,dim, NumberType>>> symm_grad_Nx;
+        std::vector<std::vector<Tensor<1,dim, NumberType>>>          grad_Nx_p_fluid;
+
+        ScratchData_ASM(const FiniteElement<dim> &fe_cell,
+                        const QGauss<dim> &qf_cell, const UpdateFlags uf_cell,
+                        const QGauss<dim - 1> & qf_face, const UpdateFlags uf_face,
+                        const TrilinosWrappers::MPI::BlockVector &solution_total    )
+          :
+          solution_total (solution_total),
+          fe_values_ref(fe_cell, qf_cell, uf_cell),
+          fe_face_values_ref(fe_cell, qf_face, uf_face),
+          local_dof_values(fe_cell.dofs_per_cell),
+          solution_grads_u_total(qf_cell.size()),
+          solution_values_p_fluid_total(qf_cell.size()),
+          solution_grads_p_fluid_total(qf_cell.size()),
+          solution_grads_face_p_fluid_total(qf_face.size()),
+          Nx(qf_cell.size(), std::vector<Tensor<1,dim>>(fe_cell.dofs_per_cell)),
+          Nx_p_fluid(qf_cell.size(), std::vector<double>(fe_cell.dofs_per_cell)),
+          grad_Nx(qf_cell.size(), std::vector<Tensor<2, dim, NumberType>>(fe_cell.dofs_per_cell)),
+          symm_grad_Nx(qf_cell.size(), std::vector<SymmetricTensor<2, dim, NumberType>> (fe_cell.dofs_per_cell)),
+          grad_Nx_p_fluid(qf_cell.size(), std::vector<Tensor<1, dim, NumberType>>(fe_cell.dofs_per_cell))
+        {}
+
+        ScratchData_ASM(const ScratchData_ASM &rhs)
+          :
+          solution_total (rhs.solution_total),
+          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()),
+          local_dof_values(rhs.local_dof_values),
+          solution_grads_u_total(rhs.solution_grads_u_total),
+          solution_values_p_fluid_total(rhs.solution_values_p_fluid_total),
+          solution_grads_p_fluid_total(rhs.solution_grads_p_fluid_total),
+          solution_grads_face_p_fluid_total(rhs.solution_grads_face_p_fluid_total),
+          Nx(rhs.Nx),
+          Nx_p_fluid(rhs.Nx_p_fluid),
+          grad_Nx(rhs.grad_Nx),
+          symm_grad_Nx(rhs.symm_grad_Nx),
+          grad_Nx_p_fluid(rhs.grad_Nx_p_fluid)
+        {}
+
+        void reset()
+        {
+          const unsigned int n_q_points = Nx_p_fluid.size();
+          const unsigned int n_dofs_per_cell = Nx_p_fluid[0].size();
+
+          Assert(local_dof_values.size() == n_dofs_per_cell, ExcInternalError());
+
+          for (unsigned int k = 0; k < n_dofs_per_cell; ++k)
+            {
+              local_dof_values[k] = 0.0;
+            }
+
+          Assert(solution_grads_u_total.size() == n_q_points, ExcInternalError());
+          Assert(solution_values_p_fluid_total.size() == n_q_points, ExcInternalError());
+          Assert(solution_grads_p_fluid_total.size() == n_q_points, ExcInternalError());
+
+          Assert(Nx.size() == n_q_points, ExcInternalError());
+          Assert(grad_Nx.size() == n_q_points, ExcInternalError());
+          Assert(symm_grad_Nx.size() == n_q_points, ExcInternalError());
+
+          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());
+
+              solution_grads_u_total[q_point] = 0.0;
+              solution_values_p_fluid_total[q_point] = 0.0;
+              solution_grads_p_fluid_total[q_point] = 0.0;
+
+              for (unsigned int k = 0; k < n_dofs_per_cell; ++k)
+                {
+                  Nx[q_point][k] = 0.0;
+                  Nx_p_fluid[q_point][k] = 0.0;
+                  grad_Nx[q_point][k] = 0.0;
+                  symm_grad_Nx[q_point][k] = 0.0;
+                  grad_Nx_p_fluid[q_point][k] = 0.0;
+                }
+            }
+
+          const unsigned int n_f_q_points = solution_grads_face_p_fluid_total.size();
+          Assert(solution_grads_face_p_fluid_total.size() == n_f_q_points, ExcInternalError());
+
+          for (unsigned int f_q_point = 0; f_q_point < n_f_q_points; ++f_q_point)
+              solution_grads_face_p_fluid_total[f_q_point] = 0.0;
+        }
+    };
+
+    //Define the boundary conditions on the mesh
+    template <int dim>
+    void Solid<dim>::make_constraints(const int &it_nr_IN)
+    {
+        pcout     << " CST " << std::flush;
+        outfile   << " CST " << std::flush;
+
+        if (it_nr_IN > 1) return;
+
+        const bool apply_dirichlet_bc = (it_nr_IN == 0);
+
+        if (apply_dirichlet_bc)
+        {
+          constraints.clear();
+          make_dirichlet_constraints(constraints);
+        }
+        else
+        {
+          for (unsigned int i=0; i<dof_handler_ref.n_dofs(); ++i)
+            if (constraints.is_inhomogeneously_constrained(i) == true)
+              constraints.set_inhomogeneity(i,0.0);
+        }
+        constraints.close();
+    }
+
+    //Set-up the FE system
+    template <int dim>
+    void Solid<dim>::system_setup(TrilinosWrappers::MPI::BlockVector &solution_delta_OUT)
+    {
+        timerconsole.enter_subsection("Setup system");
+        timerfile.enter_subsection("Setup system");
+
+        //Determine number of components per block
+        std::vector<unsigned int> block_component(n_components, u_block);
+        block_component[p_fluid_component] = p_fluid_block;
+
+        // The DOF handler is initialised and we renumber the grid in an efficient manner.
+        dof_handler_ref.distribute_dofs(fe);
+        DoFRenumbering::Cuthill_McKee(dof_handler_ref);
+        DoFRenumbering::component_wise(dof_handler_ref, block_component);
+
+        // Count the number of DoFs in each block
+        dofs_per_block = DoFTools::count_dofs_per_fe_block(dof_handler_ref, block_component);
+
+        // Setup the sparsity pattern and tangent matrix
+        all_locally_owned_dofs = DoFTools::locally_owned_dofs_per_subdomain (dof_handler_ref);
+        std::vector<IndexSet> all_locally_relevant_dofs
+        = DoFTools::locally_relevant_dofs_per_subdomain (dof_handler_ref);
+
+        locally_owned_dofs.clear();
+        locally_owned_partitioning.clear();
+        Assert(all_locally_owned_dofs.size() > this_mpi_process, ExcInternalError());
+        locally_owned_dofs = all_locally_owned_dofs[this_mpi_process];
+
+        locally_relevant_dofs.clear();
+        locally_relevant_partitioning.clear();
+        Assert(all_locally_relevant_dofs.size() > this_mpi_process, ExcInternalError());
+        locally_relevant_dofs = all_locally_relevant_dofs[this_mpi_process];
+
+        locally_owned_partitioning.reserve(n_blocks);
+        locally_relevant_partitioning.reserve(n_blocks);
+
+        for (unsigned int b=0; b<n_blocks; ++b)
+          {
+            const types::global_dof_index idx_begin
+            = std::accumulate(dofs_per_block.begin(),
+                              std::next(dofs_per_block.begin(),b), 0);
+            const types::global_dof_index idx_end
+            = std::accumulate(dofs_per_block.begin(),
+                              std::next(dofs_per_block.begin(),b+1), 0);
+            locally_owned_partitioning.push_back(locally_owned_dofs.get_view(idx_begin, idx_end));
+            locally_relevant_partitioning.push_back(locally_relevant_dofs.get_view(idx_begin, idx_end));
+          }
+
+        //Print information on screen
+        pcout  << "\nTriangulation:\n"
+               << "  Number of active cells: "
+               << triangulation.n_active_cells()
+               << " (by partition:";
+        for (unsigned int p=0; p<n_mpi_processes; ++p)
+          pcout  << (p==0 ? ' ' : '+')
+                 << (GridTools::count_cells_with_subdomain_association (triangulation,p));
+        pcout << ")"
+              << std::endl;
+        pcout << "  Number of degrees of freedom: "
+              << dof_handler_ref.n_dofs()
+              << " (by partition:";
+        for (unsigned int p=0; p<n_mpi_processes; ++p)
+          pcout  << (p==0 ? ' ' : '+')
+                 << (DoFTools::count_dofs_with_subdomain_association (dof_handler_ref,p));
+        pcout << ")"
+              << std::endl;
+        pcout   << "  Number of degrees of freedom per block: "
+            << "[n_u, n_p_fluid] = ["
+            << dofs_per_block[u_block]
+            << ", "
+            << dofs_per_block[p_fluid_block]
+            << "]"
+            << std::endl;
+
+        //Print information to file
+        outfile  << "\nTriangulation:\n"
+                 <<  "  Number of active cells: "
+                << triangulation.n_active_cells()
+                << " (by partition:";
+        for (unsigned int p=0; p<n_mpi_processes; ++p)
+          outfile << (p==0 ? ' ' : '+')
+                  << (GridTools::count_cells_with_subdomain_association (triangulation,p));
+        outfile << ")"
+                << std::endl;
+        outfile << "  Number of degrees of freedom: "
+                << dof_handler_ref.n_dofs()
+                << " (by partition:";
+        for (unsigned int p=0; p<n_mpi_processes; ++p)
+          outfile  << (p==0 ? ' ' : '+')
+                   << (DoFTools::count_dofs_with_subdomain_association (dof_handler_ref,p));
+        outfile << ")"
+                << std::endl;
+        outfile << "  Number of degrees of freedom per block: "
+            << "[n_u, n_p_fluid] = ["
+            << dofs_per_block[u_block]
+            << ", "
+            << dofs_per_block[p_fluid_block]
+            << "]"
+            << std::endl;
+
+        // We optimise the sparsity pattern to reflect this structure and prevent
+        // unnecessary data creation for the right-diagonal block components.
+        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)
+
+            //Identify "zero" matrix components of FE-system (The two components do not couple)
+            if (((ii == p_fluid_component) && (jj < p_fluid_component))
+                || ((ii < p_fluid_component) && (jj == p_fluid_component)) )
+              coupling[ii][jj] = DoFTools::none;
+
+            //The rest of components always couple
+            else
+              coupling[ii][jj] = DoFTools::always;
+
+        TrilinosWrappers::BlockSparsityPattern bsp (locally_owned_partitioning,
+                                                    mpi_communicator);
+
+        DoFTools::make_sparsity_pattern (dof_handler_ref, bsp, constraints,
+                                         false, this_mpi_process);
+        bsp.compress();
+
+        //Reinitialize the (sparse) tangent matrix with the given sparsity pattern.
+        tangent_matrix.reinit (bsp);
+
+        //Initialize the right hand side and solution vectors with number of DoFs
+        system_rhs.reinit(locally_owned_partitioning, mpi_communicator);
+        solution_n.reinit(locally_owned_partitioning, mpi_communicator);
+        solution_delta_OUT.reinit(locally_owned_partitioning, mpi_communicator);
+
+        // Non-block system
+        TrilinosWrappers::SparsityPattern sp (locally_owned_dofs,
+                                              mpi_communicator);
+        DoFTools::make_sparsity_pattern (dof_handler_ref, sp, constraints,
+                                         false, this_mpi_process);
+        sp.compress();
+        tangent_matrix_nb.reinit (sp);
+        system_rhs_nb.reinit(locally_owned_dofs, mpi_communicator);
+
+        //Set up the quadrature point history
+        setup_qph();
+
+        timerconsole.leave_subsection();
+        timerfile.leave_subsection();
+    }
+
+    //Component extractors: used to extract sub-blocks from the global matrix
+    //Description of which local element DOFs are attached to which block component
+    template <int dim>
+    void Solid<dim>::determine_component_extractors()
+    {
+        element_indices_u.clear();
+        element_indices_p_fluid.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_block)
+              element_indices_u.push_back(k);
+            else if (k_group == p_fluid_block)
+              element_indices_p_fluid.push_back(k);
+            else
+              {
+                Assert(k_group <= p_fluid_block, ExcInternalError());
+              }
+          }
+    }
+
+    //Set-up quadrature point history (QPH) data objects
+    template <int dim>
+    void Solid<dim>::setup_qph()
+    {
+        pcout     << "\nSetting up quadrature point data..." << std::endl;
+        outfile   << "\nSetting up quadrature point data..." << std::endl;
+
+        //Create QPH data objects.
+        quadrature_point_history.initialize(triangulation.begin_active(),
+                                            triangulation.end(), n_q_points);
+
+        //Setup the initial quadrature point data using the info stored in parameters
+        FilteredIterator<typename DoFHandler<dim>::active_cell_iterator>
+        cell (IteratorFilters::LocallyOwnedCell(),
+              dof_handler_ref.begin_active()),
+        endc (IteratorFilters::LocallyOwnedCell(),
+              dof_handler_ref.end());
+        for (; cell!=endc; ++cell)
+          {
+            Assert(cell->is_locally_owned(), ExcInternalError());
+            Assert(cell->subdomain_id() == this_mpi_process, ExcInternalError());
+
+            const std::vector<std::shared_ptr<PointHistory<dim, ADNumberType> > >
+                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, time);
+          }
+    }
+
+    //Solve the non-linear system using a Newton-Raphson scheme
+    template <int dim>
+    void Solid<dim>::solve_nonlinear_timestep(TrilinosWrappers::MPI::BlockVector &solution_delta_OUT)
+    {
+        //Print the load step
+        pcout  << std::endl
+               << "\nTimestep "
+               << time.get_timestep()
+               << " @ "
+               << time.get_current()
+               << "s"
+               << std::endl;
+        outfile  << std::endl
+                 << "\nTimestep "
+                 << time.get_timestep()
+                 << " @ "
+                 << time.get_current()
+                 << "s"
+                 << std::endl;
+
+        //Declare newton_update vector (solution of a Newton iteration),
+        //which must have as many positions as global DoFs.
+        TrilinosWrappers::MPI::BlockVector newton_update
+            (locally_owned_partitioning, mpi_communicator);
+
+        //Reset the error storage objects
+        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();
+
+        //Declare and initialize iterator for the Newton-Raphson algorithm steps
+        unsigned int newton_iteration = 0;
+
+        //Iterate until error is below tolerance or max number iterations are reached
+        while(newton_iteration < parameters.max_iterations_NR)
+          {
+            pcout     << " " << std::setw(2) << newton_iteration << " " << std::flush;
+            outfile   << " " << std::setw(2) << newton_iteration << " " << std::flush;
+
+            //Initialize global stiffness matrix and global force vector to zero
+            tangent_matrix = 0.0;
+            system_rhs = 0.0;
+
+            tangent_matrix_nb = 0.0;
+            system_rhs_nb = 0.0;
+
+            //Apply boundary conditions
+            make_constraints(newton_iteration);
+            assemble_system(solution_delta_OUT);
+
+            //Compute the rhs residual (error between external and internal forces in FE system)
+            get_error_residual(error_residual);
+
+            //error_residual in first iteration is stored to normalize posterior error measures
+            if (newton_iteration == 0)
+              error_residual_0 = error_residual;
+
+            // Determine the normalised residual error
+            error_residual_norm = error_residual;
+            error_residual_norm.normalise(error_residual_0);
+
+            //If both errors are below the tolerances, exit the loop.
+            // We need to check the residual vector directly for convergence
+            // in the load steps where no external forces or displacements are imposed.
+            if (  ((newton_iteration > 0)
+                && (error_update_norm.u <= parameters.tol_u)
+                && (error_update_norm.p_fluid <= parameters.tol_p_fluid)
+                && (error_residual_norm.u <= parameters.tol_f)
+                && (error_residual_norm.p_fluid  <= parameters.tol_f))
+                || ( (newton_iteration > 0)
+                    && system_rhs.l2_norm() <= parameters.tol_f) )
+              {
+                pcout   << "\n ***** CONVERGED! *****     "
+                        << system_rhs.l2_norm() << "      "
+                        << "  " << error_residual_norm.norm
+                        << "  " << error_residual_norm.u
+                        << "  " << error_residual_norm.p_fluid
+                        << "        " << error_update_norm.norm
+                        << "  " << error_update_norm.u
+                        << "  " << error_update_norm.p_fluid
+                        << "  " << std::endl;
+                outfile   << "\n ***** CONVERGED! *****     "
+                        << system_rhs.l2_norm() << "      "
+                        << "  " << error_residual_norm.norm
+                        << "  " << error_residual_norm.u
+                        << "  " << error_residual_norm.p_fluid
+                        << "        " << error_update_norm.norm
+                        << "  " << error_update_norm.u
+                        << "  " << error_update_norm.p_fluid
+                        << "  " << std::endl;
+                print_conv_footer();
+
+                break;
+              }
+
+            //Solve the linearized system
+            solve_linear_system(newton_update);
+            constraints.distribute(newton_update);
+
+            //Compute the displacement error
+            get_error_update(newton_update, error_update);
+
+            //error_update in first iteration is stored to normalize posterior error measures
+            if (newton_iteration == 0)
+              error_update_0 = error_update;
+
+            // Determine the normalised Newton update error
+            error_update_norm = error_update;
+            error_update_norm.normalise(error_update_0);
+
+            // Determine the normalised residual error
+            error_residual_norm = error_residual;
+            error_residual_norm.normalise(error_residual_0);
+
+            //Print error values
+            pcout    << " |   " << std::fixed << std::setprecision(3)
+            << std::setw(7) << std::scientific
+            << system_rhs.l2_norm()
+            << "        " << error_residual_norm.norm
+            << "  " << error_residual_norm.u
+            << "  " << error_residual_norm.p_fluid
+            << "        " << error_update_norm.norm
+            << "  " << error_update_norm.u
+            << "  " << error_update_norm.p_fluid
+            << "  " << std::endl;
+
+            outfile  << " |   " << std::fixed << std::setprecision(3)
+            << std::setw(7) << std::scientific
+            << system_rhs.l2_norm()
+            << "        " << error_residual_norm.norm
+            << "  " << error_residual_norm.u
+            << "  " << error_residual_norm.p_fluid
+            << "        " << error_update_norm.norm
+            << "  " << error_update_norm.u
+            << "  " << error_update_norm.p_fluid
+            << "  " << std::endl;
+
+            // Update
+            solution_delta_OUT += newton_update;
+            newton_update = 0.0;
+            newton_iteration++;
+          }
+
+        //If maximum allowed number of iterations for Newton algorithm are reached, print non-convergence message and abort program
+        AssertThrow (newton_iteration < parameters.max_iterations_NR, ExcMessage("No convergence in nonlinear solver!"));
+    }
+
+    //Prints the header for convergence info on console
+    template <int dim>
+    void Solid<dim>::print_conv_header()
+    {
+        static const unsigned int l_width = 120;
+
+        for (unsigned int i = 0; i < l_width; ++i)
+          {
+            pcout     << "_";
+            outfile   << "_";
+          }
+
+        pcout     << std::endl;
+        outfile   << std::endl;
+
+        pcout   << "\n       SOLVER STEP      |    SYS_RES         "
+                << "RES_NORM     RES_U      RES_P           "
+                << "NU_NORM     NU_U       NU_P " << std::endl;
+        outfile << "\n       SOLVER STEP      |    SYS_RES         "
+                << "RES_NORM     RES_U      RES_P           "
+                << "NU_NORM     NU_U       NU_P " << std::endl;
+
+        for (unsigned int i = 0; i < l_width; ++i)
+          {
+            pcout     << "_";
+            outfile   << "_";
+          }
+        pcout     << std::endl << std::endl;
+        outfile   << std::endl << std::endl;
+    }
+
+    //Prints the footer for convergence info on console
+    template <int dim>
+    void Solid<dim>::print_conv_footer()
+    {
+        static const unsigned int l_width = 120;
+
+        for (unsigned int i = 0; i < l_width; ++i)
+          {
+            pcout     << "_";
+            outfile   << "_";
+          }
+        pcout     << std::endl << std::endl;
+        outfile   << std::endl << std::endl;
+
+        pcout << "Relative errors:" << std::endl
+              << "Displacement:  "
+              << error_update.u / error_update_0.u << std::endl
+              << "Force (displ): "
+              << error_residual.u / error_residual_0.u << std::endl
+              << "Pore pressure: "
+              << error_update.p_fluid / error_update_0.p_fluid << std::endl
+              << "Force (pore):  "
+              << error_residual.p_fluid / error_residual_0.p_fluid << std::endl;
+        outfile << "Relative errors:" << std::endl
+                << "Displacement:  "
+                << error_update.u / error_update_0.u << std::endl
+                << "Force (displ): "
+                << error_residual.u / error_residual_0.u << std::endl
+                << "Pore pressure: "
+                << error_update.p_fluid / error_update_0.p_fluid << std::endl
+                << "Force (pore):  "
+                << error_residual.p_fluid / error_residual_0.p_fluid << std::endl;
+    }
+
+    //Determine the true residual error for the problem
+    template <int dim>
+    void Solid<dim>::get_error_residual(Errors &error_residual_OUT)
+    {
+        TrilinosWrappers::MPI::BlockVector error_res(system_rhs);
+        constraints.set_zero(error_res);
+
+        error_residual_OUT.norm = error_res.l2_norm();
+        error_residual_OUT.u = error_res.block(u_block).l2_norm();
+        error_residual_OUT.p_fluid = error_res.block(p_fluid_block).l2_norm();
+    }
+
+    //Determine the true Newton update error for the problem
+    template <int dim>
+    void Solid<dim>::get_error_update
+               (const TrilinosWrappers::MPI::BlockVector &newton_update_IN,
+                Errors                                   &error_update_OUT)
+    {
+        TrilinosWrappers::MPI::BlockVector error_ud(newton_update_IN);
+        constraints.set_zero(error_ud);
+
+        error_update_OUT.norm = error_ud.l2_norm();
+        error_update_OUT.u = error_ud.block(u_block).l2_norm();
+        error_update_OUT.p_fluid = error_ud.block(p_fluid_block).l2_norm();
+    }
+
+    //Compute the total solution, which is valid at any Newton step. This is required as, to reduce
+    //computational error, the total solution is only updated at the end of the timestep.
+    template <int dim>
+    TrilinosWrappers::MPI::BlockVector
+    Solid<dim>::get_total_solution(const TrilinosWrappers::MPI::BlockVector &solution_delta_IN) const
+    {
+        // Cell interpolation -> Ghosted vector
+        TrilinosWrappers::MPI::BlockVector
+             solution_total (locally_owned_partitioning,
+                             locally_relevant_partitioning,
+                             mpi_communicator,
+                             /*vector_writable = */ false);
+        TrilinosWrappers::MPI::BlockVector tmp (solution_total);
+        solution_total = solution_n;
+        tmp = solution_delta_IN;
+        solution_total += tmp;
+        return solution_total;
+    }
+
+    //Compute elemental stiffness tensor and right-hand side force vector, and assemble into global ones
+    template <int dim>
+    void Solid<dim>::assemble_system( const TrilinosWrappers::MPI::BlockVector &solution_delta )
+    {
+        timerconsole.enter_subsection("Assemble system");
+        timerfile.enter_subsection("Assemble system");
+        pcout     << " ASM_SYS " << std::flush;
+        outfile   << " ASM_SYS " << std::flush;
+
+        const TrilinosWrappers::MPI::BlockVector solution_total(get_total_solution(solution_delta));
+
+        //Info given to FEValues and FEFaceValues constructors, to indicate which data will be needed at each element.
+        const UpdateFlags uf_cell(update_values |
+                                  update_gradients |
+                                  update_JxW_values);
+        const UpdateFlags uf_face(update_values |
+                                  update_gradients |
+                                  update_normal_vectors |
+                                  update_quadrature_points |
+                                  update_JxW_values );
+
+        //Setup a copy of the data structures required for the process and pass them, along with the
+        //memory addresses of the assembly functions to the WorkStream object for processing
+        PerTaskData_ASM per_task_data(dofs_per_cell);
+        ScratchData_ASM<ADNumberType> scratch_data(fe, qf_cell, uf_cell,
+                                                   qf_face, uf_face,
+                                                   solution_total);
+
+        FilteredIterator<typename DoFHandler<dim>::active_cell_iterator>
+        cell (IteratorFilters::LocallyOwnedCell(),
+              dof_handler_ref.begin_active()),
+        endc (IteratorFilters::LocallyOwnedCell(),
+              dof_handler_ref.end());
+        for (; cell != endc; ++cell)
+          {
+            Assert(cell->is_locally_owned(), ExcInternalError());
+            Assert(cell->subdomain_id() == this_mpi_process, ExcInternalError());
+
+            assemble_system_one_cell(cell, scratch_data, per_task_data);
+            copy_local_to_global_system(per_task_data);
+          }
+        tangent_matrix.compress(VectorOperation::add);
+        system_rhs.compress(VectorOperation::add);
+
+        tangent_matrix_nb.compress(VectorOperation::add);
+        system_rhs_nb.compress(VectorOperation::add);
+
+        timerconsole.leave_subsection();
+        timerfile.leave_subsection();
+    }
+
+    //Add the local elemental contribution to the global stiffness tensor
+    // We do it twice, for the block and the non-block systems
+    template <int dim>
+    void Solid<dim>::copy_local_to_global_system (const PerTaskData_ASM &data)
+    {
+        constraints.distribute_local_to_global(data.cell_matrix,
+            data.cell_rhs,
+            data.local_dof_indices,
+            tangent_matrix,
+            system_rhs);
+
+        constraints.distribute_local_to_global(data.cell_matrix,
+            data.cell_rhs,
+            data.local_dof_indices,
+            tangent_matrix_nb,
+            system_rhs_nb);
+    }
+
+    //Compute stiffness matrix and corresponding rhs for one element
+    template <int dim>
+    void Solid<dim>::assemble_system_one_cell
+             (const typename DoFHandler<dim>::active_cell_iterator &cell,
+              ScratchData_ASM<ADNumberType>                        &scratch,
+              PerTaskData_ASM                                      &data) const
+    {
+        Assert(cell->is_locally_owned(), ExcInternalError());
+
+        data.reset();
+        scratch.reset();
+        scratch.fe_values_ref.reinit(cell);
+        cell->get_dof_indices(data.local_dof_indices);
+
+        // Setup automatic differentiation
+        for (unsigned int k = 0; k < dofs_per_cell; ++k)
+          {
+            // Initialise the dofs for the cell using the current solution.
+            scratch.local_dof_values[k] = scratch.solution_total[data.local_dof_indices[k]];
+            // Mark this cell DoF as an independent variable
+            scratch.local_dof_values[k].diff(k, dofs_per_cell);
+          }
+
+        // Update the quadrature point solution
+        // Compute the values and gradients of the solution in terms of the AD variables
+        for (unsigned int q = 0; q < n_q_points; ++q)
+          {
+            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_block)
+                  {
+                    const Tensor<2, dim> Grad_Nx_u =
+                           scratch.fe_values_ref[u_fe].gradient(k, q);
+                    for (unsigned int dd = 0; dd < dim; ++dd)
+                      {
+                        for (unsigned int ee = 0; ee < dim; ++ee)
+                          {
+                            scratch.solution_grads_u_total[q][dd][ee]
+                             += scratch.local_dof_values[k] * Grad_Nx_u[dd][ee];
+                          }
+                      }
+                  }
+                else if  (k_group == p_fluid_block)
+                  {
+                    const double Nx_p = scratch.fe_values_ref[p_fluid_fe].value(k, q);
+                    const Tensor<1, dim> Grad_Nx_p =
+                              scratch.fe_values_ref[p_fluid_fe].gradient(k, q);
+
+                    scratch.solution_values_p_fluid_total[q]
+                             += scratch.local_dof_values[k] * Nx_p;
+                    for (unsigned int dd = 0; dd < dim; ++dd)
+                      {
+                        scratch.solution_grads_p_fluid_total[q][dd]
+                            += scratch.local_dof_values[k] * Grad_Nx_p[dd];
+                      }
+                  }
+                else
+                  Assert(k_group <= p_fluid_block, ExcInternalError());
+              }
+          }
+
+        //Set up pointer "lgph" to the PointHistory object of this element
+        const std::vector<std::shared_ptr<const PointHistory<dim, ADNumberType> > >
+            lqph = quadrature_point_history.get_data(cell);
+        Assert(lqph.size() == n_q_points, ExcInternalError());
+
+
+        //Precalculate the element shape function values and gradients
+        for (unsigned int q_point = 0; q_point < n_q_points; ++q_point)
+          {
+            Tensor<2, dim, ADNumberType> F_AD = scratch.solution_grads_u_total[q_point];
+            F_AD += Tensor<2, dim, double>(Physics::Elasticity::StandardTensors<dim>::I);
+            Assert(determinant(F_AD) > 0, ExcMessage("Invalid deformation map"));
+            const Tensor<2, dim, ADNumberType> F_inv_AD = invert(F_AD);
+
+            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_block)
+                  {
+                    scratch.Nx[q_point][i] =
+                        scratch.fe_values_ref[u_fe].value(i, q_point);
+                    scratch.grad_Nx[q_point][i] =
+                        scratch.fe_values_ref[u_fe].gradient(i, q_point)*F_inv_AD;
+                    scratch.symm_grad_Nx[q_point][i] =
+                        symmetrize(scratch.grad_Nx[q_point][i]);
+                  }
+                else if  (i_group == p_fluid_block)
+                  {
+                    scratch.Nx_p_fluid[q_point][i] =
+                        scratch.fe_values_ref[p_fluid_fe].value(i, q_point);
+                    scratch.grad_Nx_p_fluid[q_point][i] =
+                        scratch.fe_values_ref[p_fluid_fe].gradient(i, q_point)*F_inv_AD;
+                  }
+                else
+                  Assert(i_group <= p_fluid_block, ExcInternalError());
+              }
+          }
+
+        //Assemble the stiffness matrix and rhs vector
+        std::vector<ADNumberType> residual_ad (dofs_per_cell, ADNumberType(0.0));
+        for (unsigned int q_point = 0; q_point < n_q_points; ++q_point)
+          {
+            Tensor<2, dim, ADNumberType> F_AD = scratch.solution_grads_u_total[q_point];
+            F_AD += Tensor<2, dim,double>(Physics::Elasticity::StandardTensors<dim>::I);
+            const ADNumberType det_F_AD = determinant(F_AD);
+
+            Assert(det_F_AD > 0, ExcInternalError());
+            const Tensor<2, dim, ADNumberType> F_inv_AD = invert(F_AD); //inverse of def. gradient tensor
+
+            const ADNumberType p_fluid = scratch.solution_values_p_fluid_total[q_point];
+
+            {
+              PointHistory<dim, ADNumberType> *lqph_q_point_nc =
+                 const_cast<PointHistory<dim, ADNumberType>*>(lqph[q_point].get());
+              lqph_q_point_nc->update_internal_equilibrium(F_AD);
+            }
+
+            //Get some info from constitutive model of solid
+            static const SymmetricTensor< 2, dim, double>
+                I (Physics::Elasticity::StandardTensors<dim>::I);
+            const SymmetricTensor<2, dim, ADNumberType>
+                tau_E = lqph[q_point]->get_tau_E(F_AD);
+            SymmetricTensor<2, dim, ADNumberType> tau_fluid_vol (I);
+            tau_fluid_vol *= -1.0 * p_fluid * det_F_AD;
+
+            //Get some info from constitutive model of fluid
+            const ADNumberType det_F_aux =  lqph[q_point]->get_converged_det_F();
+            const double det_F_converged = Tensor<0,dim,double>(det_F_aux); //Needs to be double, not AD number
+            const Tensor<1, dim, ADNumberType> overall_body_force
+                = lqph[q_point]->get_overall_body_force(F_AD, parameters);
+
+            // Define some aliases to make the assembly process easier to follow
+            const std::vector<Tensor<1,dim>> &Nu = scratch.Nx[q_point];
+            const std::vector<SymmetricTensor<2, dim, ADNumberType>>
+                &symm_grad_Nu = scratch.symm_grad_Nx[q_point];
+            const std::vector<double> &Np = scratch.Nx_p_fluid[q_point];
+            const std::vector<Tensor<1, dim, ADNumberType> > &grad_Np
+                = scratch.grad_Nx_p_fluid[q_point];
+            const Tensor<1, dim, ADNumberType> grad_p
+                = scratch.solution_grads_p_fluid_total[q_point]*F_inv_AD;
+            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_block)
+                  {
+                    residual_ad[i] += symm_grad_Nu[i] * ( tau_E + tau_fluid_vol ) * JxW;
+                    residual_ad[i] -= Nu[i] * overall_body_force * JxW;
+                  }
+                else if (i_group == p_fluid_block)
+                  {
+                    const Tensor<1, dim, ADNumberType> seepage_vel_current
+                        = lqph[q_point]->get_seepage_velocity_current(F_AD, grad_p);
+                    residual_ad[i] += Np[i] * (det_F_AD - det_F_converged) * JxW;
+                    residual_ad[i] -= time.get_delta_t() * grad_Np[i]
+                                      * seepage_vel_current * JxW;
+                  }
+                else
+                  Assert(i_group <= p_fluid_block, ExcInternalError());
+              }
+          }
+
+          // Assemble the Neumann contribution (external force contribution).
+          for (unsigned int face = 0; face < GeometryInfo<dim>::faces_per_cell; ++face) //Loop over faces in element
+            {
+              if (cell->face(face)->at_boundary() == true)
+                {
+                  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);
+                      const Point<dim>     &pt
+                          = scratch.fe_face_values_ref.quadrature_point(f_q_point);
+                      const Tensor<1, dim> traction
+                          = get_neumann_traction(cell->face(face)->boundary_id(), pt, N);
+                      const double flow
+                          = get_prescribed_fluid_flow(cell->face(face)->boundary_id(), pt);
+
+                      if ( (traction.norm() < 1e-12) && (std::abs(flow) < 1e-12) ) continue;
+
+                      const double JxW_f = scratch.fe_face_values_ref.JxW(f_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_block) && (traction.norm() > 1e-12))
+                          {
+                              const unsigned int component_i
+                                = fe.system_to_component_index(i).first;
+                              const double Nu_f
+                                = scratch.fe_face_values_ref.shape_value(i, f_q_point);
+                              residual_ad[i] -= (Nu_f * traction[component_i]) * JxW_f;
+                          }
+                          if ((i_group == p_fluid_block) && (std::abs(flow) > 1e-12))
+                          {
+                              const double Nu_p
+                                = scratch.fe_face_values_ref.shape_value(i, f_q_point);
+                              residual_ad[i] -= (Nu_p * flow) * JxW_f;
+                          }
+                        }
+                    }
+                }
+            }
+
+        // Linearise the residual
+        for (unsigned int i = 0; i < dofs_per_cell; ++i)
+          {
+            const ADNumberType &R_i = residual_ad[i];
+
+            data.cell_rhs(i) -= R_i.val();
+            for (unsigned int j=0; j<dofs_per_cell; ++j)
+              data.cell_matrix(i,j) += R_i.fastAccessDx(j);
+          }
+    }
+
+    //Store the converged values of the internal variables
+    template <int dim>
+    void Solid<dim>::update_end_timestep()
+    {
+          FilteredIterator<typename DoFHandler<dim>::active_cell_iterator>
+          cell (IteratorFilters::LocallyOwnedCell(),
+                dof_handler_ref.begin_active()),
+          endc (IteratorFilters::LocallyOwnedCell(),
+                dof_handler_ref.end());
+          for (; cell!=endc; ++cell)
+          {
+            Assert(cell->is_locally_owned(), ExcInternalError());
+            Assert(cell->subdomain_id() == this_mpi_process, ExcInternalError());
+
+            const std::vector<std::shared_ptr<PointHistory<dim, ADNumberType> > >
+                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]->update_end_timestep();
+          }
+    }
+
+
+     //Solve the linearized equations
+     template <int dim>
+     void Solid<dim>::solve_linear_system( TrilinosWrappers::MPI::BlockVector &newton_update_OUT)
+     {
+
+           timerconsole.enter_subsection("Linear solver");
+           timerfile.enter_subsection("Linear solver");
+           pcout     << " SLV " << std::flush;
+           outfile   << " SLV " << std::flush;
+
+           TrilinosWrappers::MPI::Vector newton_update_nb;
+           newton_update_nb.reinit(locally_owned_dofs, mpi_communicator);
+
+           SolverControl solver_control (tangent_matrix_nb.m(),
+                                         1.0e-6 * system_rhs_nb.l2_norm());
+           TrilinosWrappers::SolverDirect solver (solver_control);
+           solver.solve(tangent_matrix_nb, newton_update_nb, system_rhs_nb);
+
+           // Copy the non-block solution back to block system
+           for (unsigned int i=0; i<locally_owned_dofs.n_elements(); ++i)
+             {
+               const types::global_dof_index idx_i
+                              = locally_owned_dofs.nth_index_in_set(i);
+               newton_update_OUT(idx_i) = newton_update_nb(idx_i);
+             }
+           newton_update_OUT.compress(VectorOperation::insert);
+
+           timerconsole.leave_subsection();
+           timerfile.leave_subsection();
+     }
+
+    //Class to compute gradient of the pressure
+    template <int dim>
+    class GradientPostprocessor : public DataPostprocessorVector<dim>
+    {
+        public:
+          GradientPostprocessor (const unsigned int p_fluid_component)
+            :
+            DataPostprocessorVector<dim> ("grad_p",
+                                          update_gradients),
+            p_fluid_component (p_fluid_component)
+          {}
+
+          virtual ~GradientPostprocessor(){}
+
+          virtual void
+          evaluate_vector_field
+               (const DataPostprocessorInputs::Vector<dim> &input_data,
+                std::vector<Vector<double> >               &computed_quantities) const override
+          {
+            AssertDimension (input_data.solution_gradients.size(),
+                             computed_quantities.size());
+            for (unsigned int p=0; p<input_data.solution_gradients.size(); ++p)
+              {
+                AssertDimension (computed_quantities[p].size(), dim);
+                for (unsigned int d=0; d<dim; ++d)
+                  computed_quantities[p][d]
+                    = input_data.solution_gradients[p][p_fluid_component][d];
+              }
+          }
+
+        private:
+          const unsigned int  p_fluid_component;
+    };
+
+
+      //Print results to vtu file
+      template <int dim> void Solid<dim>::output_results_to_vtu
+                            (const unsigned int timestep,
+                             const double current_time,
+                             TrilinosWrappers::MPI::BlockVector solution_IN) const
+      {
+        TrilinosWrappers::MPI::BlockVector solution_total(locally_owned_partitioning,
+                                                          locally_relevant_partitioning,
+                                                          mpi_communicator,
+                                                          false);
+        solution_total = solution_IN;
+        Vector<double> material_id;
+        material_id.reinit(triangulation.n_active_cells());
+        std::vector<types::subdomain_id> partition_int(triangulation.n_active_cells());
+        GradientPostprocessor<dim> gradient_postprocessor(p_fluid_component);
+
+         //Declare local variables with number of stress components
+         //& assign value according to "dim" value
+         unsigned int num_comp_symm_tensor = 6;
+
+        //Declare local vectors to store values
+        // OUTPUT AVERAGED ON ELEMENTS -------------------------------------------
+        std::vector<Vector<double>>cauchy_stresses_total_elements
+                             (num_comp_symm_tensor,
+                              Vector<double> (triangulation.n_active_cells()));
+        std::vector<Vector<double>>cauchy_stresses_E_elements
+                             (num_comp_symm_tensor,
+                              Vector<double> (triangulation.n_active_cells()));
+        std::vector<Vector<double>>stretches_elements
+                             (dim,
+                              Vector<double> (triangulation.n_active_cells()));
+        std::vector<Vector<double>>seepage_velocity_elements
+                              (dim,
+                               Vector<double> (triangulation.n_active_cells()));
+        Vector<double> porous_dissipation_elements
+                              (triangulation.n_active_cells());
+        Vector<double> viscous_dissipation_elements
+                              (triangulation.n_active_cells());
+        Vector<double> solid_vol_fraction_elements
+                              (triangulation.n_active_cells());
+
+        // OUTPUT AVERAGED ON NODES ----------------------------------------------
+        // We need to create a new FE space with a single dof per node to avoid
+        // duplication of the output on nodes for our problem with dim+1 dofs.
+        FE_Q<dim> fe_vertex(1);
+        DoFHandler<dim> vertex_handler_ref(triangulation);
+        vertex_handler_ref.distribute_dofs(fe_vertex);
+        AssertThrow(vertex_handler_ref.n_dofs() == triangulation.n_vertices(),
+          ExcDimensionMismatch(vertex_handler_ref.n_dofs(),
+                               triangulation.n_vertices()));
+
+        Vector<double> counter_on_vertices_mpi
+                        (vertex_handler_ref.n_dofs());
+        Vector<double> sum_counter_on_vertices
+                        (vertex_handler_ref.n_dofs());
+
+        std::vector<Vector<double>>cauchy_stresses_total_vertex_mpi
+                                  (num_comp_symm_tensor,
+                                   Vector<double>(vertex_handler_ref.n_dofs()));
+        std::vector<Vector<double>>sum_cauchy_stresses_total_vertex
+                                  (num_comp_symm_tensor,
+                                   Vector<double>(vertex_handler_ref.n_dofs()));
+        std::vector<Vector<double>>cauchy_stresses_E_vertex_mpi
+                                  (num_comp_symm_tensor,
+                                   Vector<double>(vertex_handler_ref.n_dofs()));
+        std::vector<Vector<double>>sum_cauchy_stresses_E_vertex
+                                  (num_comp_symm_tensor,
+                                   Vector<double>(vertex_handler_ref.n_dofs()));
+        std::vector<Vector<double>>stretches_vertex_mpi
+                                  (dim,
+                                   Vector<double>(vertex_handler_ref.n_dofs()));
+        std::vector<Vector<double>>sum_stretches_vertex
+                                  (dim,
+                                   Vector<double>(vertex_handler_ref.n_dofs()));
+        Vector<double> porous_dissipation_vertex_mpi(vertex_handler_ref.n_dofs());
+        Vector<double> sum_porous_dissipation_vertex(vertex_handler_ref.n_dofs());
+        Vector<double> viscous_dissipation_vertex_mpi(vertex_handler_ref.n_dofs());
+        Vector<double> sum_viscous_dissipation_vertex(vertex_handler_ref.n_dofs());
+        Vector<double> solid_vol_fraction_vertex_mpi(vertex_handler_ref.n_dofs());
+        Vector<double> sum_solid_vol_fraction_vertex(vertex_handler_ref.n_dofs());
+
+        // We need to create a new FE space with a dim dof per node to
+        // be able to ouput data on nodes in vector form
+        FESystem<dim> fe_vertex_vec(FE_Q<dim>(1),dim);
+        DoFHandler<dim> vertex_vec_handler_ref(triangulation);
+        vertex_vec_handler_ref.distribute_dofs(fe_vertex_vec);
+        AssertThrow(vertex_vec_handler_ref.n_dofs() == (dim*triangulation.n_vertices()),
+          ExcDimensionMismatch(vertex_vec_handler_ref.n_dofs(),
+                               (dim*triangulation.n_vertices())));
+
+        Vector<double> seepage_velocity_vertex_vec_mpi(vertex_vec_handler_ref.n_dofs());
+        Vector<double> sum_seepage_velocity_vertex_vec(vertex_vec_handler_ref.n_dofs());
+        Vector<double> counter_on_vertices_vec_mpi(vertex_vec_handler_ref.n_dofs());
+        Vector<double> sum_counter_on_vertices_vec(vertex_vec_handler_ref.n_dofs());
+        // -----------------------------------------------------------------------
+
+        //Declare and initialize local unit vectors (to construct tensor basis)
+        std::vector<Tensor<1,dim>> basis_vectors (dim, Tensor<1,dim>() );
+        for (unsigned int i=0; i<dim; ++i)
+            basis_vectors[i][i] = 1;
+
+        //Declare an instance of the material class object
+        if (parameters.mat_type == "Neo-Hooke")
+            NeoHooke<dim,ADNumberType> material(parameters,time);
+        else if (parameters.mat_type == "Ogden")
+            Ogden<dim,ADNumberType> material(parameters,time);
+        else if (parameters.mat_type == "visco-Ogden")
+            visco_Ogden <dim,ADNumberType>material(parameters,time);
+        else
+            Assert (false, ExcMessage("Material type not implemented"));
+
+        //Define a local instance of FEValues to compute updated values required
+        //to calculate stresses
+        const UpdateFlags uf_cell(update_values | update_gradients |
+                                  update_JxW_values);
+        FEValues<dim> fe_values_ref (fe, qf_cell, uf_cell);
+
+        //Iterate through elements (cells) and Gauss Points
+        FilteredIterator<typename DoFHandler<dim>::active_cell_iterator>
+          cell(IteratorFilters::LocallyOwnedCell(),
+               dof_handler_ref.begin_active()),
+          endc(IteratorFilters::LocallyOwnedCell(),
+               dof_handler_ref.end()),
+          cell_v(IteratorFilters::LocallyOwnedCell(),
+                 vertex_handler_ref.begin_active()),
+          cell_v_vec(IteratorFilters::LocallyOwnedCell(),
+                     vertex_vec_handler_ref.begin_active());
+        //start cell loop
+        for (; cell!=endc; ++cell, ++cell_v, ++cell_v_vec)
+        {
+            Assert(cell->is_locally_owned(), ExcInternalError());
+            Assert(cell->subdomain_id() == this_mpi_process, ExcInternalError());
+
+            material_id(cell->active_cell_index())=
+              static_cast<int>(cell->material_id());
+
+            fe_values_ref.reinit(cell);
+
+            std::vector<Tensor<2,dim>> solution_grads_u(n_q_points);
+            fe_values_ref[u_fe].get_function_gradients(solution_total,
+                                                       solution_grads_u);
+
+            std::vector<double> solution_values_p_fluid_total(n_q_points);
+            fe_values_ref[p_fluid_fe].get_function_values(solution_total,
+                                                          solution_values_p_fluid_total);
+
+            std::vector<Tensor<1,dim>> solution_grads_p_fluid_AD (n_q_points);
+            fe_values_ref[p_fluid_fe].get_function_gradients(solution_total,
+                                                             solution_grads_p_fluid_AD);
+
+            //start gauss point loop
+            for (unsigned int q_point=0; q_point<n_q_points; ++q_point)
+            {
+                const Tensor<2,dim,ADNumberType>
+                  F_AD = Physics::Elasticity::Kinematics::F(solution_grads_u[q_point]);
+                ADNumberType det_F_AD = determinant(F_AD);
+                const double det_F = Tensor<0,dim,double>(det_F_AD);
+
+                const std::vector<std::shared_ptr<const PointHistory<dim,ADNumberType>>>
+                    lqph = quadrature_point_history.get_data(cell);
+                Assert(lqph.size() == n_q_points, ExcInternalError());
+
+                const double p_fluid = solution_values_p_fluid_total[q_point];
+
+                //Cauchy stress
+                static const SymmetricTensor<2,dim,double>
+                  I (Physics::Elasticity::StandardTensors<dim>::I);
+                SymmetricTensor<2,dim> sigma_E;
+                const SymmetricTensor<2,dim,ADNumberType> sigma_E_AD =
+                  lqph[q_point]->get_Cauchy_E(F_AD);
+
+                for (unsigned int i=0; i<dim; ++i)
+                    for (unsigned int j=0; j<dim; ++j)
+                       sigma_E[i][j] = Tensor<0,dim,double>(sigma_E_AD[i][j]);
+
+                SymmetricTensor<2,dim> sigma_fluid_vol (I);
+                sigma_fluid_vol *= -p_fluid;
+                const SymmetricTensor<2,dim> sigma = sigma_E + sigma_fluid_vol;
+
+                //Volumes
+                const double solid_vol_fraction = (parameters.solid_vol_frac)/det_F;
+
+                //Green-Lagrange strain
+                const Tensor<2,dim> E_strain = 0.5*(transpose(F_AD)*F_AD - I);
+
+                //Seepage velocity
+                const Tensor<2,dim,ADNumberType> F_inv = invert(F_AD);
+                const Tensor<1,dim,ADNumberType> grad_p_fluid_AD =
+                                          solution_grads_p_fluid_AD[q_point]*F_inv;
+                const Tensor<1,dim,ADNumberType> seepage_vel_AD =
+                 lqph[q_point]->get_seepage_velocity_current(F_AD, grad_p_fluid_AD);
+
+                //Dissipations
+                const double porous_dissipation =
+                  lqph[q_point]->get_porous_dissipation(F_AD, grad_p_fluid_AD);
+                const double viscous_dissipation =
+                  lqph[q_point]->get_viscous_dissipation();
+
+                // OUTPUT AVERAGED ON ELEMENTS -------------------------------------------
+                // Both average on elements and on nodes is NOT weighted with the
+                // integration point volume, i.e., we assume equal contribution of each
+                // integration point to the average. Ideally, it should be weighted,
+                // but I haven't invested time in getting it to work properly.
+                if (parameters.outtype == "elements")
+                {
+                    for (unsigned int j=0; j<dim; ++j)
+                    {
+                        cauchy_stresses_total_elements[j](cell->active_cell_index())
+                          += ((sigma*basis_vectors[j])*basis_vectors[j])/n_q_points;
+                        cauchy_stresses_E_elements[j](cell->active_cell_index())
+                          += ((sigma_E*basis_vectors[j])*basis_vectors[j])/n_q_points;
+                        stretches_elements[j](cell->active_cell_index())
+                          += std::sqrt(1.0+2.0*Tensor<0,dim,double>(E_strain[j][j]))
+                             /n_q_points;
+                        seepage_velocity_elements[j](cell->active_cell_index())
+                          +=  Tensor<0,dim,double>(seepage_vel_AD[j])/n_q_points;
+                    }
+
+                    porous_dissipation_elements(cell->active_cell_index())
+                      +=  porous_dissipation/n_q_points;
+                    viscous_dissipation_elements(cell->active_cell_index())
+                      +=  viscous_dissipation/n_q_points;
+                    solid_vol_fraction_elements(cell->active_cell_index())
+                      +=  solid_vol_fraction/n_q_points;
+
+                    cauchy_stresses_total_elements[3](cell->active_cell_index())
+                      += ((sigma*basis_vectors[0])*basis_vectors[1])/n_q_points; //sig_xy
+                    cauchy_stresses_total_elements[4](cell->active_cell_index())
+                      += ((sigma*basis_vectors[0])*basis_vectors[2])/n_q_points;//sig_xz
+                    cauchy_stresses_total_elements[5](cell->active_cell_index())
+                      += ((sigma*basis_vectors[1])*basis_vectors[2])/n_q_points;//sig_yz
+
+                    cauchy_stresses_E_elements[3](cell->active_cell_index())
+                      += ((sigma_E*basis_vectors[0])* basis_vectors[1])/n_q_points; //sig_xy
+                    cauchy_stresses_E_elements[4](cell->active_cell_index())
+                      += ((sigma_E*basis_vectors[0])* basis_vectors[2])/n_q_points;//sig_xz
+                    cauchy_stresses_E_elements[5](cell->active_cell_index())
+                      += ((sigma_E*basis_vectors[1])* basis_vectors[2])/n_q_points;//sig_yz
+
+                }
+                // OUTPUT AVERAGED ON NODES -------------------------------------------
+                else if (parameters.outtype == "nodes")
+                {
+                  for (unsigned int v=0; v<(GeometryInfo<dim>::vertices_per_cell); ++v)
+                  {
+                      types::global_dof_index local_vertex_indices =
+                                                    cell_v->vertex_dof_index(v, 0);
+                      counter_on_vertices_mpi(local_vertex_indices) += 1;
+                      for (unsigned int k=0; k<dim; ++k)
+                      {
+                          cauchy_stresses_total_vertex_mpi[k](local_vertex_indices)
+                            += (sigma*basis_vectors[k])*basis_vectors[k];
+                          cauchy_stresses_E_vertex_mpi[k](local_vertex_indices)
+                            += (sigma_E*basis_vectors[k])*basis_vectors[k];
+                          stretches_vertex_mpi[k](local_vertex_indices)
+                            += std::sqrt(1.0+2.0*Tensor<0,dim,double>(E_strain[k][k]));
+
+                          types::global_dof_index local_vertex_vec_indices =
+                                                cell_v_vec->vertex_dof_index(v, k);
+                          counter_on_vertices_vec_mpi(local_vertex_vec_indices) += 1;
+                          seepage_velocity_vertex_vec_mpi(local_vertex_vec_indices)
+                            += Tensor<0,dim,double>(seepage_vel_AD[k]);
+                      }
+
+                      porous_dissipation_vertex_mpi(local_vertex_indices)
+                        += porous_dissipation;
+                      viscous_dissipation_vertex_mpi(local_vertex_indices)
+                        += viscous_dissipation;
+                      solid_vol_fraction_vertex_mpi(local_vertex_indices)
+                        += solid_vol_fraction;
+
+                      cauchy_stresses_total_vertex_mpi[3](local_vertex_indices)
+                        += (sigma*basis_vectors[0])*basis_vectors[1]; //sig_xy
+                      cauchy_stresses_total_vertex_mpi[4](local_vertex_indices)
+                        += (sigma*basis_vectors[0])*basis_vectors[2];//sig_xz
+                      cauchy_stresses_total_vertex_mpi[5](local_vertex_indices)
+                        += (sigma*basis_vectors[1])*basis_vectors[2]; //sig_yz
+
+                      cauchy_stresses_E_vertex_mpi[3](local_vertex_indices)
+                        += (sigma_E*basis_vectors[0])*basis_vectors[1]; //sig_xy
+                      cauchy_stresses_E_vertex_mpi[4](local_vertex_indices)
+                        += (sigma_E*basis_vectors[0])*basis_vectors[2];//sig_xz
+                      cauchy_stresses_E_vertex_mpi[5](local_vertex_indices)
+                        += (sigma_E*basis_vectors[1])*basis_vectors[2]; //sig_yz
+                    }
+              }
+              //---------------------------------------------------------------
+            } //end gauss point loop
+        }//end cell loop
+
+        // Different nodes might have different amount of contributions, e.g.,
+        // corner nodes have less integration points contributing to the averaged.
+        // This is why we need a counter and divide at the end, outside the cell loop.
+        if (parameters.outtype == "nodes")
+        {
+          for (unsigned int d=0; d<(vertex_handler_ref.n_dofs()); ++d)
+          {
+            sum_counter_on_vertices[d] =
+              Utilities::MPI::sum(counter_on_vertices_mpi[d],
+                                  mpi_communicator);
+            sum_porous_dissipation_vertex[d] =
+              Utilities::MPI::sum(porous_dissipation_vertex_mpi[d],
+                                  mpi_communicator);
+            sum_viscous_dissipation_vertex[d] =
+              Utilities::MPI::sum(viscous_dissipation_vertex_mpi[d],
+                                  mpi_communicator);
+            sum_solid_vol_fraction_vertex[d] =
+              Utilities::MPI::sum(solid_vol_fraction_vertex_mpi[d],
+                                  mpi_communicator);
+
+            for (unsigned int k=0; k<num_comp_symm_tensor; ++k)
+            {
+              sum_cauchy_stresses_total_vertex[k][d] =
+                  Utilities::MPI::sum(cauchy_stresses_total_vertex_mpi[k][d],
+                                      mpi_communicator);
+              sum_cauchy_stresses_E_vertex[k][d] =
+                  Utilities::MPI::sum(cauchy_stresses_E_vertex_mpi[k][d],
+                                      mpi_communicator);
+            }
+            for (unsigned int k=0; k<dim; ++k)
+            {
+              sum_stretches_vertex[k][d] =
+                  Utilities::MPI::sum(stretches_vertex_mpi[k][d],
+                                      mpi_communicator);
+            }
+          }
+
+          for (unsigned int d=0; d<(vertex_vec_handler_ref.n_dofs()); ++d)
+          {
+              sum_counter_on_vertices_vec[d] =
+                  Utilities::MPI::sum(counter_on_vertices_vec_mpi[d],
+                                      mpi_communicator);
+              sum_seepage_velocity_vertex_vec[d] =
+                  Utilities::MPI::sum(seepage_velocity_vertex_vec_mpi[d],
+                                      mpi_communicator);
+          }
+
+          for (unsigned int d=0; d<(vertex_handler_ref.n_dofs()); ++d)
+          {
+            if (sum_counter_on_vertices[d]>0)
+            {
+              for (unsigned int i=0; i<num_comp_symm_tensor; ++i)
+              {
+                  sum_cauchy_stresses_total_vertex[i][d] /= sum_counter_on_vertices[d];
+                  sum_cauchy_stresses_E_vertex[i][d] /= sum_counter_on_vertices[d];
+              }
+              for (unsigned int i=0; i<dim; ++i)
+              {
+                  sum_stretches_vertex[i][d] /= sum_counter_on_vertices[d];
+              }
+              sum_porous_dissipation_vertex[d] /= sum_counter_on_vertices[d];
+              sum_viscous_dissipation_vertex[d] /= sum_counter_on_vertices[d];
+              sum_solid_vol_fraction_vertex[d] /= sum_counter_on_vertices[d];
+            }
+          }
+
+          for (unsigned int d=0; d<(vertex_vec_handler_ref.n_dofs()); ++d)
+          {
+            if (sum_counter_on_vertices_vec[d]>0)
+            {
+              sum_seepage_velocity_vertex_vec[d] /= sum_counter_on_vertices_vec[d];
+            }
+          }
+
+        }
+
+        // Add the results to the solution to create the output file for Paraview
+        DataOut<dim> data_out;
+        std::vector<DataComponentInterpretation::DataComponentInterpretation>
+          comp_type(dim,
+                    DataComponentInterpretation::component_is_part_of_vector);
+        comp_type.push_back(DataComponentInterpretation::component_is_scalar);
+
+        GridTools::get_subdomain_association(triangulation, partition_int);
+
+        std::vector<std::string> solution_name(dim, "displacement");
+        solution_name.push_back("pore_pressure");
+
+        data_out.attach_dof_handler(dof_handler_ref);
+        data_out.add_data_vector(solution_total,
+                                 solution_name,
+                                 DataOut<dim>::type_dof_data,
+                                 comp_type);
+
+        data_out.add_data_vector(solution_total,
+                                 gradient_postprocessor);
+
+        const Vector<double> partitioning(partition_int.begin(),
+                                          partition_int.end());
+
+        data_out.add_data_vector(partitioning, "partitioning");
+        data_out.add_data_vector(material_id, "material_id");
+
+        // Integration point results -----------------------------------------------------------
+        if (parameters.outtype == "elements")
+        {
+          data_out.add_data_vector(cauchy_stresses_total_elements[0], "cauchy_xx");
+          data_out.add_data_vector(cauchy_stresses_total_elements[1], "cauchy_yy");
+          data_out.add_data_vector(cauchy_stresses_total_elements[2], "cauchy_zz");
+          data_out.add_data_vector(cauchy_stresses_total_elements[3], "cauchy_xy");
+          data_out.add_data_vector(cauchy_stresses_total_elements[4], "cauchy_xz");
+          data_out.add_data_vector(cauchy_stresses_total_elements[5], "cauchy_yz");
+
+          data_out.add_data_vector(cauchy_stresses_E_elements[0], "cauchy_E_xx");
+          data_out.add_data_vector(cauchy_stresses_E_elements[1], "cauchy_E_yy");
+          data_out.add_data_vector(cauchy_stresses_E_elements[2], "cauchy_E_zz");
+          data_out.add_data_vector(cauchy_stresses_E_elements[3], "cauchy_E_xy");
+          data_out.add_data_vector(cauchy_stresses_E_elements[4], "cauchy_E_xz");
+          data_out.add_data_vector(cauchy_stresses_E_elements[5], "cauchy_E_yz");
+
+          data_out.add_data_vector(stretches_elements[0], "stretch_xx");
+          data_out.add_data_vector(stretches_elements[1], "stretch_yy");
+          data_out.add_data_vector(stretches_elements[2], "stretch_zz");
+
+          data_out.add_data_vector(seepage_velocity_elements[0], "seepage_vel_x");
+          data_out.add_data_vector(seepage_velocity_elements[1], "seepage_vel_y");
+          data_out.add_data_vector(seepage_velocity_elements[2], "seepage_vel_z");
+
+          data_out.add_data_vector(porous_dissipation_elements, "dissipation_porous");
+          data_out.add_data_vector(viscous_dissipation_elements, "dissipation_viscous");
+          data_out.add_data_vector(solid_vol_fraction_elements, "solid_vol_fraction");
+        }
+        else if  (parameters.outtype == "nodes")
+        {
+          data_out.add_data_vector(vertex_handler_ref,
+                                   sum_cauchy_stresses_total_vertex[0],
+                                   "cauchy_xx");
+          data_out.add_data_vector(vertex_handler_ref,
+                                   sum_cauchy_stresses_total_vertex[1],
+                                   "cauchy_yy");
+          data_out.add_data_vector(vertex_handler_ref,
+                                   sum_cauchy_stresses_total_vertex[2],
+                                   "cauchy_zz");
+          data_out.add_data_vector(vertex_handler_ref,
+                                   sum_cauchy_stresses_total_vertex[3],
+                                   "cauchy_xy");
+          data_out.add_data_vector(vertex_handler_ref,
+                                   sum_cauchy_stresses_total_vertex[4],
+                                   "cauchy_xz");
+          data_out.add_data_vector(vertex_handler_ref,
+                                   sum_cauchy_stresses_total_vertex[5],
+                                   "cauchy_yz");
+
+          data_out.add_data_vector(vertex_handler_ref,
+                                   sum_cauchy_stresses_E_vertex[0],
+                                   "cauchy_E_xx");
+          data_out.add_data_vector(vertex_handler_ref,
+                                   sum_cauchy_stresses_E_vertex[1],
+                                   "cauchy_E_yy");
+          data_out.add_data_vector(vertex_handler_ref,
+                                   sum_cauchy_stresses_E_vertex[2],
+                                   "cauchy_E_zz");
+          data_out.add_data_vector(vertex_handler_ref,
+                                   sum_cauchy_stresses_E_vertex[3],
+                                   "cauchy_E_xy");
+          data_out.add_data_vector(vertex_handler_ref,
+                                   sum_cauchy_stresses_E_vertex[4],
+                                   "cauchy_E_xz");
+          data_out.add_data_vector(vertex_handler_ref,
+                                   sum_cauchy_stresses_E_vertex[5],
+                                   "cauchy_E_yz");
+
+          data_out.add_data_vector(vertex_handler_ref,
+                                   sum_stretches_vertex[0],
+                                   "stretch_xx");
+          data_out.add_data_vector(vertex_handler_ref,
+                                   sum_stretches_vertex[1],
+                                   "stretch_yy");
+          data_out.add_data_vector(vertex_handler_ref,
+                                   sum_stretches_vertex[2],
+                                   "stretch_zz");
+
+          std::vector<DataComponentInterpretation::DataComponentInterpretation>
+           comp_type_vec(dim,
+                         DataComponentInterpretation::component_is_part_of_vector);
+          std::vector<std::string> solution_name_vec(dim,"seepage_velocity");
+
+          data_out.add_data_vector(vertex_vec_handler_ref,
+                                   sum_seepage_velocity_vertex_vec,
+                                   solution_name_vec,
+                                   comp_type_vec);
+
+          data_out.add_data_vector(vertex_handler_ref,
+                                   sum_porous_dissipation_vertex,
+                                   "dissipation_porous");
+          data_out.add_data_vector(vertex_handler_ref,
+                                   sum_viscous_dissipation_vertex,
+                                   "dissipation_viscous");
+          data_out.add_data_vector(vertex_handler_ref,
+                                   sum_solid_vol_fraction_vertex,
+                                   "solid_vol_fraction");
+        }
+      //---------------------------------------------------------------------
+
+        data_out.build_patches(degree_displ);
+
+        struct Filename
+        {
+          static std::string get_filename_vtu(unsigned int process,
+                                              unsigned int timestep,
+                                              const unsigned int n_digits = 5)
+          {
+            std::ostringstream filename_vtu;
+            filename_vtu
+            << "solution."
+            << Utilities::int_to_string(process, n_digits)
+            << "."
+            << Utilities::int_to_string(timestep, n_digits)
+            << ".vtu";
+            return filename_vtu.str();
+          }
+
+          static std::string get_filename_pvtu(unsigned int timestep,
+                                               const unsigned int n_digits = 5)
+          {
+            std::ostringstream filename_vtu;
+            filename_vtu
+            << "solution."
+            << Utilities::int_to_string(timestep, n_digits)
+            << ".pvtu";
+            return filename_vtu.str();
+          }
+
+          static std::string get_filename_pvd (void)
+          {
+            std::ostringstream filename_vtu;
+            filename_vtu
+            << "solution.pvd";
+            return filename_vtu.str();
+          }
+        };
+
+        const std::string filename_vtu = Filename::get_filename_vtu(this_mpi_process,
+                                                                    timestep);
+        std::ofstream output(filename_vtu.c_str());
+        data_out.write_vtu(output);
+
+        // We have a collection of files written in parallel
+        // This next set of steps should only be performed by master process
+        if (this_mpi_process == 0)
+        {
+          // List of all files written out at this timestep by all processors
+          std::vector<std::string> parallel_filenames_vtu;
+          for (unsigned int p=0; p<n_mpi_processes; ++p)
+          {
+            parallel_filenames_vtu.push_back(Filename::get_filename_vtu(p, timestep));
+          }
+
+          const std::string filename_pvtu(Filename::get_filename_pvtu(timestep));
+          std::ofstream pvtu_master(filename_pvtu.c_str());
+          data_out.write_pvtu_record(pvtu_master,
+                                     parallel_filenames_vtu);
+
+          // Time dependent data master file
+          static std::vector<std::pair<double,std::string>> time_and_name_history;
+          time_and_name_history.push_back(std::make_pair(current_time,
+                                                          filename_pvtu));
+          const std::string filename_pvd(Filename::get_filename_pvd());
+          std::ofstream pvd_output(filename_pvd.c_str());
+          DataOutBase::write_pvd_record(pvd_output, time_and_name_history);
+        }
+      }
+
+
+      //Print results to plotting file
+      template <int dim>
+      void Solid<dim>::output_results_to_plot(
+                                const unsigned int timestep,
+                                const double current_time,
+                                TrilinosWrappers::MPI::BlockVector solution_IN,
+                                std::vector<Point<dim> > &tracked_vertices_IN,
+                                std::ofstream &plotpointfile) const
+      {
+        TrilinosWrappers::MPI::BlockVector solution_total(locally_owned_partitioning,
+                                                          locally_relevant_partitioning,
+                                                          mpi_communicator,
+                                                          false);
+
+        (void) timestep;
+        solution_total = solution_IN;
+
+        //Variables needed to print the solution file for plotting
+        Point<dim> reaction_force;
+        Point<dim> reaction_force_pressure;
+        Point<dim> reaction_force_extra;
+        double total_fluid_flow = 0.0;
+        double total_porous_dissipation = 0.0;
+        double total_viscous_dissipation = 0.0;
+        double total_solid_vol = 0.0;
+        double total_vol_current = 0.0;
+        double total_vol_reference = 0.0;
+        std::vector<Point<dim+1>> solution_vertices(tracked_vertices_IN.size());
+
+        //Auxiliar variables needed for mpi processing
+        Tensor<1,dim> sum_reaction_mpi;
+        Tensor<1,dim> sum_reaction_pressure_mpi;
+        Tensor<1,dim> sum_reaction_extra_mpi;
+        sum_reaction_mpi = 0.0;
+        sum_reaction_pressure_mpi = 0.0;
+        sum_reaction_extra_mpi = 0.0;
+        double sum_total_flow_mpi = 0.0;
+        double sum_porous_dissipation_mpi = 0.0;
+        double sum_viscous_dissipation_mpi = 0.0;
+        double sum_solid_vol_mpi = 0.0;
+        double sum_vol_current_mpi = 0.0;
+        double sum_vol_reference_mpi = 0.0;
+
+        //Declare an instance of the material class object
+        if (parameters.mat_type == "Neo-Hooke")
+            NeoHooke<dim,ADNumberType> material(parameters,time);
+        else if (parameters.mat_type == "Ogden")
+            Ogden<dim,ADNumberType> material(parameters, time);
+        else if (parameters.mat_type == "visco-Ogden")
+            visco_Ogden <dim,ADNumberType>material(parameters,time);
+        else
+        Assert (false, ExcMessage("Material type not implemented"));
+
+        //Define a local instance of FEValues to compute updated values required
+        //to calculate stresses
+        const UpdateFlags uf_cell(update_values | update_gradients |
+                                  update_JxW_values);
+        FEValues<dim> fe_values_ref (fe, qf_cell, uf_cell);
+
+        //Iterate through elements (cells) and Gauss Points
+        FilteredIterator<typename DoFHandler<dim>::active_cell_iterator>
+          cell(IteratorFilters::LocallyOwnedCell(),
+               dof_handler_ref.begin_active()),
+          endc(IteratorFilters::LocallyOwnedCell(),
+               dof_handler_ref.end());
+        //start cell loop
+        for (; cell!=endc; ++cell)
+        {
+            Assert(cell->is_locally_owned(), ExcInternalError());
+            Assert(cell->subdomain_id() == this_mpi_process, ExcInternalError());
+
+            fe_values_ref.reinit(cell);
+
+            std::vector<Tensor<2,dim>> solution_grads_u(n_q_points);
+            fe_values_ref[u_fe].get_function_gradients(solution_total,
+                                                       solution_grads_u);
+
+            std::vector<double> solution_values_p_fluid_total(n_q_points);
+            fe_values_ref[p_fluid_fe].get_function_values(solution_total,
+                                                          solution_values_p_fluid_total);
+
+            std::vector<Tensor<1,dim >> solution_grads_p_fluid_AD(n_q_points);
+            fe_values_ref[p_fluid_fe].get_function_gradients(solution_total,
+                                                             solution_grads_p_fluid_AD);
+
+            //start gauss point loop
+            for (unsigned int q_point=0; q_point<n_q_points; ++q_point)
+            {
+                const Tensor<2,dim,ADNumberType>
+                  F_AD = Physics::Elasticity::Kinematics::F(solution_grads_u[q_point]);
+                ADNumberType det_F_AD = determinant(F_AD);
+                const double det_F = Tensor<0,dim,double>(det_F_AD);
+
+                const std::vector<std::shared_ptr<const PointHistory<dim,ADNumberType>>>
+                    lqph = quadrature_point_history.get_data(cell);
+                Assert(lqph.size() == n_q_points, ExcInternalError());
+
+                double JxW = fe_values_ref.JxW(q_point);
+
+                //Volumes
+                sum_vol_current_mpi  += det_F * JxW;
+                sum_vol_reference_mpi += JxW;
+                sum_solid_vol_mpi += parameters.solid_vol_frac * JxW * det_F;
+
+                //Seepage velocity
+                const Tensor<2,dim,ADNumberType> F_inv = invert(F_AD);
+                const Tensor<1,dim,ADNumberType>
+                  grad_p_fluid_AD =  solution_grads_p_fluid_AD[q_point]*F_inv;
+                const Tensor<1,dim,ADNumberType> seepage_vel_AD
+                = lqph[q_point]->get_seepage_velocity_current(F_AD, grad_p_fluid_AD);
+
+                //Dissipations
+                const double porous_dissipation =
+                  lqph[q_point]->get_porous_dissipation(F_AD, grad_p_fluid_AD);
+                sum_porous_dissipation_mpi += porous_dissipation * det_F * JxW;
+
+                const double viscous_dissipation = lqph[q_point]->get_viscous_dissipation();
+                sum_viscous_dissipation_mpi += viscous_dissipation * det_F * JxW;
+
+              //---------------------------------------------------------------
+            } //end gauss point loop
+
+            // Compute reaction force on load boundary & total fluid flow across
+            // drained boundary.
+            // Define a local instance of FEFaceValues to compute values required
+            // to calculate reaction force
+            const UpdateFlags uf_face( update_values | update_gradients |
+                                       update_normal_vectors | update_JxW_values );
+            FEFaceValues<dim> fe_face_values_ref(fe, qf_face, uf_face);
+
+            //start face loop
+            for (unsigned int face=0; face<GeometryInfo<dim>::faces_per_cell; ++face)
+            {
+                //Reaction force
+                if (cell->face(face)->at_boundary() == true &&
+                    cell->face(face)->boundary_id() == get_reaction_boundary_id_for_output() )
+                {
+                    fe_face_values_ref.reinit(cell, face);
+
+                    //Get displacement gradients for current face
+                    std::vector<Tensor<2,dim> > solution_grads_u_f(n_q_points_f);
+                    fe_face_values_ref[u_fe].get_function_gradients
+                                                         (solution_total,
+                                                          solution_grads_u_f);
+
+                    //Get pressure for current element
+                    std::vector< double > solution_values_p_fluid_total_f(n_q_points_f);
+                    fe_face_values_ref[p_fluid_fe].get_function_values
+                                               (solution_total,
+                                                solution_values_p_fluid_total_f);
+
+                    //start gauss points on faces loop
+                    for (unsigned int f_q_point=0; f_q_point<n_q_points_f; ++f_q_point)
+                    {
+                        const Tensor<1,dim> &N = fe_face_values_ref.normal_vector(f_q_point);
+                        const double JxW_f = fe_face_values_ref.JxW(f_q_point);
+
+                        //Compute deformation gradient from displacements gradient
+                        //(present configuration)
+                        const Tensor<2,dim,ADNumberType> F_AD =
+                          Physics::Elasticity::Kinematics::F(solution_grads_u_f[f_q_point]);
+
+                        const std::vector<std::shared_ptr<const PointHistory<dim,ADNumberType>>>
+                            lqph = quadrature_point_history.get_data(cell);
+                        Assert(lqph.size() == n_q_points, ExcInternalError());
+
+                        const double p_fluid = solution_values_p_fluid_total[f_q_point];
+
+                        //Cauchy stress
+                        static const SymmetricTensor<2,dim,double>
+                          I (Physics::Elasticity::StandardTensors<dim>::I);
+                        SymmetricTensor<2,dim> sigma_E;
+                        const SymmetricTensor<2,dim,ADNumberType> sigma_E_AD =
+                          lqph[f_q_point]->get_Cauchy_E(F_AD);
+
+                        for (unsigned int i=0; i<dim; ++i)
+                            for (unsigned int j=0; j<dim; ++j)
+                               sigma_E[i][j] = Tensor<0,dim,double>(sigma_E_AD[i][j]);
+
+                        SymmetricTensor<2,dim> sigma_fluid_vol(I);
+                        sigma_fluid_vol *= -1.0*p_fluid;
+                        const SymmetricTensor<2,dim> sigma = sigma_E+sigma_fluid_vol;
+                        sum_reaction_mpi += sigma * N * JxW_f;
+                        sum_reaction_pressure_mpi += sigma_fluid_vol * N * JxW_f;
+                        sum_reaction_extra_mpi += sigma_E * N * JxW_f;
+                    }//end gauss points on faces loop
+                }
+
+                //Fluid flow
+                if (cell->face(face)->at_boundary() == true &&
+                   (cell->face(face)->boundary_id() ==
+                      get_drained_boundary_id_for_output().first ||
+                    cell->face(face)->boundary_id() ==
+                      get_drained_boundary_id_for_output().second ) )
+                {
+                    fe_face_values_ref.reinit(cell, face);
+
+                    //Get displacement gradients for current face
+                    std::vector<Tensor<2,dim>> solution_grads_u_f(n_q_points_f);
+                    fe_face_values_ref[u_fe].get_function_gradients
+                                                            (solution_total,
+                                                             solution_grads_u_f);
+
+                    //Get pressure gradients for current face
+                    std::vector<Tensor<1,dim>> solution_grads_p_f(n_q_points_f);
+                    fe_face_values_ref[p_fluid_fe].get_function_gradients
+                                                             (solution_total,
+                                                              solution_grads_p_f);
+
+                    //start gauss points on faces loop
+                    for (unsigned int f_q_point=0; f_q_point<n_q_points_f; ++f_q_point)
+                    {
+                        const Tensor<1,dim> &N =
+                                  fe_face_values_ref.normal_vector(f_q_point);
+                        const double JxW_f = fe_face_values_ref.JxW(f_q_point);
+
+                        //Deformation gradient and inverse from displacements gradient
+                        //(present configuration)
+                        const Tensor<2,dim,ADNumberType> F_AD
+                            = Physics::Elasticity::Kinematics::F(solution_grads_u_f[f_q_point]);
+
+                        const Tensor<2,dim,ADNumberType> F_inv_AD = invert(F_AD);
+                        ADNumberType det_F_AD = determinant(F_AD);
+
+                        const std::vector<std::shared_ptr<const PointHistory<dim,ADNumberType>>>
+                            lqph = quadrature_point_history.get_data(cell);
+                        Assert(lqph.size() == n_q_points, ExcInternalError());
+
+                        //Seepage velocity
+                        Tensor<1,dim> seepage;
+                        double det_F = Tensor<0,dim,double>(det_F_AD);
+                        const Tensor<1,dim,ADNumberType> grad_p
+                                          = solution_grads_p_f[f_q_point]*F_inv_AD;
+                        const Tensor<1,dim,ADNumberType> seepage_AD
+                          = lqph[f_q_point]->get_seepage_velocity_current(F_AD, grad_p);
+
+                        for (unsigned int i=0; i<dim; ++i)
+                            seepage[i] = Tensor<0,dim,double>(seepage_AD[i]);
+
+                        sum_total_flow_mpi += (seepage/det_F) * N * JxW_f;
+                    }//end gauss points on faces loop
+                }
+            }//end face loop
+        }//end cell loop
+
+        //Sum the results from different MPI process and then add to the reaction_force vector
+        //In theory, the solution on each surface (each cell) only exists in one MPI process
+        //so, we add all MPI process, one will have the solution and the others will be zero
+        for (unsigned int d=0; d<dim; ++d)
+        {
+            reaction_force[d] = Utilities::MPI::sum(sum_reaction_mpi[d],
+                                                    mpi_communicator);
+            reaction_force_pressure[d] = Utilities::MPI::sum(sum_reaction_pressure_mpi[d],
+                                                             mpi_communicator);
+            reaction_force_extra[d] = Utilities::MPI::sum(sum_reaction_extra_mpi[d],
+                                                          mpi_communicator);
+        }
+
+        //Same for total fluid flow, and for porous and viscous dissipations
+        total_fluid_flow = Utilities::MPI::sum(sum_total_flow_mpi,
+                                               mpi_communicator);
+        total_porous_dissipation = Utilities::MPI::sum(sum_porous_dissipation_mpi,
+                                                       mpi_communicator);
+        total_viscous_dissipation = Utilities::MPI::sum(sum_viscous_dissipation_mpi,
+                                                        mpi_communicator);
+        total_solid_vol = Utilities::MPI::sum(sum_solid_vol_mpi,
+                                              mpi_communicator);
+        total_vol_current = Utilities::MPI::sum(sum_vol_current_mpi,
+                                                mpi_communicator);
+        total_vol_reference = Utilities::MPI::sum(sum_vol_reference_mpi,
+                                                  mpi_communicator);
+
+      //  Extract solution for tracked vectors
+      // Copying an MPI::BlockVector into MPI::Vector is not possible,
+      // so we copy each block of MPI::BlockVector into an MPI::Vector
+      // And then we copy the MPI::Vector into "normal" Vectors
+        TrilinosWrappers::MPI::Vector solution_vector_u_MPI(solution_total.block(u_block));
+        TrilinosWrappers::MPI::Vector solution_vector_p_MPI(solution_total.block(p_fluid_block));
+        Vector<double> solution_u_vector(solution_vector_u_MPI);
+        Vector<double> solution_p_vector(solution_vector_p_MPI);
+
+        if (this_mpi_process == 0)
+        {
+            //Append the pressure solution vector to the displacement solution vector,
+            //creating a single solution vector equivalent to the original BlockVector
+            //so FEFieldFunction will work with the dof_handler_ref.
+            Vector<double> solution_vector(solution_p_vector.size()
+                                           +solution_u_vector.size());
+
+            for (unsigned int d=0; d<(solution_u_vector.size()); ++d)
+                solution_vector[d] = solution_u_vector[d];
+
+            for (unsigned int d=0; d<(solution_p_vector.size()); ++d)
+                solution_vector[solution_u_vector.size()+d] = solution_p_vector[d];
+
+            Functions::FEFieldFunction<dim,Vector<double>>
+            find_solution(dof_handler_ref, solution_vector);
+
+            for (unsigned int p=0; p<tracked_vertices_IN.size(); ++p)
+            {
+                Vector<double> update(dim+1);
+                Point<dim> pt_ref;
+
+                pt_ref[0]= tracked_vertices_IN[p][0];
+                pt_ref[1]= tracked_vertices_IN[p][1];
+                pt_ref[2]= tracked_vertices_IN[p][2];
+
+               find_solution.vector_value(pt_ref, update);
+
+               for (unsigned int d=0; d<(dim+1); ++d)
+               {
+                   //For values close to zero, set to 0.0
+                   if (abs(update[d])<1.5*parameters.tol_u)
+                       update[d] = 0.0;
+                   solution_vertices[p][d] = update[d];
+               }
+            }
+      // Write the results to the plotting file.
+      // Add two blank lines between cycles in the cyclic loading examples so GNUPLOT can detect each cycle as a different block
+            if (( (parameters.geom_type == "Budday_cube_tension_compression_fully_fixed")||
+                  (parameters.geom_type == "Budday_cube_tension_compression")||
+                  (parameters.geom_type == "Budday_cube_shear_fully_fixed")                ) &&
+                ( (abs(current_time - parameters.end_time/3.)   <0.9*parameters.delta_t)||
+                  (abs(current_time - 2.*parameters.end_time/3.)<0.9*parameters.delta_t)   ) &&
+                  parameters.num_cycle_sets == 1 )
+            {
+                plotpointfile << std::endl<< std::endl;
+            }
+            if (( (parameters.geom_type == "Budday_cube_tension_compression_fully_fixed")||
+                  (parameters.geom_type == "Budday_cube_tension_compression")||
+                  (parameters.geom_type == "Budday_cube_shear_fully_fixed")             ) &&
+                ( (abs(current_time - parameters.end_time/9.)   <0.9*parameters.delta_t)||
+                  (abs(current_time - 2.*parameters.end_time/9.)<0.9*parameters.delta_t)||
+                  (abs(current_time - 3.*parameters.end_time/9.)<0.9*parameters.delta_t)||
+                  (abs(current_time - 5.*parameters.end_time/9.)<0.9*parameters.delta_t)||
+                  (abs(current_time - 7.*parameters.end_time/9.)<0.9*parameters.delta_t) ) &&
+                  parameters.num_cycle_sets == 2 )
+            {
+                plotpointfile << std::endl<< std::endl;
+            }
+
+            plotpointfile <<  std::setprecision(6) << std::scientific;
+            plotpointfile << std::setw(16) << current_time        << ","
+                          << std::setw(15) << total_vol_reference << ","
+                          << std::setw(15) << total_vol_current   << ","
+                          << std::setw(15) << total_solid_vol     << ",";
+
+            if (current_time == 0.0)
+            {
+                for (unsigned int p=0; p<tracked_vertices_IN.size(); ++p)
+                {
+                    for (unsigned int d=0; d<dim; ++d)
+                        plotpointfile << std::setw(15) << 0.0 << ",";
+
+                    plotpointfile << std::setw(15) << parameters.drained_pressure << ",";
+                }
+                for (unsigned int d=0; d<(3*dim+2); ++d)
+                    plotpointfile << std::setw(15) << 0.0 << ",";
+
+                plotpointfile << std::setw(15) << 0.0;
+            }
+            else
+            {
+                for (unsigned int p=0; p<tracked_vertices_IN.size(); ++p)
+                    for (unsigned int d=0; d<(dim+1); ++d)
+                        plotpointfile << std::setw(15) << solution_vertices[p][d]<< ",";
+
+                for (unsigned int d=0; d<dim; ++d)
+                    plotpointfile << std::setw(15) << reaction_force[d] << ",";
+
+                for (unsigned int d=0; d<dim; ++d)
+                    plotpointfile << std::setw(15) << reaction_force_pressure[d] << ",";
+
+                for (unsigned int d=0; d<dim; ++d)
+                    plotpointfile << std::setw(15) << reaction_force_extra[d] << ",";
+
+                plotpointfile << std::setw(15) << total_fluid_flow << ","
+                              << std::setw(15) << total_porous_dissipation<< ","
+                              << std::setw(15) << total_viscous_dissipation;
+            }
+            plotpointfile << std::endl;
+        }
+      }
+
+    //Header for console output file
+    template <int dim>
+    void Solid<dim>::print_console_file_header(std::ofstream &outputfile) const
+    {
+            outputfile << "/*-----------------------------------------------------------------------------------------";
+            outputfile << "\n\n  Poro-viscoelastic formulation to solve nonlinear solid mechanics problems using deal.ii";
+            outputfile << "\n\n  Problem setup by E Comellas and J-P Pelteret, University of Erlangen-Nuremberg, 2018";
+            outputfile << "\n\n/*-----------------------------------------------------------------------------------------";
+            outputfile << "\n\nCONSOLE OUTPUT: \n\n";
+    }
+
+    //Header for plotting output file
+    template <int dim>
+    void Solid<dim>::print_plot_file_header(std::vector<Point<dim> > &tracked_vertices,
+                                            std::ofstream &plotpointfile) const
+    {
+            plotpointfile << "#\n# *** Solution history for tracked vertices -- DOF: 0 = Ux,  1 = Uy,  2 = Uz,  3 = P ***"
+                          << std::endl;
+
+            for  (unsigned int p=0; p<tracked_vertices.size(); ++p)
+            {
+                plotpointfile << "#        Point " << p << " coordinates:  ";
+                for (unsigned int d=0; d<dim; ++d)
+                  {
+                    plotpointfile << tracked_vertices[p][d];
+                    if (!( (p == tracked_vertices.size()-1) && (d == dim-1) ))
+                        plotpointfile << ",        ";
+                  }
+                plotpointfile << std::endl;
+            }
+            plotpointfile << "#    The reaction force is the integral over the loaded surfaces in the "
+                          << "undeformed configuration of the Cauchy stress times the normal surface unit vector.\n"
+                          << "#    reac(p) corresponds to the volumetric part of the Cauchy stress due to the pore fluid pressure"
+                          << " and reac(E) corresponds to the extra part of the Cauchy stress due to the solid contribution."
+                          << std::endl
+                          << "#    The fluid flow is the integral over the drained surfaces in the "
+                          << "undeformed configuration of the seepage velocity times the normal surface unit vector."
+                          << std::endl
+                          << "# Column number:"
+                          << std::endl
+                          << "#";
+
+          unsigned int columns = 24;
+          for (unsigned int d=1; d<columns; ++d)
+              plotpointfile << std::setw(15)<< d <<",";
+
+            plotpointfile << std::setw(15)<< columns
+                          << std::endl
+                          << "#"
+                          << std::right << std::setw(16) << "Time,"
+                          << std::right << std::setw(16) << "ref vol,"
+                          << std::right << std::setw(16) << "def vol,"
+                          << std::right << std::setw(16) << "solid vol,";
+            for (unsigned int p=0; p<tracked_vertices.size(); ++p)
+                for (unsigned int d=0; d<(dim+1); ++d)
+                    plotpointfile << std::right<< std::setw(11)
+                                  <<"P" << p << "[" << d << "],";
+
+            for (unsigned int d=0; d<dim; ++d)
+                plotpointfile << std::right<< std::setw(13)
+                              << "reaction [" << d << "],";
+
+            for (unsigned int d=0; d<dim; ++d)
+                plotpointfile << std::right<< std::setw(13)
+                              << "reac(p) [" << d << "],";
+
+            for (unsigned int d=0; d<dim; ++d)
+                plotpointfile << std::right<< std::setw(13)
+                              << "reac(E) [" << d << "],";
+
+            plotpointfile << std::right<< std::setw(16)<< "fluid flow,"
+                          << std::right<< std::setw(16)<< "porous dissip,"
+                          << std::right<< std::setw(15)<< "viscous dissip"
+                          << std::endl;
+    }
+
+    //Footer for console output file
+    template <int dim>
+    void Solid<dim>::print_console_file_footer(std::ofstream &outputfile) const
+    {
+           //Copy "parameters" file at end of output file.
+           std::ifstream infile("parameters.prm");
+           std::string content = "";
+           int i;
+
+           for(i=0 ; infile.eof()!=true ; i++)
+           {
+               char aux = infile.get();
+               content += aux;
+               if(aux=='\n') content += '#';
+           }
+
+           i--;
+           content.erase(content.end()-1);
+           infile.close();
+
+           outputfile << "\n\n\n\n PARAMETERS FILE USED IN THIS COMPUTATION: \n#"
+                      << std::endl
+                      << content;
+    }
+
+    //Footer for plotting output file
+    template <int dim>
+    void Solid<dim>::print_plot_file_footer(std::ofstream &plotpointfile) const
+    {
+           //Copy "parameters" file at end of output file.
+           std::ifstream infile("parameters.prm");
+           std::string content = "";
+           int i;
+
+           for(i=0 ; infile.eof()!=true ; i++)
+           {
+               char aux = infile.get();
+               content += aux;
+               if(aux=='\n') content += '#';
+           }
+
+           i--;
+           content.erase(content.end()-1);
+           infile.close();
+
+           plotpointfile << "#"<< std::endl
+                         << "#"<< std::endl
+                         << "# PARAMETERS FILE USED IN THIS COMPUTATION:" << std::endl
+                         << "#"<< std::endl
+                         << content;
+    }
+
+
+    // @sect3{Verification examples from Ehlers and Eipper 1999}
+    // We group the definition of the geometry, boundary and loading conditions specific to
+    // the verification examples from Ehlers and Eipper 1999 into specific classes.
+
+    //@sect4{Base class: Tube geometry and boundary conditions}
+    template <int dim>
+    class VerificationEhlers1999TubeBase
+          : public Solid<dim>
+    {
+        public:
+          VerificationEhlers1999TubeBase (const Parameters::AllParameters &parameters)
+            : Solid<dim> (parameters)
+          {}
+
+          virtual ~VerificationEhlers1999TubeBase () {}
+
+        private:
+          virtual void make_grid() override
+          {
+            GridGenerator::cylinder( this->triangulation,
+                                     0.1,
+                                     0.5);
+
+            const double rot_angle = 3.0*numbers::PI/2.0;
+            GridTools::rotate( Point<3>::unit_vector(1), rot_angle, this->triangulation);
+
+            this->triangulation.reset_manifold(0);
+            static const CylindricalManifold<dim> manifold_description_3d(2);
+            this->triangulation.set_manifold (0, manifold_description_3d);
+            GridTools::scale(this->parameters.scale, this->triangulation);
+            this->triangulation.refine_global(std::max (1U, this->parameters.global_refinement));
+            this->triangulation.reset_manifold(0);
+          }
+
+          virtual void define_tracked_vertices(std::vector<Point<dim> > &tracked_vertices) override
+          {
+            tracked_vertices[0][0] = 0.0*this->parameters.scale;
+            tracked_vertices[0][1] = 0.0*this->parameters.scale;
+            tracked_vertices[0][2] = 0.5*this->parameters.scale;
+
+            tracked_vertices[1][0] = 0.0*this->parameters.scale;
+            tracked_vertices[1][1] = 0.0*this->parameters.scale;
+            tracked_vertices[1][2] = -0.5*this->parameters.scale;
+          }
+
+          virtual void make_dirichlet_constraints(AffineConstraints<double> &constraints) override
+          {
+            if (this->time.get_timestep() < 2)
+            {
+              VectorTools::interpolate_boundary_values(this->dof_handler_ref,
+                                                       2,
+                                                       Functions::ConstantFunction<dim>(this->parameters.drained_pressure,this->n_components),
+                                                       constraints,
+                                                       (this->fe.component_mask(this->pressure)));
+            }
+            else
+            {
+              VectorTools::interpolate_boundary_values(this->dof_handler_ref,
+                                                       2,
+                                                       Functions::ZeroFunction<dim>(this->n_components),
+                                                       constraints,
+                                                       (this->fe.component_mask(this->pressure)));
+            }
+
+            VectorTools::interpolate_boundary_values( this->dof_handler_ref,
+                                                      0,
+                                                      Functions::ZeroFunction<dim>(this->n_components),
+                                                      constraints,
+                                                      (this->fe.component_mask(this->x_displacement)|
+                                                       this->fe.component_mask(this->y_displacement)  ) );
+
+            VectorTools::interpolate_boundary_values( this->dof_handler_ref,
+                                                      1,
+                                                      Functions::ZeroFunction<dim>(this->n_components),
+                                                      constraints,
+                                                      (this->fe.component_mask(this->x_displacement) |
+                                                       this->fe.component_mask(this->y_displacement) |
+                                                       this->fe.component_mask(this->z_displacement) ));
+          }
+
+          virtual double
+          get_prescribed_fluid_flow (const types::boundary_id &boundary_id,
+                                     const Point<dim>         &pt) const override
+          {
+              (void)pt;
+              (void)boundary_id;
+              return 0.0;
+          }
+
+          virtual types::boundary_id
+          get_reaction_boundary_id_for_output() const override
+          {
+              return 2;
+          }
+
+          virtual  std::pair<types::boundary_id,types::boundary_id>
+          get_drained_boundary_id_for_output() const override
+          {
+              return std::make_pair(2,2);
+          }
+
+          virtual std::vector<double>
+          get_dirichlet_load(const types::boundary_id   &boundary_id,
+                             const int                  &direction) const override
+          {
+              std::vector<double> displ_incr(dim, 0.0);
+              (void)boundary_id;
+              (void)direction;
+              AssertThrow(false, ExcMessage("Displacement loading not implemented for Ehlers verification examples."));
+
+              return displ_incr;
+          }
+    };
+
+    //@sect4{Derived class: Step load example}
+    template <int dim>
+    class VerificationEhlers1999StepLoad
+          : public VerificationEhlers1999TubeBase<dim>
+    {
+        public:
+          VerificationEhlers1999StepLoad (const Parameters::AllParameters &parameters)
+            : VerificationEhlers1999TubeBase<dim> (parameters)
+          {}
+
+          virtual ~VerificationEhlers1999StepLoad () {}
+
+        private:
+            virtual Tensor<1,dim>
+            get_neumann_traction (const types::boundary_id &boundary_id,
+                                  const Point<dim>         &pt,
+                                  const Tensor<1,dim>      &N) const override
+            {
+              if (this->parameters.load_type == "pressure")
+              {
+                if (boundary_id == 2)
+                {
+                  return this->parameters.load * N;
+                }
+              }
+
+              (void)pt;
+
+              return Tensor<1,dim>();
+            }
+    };
+
+    //@sect4{Derived class: Load increasing example}
+    template <int dim>
+    class VerificationEhlers1999IncreaseLoad
+          : public VerificationEhlers1999TubeBase<dim>
+    {
+        public:
+          VerificationEhlers1999IncreaseLoad (const Parameters::AllParameters &parameters)
+            : VerificationEhlers1999TubeBase<dim> (parameters)
+          {}
+
+          virtual ~VerificationEhlers1999IncreaseLoad () {}
+
+        private:
+            virtual Tensor<1,dim>
+            get_neumann_traction (const types::boundary_id &boundary_id,
+                                  const Point<dim>         &pt,
+                                  const Tensor<1,dim>      &N) const override
+            {
+              if (this->parameters.load_type == "pressure")
+              {
+                if (boundary_id == 2)
+                {
+                  const double initial_load = this->parameters.load;
+                  const double final_load = 20.0*initial_load;
+                  const double initial_time = this->time.get_delta_t();
+                  const double final_time = this->time.get_end();
+                  const double current_time = this->time.get_current();
+                  const double load = initial_load + (final_load-initial_load)*(current_time-initial_time)/(final_time-initial_time);
+                  return load * N;
+                }
+              }
+
+              (void)pt;
+
+              return Tensor<1,dim>();
+            }
+    };
+
+    //@sect4{Class: Consolidation cube}
+    template <int dim>
+    class VerificationEhlers1999CubeConsolidation
+          : public Solid<dim>
+    {
+        public:
+          VerificationEhlers1999CubeConsolidation (const Parameters::AllParameters &parameters)
+            : Solid<dim> (parameters)
+          {}
+
+          virtual ~VerificationEhlers1999CubeConsolidation () {}
+
+        private:
+          virtual void
+          make_grid() override
+          {
+             GridGenerator::hyper_rectangle(this->triangulation,
+                                            Point<dim>(0.0, 0.0, 0.0),
+                                            Point<dim>(1.0, 1.0, 1.0),
+                                            true);
+
+             GridTools::scale(this->parameters.scale, this->triangulation);
+             this->triangulation.refine_global(std::max (1U, this->parameters.global_refinement));
+
+             typename Triangulation<dim>::active_cell_iterator cell =
+                     this->triangulation.begin_active(), endc = this->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()[2] == 1.0 * this->parameters.scale)
+                 {
+                   if (cell->face(face)->center()[0] < 0.5 * this->parameters.scale  &&
+                       cell->face(face)->center()[1] < 0.5 * this->parameters.scale)
+                       cell->face(face)->set_boundary_id(100);
+                   else
+                       cell->face(face)->set_boundary_id(101);
+                 }
+             }
+          }
+
+          virtual void
+          define_tracked_vertices(std::vector<Point<dim> > &tracked_vertices) override
+          {
+            tracked_vertices[0][0] = 0.0*this->parameters.scale;
+            tracked_vertices[0][1] = 0.0*this->parameters.scale;
+            tracked_vertices[0][2] = 1.0*this->parameters.scale;
+
+            tracked_vertices[1][0] = 0.0*this->parameters.scale;
+            tracked_vertices[1][1] = 0.0*this->parameters.scale;
+            tracked_vertices[1][2] = 0.0*this->parameters.scale;
+          }
+
+          virtual void
+          make_dirichlet_constraints(AffineConstraints<double> &constraints) override
+          {
+            if (this->time.get_timestep() < 2)
+            {
+              VectorTools::interpolate_boundary_values(this->dof_handler_ref,
+                                                       101,
+                                                       Functions::ConstantFunction<dim>(this->parameters.drained_pressure,this->n_components),
+                                                       constraints,
+                                                       (this->fe.component_mask(this->pressure)));
+            }
+            else
+            {
+              VectorTools::interpolate_boundary_values(this->dof_handler_ref,
+                                                       101,
+                                                       Functions::ZeroFunction<dim>(this->n_components),
+                                                       constraints,
+                                                       (this->fe.component_mask(this->pressure)));
+            }
+
+            VectorTools::interpolate_boundary_values( this->dof_handler_ref,
+                                                      0,
+                                                      Functions::ZeroFunction<dim>(this->n_components),
+                                                      constraints,
+                                                      this->fe.component_mask(this->x_displacement));
+
+            VectorTools::interpolate_boundary_values( this->dof_handler_ref,
+                                                      1,
+                                                      Functions::ZeroFunction<dim>(this->n_components),
+                                                      constraints,
+                                                      this->fe.component_mask(this->x_displacement));
+
+            VectorTools::interpolate_boundary_values( this->dof_handler_ref,
+                                                      2,
+                                                      Functions::ZeroFunction<dim>(this->n_components),
+                                                      constraints,
+                                                      this->fe.component_mask(this->y_displacement));
+
+            VectorTools::interpolate_boundary_values( this->dof_handler_ref,
+                                                      3,
+                                                      Functions::ZeroFunction<dim>(this->n_components),
+                                                      constraints,
+                                                      this->fe.component_mask(this->y_displacement));
+
+            VectorTools::interpolate_boundary_values( this->dof_handler_ref,
+                                                      4,
+                                                      Functions::ZeroFunction<dim>(this->n_components),
+                                                      constraints,
+                                                      ( this->fe.component_mask(this->x_displacement) |
+                                                        this->fe.component_mask(this->y_displacement) |
+                                                        this->fe.component_mask(this->z_displacement) ));
+          }
+
+          virtual Tensor<1,dim>
+          get_neumann_traction (const types::boundary_id &boundary_id,
+                                const Point<dim>         &pt,
+                                const Tensor<1,dim>      &N) const override
+          {
+            if (this->parameters.load_type == "pressure")
+            {
+              if (boundary_id == 100)
+              {
+                return this->parameters.load * N;
+              }
+            }
+
+            (void)pt;
+
+            return Tensor<1,dim>();
+          }
+
+          virtual double
+          get_prescribed_fluid_flow (const types::boundary_id &boundary_id,
+                                     const Point<dim>         &pt) const override
+          {
+              (void)pt;
+              (void)boundary_id;
+              return 0.0;
+          }
+
+          virtual types::boundary_id
+          get_reaction_boundary_id_for_output() const override
+          {
+              return 100;
+          }
+
+          virtual  std::pair<types::boundary_id,types::boundary_id>
+          get_drained_boundary_id_for_output() const override
+          {
+              return std::make_pair(101,101);
+          }
+
+          virtual std::vector<double>
+          get_dirichlet_load(const types::boundary_id   &boundary_id,
+                             const int                  &direction) const override
+          {
+              std::vector<double> displ_incr(dim, 0.0);
+              (void)boundary_id;
+              (void)direction;
+              AssertThrow(false, ExcMessage("Displacement loading not implemented for Ehlers verification examples."));
+
+              return displ_incr;
+          }
+    };
+
+    //@sect4{Franceschini experiments}
+    template <int dim>
+    class Franceschini2006Consolidation
+          : public Solid<dim>
+    {
+        public:
+        Franceschini2006Consolidation (const Parameters::AllParameters &parameters)
+            : Solid<dim> (parameters)
+          {}
+
+          virtual ~Franceschini2006Consolidation () {}
+
+        private:
+          virtual void make_grid() override
+          {
+            const Point<dim-1> mesh_center(0.0, 0.0);
+            const double radius = 0.5;
+            //const double height = 0.27;  //8.1 mm for 30 mm radius
+            const double height = 0.23;  //6.9 mm for 30 mm radius
+            Triangulation<dim-1> triangulation_in;
+            GridGenerator::hyper_ball( triangulation_in,
+                                       mesh_center,
+                                       radius);
+
+            GridGenerator::extrude_triangulation(triangulation_in,
+                                                  2,
+                                                  height,
+                                                  this->triangulation);
+
+            const CylindricalManifold<dim> cylinder_3d(2);
+            const types::manifold_id cylinder_id = 0;
+
+
+            this->triangulation.set_manifold(cylinder_id, cylinder_3d);
+
+            for (auto cell : this->triangulation.active_cell_iterators())
+            {
+              for (unsigned int face = 0; face < GeometryInfo<dim>::faces_per_cell; ++face)
+              {
+                if (cell->face(face)->at_boundary() == true)
+                {
+                  if (cell->face(face)->center()[2] == 0.0)
+                      cell->face(face)->set_boundary_id(1);
+
+                  else if (cell->face(face)->center()[2] == height)
+                      cell->face(face)->set_boundary_id(2);
+
+                  else
+                  {
+                      cell->face(face)->set_boundary_id(0);
+                      cell->face(face)->set_all_manifold_ids(cylinder_id);
+                  }
+                }
+              }
+            }
+
+            GridTools::scale(this->parameters.scale, this->triangulation);
+            this->triangulation.refine_global(std::max (1U, this->parameters.global_refinement));
+          }
+
+          virtual void define_tracked_vertices(std::vector<Point<dim> > &tracked_vertices) override
+          {
+            tracked_vertices[0][0] = 0.0*this->parameters.scale;
+            tracked_vertices[0][1] = 0.0*this->parameters.scale;
+         //  tracked_vertices[0][2] = 0.27*this->parameters.scale;
+            tracked_vertices[0][2] = 0.23*this->parameters.scale;
+
+            tracked_vertices[1][0] = 0.0*this->parameters.scale;
+            tracked_vertices[1][1] = 0.0*this->parameters.scale;
+            tracked_vertices[1][2] = 0.0*this->parameters.scale;
+          }
+
+          virtual void make_dirichlet_constraints(AffineConstraints<double> &constraints) override
+          {
+            if (this->time.get_timestep() < 2)
+            {
+              VectorTools::interpolate_boundary_values(this->dof_handler_ref,
+                                                       1,
+                                                       Functions::ConstantFunction<dim>(this->parameters.drained_pressure,this->n_components),
+                                                       constraints,
+                                                       (this->fe.component_mask(this->pressure)));
+
+              VectorTools::interpolate_boundary_values(this->dof_handler_ref,
+                                                       2,
+                                                       Functions::ConstantFunction<dim>(this->parameters.drained_pressure,this->n_components),
+                                                       constraints,
+                                                       (this->fe.component_mask(this->pressure)));
+            }
+            else
+            {
+              VectorTools::interpolate_boundary_values(this->dof_handler_ref,
+                                                       1,
+                                                       Functions::ZeroFunction<dim>(this->n_components),
+                                                       constraints,
+                                                       (this->fe.component_mask(this->pressure)));
+
+              VectorTools::interpolate_boundary_values(this->dof_handler_ref,
+                                                       2,
+                                                       Functions::ZeroFunction<dim>(this->n_components),
+                                                       constraints,
+                                                       (this->fe.component_mask(this->pressure)));
+            }
+
+            VectorTools::interpolate_boundary_values( this->dof_handler_ref,
+                                                      0,
+                                                      Functions::ZeroFunction<dim>(this->n_components),
+                                                      constraints,
+                                                      (this->fe.component_mask(this->x_displacement)|
+                                                       this->fe.component_mask(this->y_displacement)  ) );
+
+            VectorTools::interpolate_boundary_values( this->dof_handler_ref,
+                                                      1,
+                                                      Functions::ZeroFunction<dim>(this->n_components),
+                                                      constraints,
+                                                      (this->fe.component_mask(this->x_displacement) |
+                                                       this->fe.component_mask(this->y_displacement) |
+                                                       this->fe.component_mask(this->z_displacement) ));
+
+            VectorTools::interpolate_boundary_values( this->dof_handler_ref,
+                                                      2,
+                                                      Functions::ZeroFunction<dim>(this->n_components),
+                                                      constraints,
+                                                      (this->fe.component_mask(this->x_displacement) |
+                                                       this->fe.component_mask(this->y_displacement) ));
+          }
+
+          virtual double
+          get_prescribed_fluid_flow (const types::boundary_id &boundary_id,
+                                     const Point<dim>         &pt) const override
+          {
+              (void)pt;
+              (void)boundary_id;
+              return 0.0;
+          }
+
+          virtual types::boundary_id
+          get_reaction_boundary_id_for_output() const override
+          {
+              return 2;
+          }
+
+          virtual  std::pair<types::boundary_id,types::boundary_id>
+          get_drained_boundary_id_for_output() const override
+          {
+              return std::make_pair(1,2);
+          }
+
+          virtual std::vector<double>
+          get_dirichlet_load(const types::boundary_id   &boundary_id,
+                             const int                  &direction) const override
+          {
+              std::vector<double> displ_incr(dim, 0.0);
+              (void)boundary_id;
+              (void)direction;
+              AssertThrow(false, ExcMessage("Displacement loading not implemented for Franceschini examples."));
+
+              return displ_incr;
+          }
+
+          virtual Tensor<1,dim>
+          get_neumann_traction (const types::boundary_id &boundary_id,
+                                const Point<dim>         &pt,
+                                const Tensor<1,dim>      &N) const override
+          {
+            if (this->parameters.load_type == "pressure")
+            {
+              if (boundary_id == 2)
+              {
+                return (this->parameters.load * N);
+                /*
+                const double final_load = this->parameters.load;
+                const double final_load_time = 10 * this->time.get_delta_t();
+                const double current_time = this->time.get_current();
+
+
+                const double c = final_load_time / 2.0;
+                const double r = 200.0 * 0.03 / c;
+
+                const double load = final_load * std::exp(r * current_time)
+                                    / ( std::exp(c * current_time) +  std::exp(r * current_time));
+                return load * N;
+                */
+              }
+            }
+
+            (void)pt;
+
+            return Tensor<1,dim>();
+          }
+    };
+
+    // @sect3{Examples to reproduce experiments by Budday et al. 2017}
+    // We group the definition of the geometry, boundary and loading conditions specific to
+    // the examples to reproduce experiments by Budday et al. 2017 into specific classes.
+
+    //@sect4{Base class: Cube geometry and loading pattern}
+    template <int dim>
+    class BrainBudday2017BaseCube
+          : public Solid<dim>
+    {
+        public:
+            BrainBudday2017BaseCube (const Parameters::AllParameters &parameters)
+            : Solid<dim> (parameters)
+          {}
+
+          virtual ~BrainBudday2017BaseCube () {}
+
+        private:
+          virtual void
+          make_grid() override
+          {
+            GridGenerator::hyper_cube(this->triangulation,
+                                      0.0,
+                                      1.0,
+                                      true);
+
+            typename Triangulation<dim>::active_cell_iterator cell =
+                    this->triangulation.begin_active(), endc = this->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)->boundary_id() == 0 ||
+                      cell->face(face)->boundary_id() == 1 ||
+                      cell->face(face)->boundary_id() == 2 ||
+                      cell->face(face)->boundary_id() == 3    ) )
+
+                      cell->face(face)->set_boundary_id(100);
+
+            }
+
+            GridTools::scale(this->parameters.scale, this->triangulation);
+            this->triangulation.refine_global(std::max (1U, this->parameters.global_refinement));
+          }
+
+          virtual double
+          get_prescribed_fluid_flow (const types::boundary_id &boundary_id,
+                                     const Point<dim>         &pt) const override
+          {
+              (void)pt;
+              (void)boundary_id;
+              return 0.0;
+          }
+
+          virtual  std::pair<types::boundary_id,types::boundary_id>
+          get_drained_boundary_id_for_output() const override
+          {
+              return std::make_pair(100,100);
+          }
+    };
+
+    //@sect4{Derived class: Uniaxial boundary conditions}
+    template <int dim>
+    class BrainBudday2017CubeTensionCompression
+          : public BrainBudday2017BaseCube<dim>
+    {
+        public:
+          BrainBudday2017CubeTensionCompression (const Parameters::AllParameters &parameters)
+            : BrainBudday2017BaseCube<dim> (parameters)
+          {}
+
+          virtual ~BrainBudday2017CubeTensionCompression () {}
+
+        private:
+          virtual void
+          define_tracked_vertices(std::vector<Point<dim> > &tracked_vertices) override
+          {
+            tracked_vertices[0][0] = 0.5*this->parameters.scale;
+            tracked_vertices[0][1] = 0.5*this->parameters.scale;
+            tracked_vertices[0][2] = 1.0*this->parameters.scale;
+
+            tracked_vertices[1][0] = 0.5*this->parameters.scale;
+            tracked_vertices[1][1] = 0.5*this->parameters.scale;
+            tracked_vertices[1][2] = 0.5*this->parameters.scale;
+          }
+
+          virtual void
+          make_dirichlet_constraints(AffineConstraints<double> &constraints) override
+          {
+              if (this->time.get_timestep() < 2)
+              {
+                  VectorTools::interpolate_boundary_values(this->dof_handler_ref,
+                                                           100,
+                                                           Functions::ConstantFunction<dim>(this->parameters.drained_pressure,this->n_components),
+                                                           constraints,
+                                                           (this->fe.component_mask(this->pressure)));
+              }
+              else
+              {
+                  VectorTools::interpolate_boundary_values( this->dof_handler_ref,
+                                                            100,
+                                                            Functions::ZeroFunction<dim>(this->n_components),
+                                                            constraints,
+                                                            (this->fe.component_mask(this->pressure)));
+              }
+              VectorTools::interpolate_boundary_values( this->dof_handler_ref,
+                                                        4,
+                                                        Functions::ZeroFunction<dim>(this->n_components),
+                                                        constraints,
+                                                        this->fe.component_mask(this->z_displacement) );
+
+            Point<dim> fix_node(0.5*this->parameters.scale, 0.5*this->parameters.scale, 0.0);
+            typename DoFHandler<dim>::active_cell_iterator
+            cell = this->dof_handler_ref.begin_active(), endc = this->dof_handler_ref.end();
+            for (; cell != endc; ++cell)
+              for (unsigned int node = 0; node < GeometryInfo<dim>::vertices_per_cell; ++node)
+              {
+                  if (  (abs(cell->vertex(node)[2]-fix_node[2]) < (1e-6 * this->parameters.scale))
+                    &&  (abs(cell->vertex(node)[0]-fix_node[0]) < (1e-6 * this->parameters.scale)))
+                      constraints.add_line(cell->vertex_dof_index(node, 0));
+
+                  if (  (abs(cell->vertex(node)[2]-fix_node[2]) < (1e-6 * this->parameters.scale))
+                    &&  (abs(cell->vertex(node)[1]-fix_node[1]) < (1e-6 * this->parameters.scale)))
+                    constraints.add_line(cell->vertex_dof_index(node, 1));
+              }
+
+            if (this->parameters.load_type == "displacement")
+            {
+                const std::vector<double> value = get_dirichlet_load(5,2);
+                FEValuesExtractors::Scalar direction;
+                direction = this->z_displacement;
+
+                VectorTools::interpolate_boundary_values( this->dof_handler_ref,
+                                                           5,
+                                                           Functions::ConstantFunction<dim>(value[2],this->n_components),
+                                                           constraints,
+                                                           this->fe.component_mask(direction));
+            }
+          }
+
+          virtual Tensor<1,dim>
+          get_neumann_traction (const types::boundary_id &boundary_id,
+                                const Point<dim>         &pt,
+                                const Tensor<1,dim>      &N) const override
+          {
+              if (this->parameters.load_type == "pressure")
+              {
+                if (boundary_id ==  5)
+                {
+                    const double final_load   = this->parameters.load;
+                    const double current_time = this->time.get_current();
+                    const double final_time   = this->time.get_end();
+                    const double num_cycles   = 3.0;
+
+                    return  final_load/2.0 * (1.0 - std::sin(numbers::PI * (2.0*num_cycles*current_time/final_time + 0.5))) * N;
+                }
+              }
+
+              (void)pt;
+
+              return Tensor<1,dim>();
+            }
+
+          virtual types::boundary_id
+          get_reaction_boundary_id_for_output() const override
+          {
+              return 5;
+          }
+
+          virtual std::vector<double>
+          get_dirichlet_load(const types::boundary_id   &boundary_id,
+                             const int                  &direction) const override
+          {
+                std::vector<double> displ_incr(dim,0.0);
+
+                if ( (boundary_id == 5) && (direction == 2) )
+                {
+                    const double final_displ  = this->parameters.load;
+                    const double current_time = this->time.get_current();
+                    const double final_time   = this->time.get_end();
+                    const double delta_time   = this->time.get_delta_t();
+                    const double num_cycles   = 3.0;
+                    double current_displ = 0.0;
+                    double previous_displ = 0.0;
+
+                    if (this->parameters.num_cycle_sets == 1)
+                    {
+                        current_displ  = final_displ/2.0 * (1.0
+                          - std::sin(numbers::PI * (2.0*num_cycles*current_time/final_time + 0.5)));
+                        previous_displ = final_displ/2.0 * (1.0
+                          - std::sin(numbers::PI * (2.0*num_cycles*(current_time-delta_time)/final_time + 0.5)));
+                    }
+                    else
+                    {
+                        if ( current_time <= (final_time*1.0/3.0) )
+                        {
+                            current_displ  = final_displ/2.0 * (1.0 - std::sin(numbers::PI *
+                                                 (2.0*num_cycles*current_time/(final_time*1.0/3.0) + 0.5)));
+                            previous_displ = final_displ/2.0 * (1.0 - std::sin(numbers::PI *
+                                                 (2.0*num_cycles*(current_time-delta_time)/(final_time*1.0/3.0) + 0.5)));
+                        }
+                        else
+                        {
+                            current_displ  = final_displ * (1.0 - std::sin(numbers::PI *
+                                                 (2.0*num_cycles*current_time / (final_time*2.0/3.0)
+                                                  - (num_cycles - 0.5) )));
+                            previous_displ = final_displ * (1.0 - std::sin(numbers::PI *
+                                                 (2.0*num_cycles*(current_time-delta_time) / (final_time*2.0/3.0)
+                                                  - (num_cycles - 0.5))));
+                        }
+                    }
+                    displ_incr[2] = current_displ - previous_displ;
+                }
+                return displ_incr;
+          }
+    };
+
+    //@sect4{Derived class: No lateral displacement in loading surfaces}
+    template <int dim>
+    class BrainBudday2017CubeTensionCompressionFullyFixed
+          : public BrainBudday2017BaseCube<dim>
+    {
+        public:
+          BrainBudday2017CubeTensionCompressionFullyFixed (const Parameters::AllParameters &parameters)
+            : BrainBudday2017BaseCube<dim> (parameters)
+          {}
+
+          virtual ~BrainBudday2017CubeTensionCompressionFullyFixed () {}
+
+        private:
+          virtual void
+          define_tracked_vertices(std::vector<Point<dim> > &tracked_vertices) override
+          {
+            tracked_vertices[0][0] = 0.5*this->parameters.scale;
+            tracked_vertices[0][1] = 0.5*this->parameters.scale;
+            tracked_vertices[0][2] = 1.0*this->parameters.scale;
+
+            tracked_vertices[1][0] = 0.5*this->parameters.scale;
+            tracked_vertices[1][1] = 0.5*this->parameters.scale;
+            tracked_vertices[1][2] = 0.5*this->parameters.scale;
+          }
+
+          virtual void
+          make_dirichlet_constraints(AffineConstraints<double> &constraints) override
+          {
+              if (this->time.get_timestep() < 2)
+              {
+                  VectorTools::interpolate_boundary_values(this->dof_handler_ref,
+                                                           100,
+                                                           Functions::ConstantFunction<dim>(this->parameters.drained_pressure,this->n_components),
+                                                           constraints,
+                                                           (this->fe.component_mask(this->pressure)));
+              }
+              else
+              {
+                  VectorTools::interpolate_boundary_values( this->dof_handler_ref,
+                                                            100,
+                                                            Functions::ZeroFunction<dim>(this->n_components),
+                                                            constraints,
+                                                            (this->fe.component_mask(this->pressure)));
+              }
+
+              VectorTools::interpolate_boundary_values( this->dof_handler_ref,
+                                                        4,
+                                                        Functions::ZeroFunction<dim>(this->n_components),
+                                                        constraints,
+                                                      (this->fe.component_mask(this->x_displacement) |
+                                                       this->fe.component_mask(this->y_displacement) |
+                                                       this->fe.component_mask(this->z_displacement) ));
+
+
+            if (this->parameters.load_type == "displacement")
+            {
+                const std::vector<double> value = get_dirichlet_load(5,2);
+                FEValuesExtractors::Scalar direction;
+                direction = this->z_displacement;
+
+                VectorTools::interpolate_boundary_values( this->dof_handler_ref,
+                                                           5,
+                                                           Functions::ConstantFunction<dim>(value[2],this->n_components),
+                                                           constraints,
+                                                           this->fe.component_mask(direction) );
+
+               VectorTools::interpolate_boundary_values( this->dof_handler_ref,
+                                                          5,
+                                                          Functions::ZeroFunction<dim>(this->n_components),
+                                                          constraints,
+                                                          (this->fe.component_mask(this->x_displacement) |
+                                                           this->fe.component_mask(this->y_displacement) ));
+            }
+          }
+
+          virtual Tensor<1,dim>
+          get_neumann_traction (const types::boundary_id &boundary_id,
+                                const Point<dim>         &pt,
+                                const Tensor<1,dim>      &N) const override
+          {
+              if (this->parameters.load_type == "pressure")
+              {
+                if (boundary_id ==  5)
+                {
+                    const double final_load   = this->parameters.load;
+                    const double current_time = this->time.get_current();
+                    const double final_time   = this->time.get_end();
+                    const double num_cycles   = 3.0;
+
+                    return  final_load/2.0 * (1.0 - std::sin(numbers::PI * (2.0*num_cycles*current_time/final_time + 0.5))) * N;
+                }
+              }
+
+              (void)pt;
+
+              return Tensor<1,dim>();
+            }
+
+          virtual types::boundary_id
+          get_reaction_boundary_id_for_output() const override
+          {
+              return 5;
+          }
+
+          virtual std::vector<double>
+          get_dirichlet_load(const types::boundary_id   &boundary_id,
+                             const int                  &direction) const override
+          {
+                std::vector<double> displ_incr(dim,0.0);
+
+                if ( (boundary_id == 5) && (direction == 2) )
+                {
+                    const double final_displ  = this->parameters.load;
+                    const double current_time = this->time.get_current();
+                    const double final_time   = this->time.get_end();
+                    const double delta_time   = this->time.get_delta_t();
+                    const double num_cycles   = 3.0;
+                    double current_displ = 0.0;
+                    double previous_displ = 0.0;
+
+                    if (this->parameters.num_cycle_sets == 1)
+                    {
+                        current_displ  = final_displ/2.0 * (1.0 - std::sin(numbers::PI * (2.0*num_cycles*current_time/final_time + 0.5)));
+                        previous_displ = final_displ/2.0 * (1.0 - std::sin(numbers::PI * (2.0*num_cycles*(current_time-delta_time)/final_time + 0.5)));
+                    }
+                    else
+                    {
+                        if ( current_time <= (final_time*1.0/3.0) )
+                        {
+                            current_displ  = final_displ/2.0 * (1.0 - std::sin(numbers::PI *
+                                                 (2.0*num_cycles*current_time/(final_time*1.0/3.0) + 0.5)));
+                            previous_displ = final_displ/2.0 * (1.0 - std::sin(numbers::PI *
+                                                 (2.0*num_cycles*(current_time-delta_time)/(final_time*1.0/3.0) + 0.5)));
+                        }
+                        else
+                        {
+                            current_displ  = final_displ * (1.0 - std::sin(numbers::PI *
+                                                 (2.0*num_cycles*current_time / (final_time*2.0/3.0)
+                                                  - (num_cycles - 0.5) )));
+                            previous_displ = final_displ * (1.0 - std::sin(numbers::PI *
+                                                 (2.0*num_cycles*(current_time-delta_time) / (final_time*2.0/3.0)
+                                                  - (num_cycles - 0.5))));
+                        }
+                    }
+                    displ_incr[2] = current_displ - previous_displ;
+                }
+                return displ_incr;
+          }
+    };
+
+    //@sect4{Derived class: No lateral or vertical displacement in loading surface}
+    template <int dim>
+    class BrainBudday2017CubeShearFullyFixed
+          : public BrainBudday2017BaseCube<dim>
+    {
+        public:
+          BrainBudday2017CubeShearFullyFixed (const Parameters::AllParameters &parameters)
+            : BrainBudday2017BaseCube<dim> (parameters)
+          {}
+
+          virtual ~BrainBudday2017CubeShearFullyFixed () {}
+
+        private:
+          virtual void
+          define_tracked_vertices(std::vector<Point<dim> > &tracked_vertices) override
+          {
+            tracked_vertices[0][0] = 0.75*this->parameters.scale;
+            tracked_vertices[0][1] = 0.5*this->parameters.scale;
+            tracked_vertices[0][2] = 0.0*this->parameters.scale;
+
+            tracked_vertices[1][0] = 0.25*this->parameters.scale;
+            tracked_vertices[1][1] = 0.5*this->parameters.scale;
+            tracked_vertices[1][2] = 0.0*this->parameters.scale;
+          }
+
+          virtual void
+          make_dirichlet_constraints(AffineConstraints<double> &constraints) override
+          {
+              if (this->time.get_timestep() < 2)
+              {
+                  VectorTools::interpolate_boundary_values(this->dof_handler_ref,
+                                                           100,
+                                                           Functions::ConstantFunction<dim>(this->parameters.drained_pressure,this->n_components),
+                                                           constraints,
+                                                           (this->fe.component_mask(this->pressure)));
+              }
+              else
+              {
+                  VectorTools::interpolate_boundary_values( this->dof_handler_ref,
+                                                            100,
+                                                            Functions::ZeroFunction<dim>(this->n_components),
+                                                            constraints,
+                                                            (this->fe.component_mask(this->pressure)));
+              }
+
+              VectorTools::interpolate_boundary_values( this->dof_handler_ref,
+                                                        5,
+                                                        Functions::ZeroFunction<dim>(this->n_components),
+                                                        constraints,
+                                                      (this->fe.component_mask(this->x_displacement) |
+                                                       this->fe.component_mask(this->y_displacement) |
+                                                       this->fe.component_mask(this->z_displacement) ));
+
+
+            if (this->parameters.load_type == "displacement")
+            {
+                const std::vector<double> value = get_dirichlet_load(4,0);
+                FEValuesExtractors::Scalar direction;
+                direction = this->x_displacement;
+
+                VectorTools::interpolate_boundary_values( this->dof_handler_ref,
+                                                           4,
+                                                           Functions::ConstantFunction<dim>(value[0],this->n_components),
+                                                           constraints,
+                                                           this->fe.component_mask(direction));
+
+               VectorTools::interpolate_boundary_values( this->dof_handler_ref,
+                                                          4,
+                                                          Functions::ZeroFunction<dim>(this->n_components),
+                                                          constraints,
+                                                          (this->fe.component_mask(this->y_displacement) |
+                                                           this->fe.component_mask(this->z_displacement) ));
+            }
+          }
+
+          virtual Tensor<1,dim>
+          get_neumann_traction (const types::boundary_id &boundary_id,
+                                const Point<dim>         &pt,
+                                const Tensor<1,dim>      &N) const override
+          {
+              if (this->parameters.load_type == "pressure")
+              {
+                if (boundary_id ==  4)
+                {
+                    const double final_load   = this->parameters.load;
+                    const double current_time = this->time.get_current();
+                    const double final_time   = this->time.get_end();
+                    const double num_cycles   = 3.0;
+                    const Tensor<1,3> axis ({0.0,1.0,0.0});
+                    const double angle = numbers::PI;
+                    static const Tensor< 2, dim, double> R(Physics::Transformations::Rotations::rotation_matrix_3d(axis,angle));
+
+                    return  (final_load * (std::sin(2.0*(numbers::PI)*num_cycles*current_time/final_time)) * (R * N));
+                }
+              }
+
+              (void)pt;
+
+              return Tensor<1,dim>();
+            }
+
+          virtual types::boundary_id
+          get_reaction_boundary_id_for_output() const override
+          {
+              return 4;
+          }
+
+          virtual std::vector<double>
+          get_dirichlet_load(const types::boundary_id   &boundary_id,
+                             const int                  &direction) const override
+          {
+                std::vector<double> displ_incr (dim, 0.0);
+
+                if ( (boundary_id == 4) && (direction == 0) )
+                {
+                    const double final_displ  = this->parameters.load;
+                    const double current_time = this->time.get_current();
+                    const double final_time   = this->time.get_end();
+                    const double delta_time   = this->time.get_delta_t();
+                    const double num_cycles   = 3.0;
+                    double current_displ = 0.0;
+                    double previous_displ = 0.0;
+
+                    if (this->parameters.num_cycle_sets == 1)
+                    {
+                        current_displ  = final_displ * (std::sin(2.0*(numbers::PI)*num_cycles*current_time/final_time));
+                        previous_displ = final_displ * (std::sin(2.0*(numbers::PI)*num_cycles*(current_time-delta_time)/final_time));
+                    }
+                    else
+                    {
+                        AssertThrow(false, ExcMessage("Problem type not defined. Budday shear experiments implemented only for one set of cycles."));
+                    }
+                    displ_incr[0] = current_displ - previous_displ;
+                }
+                return displ_incr;
+          }
+    };
+
+}
+
+// @sect3{Main function}
+// Lastly we provide the main driver function which is similar to the other tutorials.
+int main (int argc, char *argv[])
+{
+  using namespace dealii;
+  using namespace NonLinearPoroViscoElasticity;
+
+  const unsigned int n_tbb_processes = 1;
+  Utilities::MPI::MPI_InitFinalize mpi_initialization(argc, argv, n_tbb_processes);
+
+  try
+    {
+      Parameters::AllParameters parameters ("parameters.prm");
+      if (parameters.geom_type == "Ehlers_tube_step_load")
+      {
+        VerificationEhlers1999StepLoad<3> solid_3d(parameters);
+        solid_3d.run();
+      }
+      else if (parameters.geom_type == "Ehlers_tube_increase_load")
+      {
+        VerificationEhlers1999IncreaseLoad<3> solid_3d(parameters);
+        solid_3d.run();
+      }
+      else if (parameters.geom_type == "Ehlers_cube_consolidation")
+      {
+        VerificationEhlers1999CubeConsolidation<3> solid_3d(parameters);
+        solid_3d.run();
+      }
+      else if (parameters.geom_type == "Franceschini_consolidation")
+      {
+        Franceschini2006Consolidation<3> solid_3d(parameters);
+        solid_3d.run();
+      }
+      else if (parameters.geom_type == "Budday_cube_tension_compression")
+      {
+        BrainBudday2017CubeTensionCompression<3> solid_3d(parameters);
+        solid_3d.run();
+      }
+      else if (parameters.geom_type == "Budday_cube_tension_compression_fully_fixed")
+      {
+        BrainBudday2017CubeTensionCompressionFullyFixed<3> solid_3d(parameters);
+        solid_3d.run();
+      }
+      else if (parameters.geom_type == "Budday_cube_shear_fully_fixed")
+      {
+        BrainBudday2017CubeShearFullyFixed<3> solid_3d(parameters);
+        solid_3d.run();
+      }
+      else
+      {
+        AssertThrow(false, ExcMessage("Problem type not defined. Current setting: " + parameters.geom_type));
+      }
+
+    }
+  catch (std::exception &exc)
+    {
+      if (Utilities::MPI::this_mpi_process(MPI_COMM_WORLD) == 0)
+      {
+          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 (...)
+    {
+      if (Utilities::MPI::this_mpi_process(MPI_COMM_WORLD) == 0)
+      {
+          std::cerr << std::endl << std::endl
+                    << "----------------------------------------------------"
+                    << std::endl;
+          std::cerr << "Unknown exception!" << std::endl << "Aborting!"
+                    << std::endl
+                    << "----------------------------------------------------"
+                    << std::endl;
+          return 1;
+      }
+    }
+  return 0;
+}

In the beginning the Universe was created. This has made a lot of people very angry and has been widely regarded as a bad move.

Douglas Adams


Typeset in Trocchi and Trocchi Bold Sans Serif.