text: // KRATOS  ___|  |                   |                   |
  //       \___ \  __|  __| |   |  __| __| |   |  __| _` | |
  //             | |   |    |   | (    |   |   | |   (   | |
  //       _____/ \__|_|   \__,_|\___|\__|\__,_|_|  \__,_|_| MECHANICS
  //
  //  License:         BSD License
  //                   license: structural_mechanics_application/license.txt
  //
  //  Main authors:    Vicente Mataix Ferrandiz
  //  Collaborator:    Alejandro Cornejo
  //                   Lucia Barbu
  //
  
  #if !defined(KRATOS_GENERIC_FINITE_STRAIN_ISOTROPIC_PLASTICITY_3D_H_INCLUDED)
  #define KRATOS_GENERIC_FINITE_STRAIN_ISOTROPIC_PLASTICITY_3D_H_INCLUDED
  
  // System includes
  
  // External includes
  
  // Project includes
  #include "includes/constitutive_law.h"
  
  namespace Kratos
  {
  ///@name Kratos Globals
  ///@{
  
  ///@}
  ///@name Type Definitions
  ///@{
  
      // The size type definition
      typedef std::size_t SizeType;
  
  ///@}
  ///@name  Enum's
  ///@{
  
  ///@}
  ///@name  Functions
  ///@{
  
  ///@}
  ///@name Kratos Classes
  ///@{
  
  /**
   * @class GenericFiniteStrainIsotropicPlasticity
   * @ingroup StructuralMechanicsApplication
   * @brief This class is the base class which define all the constitutive laws for plasticity in large deformation
   * @details This class considers a constitutive law integrator as an intermediate utility to compute the plasticity, as well as hyper elastic law to compute the prediction
   * This implementation is based on the multiplicative elastoplasticity kinematics (COMPUTATIONAL METHODS FOR PLASTICITY THEORY AND APPLICATIONS. EA de Souza Neto,D Perić, DRJ Owen pag. 603).
   * The main hypothesis underlying the finite strain elastoplasticity constitutive framework described here is the multiplicative decomposition of the deformation gradient, F , into elastic and plastic contributions; that is, it is assumed that the deformation gradient can be decomposed as the product F = Fe x Fp, where F and F are named, respectively, the elastic and plastic deformation gradients.
   * @tparam TConstLawIntegratorType The constitutive law integrator considered
   * @param TElasticBehaviourLaw Defines the elastic behaviour of the constitutive law (can be hyperelastic or just linear elastic, or any desired elastic behaviour)
   * @author Vicente Mataix Ferrandiz
   */
  template<class TElasticBehaviourLaw, class TConstLawIntegratorType>
  class KRATOS_API(STRUCTURAL_MECHANICS_APPLICATION) GenericFiniteStrainIsotropicPlasticity
      : public TElasticBehaviourLaw
  {
  public:
      ///@name Type Definitions
      ///@{
  
      /// The define the working dimension size, already defined in the integrator
      static constexpr SizeType Dimension = TConstLawIntegratorType::Dimension;
  
      /// The define the Voigt size, already defined in the  integrator
      static constexpr SizeType VoigtSize = TConstLawIntegratorType::VoigtSize;
  
      /// Definition of the base class
      typedef TElasticBehaviourLaw BaseType;
  
      /// The definition of the Voigt array type
      typedef array_1d<double, VoigtSize> BoundedArrayType;
  
      /// The definition of the bounded matrix type
      typedef BoundedMatrix<double, Dimension, Dimension> BoundedMatrixType;
  
      /// Counted pointer of GenericFiniteStrainIsotropicPlasticity
      KRATOS_CLASS_POINTER_DEFINITION(GenericFiniteStrainIsotropicPlasticity);
  
      /// The node definition
      typedef Node<3> NodeType;
  
      /// The geometry definition
      typedef Geometry<NodeType> GeometryType;
  
      ///@}
      ///@name Life Cycle
      ///@{
  
      /**
      * Default constructor.
      */
      GenericFiniteStrainIsotropicPlasticity()
      {
      }
  
      /**
      * Clone.
      */
      ConstitutiveLaw::Pointer Clone() const override
      {
          return Kratos::make_shared<GenericFiniteStrainIsotropicPlasticity<TElasticBehaviourLaw, TConstLawIntegratorType>>(*this);
      }
  
      /**
      * Copy constructor.
      */
      GenericFiniteStrainIsotropicPlasticity(const GenericFiniteStrainIsotropicPlasticity &rOther)
          : BaseType(rOther),
            mPlasticDissipation(rOther.mPlasticDissipation),
            mThreshold(rOther.mThreshold),
            mPlasticDeformationGradient(rOther.mPlasticDeformationGradient),
            mPreviousDeformationGradient(rOther.mPreviousDeformationGradient)
      {
      }
  
      /**
      * Destructor.
      */
      ~GenericFiniteStrainIsotropicPlasticity() override
      {
      }
  
      ///@}
      ///@name Operators
      ///@{
  
      ///@}
      ///@name Operations
      ///@{
  
      /**
       * @brief Computes the material response in terms of 1st Piola-Kirchhoff stresses and constitutive tensor
       * @see Parameters
       */
      void CalculateMaterialResponsePK1(ConstitutiveLaw::Parameters &rValues) override;
  
      /**
       * @brief Computes the material response in terms of 2nd Piola-Kirchhoff stresses and constitutive tensor
       * @see Parameters
       */
      void CalculateMaterialResponsePK2(ConstitutiveLaw::Parameters &rValues) override;
  
      /**
       * @brief Computes the material response in terms of Kirchhoff stresses and constitutive tensor
       * @see Parameters
       */
      void CalculateMaterialResponseKirchhoff(ConstitutiveLaw::Parameters &rValues) override;
  
      /**
       * @brief Computes the material response in terms of Cauchy stresses and constitutive tensor
       * @see Parameters
       */
      void CalculateMaterialResponseCauchy(ConstitutiveLaw::Parameters &rValues) override;
  
      /**
       * @brief This is to be called at the very beginning of the calculation
       * @details (e.g. from InitializeElement) in order to initialize all relevant attributes of the constitutive law
       * @param rMaterialProperties the Properties instance of the current element
       * @param rElementGeometry the geometry of the current element
       * @param rShapeFunctionsValues the shape functions values in the current integration point
       */
      void InitializeMaterial(
          const Properties& rMaterialProperties,
          const GeometryType& rElementGeometry,
          const Vector& rShapeFunctionsValues
          ) override;
  
      /**
       * @brief Finalize the material response in terms of 1st Piola-Kirchhoff stresses
       * @see Parameters
       */
      void FinalizeMaterialResponsePK1(ConstitutiveLaw::Parameters &rValues) override;
  
      /**
       * @brief Finalize the material response in terms of 2nd Piola-Kirchhoff stresses
       * @see Parameters
       */
      void FinalizeMaterialResponsePK2(ConstitutiveLaw::Parameters &rValues) override;
  
      /**
       * @brief Finalize the material response in terms of Kirchhoff stresses
       * @see Parameters
       */
      void FinalizeMaterialResponseKirchhoff(ConstitutiveLaw::Parameters &rValues) override;
      /**
       * Finalize the material response in terms of Cauchy stresses
       * @see Parameters
       */
      void FinalizeMaterialResponseCauchy(ConstitutiveLaw::Parameters &rValues) override;
  
      /**
       * @brief Returns whether this constitutive Law has specified variable (double)
       * @param rThisVariable the variable to be checked for
       * @return true if the variable is defined in the constitutive law
       */
      bool Has(const Variable<double> &rThisVariable) override;
  
      /**
       * @brief Returns whether this constitutive Law has specified variable (Vector)
       * @param rThisVariable the variable to be checked for
       * @return true if the variable is defined in the constitutive law
       */
      bool Has(const Variable<Vector> &rThisVariable) override;
  
      /**
       * @brief Returns whether this constitutive Law has specified variable (Matrix)
       * @param rThisVariable the variable to be checked for
       * @return true if the variable is defined in the constitutive law
       */
      bool Has(const Variable<Matrix> &rThisVariable) override;
  
      /**
       * @brief Sets the value of a specified variable (double)
       * @param rVariable the variable to be returned
       * @param rValue new value of the specified variable
       * @param rCurrentProcessInfo the process info
       */
      void SetValue(
          const Variable<double> &rThisVariable,
          const double& rValue,
          const ProcessInfo& rCurrentProcessInfo
          ) override;
  
      /**
       * @brief Sets the value of a specified variable (Vector)
       * @param rThisVariable the variable to be returned
       * @param rValue new value of the specified variable
       * @param rCurrentProcessInfo the process info
       */
      void SetValue(
          const Variable<Vector> &rThisVariable,
          const Vector& rValue,
          const ProcessInfo& rCurrentProcessInfo
          ) override;
  
      /**
       * @brief Sets the value of a specified variable (Matrix)
       * @param rThisVariable the variable to be returned
       * @param rValue new value of the specified variable
       * @param rCurrentProcessInfo the process info
       */
      void SetValue(
          const Variable<Matrix> &rThisVariable,
          const Matrix& rValue,
          const ProcessInfo& rCurrentProcessInfo
          ) override;
  
      /**
       * @brief Returns the value of a specified variable (double)
       * @param rThisVariable the variable to be returned
       * @param rValue a reference to the returned value
       * @return rValue output: the value of the specified variable
       */
      double& GetValue(
          const Variable<double> &rThisVariable,
          double& rValue
          ) override;
  
      /**
       * @brief Returns the value of a specified variable (Vector)
       * @param rThisVariable the variable to be returned
       * @param rValue a reference to the returned value
       * @return rValue output: the value of the specified variable
       */
      Vector& GetValue(
          const Variable<Vector> &rThisVariable,
          Vector& rValue
          ) override;
  
      /**
       * @brief Returns the value of a specified variable (Matrix)
       * @param rThisVariable the variable to be returned
       * @param rValue a reference to the returned value
       * @return rValue output: the value of the specified variable
       */
      Matrix& GetValue(
          const Variable<Matrix> &rThisVariable,
          Matrix& rValue
          ) override;
  
      /**
       * @brief If the CL requires to initialize the material response, called by the element in InitializeSolutionStep.
       */
      bool RequiresFinalizeMaterialResponse() override
      {
          return true;
      }
  
      /**
       * @brief Returns the value of a specified variable (double)
       * @param rParameterValues the needed parameters for the CL calculation
       * @param rThisVariable the variable to be returned
       * @param rValue a reference to the returned value
       * @param rValue output: the value of the specified variable
       */
      double& CalculateValue(
          ConstitutiveLaw::Parameters& rParameterValues,
          const Variable<double>& rThisVariable,
          double& rValue) override;
  
      /**
       * @brief Returns the value of a specified variable (vector)
       * @param rParameterValues the needed parameters for the CL calculation
       * @param rThisVariable the variable to be returned
       * @param rValue a reference to the returned value
       * @param rValue output: the value of the specified variable
       */
      Vector& CalculateValue(
          ConstitutiveLaw::Parameters& rParameterValues,
          const Variable<Vector>& rThisVariable,
          Vector& rValue
          ) override;
  
      /**
       * @brief Returns the value of a specified variable (matrix)
       * @param rParameterValues the needed parameters for the CL calculation
       * @param rThisVariable the variable to be returned
       * @param rValue a reference to the returned value
       * @param rValue output: the value of the specified variable
       */
      Matrix& CalculateValue(
          ConstitutiveLaw::Parameters& rParameterValues,
          const Variable<Matrix>& rThisVariable,
          Matrix& rValue
          ) override;
  
      /**
       * @brief This function provides the place to perform checks on the completeness of the input.
       * @details It is designed to be called only once (or anyway, not often) typically at the beginning
       * of the calculations, so to verify that nothing is missing from the input or that no common error is found.
       * @param rMaterialProperties The properties of the material
       * @param rElementGeometry The geometry of the element
       * @param rCurrentProcessInfo The current process info instance
       * @return 0 if OK, 1 otherwise
       */
      int Check(
          const Properties& rMaterialProperties,
          const GeometryType& rElementGeometry,
          const ProcessInfo& rCurrentProcessInfo
          ) override;
  
      ///@}
      ///@name Access
      ///@{
  
      ///@}
      ///@name Inquiry
      ///@{
  
      ///@}
      ///@name Input and output
      ///@{
  
      ///@}
      ///@name Friends
      ///@{
  
      ///@}
  
  protected:
      ///@name Protected static Member Variables
      ///@{
  
      ///@}
      ///@name Protected member Variables
      ///@{
  
      ///@}
      ///@name Protected Operators
      ///@{
  
      double& GetThreshold() { return mThreshold; }
      double& GetPlasticDissipation() { return mPlasticDissipation; }
      Matrix& GetPlasticDeformationGradient() { return mPlasticDeformationGradient; }
      Matrix& GetPreviousDeformationGradient() { return mPreviousDeformationGradient; }
  
      void SetThreshold(const double Threshold) { mThreshold = Threshold; }
      void SetPlasticDissipation(const double PlasticDissipation) { mPlasticDissipation = PlasticDissipation; }
      void SetPlasticDeformationGradient(const Matrix& rmPlasticDeformationGradient) { mPlasticDeformationGradient = rmPlasticDeformationGradient; }
      void SetPreviousDeformationGradient(const Matrix& rmPreviousDeformationGradient) { mPreviousDeformationGradient = rmPreviousDeformationGradient; }
  
      ///@}
      ///@name Protected Operations
      ///@{
  
      ///@}
      ///@name Protected  Access
      ///@{
  
      ///@}
      ///@name Protected Inquiry
      ///@{
  
      ///@}
      ///@name Protected LifeCycle
      ///@{
  
      ///@}
    private:
      ///@name Static Member Variables
      ///@{
  
      ///@}
      ///@name Member Variables
      ///@{
  
      // Converged values
      double mPlasticDissipation = 0.0;
      double mThreshold = 0.0;
      Matrix mPlasticDeformationGradient = IdentityMatrix(Dimension);
      Matrix mPreviousDeformationGradient = IdentityMatrix(Dimension);
  
      ///@}
      ///@name Private Operators
      ///@{
  
      ///@}
      ///@name Private Operations
      ///@{
  
      /**
       * @brief This method computes the tangent tensor
       * @param rValues The constitutive law parameters and flags
       * @param rStressMeasure The stress measure of the law
       */
      void CalculateTangentTensor(
          ConstitutiveLaw::Parameters &rValues,
          const ConstitutiveLaw::StressMeasure& rStressMeasure = ConstitutiveLaw::StressMeasure_Cauchy
          );
  
      ///@}
      ///@name Private  Access
      ///@{
  
      ///@}
      ///@name Private Inquiry
      ///@{
  
      ///@}
      ///@name Un accessible methods
      ///@{
  
      // Serialization
  
      friend class Serializer;
  
      void save(Serializer &rSerializer) const override
      {
          KRATOS_SERIALIZE_SAVE_BASE_CLASS(rSerializer, ConstitutiveLaw)
          rSerializer.save("PlasticDissipation", mPlasticDissipation);
          rSerializer.save("Threshold", mThreshold);
          rSerializer.save("PlasticDeformationGradient", mPlasticDeformationGradient);
          rSerializer.save("PreviousDeformationGradient", mPreviousDeformationGradient);
      }
  
      void load(Serializer &rSerializer) override
      {
          KRATOS_SERIALIZE_LOAD_BASE_CLASS(rSerializer, ConstitutiveLaw)
          rSerializer.load("PlasticDissipation", mPlasticDissipation);
          rSerializer.load("Threshold", mThreshold);
          rSerializer.load("PlasticDeformationGradient", mPlasticDeformationGradient);
          rSerializer.load("PreviousDeformationGradient", mPreviousDeformationGradient);
      }
  
      ///@}
  
  }; // Class GenericYieldSurface
  
  } // namespace Kratos
  #endif
  