MechanicalElastoPlasticDruckerPrager Class

This class implements the Drucker-Prager criteria for the elasto-plastic material law. It provides methods for evaluating stress, constitutive matrices, yield conditions, flow vectors, and their gradients, as well as handling plastic strain updates.

Contents

Methods

Author

Danilo Cavalcanti

Version History

Version 1.00.

Class Definition

classdef MechanicalElastoPlasticDruckerPrager < MechanicalElastoPlastic

Constructor method

    methods
        %------------------------------------------------------------------
        function this = MechanicalElastoPlasticDruckerPrager()
            this = this@MechanicalElastoPlastic();
            this.nstVar = 0;   % Hardening + Kinematic hardening
        end
    end

Public methods

    methods
        %------------------------------------------------------------------
        % Compute the stress vector and the constitutive matrix
        function [stress,Dt] = eval(this,material,ip)
            if strcmp(material.stressIntAlgorithm,'implicit')
                 [stress,Dt] = eval@MechanicalElastoPlastic(this,material,ip);
            elseif strcmp(material.stressIntAlgorithm,'alternative')
                [stress,Dt] = this.alternativeStressIntegration(material,ip);
            else
                disp('Error: the given stress integration algorithm is not available');
                disp('Tags of the methods available: ''implicit'', ''alternative''');
                error('Error: stressIntAlgorithm is not available');
            end
        end

        %------------------------------------------------------------------
        % Compute the stress vector and the constitutive matrix
        function [stress,Dt] = alternativeStressIntegration(this,material,ip)

            % Constitutive matrix
            De = this.elasticConstitutiveMatrix(material,ip);
            Ce = this.elasticFlexibilityMatrix(material,ip);
            Dt = De;

            % Trial stress vector
            stress = De * (ip.strain - ip.strainOld) + ip.stressOld;

            % Evaluate the yield condition
            f = this.yieldCondition(material,ip,stress);

            % Elastic step
            if f < this.returnYieldConditionTol, return, end

            % Material parameters
            [eta, xi, etaB] = this.getMohrCoulombCorrespondence(material);
            coh    = material.cohesion;
            Id     = this.gradientI1(stress);

            % Elastic properties
            K = this.bulkModulus(material);
            G = this.shearModulus(material);

            % Stress invariants
            p = this.hydrostaticStress(stress);
            J2 = this.stressInvariantJ2(stress);

            % Deviatoric stresses
            s = this.deviatoricStress(stress);

            % Plastic multiplier
            lambda = f / (G + K * eta * etaB);

            % Stress update to the smooth part of the cone
            factor = 1.0 - G * lambda / sqrt(J2);
            if J2 > 0.0
                s = factor * s;
                p = p - lambda * etaB * K;
                stress = s + p * Id;
                df = this.yieldStressGradient(material,ip,stress);
                n  = this.flowVector(material,ip,stress);
                dn = this.flowVectorGradient(material,ip,stress);
                Psi = this.pseudoInv(Ce + lambda * dn);
                Dt  = Psi - ((Psi * n) * df' * Psi)/((df' * Psi) * n);
            else
                % Return to the apex of the surface
                stress = (xi * coh / eta) * Id;
                Dt = zeros(4,4);
            end

            % Update the plastic strain
            ip.plasticstrain = ip.strain - Ce * stress;
        end

        %------------------------------------------------------------------
        function [eta, xi, etab] = getMohrCoulombCorrespondence(~,material)
            % Mohr-Coulomb parameters
            phi = material.frictionAngle;
            psi = material.dilationAngle;
            if strcmp(material.MCmatch,'inner')
                xi   = 6.0 * cos(phi) / (sqrt(3.0 * (3.0 + sin(phi))));
                eta  = 6.0 * sin(phi) / (sqrt(3.0 * (3.0 + sin(phi))));
                etab = 6.0 * sin(psi) / (sqrt(3.0 * (3.0 + sin(psi))));
            elseif  strcmp(material.MCmatch,'outer')
                xi   = 6.0 * cos(phi) / (sqrt(3.0 * (3.0 - sin(phi))));
                eta  = 6.0 * sin(phi) / (sqrt(3.0 * (3.0 - sin(phi))));
                etab = 6.0 * sin(psi) / (sqrt(3.0 * (3.0 - sin(psi))));
            elseif strcmp(material.MCmatch,'planestrain')
                xi   = 3.0 / (sqrt(9.0 + 12.0*tan(phi)*tan(phi)));
                eta  = 3.0 * tan(phi) / (sqrt(9.0 + 12.0*tan(phi)*tan(phi)));
                etab = 3.0 * tan(psi) / (sqrt(9.0 + 12.0*tan(psi)*tan(psi)));
            else
                xi   = 6.0 * cos(phi) / (sqrt(3.0 * (3.0 + sin(phi))));
                eta  = 6.0 * sin(phi) / (sqrt(3.0 * (3.0 + sin(phi))));
                etab = 6.0 * sin(psi) / (sqrt(3.0 * (3.0 + sin(psi))));
            end
        end

        %------------------------------------------------------------------
        % Yield function definition
        function f = yieldCondition(this,material,~,stress)
            % Material parameters
            [eta, xi] = this.getMohrCoulombCorrespondence(material);
            % Stress invariants
            p  = this.hydrostaticStress(stress);
            J2 = this.stressInvariantJ2(stress);
            % Yield surface
            f = sqrt(J2) + eta * p - xi * material.cohesion;
        end

        %------------------------------------------------------------------
        % Gradient of the yield function wrt to the stress vector
        function df = yieldStressGradient(this,material,ip,stress)
            % Material parameters
            eta = this.getMohrCoulombCorrespondence(material);
            % Deviatoric stress invariant
            J2 = this.stressInvariantJ2(stress);
            % Stress invariants gradients
            dI1 = this.gradientI1(stress);
            dJ2 = this.gradientJ2(stress);
            % Derivatives of the yield surface wrt to the invariants
            dfdI1 = eta / 3.0;
            if J2 > 0.0
                dfdJ2 = 1.0 /(2.0 * sqrt(J2));
            else
                dfdJ2 = 0.0;
            end
            % Yield surface gradient
            df = dfdI1 * dI1 + dfdJ2 * dJ2;
            if strcmp(ip.anm,'PlaneStress')
                df(3) = 0.0;
            end
        end

        %------------------------------------------------------------------
        % Flow vector
        function n = flowVector(this,material,ip,stress)
            % Material parameters
            [~,~,etaB] = this.getMohrCoulombCorrespondence(material);
            % Deviatoric stress invariant
            J2 = this.stressInvariantJ2(stress);
            % Stress invariants gradients
            dI1 = this.gradientI1(stress);
            dJ2 = this.gradientJ2(stress);
            % Derivatives of the yield surface wrt to the invariants
            dfdI1 = etaB / 3.0;
            if J2 > 0.0
                dfdJ2 = 1.0 /(2.0 * sqrt(J2));
            else
                dfdJ2 = 0.0;
            end
            % Yield surface gradient
            n = dfdI1 * dI1 + dfdJ2 * dJ2;
            if strcmp(ip.anm,'PlaneStress')
                n(3) = 0.0;
            end
        end

        %------------------------------------------------------------------
        % Flow vector gradient
        function dn = flowVectorGradient(this,~,ip,stress)
            % Deviatoric stress invariant
            J2   = this.stressInvariantJ2(stress);
            dJ2  = this.gradientJ2(stress);
            d2J2 = this.hessianJ2();
            % Derivatives of the yield surface wrt to the invariants
            if J2 > 0.0
                dfdJ2 = 0.5 * sqrt(1.0 / J2);
                d2fdJ2 = -0.25 * sqrt(1.0 / J2 / J2 / J2);
            else
                dfdJ2 = 0.0;
                d2fdJ2 = 0.0;
            end
            % Yield surface gradient
            dn = d2fdJ2 * (dJ2 * dJ2') + dfdJ2 * d2J2;
            if strcmp(ip.anm,'PlaneStress')
                dn(3,:) = 0.0;
                dn(:,3) = 0.0;
                dn(3,3) = 1.0;
            end
        end

        %------------------------------------------------------------------
        % Computes the pseudoinverse of a given matrix using SVD
        function Ai = pseudoInv(~,A)
            % Assume A is your input matrix
            [U, S, V] = svd(A);  % Compute the SVD of A

            % Invert the non-zero singular values in S
            S_inv = zeros(size(S'));  % Initialize a matrix for the pseudoinverse of S
            tolerance = 1e-10;  % A tolerance for small singular values
            for i = 1:min(size(S))
                if S(i, i) > tolerance
                    S_inv(i, i) = 1 / S(i, i);  % Inverse of the singular value
                end
            end

            % Compute the pseudoinverse of A
            Ai = V * S_inv * U';
        end

        %------------------------------------------------------------------
        % Returns the hardening value
        function h = hardening(~,~,~,~)
            h = 0.0;
        end

        %------------------------------------------------------------------
        % Gradient of the hardening law wrt to the stress vector
        function dh = hardeningStressGradient(~,~,~,~)
            dh = 0.0;
        end

    end
end