diff --git a/Documentation/ProjectFile/material/solid/constitutive_relation/Lubby2/nonlinear_solver/i_nonlinear_solver.md b/Documentation/ProjectFile/material/solid/constitutive_relation/Lubby2/nonlinear_solver/i_nonlinear_solver.md deleted file mode 100644 index f6d09b0017c9833e58880901daacfa3631a13458..0000000000000000000000000000000000000000 --- a/Documentation/ProjectFile/material/solid/constitutive_relation/Lubby2/nonlinear_solver/i_nonlinear_solver.md +++ /dev/null @@ -1,2 +0,0 @@ -Local nonlinear solver configuration used in the constitutive relation -computation. The nonlinear solver is the NumLib::NewtonRaphson solver. diff --git a/Documentation/ProjectFile/material/solid/constitutive_relation/Lubby2/nonlinear_solver/t_error_tolerance.md b/Documentation/ProjectFile/material/solid/constitutive_relation/Lubby2/nonlinear_solver/t_error_tolerance.md deleted file mode 100644 index ccae39ea3ad802a7b785d4e758ad7b39757862cd..0000000000000000000000000000000000000000 --- a/Documentation/ProjectFile/material/solid/constitutive_relation/Lubby2/nonlinear_solver/t_error_tolerance.md +++ /dev/null @@ -1 +0,0 @@ -\copydoc NumLib::NewtonRaphson::_tolerance_squared diff --git a/Documentation/ProjectFile/material/solid/constitutive_relation/Lubby2/nonlinear_solver/t_maximum_iterations.md b/Documentation/ProjectFile/material/solid/constitutive_relation/Lubby2/nonlinear_solver/t_maximum_iterations.md deleted file mode 100644 index c9b32edcfe5664c6a8bf684a2be2043ac4658c28..0000000000000000000000000000000000000000 --- a/Documentation/ProjectFile/material/solid/constitutive_relation/Lubby2/nonlinear_solver/t_maximum_iterations.md +++ /dev/null @@ -1 +0,0 @@ -\copydoc NumLib::NewtonRaphson::_maximum_iterations diff --git a/Documentation/ProjectFile/material/solid/constitutive_relation/Ehlers/nonlinear_solver/i_nonlinear_solver.md b/Documentation/ProjectFile/material/solid/constitutive_relation/nonlinear_solver/i_nonlinear_solver.md similarity index 100% rename from Documentation/ProjectFile/material/solid/constitutive_relation/Ehlers/nonlinear_solver/i_nonlinear_solver.md rename to Documentation/ProjectFile/material/solid/constitutive_relation/nonlinear_solver/i_nonlinear_solver.md diff --git a/Documentation/ProjectFile/material/solid/constitutive_relation/Ehlers/nonlinear_solver/t_error_tolerance.md b/Documentation/ProjectFile/material/solid/constitutive_relation/nonlinear_solver/t_error_tolerance.md similarity index 100% rename from Documentation/ProjectFile/material/solid/constitutive_relation/Ehlers/nonlinear_solver/t_error_tolerance.md rename to Documentation/ProjectFile/material/solid/constitutive_relation/nonlinear_solver/t_error_tolerance.md diff --git a/Documentation/ProjectFile/material/solid/constitutive_relation/Ehlers/nonlinear_solver/t_maximum_iterations.md b/Documentation/ProjectFile/material/solid/constitutive_relation/nonlinear_solver/t_maximum_iterations.md similarity index 100% rename from Documentation/ProjectFile/material/solid/constitutive_relation/Ehlers/nonlinear_solver/t_maximum_iterations.md rename to Documentation/ProjectFile/material/solid/constitutive_relation/nonlinear_solver/t_maximum_iterations.md diff --git a/MaterialLib/SolidModels/CreateConstitutiveRelation.cpp b/MaterialLib/SolidModels/CreateConstitutiveRelation.cpp new file mode 100644 index 0000000000000000000000000000000000000000..29de544b866b0f4f7a7628ec09786a25f616c97f --- /dev/null +++ b/MaterialLib/SolidModels/CreateConstitutiveRelation.cpp @@ -0,0 +1,75 @@ +/** + * \copyright + * Copyright (c) 2012-2018, OpenGeoSys Community (http://www.opengeosys.org) + * Distributed under a Modified BSD License. + * See accompanying file LICENSE.txt or + * http://www.opengeosys.org/project/license + * + * \file CreateConstitutiveRelation.cpp + * Created on July 10, 2018, 12:09 PM + */ + +#include "CreateConstitutiveRelation.h" +#include "CreateEhlers.h" +#include "CreateLinearElasticIsotropic.h" +#include "CreateLubby2.h" + +#include "MechanicsBase.h" + +#include "BaseLib/ConfigTree.h" +#include "BaseLib/Error.h" + +#include "ProcessLib/Parameter/Parameter.h" + +namespace MaterialLib +{ +namespace Solids +{ +template <int DisplacementDim> +std::unique_ptr<MaterialLib::Solids::MechanicsBase<DisplacementDim>> +createConstitutiveRelation( + std::vector<std::unique_ptr<ProcessLib::ParameterBase>> const& parameters, + BaseLib::ConfigTree const& config) +{ + auto const constitutive_relation_config = + //! \ogs_file_param{material__solid__constitutive_relation} + config.getConfigSubtree("constitutive_relation"); + + auto const type = + //! \ogs_file_param{material__solid__constitutive_relation__type} + constitutive_relation_config.peekConfigParameter<std::string>("type"); + + if (type == "Ehlers") + { + return MaterialLib::Solids::Ehlers::createEhlers<DisplacementDim>( + parameters, constitutive_relation_config); + } + else if (type == "LinearElasticIsotropic") + { + return MaterialLib::Solids::createLinearElasticIsotropic< + DisplacementDim>(parameters, constitutive_relation_config); + } + else if (type == "Lubby2") + { + return MaterialLib::Solids::Lubby2::createLubby2<DisplacementDim>( + parameters, constitutive_relation_config); + } + else + { + OGS_FATAL( + "Cannot construct constitutive relation of given type \'%s\'.", + type.c_str()); + } +} + +template std::unique_ptr<MaterialLib::Solids::MechanicsBase<2>> +createConstitutiveRelation<2>( + std::vector<std::unique_ptr<ProcessLib::ParameterBase>> const& parameters, + BaseLib::ConfigTree const& config); + +template std::unique_ptr<MaterialLib::Solids::MechanicsBase<3>> +createConstitutiveRelation<3>( + std::vector<std::unique_ptr<ProcessLib::ParameterBase>> const& parameters, + BaseLib::ConfigTree const& config); +} +} diff --git a/MaterialLib/SolidModels/CreateConstitutiveRelation.h b/MaterialLib/SolidModels/CreateConstitutiveRelation.h new file mode 100644 index 0000000000000000000000000000000000000000..15c43ebf81a20513d59894b0c8be6b0a036049b6 --- /dev/null +++ b/MaterialLib/SolidModels/CreateConstitutiveRelation.h @@ -0,0 +1,50 @@ +/** + * \copyright + * Copyright (c) 2012-2018, OpenGeoSys Community (http://www.opengeosys.org) + * Distributed under a Modified BSD License. + * See accompanying file LICENSE.txt or + * http://www.opengeosys.org/project/license + * + * \file CreateConstitutiveRelation.h + * Created on July 10, 2018, 12:09 PM + */ + +#pragma once + +#include <memory> +#include <vector> + +namespace BaseLib +{ +class ConfigTree; +} + +namespace ProcessLib +{ +struct ParameterBase; +} + +namespace MaterialLib +{ +namespace Solids +{ +template <int DisplacementDim> +struct MechanicsBase; + +template <int DisplacementDim> +std::unique_ptr<MaterialLib::Solids::MechanicsBase<DisplacementDim>> +createConstitutiveRelation( + std::vector<std::unique_ptr<ProcessLib::ParameterBase>> const& parameters, + BaseLib::ConfigTree const& config); + +extern template std::unique_ptr<MaterialLib::Solids::MechanicsBase<2>> +createConstitutiveRelation<2>( + std::vector<std::unique_ptr<ProcessLib::ParameterBase>> const& parameters, + BaseLib::ConfigTree const& config); + +extern template std::unique_ptr<MaterialLib::Solids::MechanicsBase<3>> +createConstitutiveRelation<3>( + std::vector<std::unique_ptr<ProcessLib::ParameterBase>> const& parameters, + BaseLib::ConfigTree const& config); +} +} diff --git a/MaterialLib/SolidModels/CreateEhlers.h b/MaterialLib/SolidModels/CreateEhlers.h index 3969fef891a576da7202fbee04e4e01d34318ed0..7d181c1d85ec1439a4a23fdd277bfb80b959b8fa 100644 --- a/MaterialLib/SolidModels/CreateEhlers.h +++ b/MaterialLib/SolidModels/CreateEhlers.h @@ -9,6 +9,7 @@ #pragma once +#include "CreateNewtonRaphsonSolverParameters.h" #include "ProcessLib/Utils/ProcessUtils.h" // required for findParameter #include "Ehlers.h" @@ -18,25 +19,6 @@ namespace Solids { namespace Ehlers { -inline NumLib::NewtonRaphsonSolverParameters -createNewtonRaphsonSolverParameters(BaseLib::ConfigTree const& config) -{ - DBUG("Create local nonlinear solver parameters."); - auto const maximum_iterations = - //! \ogs_file_param{material__solid__constitutive_relation__Ehlers__nonlinear_solver__maximum_iterations} - config.getConfigParameter<int>("maximum_iterations"); - - DBUG("\tmaximum_iterations: %d.", maximum_iterations); - - auto const error_tolerance = - //! \ogs_file_param{material__solid__constitutive_relation__Ehlers__nonlinear_solver__error_tolerance} - config.getConfigParameter<double>("error_tolerance"); - - DBUG("\terror_tolerance: %g.", error_tolerance); - - return {maximum_iterations, error_tolerance}; -} - inline std::unique_ptr<DamagePropertiesParameters> createDamageProperties( std::vector<std::unique_ptr<ProcessLib::ParameterBase>> const& parameters, BaseLib::ConfigTree const& config) @@ -184,11 +166,8 @@ std::unique_ptr<SolidEhlers<DisplacementDim>> createEhlers( createDamageProperties(parameters, *ehlers_damage_config); } - auto const& nonlinear_solver_config = - //! \ogs_file_param{material__solid__constitutive_relation__Ehlers__nonlinear_solver} - config.getConfigSubtree("nonlinear_solver"); auto const nonlinear_solver_parameters = - createNewtonRaphsonSolverParameters(nonlinear_solver_config); + createNewtonRaphsonSolverParameters(config); return std::make_unique<SolidEhlers<DisplacementDim>>( nonlinear_solver_parameters, mp, std::move(ehlers_damage_properties)); diff --git a/MaterialLib/SolidModels/CreateLubby2.h b/MaterialLib/SolidModels/CreateLubby2.h index 145d17e970a1ef847b09b299de0af8c15827bc1f..569d546e3805977d0838c53cf9a4aee6d51165c0 100644 --- a/MaterialLib/SolidModels/CreateLubby2.h +++ b/MaterialLib/SolidModels/CreateLubby2.h @@ -9,6 +9,7 @@ #pragma once +#include "CreateNewtonRaphsonSolverParameters.h" #include "ProcessLib/Utils/ProcessUtils.h" // required for findParameter #include "Lubby2.h" @@ -19,25 +20,6 @@ namespace Solids { namespace Lubby2 { -inline NumLib::NewtonRaphsonSolverParameters -createNewtonRaphsonSolverParameters(BaseLib::ConfigTree const& config) -{ - DBUG("Create local nonlinear solver parameters."); - auto const maximum_iterations = - //! \ogs_file_param{material__solid__constitutive_relation__Lubby2__nonlinear_solver__maximum_iterations} - config.getConfigParameter<int>("maximum_iterations"); - - DBUG("\tmaximum_iterations: %d.", maximum_iterations); - - auto const error_tolerance = - //! \ogs_file_param{material__solid__constitutive_relation__Lubby2__nonlinear_solver__error_tolerance} - config.getConfigParameter<double>("error_tolerance"); - - DBUG("\terror_tolerance: %g.", error_tolerance); - - return {maximum_iterations, error_tolerance}; -} - template <int DisplacementDim> std::unique_ptr<Lubby2<DisplacementDim>> createLubby2( std::vector<std::unique_ptr<ProcessLib::ParameterBase>> const& parameters, @@ -117,11 +99,8 @@ std::unique_ptr<Lubby2<DisplacementDim>> createLubby2( maxwell_viscosity, dependency_parameter_mK, dependency_parameter_mvK, dependency_parameter_mvM}; - auto const& nonlinear_solver_config = - //! \ogs_file_param{material__solid__constitutive_relation__Lubby2__nonlinear_solver} - config.getConfigSubtree("nonlinear_solver"); auto const nonlinear_solver_parameters = - createNewtonRaphsonSolverParameters(nonlinear_solver_config); + createNewtonRaphsonSolverParameters(config); return std::unique_ptr<Lubby2<DisplacementDim>>{ new Lubby2<DisplacementDim>{nonlinear_solver_parameters, mp}}; diff --git a/MaterialLib/SolidModels/CreateNewtonRaphsonSolverParameters.cpp b/MaterialLib/SolidModels/CreateNewtonRaphsonSolverParameters.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2ffd162f6fa36abce71c2bdcc9303fa04bc205d4 --- /dev/null +++ b/MaterialLib/SolidModels/CreateNewtonRaphsonSolverParameters.cpp @@ -0,0 +1,43 @@ +/** + * \copyright + * Copyright (c) 2012-2018, OpenGeoSys Community (http://www.opengeosys.org) + * Distributed under a Modified BSD License. + * See accompanying file LICENSE.txt or + * http://www.opengeosys.org/project/license + * + * \file CreateNewtonRaphsonSolverParameters.cpp + * Created on July 10, 2018, 11:32 AM + */ + +#include "CreateNewtonRaphsonSolverParameters.h" + +#include "BaseLib/ConfigTree.h" +#include "BaseLib/Error.h" + +#include "NumLib/NewtonRaphson.h" + +namespace MaterialLib +{ +NumLib::NewtonRaphsonSolverParameters createNewtonRaphsonSolverParameters( + BaseLib::ConfigTree const& config) +{ + DBUG("Create local nonlinear solver parameters."); + auto const& nonlinear_solver_config = + //! \ogs_file_param{material__solid__constitutive_relation__nonlinear_solver} + config.getConfigSubtree("nonlinear_solver"); + + auto const maximum_iterations = + //! \ogs_file_param{material__solid__constitutive_relation__nonlinear_solver__maximum_iterations} + nonlinear_solver_config.getConfigParameter<int>("maximum_iterations"); + + DBUG("\tmaximum_iterations: %d.", maximum_iterations); + + auto const error_tolerance = + //! \ogs_file_param{material__solid__constitutive_relation__nonlinear_solver__error_tolerance} + nonlinear_solver_config.getConfigParameter<double>("error_tolerance"); + + DBUG("\terror_tolerance: %g.", error_tolerance); + + return {maximum_iterations, error_tolerance}; +} +} diff --git a/MaterialLib/SolidModels/CreateNewtonRaphsonSolverParameters.h b/MaterialLib/SolidModels/CreateNewtonRaphsonSolverParameters.h new file mode 100644 index 0000000000000000000000000000000000000000..6ecfb79d875d63b23b678d22f22f64590eb0f8da --- /dev/null +++ b/MaterialLib/SolidModels/CreateNewtonRaphsonSolverParameters.h @@ -0,0 +1,28 @@ +/** + * \copyright + * Copyright (c) 2012-2018, OpenGeoSys Community (http://www.opengeosys.org) + * Distributed under a Modified BSD License. + * See accompanying file LICENSE.txt or + * http://www.opengeosys.org/project/license + * + * \file CreateNewtonRaphsonSolverParameters.h + * Created on July 10, 2018, 11:32 AM + */ + +#pragma once + +namespace BaseLib +{ +class ConfigTree; +} + +namespace NumLib +{ +struct NewtonRaphsonSolverParameters; +} + +namespace MaterialLib +{ +NumLib::NewtonRaphsonSolverParameters createNewtonRaphsonSolverParameters( + BaseLib::ConfigTree const& config); +} diff --git a/MaterialLib/SolidModels/Ehlers-impl.h b/MaterialLib/SolidModels/Ehlers-impl.h deleted file mode 100644 index e6327db8434afaa341e42cc7d5db06f995c6c5aa..0000000000000000000000000000000000000000 --- a/MaterialLib/SolidModels/Ehlers-impl.h +++ /dev/null @@ -1,717 +0,0 @@ -/** - * \copyright - * Copyright (c) 2012-2018, OpenGeoSys Community (http://www.opengeosys.org) - * Distributed under a Modified BSD License. - * See accompanying file LICENSE.txt or - * http://www.opengeosys.org/project/license - * - */ - -/** - * Common convenitions for naming: - * x_D - deviatoric part of tensor x - * x_V - volumetric part of tensor x - * x_p - a variable related to plastic potential - * x_prev - value of x in previous time step - * - * Variables used in the code: - * eps_D - deviatoric strain - * eps_p_D_dot - deviatoric increment of plastic strain - * eps_p_eff_dot - increment of effective plastic strain - * eps_p_V_dot - volumetric increment of plastic strain - * sigma_D_inverse_D - deviatoric part of sigma_D_inverse - * - * derivation of the flow rule - * theta - J3 / J2^(3 / 2) from yield function - * dtheta_dsigma - derivative of theta - * sqrtPhi - square root of Phi from plastic potential - * flow_D - deviatoric part of flow - * flow_V - volumetric part of flow - * lambda_flow_D - deviatoric increment of plastic strain - * - */ -#pragma once - -#include <boost/math/special_functions/pow.hpp> - -#include "MathLib/LinAlg/Eigen/EigenMapTools.h" - -namespace MaterialLib -{ -namespace Solids -{ -namespace Ehlers -{ -/// Special product of \c v with itself: \f$v \odot v\f$. -/// The tensor \c v is given in Kelvin mapping. -/// \note Implementation only for 2 and 3 dimensions. -/// \attention Pay attention to the sign of the result, which normally would be -/// negative, but the returned value is not negated. This has to do with \f$ -/// d(A^{-1})/dA = -A^{-1} \odot A^{-1} \f$. -template <int DisplacementDim> -MathLib::KelvinVector::KelvinMatrixType<DisplacementDim> sOdotS( - MathLib::KelvinVector::KelvinVectorType<DisplacementDim> const& v); - -template <int DisplacementDim> -struct PhysicalStressWithInvariants final -{ - static int const KelvinVectorSize = - MathLib::KelvinVector::KelvinVectorDimensions<DisplacementDim>::value; - using Invariants = MathLib::KelvinVector::Invariants<KelvinVectorSize>; - using KelvinVector = - MathLib::KelvinVector::KelvinVectorType<DisplacementDim>; - - explicit PhysicalStressWithInvariants(KelvinVector const& stress) - : value{stress}, - D{Invariants::deviatoric_projection * stress}, - I_1{Invariants::trace(stress)}, - J_2{Invariants::J2(D)}, - J_3{Invariants::J3(D)} - { - } - - KelvinVector value; - KelvinVector D; - double I_1; - double J_2; - double J_3; - - EIGEN_MAKE_ALIGNED_OPERATOR_NEW; -}; - -/// Holds powers of 1 + gamma_p*theta to base 0, m_p, and m_p-1. -struct OnePlusGamma_pTheta final -{ - OnePlusGamma_pTheta(double const gamma_p, double const theta, - double const m_p) - : value{1 + gamma_p * theta}, - pow_m_p{std::pow(value, m_p)}, - pow_m_p1{pow_m_p / value} - { - } - - double const value; - double const pow_m_p; - double const pow_m_p1; -}; - -template <int DisplacementDim> -double plasticFlowVolumetricPart( - PhysicalStressWithInvariants<DisplacementDim> const& s, - double const sqrtPhi, double const alpha_p, double const beta_p, - double const delta_p, double const epsilon_p) -{ - return 3 * (alpha_p * s.I_1 + - 4 * boost::math::pow<2>(delta_p) * boost::math::pow<3>(s.I_1)) / - (2 * sqrtPhi) + - 3 * beta_p + 6 * epsilon_p * s.I_1; -} - -template <int DisplacementDim> -typename SolidEhlers<DisplacementDim>::KelvinVector plasticFlowDeviatoricPart( - PhysicalStressWithInvariants<DisplacementDim> const& s, - OnePlusGamma_pTheta const& one_gt, double const sqrtPhi, - typename SolidEhlers<DisplacementDim>::KelvinVector const& dtheta_dsigma, - double const gamma_p, double const m_p) -{ - return (one_gt.pow_m_p * - (s.D + s.J_2 * m_p * gamma_p * dtheta_dsigma / one_gt.value)) / - (2 * sqrtPhi); -} - -template <int DisplacementDim> -double yieldFunction(MaterialProperties const& mp, - PhysicalStressWithInvariants<DisplacementDim> const& s, - double const k) -{ - double const I_1_squared = boost::math::pow<2>(s.I_1); - assert(s.J_2 != 0); - - return std::sqrt( - s.J_2 * - std::pow(1 + mp.gamma * s.J_3 / (s.J_2 * std::sqrt(s.J_2)), - mp.m) + - mp.alpha / 2. * I_1_squared + - boost::math::pow<2>(mp.delta) * - boost::math::pow<2>(I_1_squared)) + - mp.beta * s.I_1 + mp.epsilon * I_1_squared - k; -} - -template <int DisplacementDim> -typename SolidEhlers<DisplacementDim>::ResidualVectorType -calculatePlasticResidual( - MathLib::KelvinVector::KelvinVectorType<DisplacementDim> const& eps_D, - double const eps_V, - PhysicalStressWithInvariants<DisplacementDim> const& s, - MathLib::KelvinVector::KelvinVectorType<DisplacementDim> const& eps_p_D, - MathLib::KelvinVector::KelvinVectorType<DisplacementDim> const& eps_p_D_dot, - double const eps_p_V, - double const eps_p_V_dot, - double const eps_p_eff_dot, - double const lambda, - double const k, - MaterialProperties const& mp) -{ - static int const KelvinVectorSize = - MathLib::KelvinVector::KelvinVectorDimensions<DisplacementDim>::value; - using Invariants = MathLib::KelvinVector::Invariants<KelvinVectorSize>; - using KelvinVector = - MathLib::KelvinVector::KelvinVectorType<DisplacementDim>; - - auto const& P_dev = Invariants::deviatoric_projection; - auto const& identity2 = Invariants::identity2; - - double const theta = s.J_3 / (s.J_2 * std::sqrt(s.J_2)); - - typename SolidEhlers<DisplacementDim>::ResidualVectorType residual; - // calculate stress residual - residual.template segment<KelvinVectorSize>(0).noalias() = - s.value / mp.G - 2 * (eps_D - eps_p_D) - - mp.K / mp.G * (eps_V - eps_p_V) * identity2; - - // deviatoric plastic strain - KelvinVector const sigma_D_inverse_D = - P_dev * MathLib::KelvinVector::inverse(s.D); - KelvinVector const dtheta_dsigma = - theta * sigma_D_inverse_D - 3. / 2. * theta / s.J_2 * s.D; - - OnePlusGamma_pTheta const one_gt{mp.gamma_p, theta, mp.m_p}; - double const sqrtPhi = std::sqrt( - s.J_2 * one_gt.pow_m_p + mp.alpha_p / 2. * boost::math::pow<2>(s.I_1) + - boost::math::pow<2>(mp.delta_p) * boost::math::pow<4>(s.I_1)); - KelvinVector const flow_D = plasticFlowDeviatoricPart( - s, one_gt, sqrtPhi, dtheta_dsigma, mp.gamma_p, mp.m_p); - KelvinVector const lambda_flow_D = lambda * flow_D; - - residual.template segment<KelvinVectorSize>(KelvinVectorSize).noalias() = - eps_p_D_dot - lambda_flow_D; - - // plastic volume strain - { - double const flow_V = plasticFlowVolumetricPart<DisplacementDim>( - s, sqrtPhi, mp.alpha_p, mp.beta_p, mp.delta_p, mp.epsilon_p); - residual(2 * KelvinVectorSize, 0) = eps_p_V_dot - lambda * flow_V; - } - - // evolution of plastic equivalent strain - residual(2 * KelvinVectorSize + 1) = - eps_p_eff_dot - - std::sqrt(2. / 3. * lambda_flow_D.transpose() * lambda_flow_D); - - // yield function (for plastic multiplier) - residual(2 * KelvinVectorSize + 2) = yieldFunction(mp, s, k) / mp.G; - return residual; -} - -template <int DisplacementDim> -typename SolidEhlers<DisplacementDim>::JacobianMatrix calculatePlasticJacobian( - double const dt, - PhysicalStressWithInvariants<DisplacementDim> const& s, - double const lambda, - MaterialProperties const& mp) -{ - static int const KelvinVectorSize = - MathLib::KelvinVector::KelvinVectorDimensions<DisplacementDim>::value; - using Invariants = MathLib::KelvinVector::Invariants<KelvinVectorSize>; - using KelvinVector = - MathLib::KelvinVector::KelvinVectorType<DisplacementDim>; - using KelvinMatrix = - MathLib::KelvinVector::KelvinMatrixType<DisplacementDim>; - - auto const& P_dev = Invariants::deviatoric_projection; - auto const& identity2 = Invariants::identity2; - - double const theta = s.J_3 / (s.J_2 * std::sqrt(s.J_2)); - OnePlusGamma_pTheta const one_gt{mp.gamma_p, theta, mp.m_p}; - - // inverse of deviatoric stress tensor - if (Invariants::determinant(s.D) == 0) - { - OGS_FATAL("Determinant is zero. Matrix is non-invertable."); - } - // inverse of sigma_D - KelvinVector const sigma_D_inverse = MathLib::KelvinVector::inverse(s.D); - KelvinVector const sigma_D_inverse_D = P_dev * sigma_D_inverse; - - KelvinVector const dtheta_dsigma = - theta * sigma_D_inverse_D - 3. / 2. * theta / s.J_2 * s.D; - - // deviatoric flow - double const sqrtPhi = std::sqrt( - s.J_2 * one_gt.pow_m_p + mp.alpha_p / 2. * boost::math::pow<2>(s.I_1) + - boost::math::pow<2>(mp.delta_p) * boost::math::pow<4>(s.I_1)); - KelvinVector const flow_D = plasticFlowDeviatoricPart( - s, one_gt, sqrtPhi, dtheta_dsigma, mp.gamma_p, mp.m_p); - KelvinVector const lambda_flow_D = lambda * flow_D; - - typename SolidEhlers<DisplacementDim>::JacobianMatrix jacobian = - SolidEhlers<DisplacementDim>::JacobianMatrix::Zero(); - - // G_11 - jacobian.template block<KelvinVectorSize, KelvinVectorSize>(0, 0) - .noalias() = KelvinMatrix::Identity(); - - // G_12 - jacobian - .template block<KelvinVectorSize, KelvinVectorSize>(0, KelvinVectorSize) - .noalias() = 2 * KelvinMatrix::Identity(); - - // G_13 - jacobian.template block<KelvinVectorSize, 1>(0, 2 * KelvinVectorSize) - .noalias() = mp.K / mp.G * identity2; - - // G_14 and G_15 are zero - - // G_21 -- derivative of deviatoric flow - - double const gm_p = mp.gamma_p * mp.m_p; - // intermediate variable for derivative of deviatoric flow - KelvinVector const M0 = s.J_2 / one_gt.value * dtheta_dsigma; - // derivative of Phi w.r.t. sigma - KelvinVector const dPhi_dsigma = - one_gt.pow_m_p * (s.D + gm_p * M0) + - (mp.alpha_p * s.I_1 + - 4 * boost::math::pow<2>(mp.delta_p) * boost::math::pow<3>(s.I_1)) * - identity2; - - // intermediate variable for derivative of deviatoric flow - KelvinMatrix const M1 = - one_gt.pow_m_p * - (s.D * dPhi_dsigma.transpose() + gm_p * M0 * dPhi_dsigma.transpose()); - // intermediate variable for derivative of deviatoric flow - KelvinMatrix const M2 = - one_gt.pow_m_p * (P_dev + s.D * gm_p * M0.transpose()); - // second derivative of theta - KelvinMatrix const d2theta_dsigma2 = - theta * P_dev * sOdotS<DisplacementDim>(sigma_D_inverse) * P_dev + - sigma_D_inverse_D * dtheta_dsigma.transpose() - - 3. / 2. * theta / s.J_2 * P_dev - - 3. / 2. * dtheta_dsigma / s.J_2 * s.D.transpose() + - 3. / 2. * theta / boost::math::pow<2>(s.J_2) * s.D * s.D.transpose(); - - // intermediate variable for derivative of deviatoric flow - KelvinMatrix const M3 = - gm_p * one_gt.pow_m_p1 * - ((s.D + (gm_p - mp.gamma_p) * M0) * dtheta_dsigma.transpose() + - s.J_2 * d2theta_dsigma2); - - // derivative of flow_D w.r.t. sigma - KelvinMatrix const dflow_D_dsigma = - (-M1 / (4 * boost::math::pow<3>(sqrtPhi)) + (M2 + M3) / (2 * sqrtPhi)) * - mp.G; - jacobian - .template block<KelvinVectorSize, KelvinVectorSize>(KelvinVectorSize, 0) - .noalias() = -lambda * dflow_D_dsigma; - - // G_22 - jacobian - .template block<KelvinVectorSize, KelvinVectorSize>(KelvinVectorSize, - KelvinVectorSize) - .noalias() = KelvinMatrix::Identity() / dt; - - // G_23 and G_24 are zero - - // G_25 - jacobian - .template block<KelvinVectorSize, 1>(KelvinVectorSize, - 2 * KelvinVectorSize + 2) - .noalias() = -flow_D; - - // G_31 - { - // derivative of flow_V w.r.t. sigma - KelvinVector const dflow_V_dsigma = - 3 * mp.G * - (-(mp.alpha_p * s.I_1 + - 4 * boost::math::pow<2>(mp.delta_p) * - boost::math::pow<3>(s.I_1)) / - (4 * boost::math::pow<3>(sqrtPhi)) * dPhi_dsigma + - (mp.alpha_p * identity2 + - 12 * boost::math::pow<2>(mp.delta_p * s.I_1) * identity2) / - (2 * sqrtPhi) + - 2 * mp.epsilon_p * identity2); - - jacobian.template block<1, KelvinVectorSize>(2 * KelvinVectorSize, 0) - .noalias() = -lambda * dflow_V_dsigma.transpose(); - } - - // G_32 is zero - - // G_33 - jacobian(2 * KelvinVectorSize, 2 * KelvinVectorSize) = 1. / dt; - - // G_34 is zero - - // G_35 - { - double const flow_V = plasticFlowVolumetricPart<DisplacementDim>( - s, sqrtPhi, mp.alpha_p, mp.beta_p, mp.delta_p, mp.epsilon_p); - jacobian(2 * KelvinVectorSize, 2 * KelvinVectorSize + 2) = -flow_V; - } - - // increment of effectiv plastic strain - double const eff_flow = - std::sqrt(2. / 3. * lambda_flow_D.transpose() * lambda_flow_D); - - if (eff_flow > 0) - { - // intermediate variable for derivative of plastic jacobian - KelvinVector const eff_flow23_lambda_flow_D = - -2 / 3. / eff_flow * lambda_flow_D; - // G_41 - jacobian - .template block<1, KelvinVectorSize>(2 * KelvinVectorSize + 1, 0) - .noalias() = lambda * dflow_D_dsigma * eff_flow23_lambda_flow_D; - // G_45 - jacobian(2 * KelvinVectorSize + 1, 2 * KelvinVectorSize + 2) = - eff_flow23_lambda_flow_D.transpose() * flow_D; - } - - // G_42 and G_43 are zero - - // G_44 - jacobian(2 * KelvinVectorSize + 1, 2 * KelvinVectorSize + 1) = 1. / dt; - - // G_51 - { - double const one_gt_pow_m = std::pow(one_gt.value, mp.m); - double const gm = mp.gamma * mp.m; - // derivative of yield function w.r.t. sigma - KelvinVector const dF_dsigma = - mp.G * (one_gt_pow_m * (s.D + gm * M0) + - (mp.alpha * s.I_1 + - 4 * boost::math::pow<2>(mp.delta) * - boost::math::pow<3>(s.I_1)) * - identity2) / - (2. * sqrtPhi) + - mp.G * (mp.beta + 2 * mp.epsilon_p * s.I_1) * identity2; - - jacobian - .template block<1, KelvinVectorSize>(2 * KelvinVectorSize + 2, 0) - .noalias() = dF_dsigma.transpose() / mp.G; - } - - // G_54 - jacobian(2 * KelvinVectorSize + 2, 2 * KelvinVectorSize + 1) = - -mp.kappa * mp.hardening_coefficient / mp.G; - - // G_52, G_53, G_55 are zero - return jacobian; -} - -/// Calculates the derivative of the residuals with respect to total -/// strain. Implementation fully implicit only. -template <int DisplacementDim> -MathLib::KelvinVector::KelvinMatrixType<DisplacementDim> calculateDResidualDEps( - double const K, double const G) -{ - static int const KelvinVectorSize = - MathLib::KelvinVector::KelvinVectorDimensions<DisplacementDim>::value; - using Invariants = MathLib::KelvinVector::Invariants<KelvinVectorSize>; - - auto const& P_dev = Invariants::deviatoric_projection; - auto const& P_sph = Invariants::spherical_projection; - auto const& I = - MathLib::KelvinVector::KelvinMatrixType<DisplacementDim>::Identity(); - - return -2. * I * P_dev - 3. * K / G * I * P_sph; -} - -inline double calculateIsotropicHardening(double const kappa, - double const hardening_coefficient, - double const eps_p_eff) -{ - return kappa * (1. + eps_p_eff * hardening_coefficient); -} - -template <int DisplacementDim> -typename SolidEhlers<DisplacementDim>::KelvinVector predict_sigma( - double const G, double const K, - typename SolidEhlers<DisplacementDim>::KelvinVector const& sigma_prev, - typename SolidEhlers<DisplacementDim>::KelvinVector const& eps, - typename SolidEhlers<DisplacementDim>::KelvinVector const& eps_prev, - double const eps_V) -{ - static int const KelvinVectorSize = - MathLib::KelvinVector::KelvinVectorDimensions<DisplacementDim>::value; - using Invariants = MathLib::KelvinVector::Invariants<KelvinVectorSize>; - auto const& P_dev = Invariants::deviatoric_projection; - - // dimensionless initial hydrostatic pressure - double const pressure_prev = Invariants::trace(sigma_prev) / (-3. * G); - // initial strain invariant - double const e_prev = Invariants::trace(eps_prev); - // dimensioness hydrostatic stress increment - double const pressure = pressure_prev - K / G * (eps_V - e_prev); - // dimensionless deviatoric initial stress - typename SolidEhlers<DisplacementDim>::KelvinVector const sigma_D_prev = - P_dev * sigma_prev / G; - // dimensionless deviatoric stress - typename SolidEhlers<DisplacementDim>::KelvinVector const sigma_D = - sigma_D_prev + 2 * P_dev * (eps - eps_prev); - return sigma_D - pressure * Invariants::identity2; -} - -/// Split the agglomerated solution vector in separate items. The arrangement -/// must be the same as in the newton() function. -template <typename ResidualVector, typename KelvinVector> -std::tuple<KelvinVector, PlasticStrain<KelvinVector>, double> -splitSolutionVector(ResidualVector const& solution) -{ - static auto const size = KelvinVector::SizeAtCompileTime; - return std::forward_as_tuple( - solution.template segment<size>(size * 0), - PlasticStrain<KelvinVector>{solution.template segment<size>(size * 1), - solution[size * 2], solution[size * 2 + 1]}, - solution[size * 2 + 2]); -} - -template <int DisplacementDim> -boost::optional<std::tuple<typename SolidEhlers<DisplacementDim>::KelvinVector, - std::unique_ptr<typename MechanicsBase< - DisplacementDim>::MaterialStateVariables>, - typename SolidEhlers<DisplacementDim>::KelvinMatrix>> -SolidEhlers<DisplacementDim>::integrateStress( - double const t, - ProcessLib::SpatialPosition const& x, - double const dt, - KelvinVector const& eps_prev, - KelvinVector const& eps, - KelvinVector const& sigma_prev, - typename MechanicsBase<DisplacementDim>::MaterialStateVariables const& - material_state_variables) -{ - assert(dynamic_cast<StateVariables<DisplacementDim> const*>( - &material_state_variables) != nullptr); - - StateVariables<DisplacementDim> state = - static_cast<StateVariables<DisplacementDim> const&>( - material_state_variables); - state.setInitialConditions(); - - using Invariants = MathLib::KelvinVector::Invariants<KelvinVectorSize>; - - // volumetric strain - double const eps_V = Invariants::trace(eps); - - auto const& P_dev = Invariants::deviatoric_projection; - // deviatoric strain - KelvinVector const eps_D = P_dev * eps; - - // do the evaluation once per function call. - MaterialProperties const mp(t, x, _mp); - - KelvinVector sigma = predict_sigma<DisplacementDim>(mp.G, mp.K, sigma_prev, - eps, eps_prev, eps_V); - - KelvinMatrix tangentStiffness; - - PhysicalStressWithInvariants<DisplacementDim> s{mp.G * sigma}; - // Quit early if sigma is zero (nothing to do) or if we are still in elastic - // zone. - if ((sigma.squaredNorm() == 0 || - yieldFunction( - mp, s, - calculateIsotropicHardening(mp.kappa, mp.hardening_coefficient, - state.eps_p.eff)) < 0)) - { - tangentStiffness.setZero(); - tangentStiffness.template topLeftCorner<3, 3>().setConstant( - mp.K - 2. / 3 * mp.G); - tangentStiffness.noalias() += 2 * mp.G * KelvinMatrix::Identity(); - } - else - { - // Linear solver for the newton loop is required after the loop with the - // same matrix. This saves one decomposition. - Eigen::FullPivLU<Eigen::Matrix<double, JacobianResidualSize, - JacobianResidualSize, Eigen::RowMajor>> - linear_solver; - - { - static int const KelvinVectorSize = - MathLib::KelvinVector::KelvinVectorDimensions< - DisplacementDim>::value; - using KelvinVector = - MathLib::KelvinVector::KelvinVectorType<DisplacementDim>; - using ResidualVectorType = - Eigen::Matrix<double, JacobianResidualSize, 1>; - using JacobianMatrix = - Eigen::Matrix<double, JacobianResidualSize, - JacobianResidualSize, Eigen::RowMajor>; - - JacobianMatrix jacobian; - - // Agglomerated solution vector construction. It is later split - // into individual parts by splitSolutionVector(). - ResidualVectorType solution; - solution << sigma, state.eps_p.D, state.eps_p.V, state.eps_p.eff, 0; - - auto const update_residual = [&](ResidualVectorType& residual) { - - auto const& eps_p_D = - solution.template segment<KelvinVectorSize>( - KelvinVectorSize); - KelvinVector const eps_p_D_dot = - (eps_p_D - state.eps_p_prev.D) / dt; - - double const& eps_p_V = solution[KelvinVectorSize * 2]; - double const eps_p_V_dot = - (eps_p_V - state.eps_p_prev.V) / dt; - - double const& eps_p_eff = solution[KelvinVectorSize * 2 + 1]; - double const eps_p_eff_dot = - (eps_p_eff - state.eps_p_prev.eff) / dt; - - double const k_hardening = calculateIsotropicHardening( - mp.kappa, mp.hardening_coefficient, - solution[KelvinVectorSize * 2 + 1]); - residual = calculatePlasticResidual<DisplacementDim>( - eps_D, eps_V, s, - solution.template segment<KelvinVectorSize>( - KelvinVectorSize), - eps_p_D_dot, solution[KelvinVectorSize * 2], eps_p_V_dot, - eps_p_eff_dot, solution[KelvinVectorSize * 2 + 2], - k_hardening, mp); - }; - - auto const update_jacobian = [&](JacobianMatrix& jacobian) { - jacobian = calculatePlasticJacobian<DisplacementDim>( - dt, s, solution[KelvinVectorSize * 2 + 2], mp); - }; - - auto const update_solution = - [&](ResidualVectorType const& increment) { - solution += increment; - s = PhysicalStressWithInvariants<DisplacementDim>{ - mp.G * solution.template segment<KelvinVectorSize>(0)}; - }; - - auto newton_solver = NumLib::NewtonRaphson< - decltype(linear_solver), JacobianMatrix, - decltype(update_jacobian), ResidualVectorType, - decltype(update_residual), decltype(update_solution)>( - linear_solver, update_jacobian, update_residual, - update_solution, _nonlinear_solver_parameters); - - auto const success_iterations = newton_solver.solve(jacobian); - - if (!success_iterations) - return {}; - - // If the Newton loop didn't run, the linear solver will not be - // initialized. - // This happens usually for the first iteration of the first - // timestep. - if (*success_iterations == 0) - linear_solver.compute(jacobian); - - std::tie(sigma, state.eps_p, std::ignore) = - splitSolutionVector<ResidualVectorType, KelvinVector>(solution); - } - - // Calculate residual derivative w.r.t. strain - Eigen::Matrix<double, JacobianResidualSize, KelvinVectorSize, - Eigen::RowMajor> - dresidual_deps = - Eigen::Matrix<double, JacobianResidualSize, KelvinVectorSize, - Eigen::RowMajor>::Zero(); - dresidual_deps.template block<KelvinVectorSize, KelvinVectorSize>(0, 0) - .noalias() = calculateDResidualDEps<DisplacementDim>(mp.K, mp.G); - - tangentStiffness = - mp.G * - linear_solver.solve(-dresidual_deps) - .template block<KelvinVectorSize, KelvinVectorSize>(0, 0); - } - - KelvinVector sigma_final = mp.G * sigma; - - return {std::make_tuple( - sigma_final, - std::unique_ptr< - typename MechanicsBase<DisplacementDim>::MaterialStateVariables>{ - new StateVariables<DisplacementDim>{ - static_cast<StateVariables<DisplacementDim> const&>(state)}}, - tangentStiffness)}; -} - -template <int DisplacementDim> -std::vector<typename MechanicsBase<DisplacementDim>::InternalVariable> -SolidEhlers<DisplacementDim>::getInternalVariables() const -{ - return { - {"damage.kappa_d", 1, - [](typename MechanicsBase< - DisplacementDim>::MaterialStateVariables const& state, - std::vector<double>& cache) -> std::vector<double> const& { - assert(dynamic_cast<StateVariables<DisplacementDim> const*>( - &state) != nullptr); - auto const& ehlers_state = - static_cast<StateVariables<DisplacementDim> const&>(state); - - cache.resize(1); - cache.front() = ehlers_state.damage.kappa_d(); - return cache; - }}, - {"damage.value", 1, - [](typename MechanicsBase< - DisplacementDim>::MaterialStateVariables const& state, - std::vector<double>& cache) -> std::vector<double> const& { - assert(dynamic_cast<StateVariables<DisplacementDim> const*>( - &state) != nullptr); - auto const& ehlers_state = - static_cast<StateVariables<DisplacementDim> const&>(state); - - cache.resize(1); - cache.front() = ehlers_state.damage.value(); - return cache; - }}, - {"eps_p.D", KelvinVector::RowsAtCompileTime, - [](typename MechanicsBase< - DisplacementDim>::MaterialStateVariables const& state, - std::vector<double>& cache) -> std::vector<double> const& { - assert(dynamic_cast<StateVariables<DisplacementDim> const*>( - &state) != nullptr); - auto const& ehlers_state = - static_cast<StateVariables<DisplacementDim> const&>(state); - - cache.resize(KelvinVector::RowsAtCompileTime); - MathLib::toVector<KelvinVector>(cache, - KelvinVector::RowsAtCompileTime) = - MathLib::KelvinVector::kelvinVectorToSymmetricTensor( - ehlers_state.eps_p.D); - - return cache; - }}, - {"eps_p.V", 1, - [](typename MechanicsBase< - DisplacementDim>::MaterialStateVariables const& state, - std::vector<double>& cache) -> std::vector<double> const& { - assert(dynamic_cast<StateVariables<DisplacementDim> const*>( - &state) != nullptr); - auto const& ehlers_state = - static_cast<StateVariables<DisplacementDim> const&>(state); - - cache.resize(1); - cache.front() = ehlers_state.eps_p.V; - return cache; - }}, - {"eps_p.eff", 1, - [](typename MechanicsBase< - DisplacementDim>::MaterialStateVariables const& state, - std::vector<double>& cache) -> std::vector<double> const& { - assert(dynamic_cast<StateVariables<DisplacementDim> const*>( - &state) != nullptr); - auto const& ehlers_state = - static_cast<StateVariables<DisplacementDim> const&>(state); - - cache.resize(1); - cache.front() = ehlers_state.eps_p.eff; - return cache; - }}}; -} - -} // namespace Ehlers -} // namespace Solids -} // namespace MaterialLib diff --git a/MaterialLib/SolidModels/Ehlers.cpp b/MaterialLib/SolidModels/Ehlers.cpp index 12a63de586f90a8e05c658179775dd93cac7f44f..99820eaf96f4b663939b88beca59dcbaeb2bfbe6 100644 --- a/MaterialLib/SolidModels/Ehlers.cpp +++ b/MaterialLib/SolidModels/Ehlers.cpp @@ -8,7 +8,33 @@ */ #include "Ehlers.h" -#include "Ehlers-impl.h" +#include <boost/math/special_functions/pow.hpp> + +#include "MathLib/LinAlg/Eigen/EigenMapTools.h" + +/** + * Common convenitions for naming: + * x_D - deviatoric part of tensor x + * x_V - volumetric part of tensor x + * x_p - a variable related to plastic potential + * x_prev - value of x in previous time step + * + * Variables used in the code: + * eps_D - deviatoric strain + * eps_p_D_dot - deviatoric increment of plastic strain + * eps_p_eff_dot - increment of effective plastic strain + * eps_p_V_dot - volumetric increment of plastic strain + * sigma_D_inverse_D - deviatoric part of sigma_D_inverse + * + * derivation of the flow rule + * theta - J3 / J2^(3 / 2) from yield function + * dtheta_dsigma - derivative of theta + * sqrtPhi - square root of Phi from plastic potential + * flow_D - deviatoric part of flow + * flow_V - volumetric part of flow + * lambda_flow_D - deviatoric increment of plastic strain + * + */ namespace MaterialLib { @@ -16,6 +42,677 @@ namespace Solids { namespace Ehlers { + +/// Special product of \c v with itself: \f$v \odot v\f$. +/// The tensor \c v is given in Kelvin mapping. +/// \note Implementation only for 2 and 3 dimensions. +/// \attention Pay attention to the sign of the result, which normally would be +/// negative, but the returned value is not negated. This has to do with \f$ +/// d(A^{-1})/dA = -A^{-1} \odot A^{-1} \f$. +template <int DisplacementDim> +MathLib::KelvinVector::KelvinMatrixType<DisplacementDim> sOdotS( + MathLib::KelvinVector::KelvinVectorType<DisplacementDim> const& v); + +template <int DisplacementDim> +struct PhysicalStressWithInvariants final +{ + static int const KelvinVectorSize = + MathLib::KelvinVector::KelvinVectorDimensions<DisplacementDim>::value; + using Invariants = MathLib::KelvinVector::Invariants<KelvinVectorSize>; + using KelvinVector = + MathLib::KelvinVector::KelvinVectorType<DisplacementDim>; + + explicit PhysicalStressWithInvariants(KelvinVector const& stress) + : value{stress}, + D{Invariants::deviatoric_projection * stress}, + I_1{Invariants::trace(stress)}, + J_2{Invariants::J2(D)}, + J_3{Invariants::J3(D)} + { + } + + KelvinVector value; + KelvinVector D; + double I_1; + double J_2; + double J_3; + + EIGEN_MAKE_ALIGNED_OPERATOR_NEW; +}; + +/// Holds powers of 1 + gamma_p*theta to base 0, m_p, and m_p-1. +struct OnePlusGamma_pTheta final +{ + OnePlusGamma_pTheta(double const gamma_p, double const theta, + double const m_p) + : value{1 + gamma_p * theta}, + pow_m_p{std::pow(value, m_p)}, + pow_m_p1{pow_m_p / value} + { + } + + double const value; + double const pow_m_p; + double const pow_m_p1; +}; + +template <int DisplacementDim> +double plasticFlowVolumetricPart( + PhysicalStressWithInvariants<DisplacementDim> const& s, + double const sqrtPhi, double const alpha_p, double const beta_p, + double const delta_p, double const epsilon_p) +{ + return 3 * (alpha_p * s.I_1 + + 4 * boost::math::pow<2>(delta_p) * boost::math::pow<3>(s.I_1)) / + (2 * sqrtPhi) + + 3 * beta_p + 6 * epsilon_p * s.I_1; +} + +template <int DisplacementDim> +typename SolidEhlers<DisplacementDim>::KelvinVector plasticFlowDeviatoricPart( + PhysicalStressWithInvariants<DisplacementDim> const& s, + OnePlusGamma_pTheta const& one_gt, double const sqrtPhi, + typename SolidEhlers<DisplacementDim>::KelvinVector const& dtheta_dsigma, + double const gamma_p, double const m_p) +{ + return (one_gt.pow_m_p * + (s.D + s.J_2 * m_p * gamma_p * dtheta_dsigma / one_gt.value)) / + (2 * sqrtPhi); +} + +template <int DisplacementDim> +double yieldFunction(MaterialProperties const& mp, + PhysicalStressWithInvariants<DisplacementDim> const& s, + double const k) +{ + double const I_1_squared = boost::math::pow<2>(s.I_1); + assert(s.J_2 != 0); + + return std::sqrt( + s.J_2 * + std::pow(1 + mp.gamma * s.J_3 / (s.J_2 * std::sqrt(s.J_2)), + mp.m) + + mp.alpha / 2. * I_1_squared + + boost::math::pow<2>(mp.delta) * + boost::math::pow<2>(I_1_squared)) + + mp.beta * s.I_1 + mp.epsilon * I_1_squared - k; +} + +template <int DisplacementDim> +typename SolidEhlers<DisplacementDim>::ResidualVectorType +calculatePlasticResidual( + MathLib::KelvinVector::KelvinVectorType<DisplacementDim> const& eps_D, + double const eps_V, + PhysicalStressWithInvariants<DisplacementDim> const& s, + MathLib::KelvinVector::KelvinVectorType<DisplacementDim> const& eps_p_D, + MathLib::KelvinVector::KelvinVectorType<DisplacementDim> const& eps_p_D_dot, + double const eps_p_V, + double const eps_p_V_dot, + double const eps_p_eff_dot, + double const lambda, + double const k, + MaterialProperties const& mp) +{ + static int const KelvinVectorSize = + MathLib::KelvinVector::KelvinVectorDimensions<DisplacementDim>::value; + using Invariants = MathLib::KelvinVector::Invariants<KelvinVectorSize>; + using KelvinVector = + MathLib::KelvinVector::KelvinVectorType<DisplacementDim>; + + auto const& P_dev = Invariants::deviatoric_projection; + auto const& identity2 = Invariants::identity2; + + double const theta = s.J_3 / (s.J_2 * std::sqrt(s.J_2)); + + typename SolidEhlers<DisplacementDim>::ResidualVectorType residual; + // calculate stress residual + residual.template segment<KelvinVectorSize>(0).noalias() = + s.value / mp.G - 2 * (eps_D - eps_p_D) - + mp.K / mp.G * (eps_V - eps_p_V) * identity2; + + // deviatoric plastic strain + KelvinVector const sigma_D_inverse_D = + P_dev * MathLib::KelvinVector::inverse(s.D); + KelvinVector const dtheta_dsigma = + theta * sigma_D_inverse_D - 3. / 2. * theta / s.J_2 * s.D; + + OnePlusGamma_pTheta const one_gt{mp.gamma_p, theta, mp.m_p}; + double const sqrtPhi = std::sqrt( + s.J_2 * one_gt.pow_m_p + mp.alpha_p / 2. * boost::math::pow<2>(s.I_1) + + boost::math::pow<2>(mp.delta_p) * boost::math::pow<4>(s.I_1)); + KelvinVector const flow_D = plasticFlowDeviatoricPart( + s, one_gt, sqrtPhi, dtheta_dsigma, mp.gamma_p, mp.m_p); + KelvinVector const lambda_flow_D = lambda * flow_D; + + residual.template segment<KelvinVectorSize>(KelvinVectorSize).noalias() = + eps_p_D_dot - lambda_flow_D; + + // plastic volume strain + { + double const flow_V = plasticFlowVolumetricPart<DisplacementDim>( + s, sqrtPhi, mp.alpha_p, mp.beta_p, mp.delta_p, mp.epsilon_p); + residual(2 * KelvinVectorSize, 0) = eps_p_V_dot - lambda * flow_V; + } + + // evolution of plastic equivalent strain + residual(2 * KelvinVectorSize + 1) = + eps_p_eff_dot - + std::sqrt(2. / 3. * lambda_flow_D.transpose() * lambda_flow_D); + + // yield function (for plastic multiplier) + residual(2 * KelvinVectorSize + 2) = yieldFunction(mp, s, k) / mp.G; + return residual; +} + +template <int DisplacementDim> +typename SolidEhlers<DisplacementDim>::JacobianMatrix calculatePlasticJacobian( + double const dt, + PhysicalStressWithInvariants<DisplacementDim> const& s, + double const lambda, + MaterialProperties const& mp) +{ + static int const KelvinVectorSize = + MathLib::KelvinVector::KelvinVectorDimensions<DisplacementDim>::value; + using Invariants = MathLib::KelvinVector::Invariants<KelvinVectorSize>; + using KelvinVector = + MathLib::KelvinVector::KelvinVectorType<DisplacementDim>; + using KelvinMatrix = + MathLib::KelvinVector::KelvinMatrixType<DisplacementDim>; + + auto const& P_dev = Invariants::deviatoric_projection; + auto const& identity2 = Invariants::identity2; + + double const theta = s.J_3 / (s.J_2 * std::sqrt(s.J_2)); + OnePlusGamma_pTheta const one_gt{mp.gamma_p, theta, mp.m_p}; + + // inverse of deviatoric stress tensor + if (Invariants::determinant(s.D) == 0) + { + OGS_FATAL("Determinant is zero. Matrix is non-invertable."); + } + // inverse of sigma_D + KelvinVector const sigma_D_inverse = MathLib::KelvinVector::inverse(s.D); + KelvinVector const sigma_D_inverse_D = P_dev * sigma_D_inverse; + + KelvinVector const dtheta_dsigma = + theta * sigma_D_inverse_D - 3. / 2. * theta / s.J_2 * s.D; + + // deviatoric flow + double const sqrtPhi = std::sqrt( + s.J_2 * one_gt.pow_m_p + mp.alpha_p / 2. * boost::math::pow<2>(s.I_1) + + boost::math::pow<2>(mp.delta_p) * boost::math::pow<4>(s.I_1)); + KelvinVector const flow_D = plasticFlowDeviatoricPart( + s, one_gt, sqrtPhi, dtheta_dsigma, mp.gamma_p, mp.m_p); + KelvinVector const lambda_flow_D = lambda * flow_D; + + typename SolidEhlers<DisplacementDim>::JacobianMatrix jacobian = + SolidEhlers<DisplacementDim>::JacobianMatrix::Zero(); + + // G_11 + jacobian.template block<KelvinVectorSize, KelvinVectorSize>(0, 0) + .noalias() = KelvinMatrix::Identity(); + + // G_12 + jacobian + .template block<KelvinVectorSize, KelvinVectorSize>(0, KelvinVectorSize) + .noalias() = 2 * KelvinMatrix::Identity(); + + // G_13 + jacobian.template block<KelvinVectorSize, 1>(0, 2 * KelvinVectorSize) + .noalias() = mp.K / mp.G * identity2; + + // G_14 and G_15 are zero + + // G_21 -- derivative of deviatoric flow + + double const gm_p = mp.gamma_p * mp.m_p; + // intermediate variable for derivative of deviatoric flow + KelvinVector const M0 = s.J_2 / one_gt.value * dtheta_dsigma; + // derivative of Phi w.r.t. sigma + KelvinVector const dPhi_dsigma = + one_gt.pow_m_p * (s.D + gm_p * M0) + + (mp.alpha_p * s.I_1 + + 4 * boost::math::pow<2>(mp.delta_p) * boost::math::pow<3>(s.I_1)) * + identity2; + + // intermediate variable for derivative of deviatoric flow + KelvinMatrix const M1 = + one_gt.pow_m_p * + (s.D * dPhi_dsigma.transpose() + gm_p * M0 * dPhi_dsigma.transpose()); + // intermediate variable for derivative of deviatoric flow + KelvinMatrix const M2 = + one_gt.pow_m_p * (P_dev + s.D * gm_p * M0.transpose()); + // second derivative of theta + KelvinMatrix const d2theta_dsigma2 = + theta * P_dev * sOdotS<DisplacementDim>(sigma_D_inverse) * P_dev + + sigma_D_inverse_D * dtheta_dsigma.transpose() - + 3. / 2. * theta / s.J_2 * P_dev - + 3. / 2. * dtheta_dsigma / s.J_2 * s.D.transpose() + + 3. / 2. * theta / boost::math::pow<2>(s.J_2) * s.D * s.D.transpose(); + + // intermediate variable for derivative of deviatoric flow + KelvinMatrix const M3 = + gm_p * one_gt.pow_m_p1 * + ((s.D + (gm_p - mp.gamma_p) * M0) * dtheta_dsigma.transpose() + + s.J_2 * d2theta_dsigma2); + + // derivative of flow_D w.r.t. sigma + KelvinMatrix const dflow_D_dsigma = + (-M1 / (4 * boost::math::pow<3>(sqrtPhi)) + (M2 + M3) / (2 * sqrtPhi)) * + mp.G; + jacobian + .template block<KelvinVectorSize, KelvinVectorSize>(KelvinVectorSize, 0) + .noalias() = -lambda * dflow_D_dsigma; + + // G_22 + jacobian + .template block<KelvinVectorSize, KelvinVectorSize>(KelvinVectorSize, + KelvinVectorSize) + .noalias() = KelvinMatrix::Identity() / dt; + + // G_23 and G_24 are zero + + // G_25 + jacobian + .template block<KelvinVectorSize, 1>(KelvinVectorSize, + 2 * KelvinVectorSize + 2) + .noalias() = -flow_D; + + // G_31 + { + // derivative of flow_V w.r.t. sigma + KelvinVector const dflow_V_dsigma = + 3 * mp.G * + (-(mp.alpha_p * s.I_1 + + 4 * boost::math::pow<2>(mp.delta_p) * + boost::math::pow<3>(s.I_1)) / + (4 * boost::math::pow<3>(sqrtPhi)) * dPhi_dsigma + + (mp.alpha_p * identity2 + + 12 * boost::math::pow<2>(mp.delta_p * s.I_1) * identity2) / + (2 * sqrtPhi) + + 2 * mp.epsilon_p * identity2); + + jacobian.template block<1, KelvinVectorSize>(2 * KelvinVectorSize, 0) + .noalias() = -lambda * dflow_V_dsigma.transpose(); + } + + // G_32 is zero + + // G_33 + jacobian(2 * KelvinVectorSize, 2 * KelvinVectorSize) = 1. / dt; + + // G_34 is zero + + // G_35 + { + double const flow_V = plasticFlowVolumetricPart<DisplacementDim>( + s, sqrtPhi, mp.alpha_p, mp.beta_p, mp.delta_p, mp.epsilon_p); + jacobian(2 * KelvinVectorSize, 2 * KelvinVectorSize + 2) = -flow_V; + } + + // increment of effectiv plastic strain + double const eff_flow = + std::sqrt(2. / 3. * lambda_flow_D.transpose() * lambda_flow_D); + + if (eff_flow > 0) + { + // intermediate variable for derivative of plastic jacobian + KelvinVector const eff_flow23_lambda_flow_D = + -2 / 3. / eff_flow * lambda_flow_D; + // G_41 + jacobian + .template block<1, KelvinVectorSize>(2 * KelvinVectorSize + 1, 0) + .noalias() = lambda * dflow_D_dsigma * eff_flow23_lambda_flow_D; + // G_45 + jacobian(2 * KelvinVectorSize + 1, 2 * KelvinVectorSize + 2) = + eff_flow23_lambda_flow_D.transpose() * flow_D; + } + + // G_42 and G_43 are zero + + // G_44 + jacobian(2 * KelvinVectorSize + 1, 2 * KelvinVectorSize + 1) = 1. / dt; + + // G_51 + { + double const one_gt_pow_m = std::pow(one_gt.value, mp.m); + double const gm = mp.gamma * mp.m; + // derivative of yield function w.r.t. sigma + KelvinVector const dF_dsigma = + mp.G * (one_gt_pow_m * (s.D + gm * M0) + + (mp.alpha * s.I_1 + + 4 * boost::math::pow<2>(mp.delta) * + boost::math::pow<3>(s.I_1)) * + identity2) / + (2. * sqrtPhi) + + mp.G * (mp.beta + 2 * mp.epsilon_p * s.I_1) * identity2; + + jacobian + .template block<1, KelvinVectorSize>(2 * KelvinVectorSize + 2, 0) + .noalias() = dF_dsigma.transpose() / mp.G; + } + + // G_54 + jacobian(2 * KelvinVectorSize + 2, 2 * KelvinVectorSize + 1) = + -mp.kappa * mp.hardening_coefficient / mp.G; + + // G_52, G_53, G_55 are zero + return jacobian; +} + +/// Calculates the derivative of the residuals with respect to total +/// strain. Implementation fully implicit only. +template <int DisplacementDim> +MathLib::KelvinVector::KelvinMatrixType<DisplacementDim> calculateDResidualDEps( + double const K, double const G) +{ + static int const KelvinVectorSize = + MathLib::KelvinVector::KelvinVectorDimensions<DisplacementDim>::value; + using Invariants = MathLib::KelvinVector::Invariants<KelvinVectorSize>; + + auto const& P_dev = Invariants::deviatoric_projection; + auto const& P_sph = Invariants::spherical_projection; + auto const& I = + MathLib::KelvinVector::KelvinMatrixType<DisplacementDim>::Identity(); + + return -2. * I * P_dev - 3. * K / G * I * P_sph; +} + +inline double calculateIsotropicHardening(double const kappa, + double const hardening_coefficient, + double const eps_p_eff) +{ + return kappa * (1. + eps_p_eff * hardening_coefficient); +} + +template <int DisplacementDim> +typename SolidEhlers<DisplacementDim>::KelvinVector predict_sigma( + double const G, double const K, + typename SolidEhlers<DisplacementDim>::KelvinVector const& sigma_prev, + typename SolidEhlers<DisplacementDim>::KelvinVector const& eps, + typename SolidEhlers<DisplacementDim>::KelvinVector const& eps_prev, + double const eps_V) +{ + static int const KelvinVectorSize = + MathLib::KelvinVector::KelvinVectorDimensions<DisplacementDim>::value; + using Invariants = MathLib::KelvinVector::Invariants<KelvinVectorSize>; + auto const& P_dev = Invariants::deviatoric_projection; + + // dimensionless initial hydrostatic pressure + double const pressure_prev = Invariants::trace(sigma_prev) / (-3. * G); + // initial strain invariant + double const e_prev = Invariants::trace(eps_prev); + // dimensioness hydrostatic stress increment + double const pressure = pressure_prev - K / G * (eps_V - e_prev); + // dimensionless deviatoric initial stress + typename SolidEhlers<DisplacementDim>::KelvinVector const sigma_D_prev = + P_dev * sigma_prev / G; + // dimensionless deviatoric stress + typename SolidEhlers<DisplacementDim>::KelvinVector const sigma_D = + sigma_D_prev + 2 * P_dev * (eps - eps_prev); + return sigma_D - pressure * Invariants::identity2; +} + +/// Split the agglomerated solution vector in separate items. The arrangement +/// must be the same as in the newton() function. +template <typename ResidualVector, typename KelvinVector> +std::tuple<KelvinVector, PlasticStrain<KelvinVector>, double> +splitSolutionVector(ResidualVector const& solution) +{ + static auto const size = KelvinVector::SizeAtCompileTime; + return std::forward_as_tuple( + solution.template segment<size>(size * 0), + PlasticStrain<KelvinVector>{solution.template segment<size>(size * 1), + solution[size * 2], solution[size * 2 + 1]}, + solution[size * 2 + 2]); +} + +template <int DisplacementDim> +boost::optional<std::tuple<typename SolidEhlers<DisplacementDim>::KelvinVector, + std::unique_ptr<typename MechanicsBase< + DisplacementDim>::MaterialStateVariables>, + typename SolidEhlers<DisplacementDim>::KelvinMatrix>> +SolidEhlers<DisplacementDim>::integrateStress( + double const t, + ProcessLib::SpatialPosition const& x, + double const dt, + KelvinVector const& eps_prev, + KelvinVector const& eps, + KelvinVector const& sigma_prev, + typename MechanicsBase<DisplacementDim>::MaterialStateVariables const& + material_state_variables) +{ + assert(dynamic_cast<StateVariables<DisplacementDim> const*>( + &material_state_variables) != nullptr); + + StateVariables<DisplacementDim> state = + static_cast<StateVariables<DisplacementDim> const&>( + material_state_variables); + state.setInitialConditions(); + + using Invariants = MathLib::KelvinVector::Invariants<KelvinVectorSize>; + + // volumetric strain + double const eps_V = Invariants::trace(eps); + + auto const& P_dev = Invariants::deviatoric_projection; + // deviatoric strain + KelvinVector const eps_D = P_dev * eps; + + // do the evaluation once per function call. + MaterialProperties const mp(t, x, _mp); + + KelvinVector sigma = predict_sigma<DisplacementDim>(mp.G, mp.K, sigma_prev, + eps, eps_prev, eps_V); + + KelvinMatrix tangentStiffness; + + PhysicalStressWithInvariants<DisplacementDim> s{mp.G * sigma}; + // Quit early if sigma is zero (nothing to do) or if we are still in elastic + // zone. + if ((sigma.squaredNorm() == 0 || + yieldFunction( + mp, s, + calculateIsotropicHardening(mp.kappa, mp.hardening_coefficient, + state.eps_p.eff)) < 0)) + { + tangentStiffness.setZero(); + tangentStiffness.template topLeftCorner<3, 3>().setConstant( + mp.K - 2. / 3 * mp.G); + tangentStiffness.noalias() += 2 * mp.G * KelvinMatrix::Identity(); + } + else + { + // Linear solver for the newton loop is required after the loop with the + // same matrix. This saves one decomposition. + Eigen::FullPivLU<Eigen::Matrix<double, JacobianResidualSize, + JacobianResidualSize, Eigen::RowMajor>> + linear_solver; + + { + static int const KelvinVectorSize = + MathLib::KelvinVector::KelvinVectorDimensions< + DisplacementDim>::value; + using KelvinVector = + MathLib::KelvinVector::KelvinVectorType<DisplacementDim>; + using ResidualVectorType = + Eigen::Matrix<double, JacobianResidualSize, 1>; + using JacobianMatrix = + Eigen::Matrix<double, JacobianResidualSize, + JacobianResidualSize, Eigen::RowMajor>; + + JacobianMatrix jacobian; + + // Agglomerated solution vector construction. It is later split + // into individual parts by splitSolutionVector(). + ResidualVectorType solution; + solution << sigma, state.eps_p.D, state.eps_p.V, state.eps_p.eff, 0; + + auto const update_residual = [&](ResidualVectorType& residual) { + + auto const& eps_p_D = + solution.template segment<KelvinVectorSize>( + KelvinVectorSize); + KelvinVector const eps_p_D_dot = + (eps_p_D - state.eps_p_prev.D) / dt; + + double const& eps_p_V = solution[KelvinVectorSize * 2]; + double const eps_p_V_dot = + (eps_p_V - state.eps_p_prev.V) / dt; + + double const& eps_p_eff = solution[KelvinVectorSize * 2 + 1]; + double const eps_p_eff_dot = + (eps_p_eff - state.eps_p_prev.eff) / dt; + + double const k_hardening = calculateIsotropicHardening( + mp.kappa, mp.hardening_coefficient, + solution[KelvinVectorSize * 2 + 1]); + residual = calculatePlasticResidual<DisplacementDim>( + eps_D, eps_V, s, + solution.template segment<KelvinVectorSize>( + KelvinVectorSize), + eps_p_D_dot, solution[KelvinVectorSize * 2], eps_p_V_dot, + eps_p_eff_dot, solution[KelvinVectorSize * 2 + 2], + k_hardening, mp); + }; + + auto const update_jacobian = [&](JacobianMatrix& jacobian) { + jacobian = calculatePlasticJacobian<DisplacementDim>( + dt, s, solution[KelvinVectorSize * 2 + 2], mp); + }; + + auto const update_solution = + [&](ResidualVectorType const& increment) { + solution += increment; + s = PhysicalStressWithInvariants<DisplacementDim>{ + mp.G * solution.template segment<KelvinVectorSize>(0)}; + }; + + auto newton_solver = NumLib::NewtonRaphson< + decltype(linear_solver), JacobianMatrix, + decltype(update_jacobian), ResidualVectorType, + decltype(update_residual), decltype(update_solution)>( + linear_solver, update_jacobian, update_residual, + update_solution, _nonlinear_solver_parameters); + + auto const success_iterations = newton_solver.solve(jacobian); + + if (!success_iterations) + return {}; + + // If the Newton loop didn't run, the linear solver will not be + // initialized. + // This happens usually for the first iteration of the first + // timestep. + if (*success_iterations == 0) + linear_solver.compute(jacobian); + + std::tie(sigma, state.eps_p, std::ignore) = + splitSolutionVector<ResidualVectorType, KelvinVector>(solution); + } + + // Calculate residual derivative w.r.t. strain + Eigen::Matrix<double, JacobianResidualSize, KelvinVectorSize, + Eigen::RowMajor> + dresidual_deps = + Eigen::Matrix<double, JacobianResidualSize, KelvinVectorSize, + Eigen::RowMajor>::Zero(); + dresidual_deps.template block<KelvinVectorSize, KelvinVectorSize>(0, 0) + .noalias() = calculateDResidualDEps<DisplacementDim>(mp.K, mp.G); + + tangentStiffness = + mp.G * + linear_solver.solve(-dresidual_deps) + .template block<KelvinVectorSize, KelvinVectorSize>(0, 0); + } + + KelvinVector sigma_final = mp.G * sigma; + + return {std::make_tuple( + sigma_final, + std::unique_ptr< + typename MechanicsBase<DisplacementDim>::MaterialStateVariables>{ + new StateVariables<DisplacementDim>{ + static_cast<StateVariables<DisplacementDim> const&>(state)}}, + tangentStiffness)}; +} + +template <int DisplacementDim> +std::vector<typename MechanicsBase<DisplacementDim>::InternalVariable> +SolidEhlers<DisplacementDim>::getInternalVariables() const +{ + return { + {"damage.kappa_d", 1, + [](typename MechanicsBase< + DisplacementDim>::MaterialStateVariables const& state, + std::vector<double>& cache) -> std::vector<double> const& { + assert(dynamic_cast<StateVariables<DisplacementDim> const*>( + &state) != nullptr); + auto const& ehlers_state = + static_cast<StateVariables<DisplacementDim> const&>(state); + + cache.resize(1); + cache.front() = ehlers_state.damage.kappa_d(); + return cache; + }}, + {"damage.value", 1, + [](typename MechanicsBase< + DisplacementDim>::MaterialStateVariables const& state, + std::vector<double>& cache) -> std::vector<double> const& { + assert(dynamic_cast<StateVariables<DisplacementDim> const*>( + &state) != nullptr); + auto const& ehlers_state = + static_cast<StateVariables<DisplacementDim> const&>(state); + + cache.resize(1); + cache.front() = ehlers_state.damage.value(); + return cache; + }}, + {"eps_p.D", KelvinVector::RowsAtCompileTime, + [](typename MechanicsBase< + DisplacementDim>::MaterialStateVariables const& state, + std::vector<double>& cache) -> std::vector<double> const& { + assert(dynamic_cast<StateVariables<DisplacementDim> const*>( + &state) != nullptr); + auto const& ehlers_state = + static_cast<StateVariables<DisplacementDim> const&>(state); + + cache.resize(KelvinVector::RowsAtCompileTime); + MathLib::toVector<KelvinVector>(cache, + KelvinVector::RowsAtCompileTime) = + MathLib::KelvinVector::kelvinVectorToSymmetricTensor( + ehlers_state.eps_p.D); + + return cache; + }}, + {"eps_p.V", 1, + [](typename MechanicsBase< + DisplacementDim>::MaterialStateVariables const& state, + std::vector<double>& cache) -> std::vector<double> const& { + assert(dynamic_cast<StateVariables<DisplacementDim> const*>( + &state) != nullptr); + auto const& ehlers_state = + static_cast<StateVariables<DisplacementDim> const&>(state); + + cache.resize(1); + cache.front() = ehlers_state.eps_p.V; + return cache; + }}, + {"eps_p.eff", 1, + [](typename MechanicsBase< + DisplacementDim>::MaterialStateVariables const& state, + std::vector<double>& cache) -> std::vector<double> const& { + assert(dynamic_cast<StateVariables<DisplacementDim> const*>( + &state) != nullptr); + auto const& ehlers_state = + static_cast<StateVariables<DisplacementDim> const&>(state); + + cache.resize(1); + cache.front() = ehlers_state.eps_p.eff; + return cache; + }}}; +} + template class SolidEhlers<2>; template class SolidEhlers<3>; diff --git a/MaterialLib/SolidModels/LinearElasticIsotropic-impl.h b/MaterialLib/SolidModels/LinearElasticIsotropic-impl.h deleted file mode 100644 index f7b0e7ea3e3d37d8d80e9071eebd8de2c6bae614..0000000000000000000000000000000000000000 --- a/MaterialLib/SolidModels/LinearElasticIsotropic-impl.h +++ /dev/null @@ -1,55 +0,0 @@ -/** - * \copyright - * Copyright (c) 2012-2018, OpenGeoSys Community (http://www.opengeosys.org) - * Distributed under a Modified BSD License. - * See accompanying file LICENSE.txt or - * http://www.opengeosys.org/project/license - * - */ - -#pragma once - -#include "LinearElasticIsotropic.h" - -namespace MaterialLib -{ -namespace Solids -{ -template <int DisplacementDim> -boost::optional< - std::tuple<typename LinearElasticIsotropic<DisplacementDim>::KelvinVector, - std::unique_ptr<typename MechanicsBase< - DisplacementDim>::MaterialStateVariables>, - typename LinearElasticIsotropic<DisplacementDim>::KelvinMatrix>> -LinearElasticIsotropic<DisplacementDim>::integrateStress( - double const t, - ProcessLib::SpatialPosition const& x, - double const /*dt*/, - KelvinVector const& eps_prev, - KelvinVector const& eps, - KelvinVector const& sigma_prev, - typename MechanicsBase<DisplacementDim>::MaterialStateVariables const& - material_state_variables) -{ - KelvinMatrix C = KelvinMatrix::Zero(); - - C.template topLeftCorner<3, 3>().setConstant(_mp.lambda(t, x)); - C.noalias() += 2 * _mp.mu(t, x) * KelvinMatrix::Identity(); - - KelvinVector sigma = sigma_prev + C * (eps - eps_prev); - - return {std::make_tuple( - sigma, - std::unique_ptr< - typename MechanicsBase<DisplacementDim>::MaterialStateVariables>{ - new MaterialStateVariables{ - static_cast<MaterialStateVariables const&>( - material_state_variables)}}, - C)}; -} - -extern template class LinearElasticIsotropic<2>; -extern template class LinearElasticIsotropic<3>; - -} // namespace Solids -} // namespace MaterialLib diff --git a/MaterialLib/SolidModels/LinearElasticIsotropic.cpp b/MaterialLib/SolidModels/LinearElasticIsotropic.cpp index 1e5d988b4123a999e969dbfad2fda98927aade03..9aa837a7f7b711db90bf9efbe03cd54fdab24bc3 100644 --- a/MaterialLib/SolidModels/LinearElasticIsotropic.cpp +++ b/MaterialLib/SolidModels/LinearElasticIsotropic.cpp @@ -8,12 +8,43 @@ */ #include "LinearElasticIsotropic.h" -#include "LinearElasticIsotropic-impl.h" namespace MaterialLib { namespace Solids { +template <int DisplacementDim> +boost::optional< + std::tuple<typename LinearElasticIsotropic<DisplacementDim>::KelvinVector, + std::unique_ptr<typename MechanicsBase< + DisplacementDim>::MaterialStateVariables>, + typename LinearElasticIsotropic<DisplacementDim>::KelvinMatrix>> +LinearElasticIsotropic<DisplacementDim>::integrateStress( + double const t, + ProcessLib::SpatialPosition const& x, + double const /*dt*/, + KelvinVector const& eps_prev, + KelvinVector const& eps, + KelvinVector const& sigma_prev, + typename MechanicsBase<DisplacementDim>::MaterialStateVariables const& + material_state_variables) +{ + KelvinMatrix C = KelvinMatrix::Zero(); + + C.template topLeftCorner<3, 3>().setConstant(_mp.lambda(t, x)); + C.noalias() += 2 * _mp.mu(t, x) * KelvinMatrix::Identity(); + + KelvinVector sigma = sigma_prev + C * (eps - eps_prev); + + return {std::make_tuple( + sigma, + std::unique_ptr< + typename MechanicsBase<DisplacementDim>::MaterialStateVariables>{ + new MaterialStateVariables{ + static_cast<MaterialStateVariables const&>( + material_state_variables)}}, + C)}; +} template class LinearElasticIsotropic<2>; template class LinearElasticIsotropic<3>; diff --git a/MaterialLib/SolidModels/Lubby2-impl.h b/MaterialLib/SolidModels/Lubby2-impl.h deleted file mode 100644 index 6a3ce0fbe70c903c3f36dd02af5a27cf102378b2..0000000000000000000000000000000000000000 --- a/MaterialLib/SolidModels/Lubby2-impl.h +++ /dev/null @@ -1,306 +0,0 @@ -/** - * \copyright - * Copyright (c) 2012-2018, OpenGeoSys Community (http://www.opengeosys.org) - * Distributed under a Modified BSD License. - * See accompanying file LICENSE.txt or - * http://www.opengeosys.org/project/license - * - */ - -#pragma once - -namespace MaterialLib -{ -namespace Solids -{ -namespace Lubby2 -{ -/// Calculates the 18x6 derivative of the residuals with respect to total -/// strain. -/// -/// Function definition can not be moved into implementation because of a -/// MSVC compiler errors. See -/// http://stackoverflow.com/questions/1484885/strange-vc-compile-error-c2244 -/// and https://support.microsoft.com/en-us/kb/930198 -template <int DisplacementDim> -Eigen::Matrix<double, Lubby2<DisplacementDim>::JacobianResidualSize, - Lubby2<DisplacementDim>::KelvinVectorSize> -calculatedGdEBurgers() -{ - Eigen::Matrix<double, Lubby2<DisplacementDim>::JacobianResidualSize, - Lubby2<DisplacementDim>::KelvinVectorSize> - dGdE = - Eigen::Matrix<double, Lubby2<DisplacementDim>::JacobianResidualSize, - Lubby2<DisplacementDim>::KelvinVectorSize>::Zero(); - dGdE.template topLeftCorner<Lubby2<DisplacementDim>::KelvinVectorSize, - Lubby2<DisplacementDim>::KelvinVectorSize>() - .diagonal() - .setConstant(-2); - return dGdE; -} - -template <int DisplacementDim, typename LinearSolver> -MathLib::KelvinVector::KelvinMatrixType<DisplacementDim> tangentStiffnessA( - double const GM0, double const KM0, LinearSolver const& linear_solver) -{ - // Calculate dGdE for time step - auto const dGdE = calculatedGdEBurgers<DisplacementDim>(); - - // Consistent tangent from local Newton iteration of material - // functionals. - // Only the upper left block is relevant for the global tangent. - static int const KelvinVectorSize = - MathLib::KelvinVector::KelvinVectorDimensions<DisplacementDim>::value; - using KelvinMatrix = - MathLib::KelvinVector::KelvinMatrixType<DisplacementDim>; - - KelvinMatrix const dzdE = - linear_solver.solve(-dGdE) - .template topLeftCorner<KelvinVectorSize, KelvinVectorSize>(); - - using Invariants = MathLib::KelvinVector::Invariants<KelvinVectorSize>; - auto const& P_sph = Invariants::spherical_projection; - auto const& P_dev = Invariants::deviatoric_projection; - - KelvinMatrix C = GM0 * dzdE * P_dev + 3. * KM0 * P_sph; - return C; -}; - -template <int DisplacementDim> -boost::optional<std::tuple<typename Lubby2<DisplacementDim>::KelvinVector, - std::unique_ptr<typename MechanicsBase< - DisplacementDim>::MaterialStateVariables>, - typename Lubby2<DisplacementDim>::KelvinMatrix>> -Lubby2<DisplacementDim>::integrateStress( - double const t, - ProcessLib::SpatialPosition const& x, - double const dt, - KelvinVector const& /*eps_prev*/, - KelvinVector const& eps, - KelvinVector const& /*sigma_prev*/, - typename MechanicsBase<DisplacementDim>::MaterialStateVariables const& - material_state_variables) -{ - using Invariants = MathLib::KelvinVector::Invariants<KelvinVectorSize>; - - assert(dynamic_cast<MaterialStateVariables const*>( - &material_state_variables) != nullptr); - MaterialStateVariables state( - static_cast<MaterialStateVariables const&>(material_state_variables)); - state.setInitialConditions(); - - auto local_lubby2_properties = - detail::LocalLubby2Properties<DisplacementDim>{t, x, _mp}; - - // calculation of deviatoric parts - auto const& P_dev = Invariants::deviatoric_projection; - KelvinVector const epsd_i = P_dev * eps; - - // initial guess as elastic predictor - KelvinVector sigd_j = 2.0 * (epsd_i - state.eps_M_t - state.eps_K_t); - - // Calculate effective stress and update material properties - double sig_eff = Invariants::equivalentStress(sigd_j); - local_lubby2_properties.update(sig_eff); - - using LocalJacobianMatrix = - Eigen::Matrix<double, KelvinVectorSize * 3, KelvinVectorSize * 3, - Eigen::RowMajor>; - - // Linear solver for the newton loop is required after the loop with the - // same matrix. This saves one decomposition. - Eigen::FullPivLU<LocalJacobianMatrix> linear_solver; - - // Different solvers are available for the solution of the local system. - // TODO Make the following choice of linear solvers available from the - // input file configuration: - // K_loc.partialPivLu().solve(-res_loc); - // K_loc.fullPivLu().solve(-res_loc); - // K_loc.householderQr().solve(-res_loc); - // K_loc.colPivHouseholderQr().solve(res_loc); - // K_loc.fullPivHouseholderQr().solve(-res_loc); - // K_loc.llt().solve(-res_loc); - // K_loc.ldlt().solve(-res_loc); - - LocalJacobianMatrix K_loc; - { // Local Newton solver - using LocalResidualVector = - Eigen::Matrix<double, KelvinVectorSize * 3, 1>; - - auto const update_residual = [&](LocalResidualVector& residual) { - calculateResidualBurgers( - dt, epsd_i, sigd_j, state.eps_K_j, state.eps_K_t, state.eps_M_j, - state.eps_M_t, residual, local_lubby2_properties); - }; - - auto const update_jacobian = [&](LocalJacobianMatrix& jacobian) { - calculateJacobianBurgers( - t, x, dt, jacobian, sig_eff, sigd_j, state.eps_K_j, - local_lubby2_properties); // for solution dependent Jacobians - }; - - auto const update_solution = [&](LocalResidualVector const& increment) { - // increment solution vectors - sigd_j.noalias() += increment.template segment<KelvinVectorSize>( - KelvinVectorSize * 0); - state.eps_K_j.noalias() += - increment.template segment<KelvinVectorSize>(KelvinVectorSize * - 1); - state.eps_M_j.noalias() += - increment.template segment<KelvinVectorSize>(KelvinVectorSize * - 2); - - // Calculate effective stress and update material properties - sig_eff = MathLib::KelvinVector::Invariants< - KelvinVectorSize>::equivalentStress(sigd_j); - local_lubby2_properties.update(sig_eff); - }; - - auto newton_solver = NumLib::NewtonRaphson< - decltype(linear_solver), LocalJacobianMatrix, - decltype(update_jacobian), LocalResidualVector, - decltype(update_residual), decltype(update_solution)>( - linear_solver, update_jacobian, update_residual, update_solution, - _nonlinear_solver_parameters); - - auto const success_iterations = newton_solver.solve(K_loc); - - if (!success_iterations) - return {}; - - // If the Newton loop didn't run, the linear solver will not be - // initialized. - // This happens usually for the first iteration of the first timestep. - if (*success_iterations == 0) - linear_solver.compute(K_loc); - } - - KelvinMatrix C = - tangentStiffnessA<DisplacementDim>(local_lubby2_properties.GM0, - local_lubby2_properties.KM0, - linear_solver); - - // Hydrostatic part for the stress and the tangent. - double const eps_i_trace = Invariants::trace(eps); - KelvinVector const sigma = - local_lubby2_properties.GM0 * sigd_j + - local_lubby2_properties.KM0 * eps_i_trace * Invariants::identity2; - return {std::make_tuple( - sigma, - std::unique_ptr< - typename MechanicsBase<DisplacementDim>::MaterialStateVariables>{ - new MaterialStateVariables{state}}, - C)}; -} - -template <int DisplacementDim> -void Lubby2<DisplacementDim>::calculateResidualBurgers( - const double dt, - const KelvinVector& strain_curr, - const KelvinVector& stress_curr, - KelvinVector& strain_Kel_curr, - const KelvinVector& strain_Kel_t, - KelvinVector& strain_Max_curr, - const KelvinVector& strain_Max_t, - ResidualVector& res, - detail::LocalLubby2Properties<DisplacementDim> const& properties) -{ - // calculate stress residual - res.template segment<KelvinVectorSize>(0).noalias() = - stress_curr - 2. * (strain_curr - strain_Kel_curr - strain_Max_curr); - - // calculate Kelvin strain residual - res.template segment<KelvinVectorSize>(KelvinVectorSize).noalias() = - 1. / dt * (strain_Kel_curr - strain_Kel_t) - - 1. / (2. * properties.etaK) * (properties.GM0 * stress_curr - - 2. * properties.GK * strain_Kel_curr); - - // calculate Maxwell strain residual - res.template segment<KelvinVectorSize>(2 * KelvinVectorSize).noalias() = - 1. / dt * (strain_Max_curr - strain_Max_t) - - 0.5 * properties.GM0 / properties.etaM * stress_curr; -} - -template <int DisplacementDim> -void Lubby2<DisplacementDim>::calculateJacobianBurgers( - double const t, - ProcessLib::SpatialPosition const& x, - const double dt, - JacobianMatrix& Jac, - double s_eff, - const KelvinVector& sig_i, - const KelvinVector& eps_K_i, - detail::LocalLubby2Properties<DisplacementDim> const& properties) -{ - Jac.setZero(); - - // build G_11 - Jac.template block<KelvinVectorSize, KelvinVectorSize>(0, 0).setIdentity(); - - // build G_12 - Jac.template block<KelvinVectorSize, KelvinVectorSize>(0, KelvinVectorSize) - .diagonal() - .setConstant(2); - - // build G_13 - Jac.template block<KelvinVectorSize, KelvinVectorSize>(0, - 2 * KelvinVectorSize) - .diagonal() - .setConstant(2); - - // build G_21 - Jac.template block<KelvinVectorSize, KelvinVectorSize>(KelvinVectorSize, 0) - .noalias() = - -0.5 * properties.GM0 / properties.etaK * KelvinMatrix::Identity(); - if (s_eff > 0.) - { - KelvinVector const eps_K_aid = - 1. / (properties.etaK * properties.etaK) * - (properties.GM0 * sig_i - 2. * properties.GK * eps_K_i); - - KelvinVector const dG_K = 1.5 * _mp.mK(t, x)[0] * properties.GK * - properties.GM0 / s_eff * sig_i; - KelvinVector const dmu_vK = 1.5 * _mp.mvK(t, x)[0] * properties.GM0 * - properties.etaK / s_eff * sig_i; - Jac.template block<KelvinVectorSize, KelvinVectorSize>(KelvinVectorSize, - 0) - .noalias() += 0.5 * eps_K_aid * dmu_vK.transpose() + - 1. / properties.etaK * eps_K_i * dG_K.transpose(); - } - - // build G_22 - Jac.template block<KelvinVectorSize, KelvinVectorSize>(KelvinVectorSize, - KelvinVectorSize) - .diagonal() - .setConstant(1. / dt + properties.GK / properties.etaK); - - // nothing to do for G_23 - - // build G_31 - Jac.template block<KelvinVectorSize, KelvinVectorSize>(2 * KelvinVectorSize, - 0) - .noalias() = - -0.5 * properties.GM0 / properties.etaM * KelvinMatrix::Identity(); - if (s_eff > 0.) - { - KelvinVector const dmu_vM = 1.5 * _mp.mvM(t, x)[0] * properties.GM0 * - properties.etaM / s_eff * sig_i; - Jac.template block<KelvinVectorSize, KelvinVectorSize>( - 2 * KelvinVectorSize, 0) - .noalias() += 0.5 * properties.GM0 / - (properties.etaM * properties.etaM) * sig_i * - dmu_vM.transpose(); - } - - // nothing to do for G_32 - - // build G_33 - Jac.template block<KelvinVectorSize, KelvinVectorSize>(2 * KelvinVectorSize, - 2 * KelvinVectorSize) - .diagonal() - .setConstant(1. / dt); -} - -} // namespace Lubby2 -} // namespace Solids -} // namespace MaterialLib diff --git a/MaterialLib/SolidModels/Lubby2.cpp b/MaterialLib/SolidModels/Lubby2.cpp index 983ab6e48d05cc00ce550a3053bc30cb8306970f..97f40ac3bca4550a5791a7cb20257914197c9eeb 100644 --- a/MaterialLib/SolidModels/Lubby2.cpp +++ b/MaterialLib/SolidModels/Lubby2.cpp @@ -8,7 +8,6 @@ */ #include "Lubby2.h" -#include "Lubby2-impl.h" namespace MaterialLib { @@ -16,6 +15,293 @@ namespace Solids { namespace Lubby2 { + +/// Calculates the 18x6 derivative of the residuals with respect to total +/// strain. +/// +/// Function definition can not be moved into implementation because of a +/// MSVC compiler errors. See +/// http://stackoverflow.com/questions/1484885/strange-vc-compile-error-c2244 +/// and https://support.microsoft.com/en-us/kb/930198 +template <int DisplacementDim> +Eigen::Matrix<double, Lubby2<DisplacementDim>::JacobianResidualSize, + Lubby2<DisplacementDim>::KelvinVectorSize> +calculatedGdEBurgers() +{ + Eigen::Matrix<double, Lubby2<DisplacementDim>::JacobianResidualSize, + Lubby2<DisplacementDim>::KelvinVectorSize> + dGdE = + Eigen::Matrix<double, Lubby2<DisplacementDim>::JacobianResidualSize, + Lubby2<DisplacementDim>::KelvinVectorSize>::Zero(); + dGdE.template topLeftCorner<Lubby2<DisplacementDim>::KelvinVectorSize, + Lubby2<DisplacementDim>::KelvinVectorSize>() + .diagonal() + .setConstant(-2); + return dGdE; +} + +template <int DisplacementDim, typename LinearSolver> +MathLib::KelvinVector::KelvinMatrixType<DisplacementDim> tangentStiffnessA( + double const GM0, double const KM0, LinearSolver const& linear_solver) +{ + // Calculate dGdE for time step + auto const dGdE = calculatedGdEBurgers<DisplacementDim>(); + + // Consistent tangent from local Newton iteration of material + // functionals. + // Only the upper left block is relevant for the global tangent. + static int const KelvinVectorSize = + MathLib::KelvinVector::KelvinVectorDimensions<DisplacementDim>::value; + using KelvinMatrix = + MathLib::KelvinVector::KelvinMatrixType<DisplacementDim>; + + KelvinMatrix const dzdE = + linear_solver.solve(-dGdE) + .template topLeftCorner<KelvinVectorSize, KelvinVectorSize>(); + + using Invariants = MathLib::KelvinVector::Invariants<KelvinVectorSize>; + auto const& P_sph = Invariants::spherical_projection; + auto const& P_dev = Invariants::deviatoric_projection; + + KelvinMatrix C = GM0 * dzdE * P_dev + 3. * KM0 * P_sph; + return C; +}; + +template <int DisplacementDim> +boost::optional<std::tuple<typename Lubby2<DisplacementDim>::KelvinVector, + std::unique_ptr<typename MechanicsBase< + DisplacementDim>::MaterialStateVariables>, + typename Lubby2<DisplacementDim>::KelvinMatrix>> +Lubby2<DisplacementDim>::integrateStress( + double const t, + ProcessLib::SpatialPosition const& x, + double const dt, + KelvinVector const& /*eps_prev*/, + KelvinVector const& eps, + KelvinVector const& /*sigma_prev*/, + typename MechanicsBase<DisplacementDim>::MaterialStateVariables const& + material_state_variables) +{ + using Invariants = MathLib::KelvinVector::Invariants<KelvinVectorSize>; + + assert(dynamic_cast<MaterialStateVariables const*>( + &material_state_variables) != nullptr); + MaterialStateVariables state( + static_cast<MaterialStateVariables const&>(material_state_variables)); + state.setInitialConditions(); + + auto local_lubby2_properties = + detail::LocalLubby2Properties<DisplacementDim>{t, x, _mp}; + + // calculation of deviatoric parts + auto const& P_dev = Invariants::deviatoric_projection; + KelvinVector const epsd_i = P_dev * eps; + + // initial guess as elastic predictor + KelvinVector sigd_j = 2.0 * (epsd_i - state.eps_M_t - state.eps_K_t); + + // Calculate effective stress and update material properties + double sig_eff = Invariants::equivalentStress(sigd_j); + local_lubby2_properties.update(sig_eff); + + using LocalJacobianMatrix = + Eigen::Matrix<double, KelvinVectorSize * 3, KelvinVectorSize * 3, + Eigen::RowMajor>; + + // Linear solver for the newton loop is required after the loop with the + // same matrix. This saves one decomposition. + Eigen::FullPivLU<LocalJacobianMatrix> linear_solver; + + // Different solvers are available for the solution of the local system. + // TODO Make the following choice of linear solvers available from the + // input file configuration: + // K_loc.partialPivLu().solve(-res_loc); + // K_loc.fullPivLu().solve(-res_loc); + // K_loc.householderQr().solve(-res_loc); + // K_loc.colPivHouseholderQr().solve(res_loc); + // K_loc.fullPivHouseholderQr().solve(-res_loc); + // K_loc.llt().solve(-res_loc); + // K_loc.ldlt().solve(-res_loc); + + LocalJacobianMatrix K_loc; + { // Local Newton solver + using LocalResidualVector = + Eigen::Matrix<double, KelvinVectorSize * 3, 1>; + + auto const update_residual = [&](LocalResidualVector& residual) { + calculateResidualBurgers( + dt, epsd_i, sigd_j, state.eps_K_j, state.eps_K_t, state.eps_M_j, + state.eps_M_t, residual, local_lubby2_properties); + }; + + auto const update_jacobian = [&](LocalJacobianMatrix& jacobian) { + calculateJacobianBurgers( + t, x, dt, jacobian, sig_eff, sigd_j, state.eps_K_j, + local_lubby2_properties); // for solution dependent Jacobians + }; + + auto const update_solution = [&](LocalResidualVector const& increment) { + // increment solution vectors + sigd_j.noalias() += increment.template segment<KelvinVectorSize>( + KelvinVectorSize * 0); + state.eps_K_j.noalias() += + increment.template segment<KelvinVectorSize>(KelvinVectorSize * + 1); + state.eps_M_j.noalias() += + increment.template segment<KelvinVectorSize>(KelvinVectorSize * + 2); + + // Calculate effective stress and update material properties + sig_eff = MathLib::KelvinVector::Invariants< + KelvinVectorSize>::equivalentStress(sigd_j); + local_lubby2_properties.update(sig_eff); + }; + + auto newton_solver = NumLib::NewtonRaphson< + decltype(linear_solver), LocalJacobianMatrix, + decltype(update_jacobian), LocalResidualVector, + decltype(update_residual), decltype(update_solution)>( + linear_solver, update_jacobian, update_residual, update_solution, + _nonlinear_solver_parameters); + + auto const success_iterations = newton_solver.solve(K_loc); + + if (!success_iterations) + return {}; + + // If the Newton loop didn't run, the linear solver will not be + // initialized. + // This happens usually for the first iteration of the first timestep. + if (*success_iterations == 0) + linear_solver.compute(K_loc); + } + + KelvinMatrix C = + tangentStiffnessA<DisplacementDim>(local_lubby2_properties.GM0, + local_lubby2_properties.KM0, + linear_solver); + + // Hydrostatic part for the stress and the tangent. + double const eps_i_trace = Invariants::trace(eps); + KelvinVector const sigma = + local_lubby2_properties.GM0 * sigd_j + + local_lubby2_properties.KM0 * eps_i_trace * Invariants::identity2; + return {std::make_tuple( + sigma, + std::unique_ptr< + typename MechanicsBase<DisplacementDim>::MaterialStateVariables>{ + new MaterialStateVariables{state}}, + C)}; +} + +template <int DisplacementDim> +void Lubby2<DisplacementDim>::calculateResidualBurgers( + const double dt, + const KelvinVector& strain_curr, + const KelvinVector& stress_curr, + KelvinVector& strain_Kel_curr, + const KelvinVector& strain_Kel_t, + KelvinVector& strain_Max_curr, + const KelvinVector& strain_Max_t, + ResidualVector& res, + detail::LocalLubby2Properties<DisplacementDim> const& properties) +{ + // calculate stress residual + res.template segment<KelvinVectorSize>(0).noalias() = + stress_curr - 2. * (strain_curr - strain_Kel_curr - strain_Max_curr); + + // calculate Kelvin strain residual + res.template segment<KelvinVectorSize>(KelvinVectorSize).noalias() = + 1. / dt * (strain_Kel_curr - strain_Kel_t) - + 1. / (2. * properties.etaK) * (properties.GM0 * stress_curr - + 2. * properties.GK * strain_Kel_curr); + + // calculate Maxwell strain residual + res.template segment<KelvinVectorSize>(2 * KelvinVectorSize).noalias() = + 1. / dt * (strain_Max_curr - strain_Max_t) - + 0.5 * properties.GM0 / properties.etaM * stress_curr; +} + +template <int DisplacementDim> +void Lubby2<DisplacementDim>::calculateJacobianBurgers( + double const t, + ProcessLib::SpatialPosition const& x, + const double dt, + JacobianMatrix& Jac, + double s_eff, + const KelvinVector& sig_i, + const KelvinVector& eps_K_i, + detail::LocalLubby2Properties<DisplacementDim> const& properties) +{ + Jac.setZero(); + + // build G_11 + Jac.template block<KelvinVectorSize, KelvinVectorSize>(0, 0).setIdentity(); + + // build G_12 + Jac.template block<KelvinVectorSize, KelvinVectorSize>(0, KelvinVectorSize) + .diagonal() + .setConstant(2); + + // build G_13 + Jac.template block<KelvinVectorSize, KelvinVectorSize>(0, + 2 * KelvinVectorSize) + .diagonal() + .setConstant(2); + + // build G_21 + Jac.template block<KelvinVectorSize, KelvinVectorSize>(KelvinVectorSize, 0) + .noalias() = + -0.5 * properties.GM0 / properties.etaK * KelvinMatrix::Identity(); + if (s_eff > 0.) + { + KelvinVector const eps_K_aid = + 1. / (properties.etaK * properties.etaK) * + (properties.GM0 * sig_i - 2. * properties.GK * eps_K_i); + + KelvinVector const dG_K = 1.5 * _mp.mK(t, x)[0] * properties.GK * + properties.GM0 / s_eff * sig_i; + KelvinVector const dmu_vK = 1.5 * _mp.mvK(t, x)[0] * properties.GM0 * + properties.etaK / s_eff * sig_i; + Jac.template block<KelvinVectorSize, KelvinVectorSize>(KelvinVectorSize, + 0) + .noalias() += 0.5 * eps_K_aid * dmu_vK.transpose() + + 1. / properties.etaK * eps_K_i * dG_K.transpose(); + } + + // build G_22 + Jac.template block<KelvinVectorSize, KelvinVectorSize>(KelvinVectorSize, + KelvinVectorSize) + .diagonal() + .setConstant(1. / dt + properties.GK / properties.etaK); + + // nothing to do for G_23 + + // build G_31 + Jac.template block<KelvinVectorSize, KelvinVectorSize>(2 * KelvinVectorSize, + 0) + .noalias() = + -0.5 * properties.GM0 / properties.etaM * KelvinMatrix::Identity(); + if (s_eff > 0.) + { + KelvinVector const dmu_vM = 1.5 * _mp.mvM(t, x)[0] * properties.GM0 * + properties.etaM / s_eff * sig_i; + Jac.template block<KelvinVectorSize, KelvinVectorSize>( + 2 * KelvinVectorSize, 0) + .noalias() += 0.5 * properties.GM0 / + (properties.etaM * properties.etaM) * sig_i * + dmu_vM.transpose(); + } + + // nothing to do for G_32 + + // build G_33 + Jac.template block<KelvinVectorSize, KelvinVectorSize>(2 * KelvinVectorSize, + 2 * KelvinVectorSize) + .diagonal() + .setConstant(1. / dt); +} + template class Lubby2<2>; template class Lubby2<3>; diff --git a/ProcessLib/HydroMechanics/CreateHydroMechanicsProcess.cpp b/ProcessLib/HydroMechanics/CreateHydroMechanicsProcess.cpp index 61782e91cc3a90717f19fa5da681e41dee02bc0a..4914d6fce61003187e7b618e43e4ed74b5bbd158 100644 --- a/ProcessLib/HydroMechanics/CreateHydroMechanicsProcess.cpp +++ b/ProcessLib/HydroMechanics/CreateHydroMechanicsProcess.cpp @@ -11,8 +11,10 @@ #include <cassert> -#include "MaterialLib/SolidModels/CreateLinearElasticIsotropic.h" +#include "MaterialLib/SolidModels/MechanicsBase.h" +#include "MaterialLib/SolidModels/CreateConstitutiveRelation.h" #include "ProcessLib/Output/CreateSecondaryVariables.h" +#include "ProcessLib/Utils/ProcessUtils.h" #include "HydroMechanicsProcess.h" #include "HydroMechanicsProcessData.h" @@ -100,29 +102,9 @@ std::unique_ptr<Process> createHydroMechanicsProcess( } // Constitutive relation. - // read type; - auto const constitutive_relation_config = - //! \ogs_file_param{prj__processes__process__HYDRO_MECHANICS__constitutive_relation} - config.getConfigSubtree("constitutive_relation"); - - auto const type = - //! \ogs_file_param{prj__processes__process__HYDRO_MECHANICS__constitutive_relation__type} - constitutive_relation_config.peekConfigParameter<std::string>("type"); - - std::unique_ptr<MaterialLib::Solids::MechanicsBase<DisplacementDim>> - material = nullptr; - if (type == "LinearElasticIsotropic") - { - material = - MaterialLib::Solids::createLinearElasticIsotropic<DisplacementDim>( - parameters, constitutive_relation_config); - } - else - { - OGS_FATAL( - "Cannot construct constitutive relation of given type \'%s\'.", - type.c_str()); - } + auto material = + MaterialLib::Solids::createConstitutiveRelation<DisplacementDim>( + parameters, config); // Intrinsic permeability auto& intrinsic_permeability = findParameter<double>( diff --git a/ProcessLib/LIE/HydroMechanics/CreateHydroMechanicsProcess.cpp b/ProcessLib/LIE/HydroMechanics/CreateHydroMechanicsProcess.cpp index 44a21ff9b3e481b3a9d52c2fc173ce8e48d8c64e..5a8552fb5177c29132a0c66a5d615db28206bdbe 100644 --- a/ProcessLib/LIE/HydroMechanics/CreateHydroMechanicsProcess.cpp +++ b/ProcessLib/LIE/HydroMechanics/CreateHydroMechanicsProcess.cpp @@ -14,7 +14,7 @@ #include "MaterialLib/FractureModels/CreateCohesiveZoneModeI.h" #include "MaterialLib/FractureModels/CreateLinearElasticIsotropic.h" #include "MaterialLib/FractureModels/CreateMohrCoulomb.h" -#include "MaterialLib/SolidModels/CreateLinearElasticIsotropic.h" +#include "MaterialLib/SolidModels/CreateConstitutiveRelation.h" #include "ProcessLib/Output/CreateSecondaryVariables.h" #include "ProcessLib/Utils/ProcessUtils.h" // required for findParameter @@ -125,28 +125,9 @@ std::unique_ptr<Process> createHydroMechanicsProcess( // Constitutive relation. - // read type; - auto const constitutive_relation_config = - //! \ogs_file_param{prj__processes__process__HYDRO_MECHANICS_WITH_LIE__constitutive_relation} - config.getConfigSubtree("constitutive_relation"); - - auto const type = - //! \ogs_file_param{prj__processes__process__HYDRO_MECHANICS_WITH_LIE__constitutive_relation__type} - constitutive_relation_config.peekConfigParameter<std::string>("type"); - - std::unique_ptr<MaterialLib::Solids::MechanicsBase<GlobalDim>> material = - nullptr; - if (type == "LinearElasticIsotropic") - { - material = MaterialLib::Solids::createLinearElasticIsotropic<GlobalDim>( - parameters, constitutive_relation_config); - } - else - { - OGS_FATAL( - "Cannot construct constitutive relation of given type \'%s\'.", - type.c_str()); - } + auto material = + MaterialLib::Solids::createConstitutiveRelation<GlobalDim>( + parameters, config); // Intrinsic permeability auto& intrinsic_permeability = findParameter<double>( diff --git a/ProcessLib/LIE/SmallDeformation/CreateSmallDeformationProcess.cpp b/ProcessLib/LIE/SmallDeformation/CreateSmallDeformationProcess.cpp index 9038979f191a1a1a36c09551d5c871c986930339..b834695aca4de61eb4f74431dd8c51fcdfb81463 100644 --- a/ProcessLib/LIE/SmallDeformation/CreateSmallDeformationProcess.cpp +++ b/ProcessLib/LIE/SmallDeformation/CreateSmallDeformationProcess.cpp @@ -14,7 +14,7 @@ #include "MaterialLib/FractureModels/CreateCohesiveZoneModeI.h" #include "MaterialLib/FractureModels/CreateLinearElasticIsotropic.h" #include "MaterialLib/FractureModels/CreateMohrCoulomb.h" -#include "MaterialLib/SolidModels/CreateLinearElasticIsotropic.h" +#include "MaterialLib/SolidModels/CreateConstitutiveRelation.h" #include "ProcessLib/Output/CreateSecondaryVariables.h" #include "ProcessLib/Utils/ProcessUtils.h" // required for findParameter @@ -99,29 +99,9 @@ std::unique_ptr<Process> createSmallDeformationProcess( process_variables.push_back(std::move(per_process_variables)); // Constitutive relation. - // read type; - auto const constitutive_relation_config = - //! \ogs_file_param{prj__processes__process__SMALL_DEFORMATION_WITH_LIE__constitutive_relation} - config.getConfigSubtree("constitutive_relation"); - - auto const type = - //! \ogs_file_param{prj__processes__process__SMALL_DEFORMATION_WITH_LIE__constitutive_relation__type} - constitutive_relation_config.peekConfigParameter<std::string>("type"); - - std::unique_ptr<MaterialLib::Solids::MechanicsBase<DisplacementDim>> - material = nullptr; - if (type == "LinearElasticIsotropic") - { - material = - MaterialLib::Solids::createLinearElasticIsotropic<DisplacementDim>( - parameters, constitutive_relation_config); - } - else - { - OGS_FATAL( - "Cannot construct constitutive relation of given type \'%s\'.", - type.c_str()); - } + auto material = + MaterialLib::Solids::createConstitutiveRelation<DisplacementDim>( + parameters, config); // Fracture constitutive relation. // read type; diff --git a/ProcessLib/SmallDeformation/CreateSmallDeformationProcess.cpp b/ProcessLib/SmallDeformation/CreateSmallDeformationProcess.cpp index 0df0542d83eeee8e96ef7f1a30631d2a8369ef91..ca1ee9024aba05f118b75ed5b3afb62f6ec2c533 100644 --- a/ProcessLib/SmallDeformation/CreateSmallDeformationProcess.cpp +++ b/ProcessLib/SmallDeformation/CreateSmallDeformationProcess.cpp @@ -11,10 +11,9 @@ #include <cassert> -#include "MaterialLib/SolidModels/CreateEhlers.h" -#include "MaterialLib/SolidModels/CreateLinearElasticIsotropic.h" -#include "MaterialLib/SolidModels/CreateLubby2.h" +#include "MaterialLib/SolidModels/CreateConstitutiveRelation.h" #include "ProcessLib/Output/CreateSecondaryVariables.h" +#include "ProcessLib/Utils/ProcessUtils.h" #include "SmallDeformationProcess.h" #include "SmallDeformationProcessData.h" @@ -66,39 +65,9 @@ createSmallDeformationProcess( process_variables.push_back(std::move(per_process_variables)); // Constitutive relation. - // read type; - auto const constitutive_relation_config = - //! \ogs_file_param{prj__processes__process__SMALL_DEFORMATION__constitutive_relation} - config.getConfigSubtree("constitutive_relation"); - - auto const type = - //! \ogs_file_param{prj__processes__process__SMALL_DEFORMATION__constitutive_relation__type} - constitutive_relation_config.peekConfigParameter<std::string>("type"); - - std::unique_ptr<MaterialLib::Solids::MechanicsBase<DisplacementDim>> - material = nullptr; - if (type == "Ehlers") - { - material = MaterialLib::Solids::Ehlers::createEhlers<DisplacementDim>( - parameters, constitutive_relation_config); - } - else if (type == "LinearElasticIsotropic") - { - material = - MaterialLib::Solids::createLinearElasticIsotropic<DisplacementDim>( - parameters, constitutive_relation_config); - } - else if (type == "Lubby2") - { - material = MaterialLib::Solids::Lubby2::createLubby2<DisplacementDim>( - parameters, constitutive_relation_config); - } - else - { - OGS_FATAL( - "Cannot construct constitutive relation of given type \'%s\'.", - type.c_str()); - } + auto material = + MaterialLib::Solids::createConstitutiveRelation<DisplacementDim>( + parameters, config); // Solid density auto& solid_density = findParameter<double>( diff --git a/ProcessLib/ThermoMechanics/CreateThermoMechanicsProcess.cpp b/ProcessLib/ThermoMechanics/CreateThermoMechanicsProcess.cpp index e8994170c3b507c1e5c43fbfd4618d8b8bc5c89a..e57ed7bf8cc78562db7ea3a9c01a68fc6952bd08 100644 --- a/ProcessLib/ThermoMechanics/CreateThermoMechanicsProcess.cpp +++ b/ProcessLib/ThermoMechanics/CreateThermoMechanicsProcess.cpp @@ -11,10 +11,10 @@ #include <cassert> -#include "MaterialLib/SolidModels/CreateEhlers.h" -#include "MaterialLib/SolidModels/CreateLinearElasticIsotropic.h" -#include "MaterialLib/SolidModels/CreateLubby2.h" +#include "MaterialLib/SolidModels/MechanicsBase.h" +#include "MaterialLib/SolidModels/CreateConstitutiveRelation.h" #include "ProcessLib/Output/CreateSecondaryVariables.h" +#include "ProcessLib/Utils/ProcessUtils.h" #include "ThermoMechanicsProcess.h" #include "ThermoMechanicsProcessData.h" @@ -101,39 +101,9 @@ std::unique_ptr<Process> createThermoMechanicsProcess( } // Constitutive relation. - // read type; - auto const constitutive_relation_config = - //! \ogs_file_param{prj__processes__process__THERMO_MECHANICS__constitutive_relation} - config.getConfigSubtree("constitutive_relation"); - - auto const type = - //! \ogs_file_param{prj__processes__process__THERMO_MECHANICS__constitutive_relation__type} - constitutive_relation_config.peekConfigParameter<std::string>("type"); - - std::unique_ptr<MaterialLib::Solids::MechanicsBase<DisplacementDim>> - material = nullptr; - if (type == "Ehlers") - { - material = MaterialLib::Solids::Ehlers::createEhlers<DisplacementDim>( - parameters, constitutive_relation_config); - } - else if (type == "LinearElasticIsotropic") - { - material = - MaterialLib::Solids::createLinearElasticIsotropic<DisplacementDim>( - parameters, constitutive_relation_config); - } - else if (type == "Lubby2") - { - material = MaterialLib::Solids::Lubby2::createLubby2<DisplacementDim>( - parameters, constitutive_relation_config); - } - else - { - OGS_FATAL( - "Cannot construct constitutive relation of given type \'%s\'.", - type.c_str()); - } + auto material = + MaterialLib::Solids::createConstitutiveRelation<DisplacementDim>( + parameters, config); // Reference solid density auto& reference_solid_density = findParameter<double>(