From b61bdb31d0bf3801fc391d8d13ce9bbc7d6210cf Mon Sep 17 00:00:00 2001
From: "Dmitry Yu. Naumov" <github@naumov.de>
Date: Fri, 9 Nov 2018 18:47:11 +0100
Subject: [PATCH] [MatL] Extract calculateDegradedStress().

The multiple inheritance for the phase field extension
is not actually needed and can be completely avoided.
---
 .../LinearElasticIsotropicPhaseField.cpp      |  21 ---
 .../LinearElasticIsotropicPhaseField.h        | 175 +++++++-----------
 MaterialLib/SolidModels/PhaseFieldExtension.h |  89 ---------
 ProcessLib/PhaseField/PhaseFieldFEM.h         |  24 ++-
 4 files changed, 78 insertions(+), 231 deletions(-)
 delete mode 100644 MaterialLib/SolidModels/LinearElasticIsotropicPhaseField.cpp
 delete mode 100644 MaterialLib/SolidModels/PhaseFieldExtension.h

diff --git a/MaterialLib/SolidModels/LinearElasticIsotropicPhaseField.cpp b/MaterialLib/SolidModels/LinearElasticIsotropicPhaseField.cpp
deleted file mode 100644
index 2cfed161f5d..00000000000
--- a/MaterialLib/SolidModels/LinearElasticIsotropicPhaseField.cpp
+++ /dev/null
@@ -1,21 +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
- *
- */
-
-#include "LinearElasticIsotropicPhaseField.h"
-
-namespace MaterialLib
-{
-namespace Solids
-{
-
-template class LinearElasticIsotropicPhaseField<2>;
-template class LinearElasticIsotropicPhaseField<3>;
-
-}   // namespace Solids
-}   // namespace MaterialLib
diff --git a/MaterialLib/SolidModels/LinearElasticIsotropicPhaseField.h b/MaterialLib/SolidModels/LinearElasticIsotropicPhaseField.h
index 003c68e70ff..ae497050da9 100644
--- a/MaterialLib/SolidModels/LinearElasticIsotropicPhaseField.h
+++ b/MaterialLib/SolidModels/LinearElasticIsotropicPhaseField.h
@@ -11,135 +11,84 @@
 
 #include "MathLib/KelvinVector.h"
 
-#include "LinearElasticIsotropic.h"
-#include "PhaseFieldExtension.h"
-
 namespace MaterialLib
 {
 namespace Solids
 {
+namespace Phasefield
+{
+/** Decompose the stiffness into tensile and compressive part.
+ * Judging by the physical observations, compression perpendicular
+ * to a crack does not cause crack propagation. Thus,
+ * the phase-field parameter is only involved into the tensile part
+ * to degrade the elastic strain energy.
+ */
 template <int DisplacementDim>
-class LinearElasticIsotropicPhaseField final
-    : public LinearElasticIsotropic<DisplacementDim>,
-      public PhaseFieldExtension<DisplacementDim>
+std::tuple<MathLib::KelvinVector::KelvinVectorType<
+               DisplacementDim> /* sigma_real */,
+           MathLib::KelvinVector::KelvinVectorType<
+               DisplacementDim> /* sigma_tensile */,
+           MathLib::KelvinVector::KelvinMatrixType<
+               DisplacementDim> /* C_tensile */,
+           MathLib::KelvinVector::KelvinMatrixType<
+               DisplacementDim> /* C_compressive */,
+           double /* strain_energy_tensile */,
+           double /* elastic_energy */
+           >
+calculateDegradedStress(
+    double const degradation,
+    double const bulk_modulus,
+    double const mu,
+    MathLib::KelvinVector::KelvinVectorType<DisplacementDim> const& eps)
 {
-public:
     static int const KelvinVectorSize =
         MathLib::KelvinVector::KelvinVectorDimensions<DisplacementDim>::value;
     using KelvinVector =
         MathLib::KelvinVector::KelvinVectorType<DisplacementDim>;
     using KelvinMatrix =
         MathLib::KelvinVector::KelvinMatrixType<DisplacementDim>;
+    using Invariants = MathLib::KelvinVector::Invariants<KelvinVectorSize>;
+    // calculation of deviatoric parts
+    auto const& P_dev = Invariants::deviatoric_projection;
+    KelvinVector const epsd_curr = P_dev * eps;
 
-    explicit LinearElasticIsotropicPhaseField(
-        typename LinearElasticIsotropic<DisplacementDim>::MaterialProperties&&
-            material_properties)
-        : LinearElasticIsotropic<DisplacementDim>(
-              std::move(material_properties))
-    {
-    }
-
-    std::unique_ptr<
-        typename MechanicsBase<DisplacementDim>::MaterialStateVariables>
-    createMaterialStateVariables() const override
-    {
-        return LinearElasticIsotropic<
-            DisplacementDim>::createMaterialStateVariables();
-    }
-
-    boost::optional<std::tuple<KelvinVector,
-                               std::unique_ptr<typename MechanicsBase<
-                                   DisplacementDim>::MaterialStateVariables>,
-                               KelvinMatrix>>
-    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,
-        double const T) const override
-    {
-        return LinearElasticIsotropic<DisplacementDim>::integrateStress(
-            t, x, dt, eps_prev, eps, sigma_prev, material_state_variables, T);
-    }
+    // Hydrostatic part for the stress and the tangent.
+    double const eps_curr_trace = Invariants::trace(eps);
 
-    double computeFreeEnergyDensity(
-        double const t,
-        ProcessLib::SpatialPosition const& x,
-        double const dt,
-        KelvinVector const& eps,
-        KelvinVector const& sigma,
-        typename MechanicsBase<DisplacementDim>::MaterialStateVariables const&
-            material_state_variables) const override
-    {
-        return LinearElasticIsotropic<DisplacementDim>::
-            computeFreeEnergyDensity(
-                t, x, dt, eps, sigma, material_state_variables);
-    }
+    KelvinMatrix C_tensile = KelvinMatrix::Zero();
+    KelvinMatrix C_compressive = KelvinMatrix::Zero();
 
-    /** Decompose the stiffness into tensile and compressive part.
-     * Judging by the physical observations, compression perpendicular
-     * to a crack does not cause crack propagation. Thus,
-     * the phase-field parameter is only involved into the tensile part
-     * to degrade the elastic strain energy.
-     */
-    bool calculateDegradedStress(double const t,
-                                 ProcessLib::SpatialPosition const& x,
-                                 KelvinVector const& eps,
-                                 double& strain_energy_tensile,
-                                 KelvinVector& sigma_tensile,
-                                 KelvinVector& sigma_compressive,
-                                 KelvinMatrix& C_tensile,
-                                 KelvinMatrix& C_compressive,
-                                 KelvinVector& sigma_real,
-                                 double const degradation,
-                                 double& elastic_energy) const override
+    if (eps_curr_trace >= 0)
     {
-        using Invariants = MathLib::KelvinVector::Invariants<KelvinVectorSize>;
-        // calculation of deviatoric parts
-        auto const& P_dev = Invariants::deviatoric_projection;
-        KelvinVector const epsd_curr = P_dev * eps;
-
-        // Hydrostatic part for the stress and the tangent.
-        double const eps_curr_trace = Invariants::trace(eps);
-
-        auto const& K =
-            LinearElasticIsotropic<DisplacementDim>::_mp.bulk_modulus(t, x);
-        auto const& mu = LinearElasticIsotropic<DisplacementDim>::_mp.mu(t, x);
-
-        C_tensile = KelvinMatrix::Zero();
-        C_compressive = KelvinMatrix::Zero();
-
-        if (eps_curr_trace >= 0)
-        {
-            strain_energy_tensile = K / 2 * eps_curr_trace * eps_curr_trace +
-                                    mu * epsd_curr.transpose() * epsd_curr;
-            sigma_tensile.noalias() =
-                K * eps_curr_trace * Invariants::identity2 + 2 * mu * epsd_curr;
-            sigma_compressive.noalias() = KelvinVector::Zero();
-            C_tensile.template topLeftCorner<3, 3>().setConstant(K);
-            C_tensile.noalias() += 2 * mu * P_dev * KelvinMatrix::Identity();
-            elastic_energy = degradation * strain_energy_tensile;
-        }
-        else
-        {
-            strain_energy_tensile = mu * epsd_curr.transpose() * epsd_curr;
-            sigma_tensile.noalias() = 2 * mu * epsd_curr;
-            sigma_compressive.noalias() =
-                K * eps_curr_trace * Invariants::identity2;
-            C_tensile.noalias() = 2 * mu * P_dev * KelvinMatrix::Identity();
-            C_compressive.template topLeftCorner<3, 3>().setConstant(K);
-            elastic_energy = K / 2 * eps_curr_trace * eps_curr_trace +
-                             mu * epsd_curr.transpose() * epsd_curr;
-        }
-
-        sigma_real.noalias() = degradation * sigma_tensile + sigma_compressive;
-        return true;
+        double const strain_energy_tensile =
+            bulk_modulus / 2 * eps_curr_trace * eps_curr_trace +
+            mu * epsd_curr.transpose() * epsd_curr;
+        KelvinVector const sigma_tensile =
+            bulk_modulus * eps_curr_trace * Invariants::identity2 +
+            2 * mu * epsd_curr;
+        C_tensile.template topLeftCorner<3, 3>().setConstant(bulk_modulus);
+        C_tensile.noalias() += 2 * mu * P_dev * KelvinMatrix::Identity();
+        double const elastic_energy = degradation * strain_energy_tensile;
+        KelvinVector const sigma_real =
+            degradation * sigma_tensile;  // + sigma_compressive, which is zero;
+        return std::make_tuple(sigma_real, sigma_tensile, C_tensile,
+                               C_compressive, strain_energy_tensile,
+                               elastic_energy);
     }
-};
-
-extern template class LinearElasticIsotropicPhaseField<2>;
-extern template class LinearElasticIsotropicPhaseField<3>;
-
+    double const strain_energy_tensile = mu * epsd_curr.transpose() * epsd_curr;
+    KelvinVector const sigma_tensile = 2 * mu * epsd_curr;
+    KelvinVector const sigma_compressive =
+        bulk_modulus * eps_curr_trace * Invariants::identity2;
+    C_tensile.noalias() = 2 * mu * P_dev * KelvinMatrix::Identity();
+    C_compressive.template topLeftCorner<3, 3>().setConstant(bulk_modulus);
+    double const elastic_energy =
+        bulk_modulus / 2 * eps_curr_trace * eps_curr_trace +
+        mu * epsd_curr.transpose() * epsd_curr;
+    KelvinVector const sigma_real =
+        degradation * sigma_tensile + sigma_compressive;
+    return std::make_tuple(sigma_real, sigma_tensile, C_tensile, C_compressive,
+                           strain_energy_tensile, elastic_energy);
+}
+}  // namespace Phasefield
 }  // namespace Solids
 }  // namespace MaterialLib
diff --git a/MaterialLib/SolidModels/PhaseFieldExtension.h b/MaterialLib/SolidModels/PhaseFieldExtension.h
deleted file mode 100644
index 425da16cf2b..00000000000
--- a/MaterialLib/SolidModels/PhaseFieldExtension.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/**
- * \file
- * \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 "MechanicsBase.h"
-
-namespace MaterialLib
-{
-namespace Solids
-{
-template <int DisplacementDim>
-struct PhaseFieldExtension : public MechanicsBase<DisplacementDim>
-{
-    using KelvinVector =
-        MathLib::KelvinVector::KelvinVectorType<DisplacementDim>;
-    using KelvinMatrix =
-        MathLib::KelvinVector::KelvinMatrixType<DisplacementDim>;
-    virtual bool calculateDegradedStress(double const t,
-                                         ProcessLib::SpatialPosition const& x,
-                                         KelvinVector const& eps,
-                                         double& strain_energy_tensile,
-                                         KelvinVector& sigma_tensile,
-                                         KelvinVector& sigma_compressive,
-                                         KelvinMatrix& C_tensile,
-                                         KelvinMatrix& C_compressive,
-                                         KelvinVector& sigma_real,
-                                         double const degradation,
-                                         double& elastic_energy) const = 0;
-
-    /// Dynamic size Kelvin vector and matrix wrapper for the polymorphic
-    /// constitutive relation compute function.
-    bool calculateDegradedStress(
-        double const t,
-        ProcessLib::SpatialPosition const& x,
-        Eigen::Matrix<double, Eigen::Dynamic, 1> const& eps,
-        double& strain_energy_tensile,
-        Eigen::Matrix<double, Eigen::Dynamic, 1>& sigma_tensile,
-        Eigen::Matrix<double, Eigen::Dynamic, 1>& sigma_compressive,
-        Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>&
-            C_tensile,
-        Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>&
-            C_compressive,
-        Eigen::Matrix<double, Eigen::Dynamic, 1>& sigma_real,
-        double const degradation,
-        double& elastic_energy) const
-    {
-        // TODO Avoid copies of data:
-        // Using MatrixBase<Derived> not possible because template functions
-        // cannot be virtual. Maybe there is a workaround for this.  Using
-        // Map<Matrix<double, ...>> makes the interface (for the material model
-        // implementation) unnecessary difficult.
-        KelvinVector const eps_{eps};
-        KelvinVector sigma_tensile_{sigma_tensile};
-        KelvinVector sigma_compressive_{sigma_compressive};
-        KelvinMatrix C_tensile_{C_tensile};
-        KelvinMatrix C_compressive_{C_compressive};
-        KelvinVector sigma_real_{sigma_real};
-
-        bool const result = calculateDegradedStress(t,
-                                                    x,
-                                                    eps_,
-                                                    strain_energy_tensile,
-                                                    sigma_tensile_,
-                                                    sigma_compressive_,
-                                                    C_tensile_,
-                                                    C_compressive_,
-                                                    sigma_real_,
-                                                    degradation,
-                                                    elastic_energy);
-
-        sigma_tensile = sigma_tensile_;
-        sigma_compressive = sigma_compressive_;
-        C_tensile = C_tensile_;
-        C_compressive = C_compressive_;
-        sigma_real = sigma_real_;
-        return result;
-    }
-};
-
-}  // namespace Solids
-}  // namespace MaterialLib
diff --git a/ProcessLib/PhaseField/PhaseFieldFEM.h b/ProcessLib/PhaseField/PhaseFieldFEM.h
index ec85389e166..32466594ff3 100644
--- a/ProcessLib/PhaseField/PhaseFieldFEM.h
+++ b/ProcessLib/PhaseField/PhaseFieldFEM.h
@@ -70,20 +70,28 @@ struct IntegrationPointData final
 
     template <typename DisplacementVectorType>
     void updateConstitutiveRelation(double const t,
-                                    SpatialPosition const& x_position,
+                                    SpatialPosition const& x,
                                     double const /*dt*/,
                                     DisplacementVectorType const& /*u*/,
                                     double const degradation)
     {
-        static_cast<
-            MaterialLib::Solids::PhaseFieldExtension<DisplacementDim> const&>(
-            solid_material)
-            .calculateDegradedStress(t, x_position, eps, strain_energy_tensile,
-                                     sigma_tensile, sigma_compressive,
-                                     C_tensile, C_compressive, sigma,
-                                     degradation, elastic_energy);
+        auto linear_elastic_mp =
+            static_cast<MaterialLib::Solids::LinearElasticIsotropic<
+                DisplacementDim> const&>(solid_material)
+                .getMaterialProperties();
+
+        auto const bulk_modulus = linear_elastic_mp.bulk_modulus(t, x);
+        auto const mu = linear_elastic_mp.mu(t, x);
+
+        std::tie(sigma, sigma_tensile, C_tensile, C_compressive,
+                 strain_energy_tensile, elastic_energy) =
+            MaterialLib::Solids::Phasefield::calculateDegradedStress<
+                DisplacementDim>(degradation, bulk_modulus, mu, eps);
     }
     EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
+
+    static constexpr int kelvin_vector_size =
+        MathLib::KelvinVector::KelvinVectorDimensions<DisplacementDim>::value;
 };
 
 /// Used by for extrapolation of the integration point values. It is ordered
-- 
GitLab