EnrichedElement_H class

This class extends the RegularElement_H class to define a finite element for single-phase fluid flow that incorporates enriched elements to handle discontinuities. It provides methods to compute element data, manage discontinuities, and calculate enriched degrees of freedom.

Contents

Methods

Author

Danilo Cavalcanti

Version History

Version 1.00.

Class definition

classdef EnrichedElement_H < RegularElement_H

Public attributes

    properties (SetAccess = public, GetAccess = public)
        discontinuity = [];
    end

Constructor method

    methods
        %------------------------------------------------------------------
        function this = EnrichedElement_H(node, elem, t, ...
                mat, intOrder, glu, massLumping, lumpStrategy, ...
                isAxisSymmetric)
            this = this@RegularElement_H(node, elem, t, ...
                mat, intOrder, glu, massLumping, lumpStrategy, ...
                isAxisSymmetric);
        end
    end

Public methods

    methods
        %------------------------------------------------------------------
        % Computes the element data for the current element based on wether
        % the element contains a discontinuity or not.
        %
        % Outputs:
        %   Ke    - Element stiffness matrix.
        %   Ce    - Element damping matrix.
        %   fi    - Internal force vector.
        %   fe    - External force vector.
        %   dfidu - Derivative of internal force with respect to
        %           displacement.
        function [Ke, Ce, fi, fe, dfidu] = elementData(this)

           dfidu = zeros(this.ngle);
           if isempty(this.discontinuity)
               % Get the continuum contribution
               [Ke, Ce, fi, fe] = elementData@RegularElement_H(this);
           else
               % Compute contribution of the continuum
               [Hcc, Hcj, Hjc, Hjj, Scc, Scj, Sjc, Sjj, fic, fij, fec, fej] = this.fillElementSubData();

               % Compute contribution of the discontinuity
               [Hdd, Sdd, Lcc, Lcj, Lcd, Ljc, Ljj, Ljd, Ldc, Ldj, Ldd, Tdc, Tdj] = getDiscontinuitiesData(this);

               % Condense the internal pressure dofs
               Hcc = Hcc + Tdc' * Hdd * Tdc;
               Hcj = Hcj + Tdc' * Hdd * Tdj;
               Hjc = Hjc + Tdj' * Hdd * Tdc;
               Hjj = Hjj + Tdj' * Hdd * Tdj;

               Scc = Scc + Tdc' * Sdd * Tdc;
               Scj = Scj + Tdc' * Sdd * Tdj;
               Sjc = Sjc + Tdj' * Sdd * Tdc;
               Sjj = Sjj + Tdj' * Sdd * Tdj;

               Lcc = Lcc + Tdc' * Ldd * Tdc - Lcd * Tdc - Tdc' * Ldc;
               Lcj = Lcj + Tdc' * Ldd * Tdj - Lcd * Tdj - Tdc' * Ldj;
               Ljc = Ljc + Tdj' * Ldd * Tdc - Ljd * Tdc - Tdj' * Ldc;
               Ljj = Ljj + Tdj' * Ldd * Tdj - Ljd * Tdj - Tdj' * Ldj;

               % Add contribution of the coupling matrices
               Hcc = Hcc + Lcc;
               Hcj = Hcj + Lcj;
               Hjc = Hjc + Ljc;
               Hjj = Hjj + Ljj;

               % Assemble the element matrices
               Ke = [ Hcc, Hcj;
                      Hjc, Hjj];

               Ce = [ Scc, Scj;
                      Sjc, Sjj];

               fi = [fic; fij];

               fe = [fec; fej];
           end
        end

        %------------------------------------------------------------------
        % Computes and assembles the sub-matrices and sub-vectors for an
        % enriched finite element
        function [Hcc, Hcj, Hjc, Hjj, Scc, Scj, Sjc, Sjj, fic, fij, fec, fej] = fillElementSubData(this)

            % Each discontinuity has a pressure jump dof
            nPJumpDofs = this.getNumberOfDiscontinuities();

            % Initialize fluid-flow sub-matrices
            Hcc = zeros(this.nglp , this.nglp);
            Hcj = zeros(this.nglp , nPJumpDofs);
            Hjc = zeros(nPJumpDofs, this.nglp);
            Hjj = zeros(nPJumpDofs, nPJumpDofs);

            % Initialize compressibity sub-matrices
            Scc = zeros(this.nglp , this.nglp);
            Scj = zeros(this.nglp , nPJumpDofs);
            Sjc = zeros(nPJumpDofs, this.nglp);
            Sjj = zeros(nPJumpDofs, nPJumpDofs);

            % Initialize external force vector
            fec = zeros(this.nglp, 1);
            fej = zeros(nPJumpDofs, 1);

            % Initialize internal force vector
            fic = zeros(this.nglp, 1);
            fij = zeros(nPJumpDofs, 1);

            % Vector of the nodal dofs
            pl = this.getNodalPressure();

            % Numerical integration of the sub-matrices
            for i = 1:this.nIntPoints

                % Shape function matrix
                Np = this.shape.shapeFncMtrx(this.intPoint(i).X);

                % Cartesian coordinates of the integration point
                Xcar = this.shape.coordNaturalToCartesian(this.node,this.intPoint(i).X);

                % Enriched shape function matrix
                Npenr = this.enrichedShapeFncMtrx(Np, Xcar);

                % Compute the B matrix at the int. point and the detJ
                [Bp, detJ] = this.shape.dNdxMatrix(this.node,this.intPoint(i).X);

                % Compute the G matrix
                G = this.Gmatrix(Bp);

                % Pressure values at the integration point
                pIP = Np * pl;

                % Compute the permeability matrix
                kh = this.intPoint(i).constitutiveMdl.permeabilityTensor();

                % Get compressibility coefficient
                comp = this.intPoint(i).constitutiveMdl.compressibilityCoeff();

                % Numerical integration coefficient
                c = this.intPoint(i).w * detJ * this.t;
                if this.isAxisSymmetric
                    c = c * this.shape.axisSymmetricFactor(Np,this.node);
                end

                % Compute permeability sub-matrices
                Hcc = Hcc + Bp' * kh * Bp * c;
                Hcj = Hcj + Bp' * kh * G  * c;
                Hjc = Hjc + G'  * kh * Bp * c;
                Hjj = Hjj + G'  * kh * G  * c;

                % Compute compressibility matrices
                Scc = Scc + Np'    * comp * Np    * c;
                Scj = Scj + Np'    * comp * Npenr * c;
                Sjc = Sjc + Npenr' * comp * Np    * c;
                Sjj = Sjj + Npenr' * comp * Npenr * c;

                % Compute the gravity forces
                if (this.gravityOn)
                    fec = this.addGravityForces(fec,Bp,kh,pIP,c);
                end
            end

        end

        %------------------------------------------------------------------
        % Computes the stiffness matrix and force vector contributions
        % from discontinuities in the enriched element
        function [Hdd, Sdd, Lcc, Lcj, Lcd, Ljc, Ljj, Ljd, Ldc, Ldj, Ldd, Tdc, Tdj] = getDiscontinuitiesData(this)

            nDiscontinuities  = this.getNumberOfDiscontinuities();
            nPJumpDofs        = nDiscontinuities;
            nPIntDofs         = nDiscontinuities * 2;

            % Initialize the output data
            Hdd = zeros(nPIntDofs,nPIntDofs);
            Sdd = zeros(nPIntDofs,nPIntDofs);

            % Flow coupling matrices
            Lcc = zeros(this.nglp  , this.nglp);
            Lcj = zeros(this.nglp  , nPJumpDofs);
            Lcd = zeros(this.nglp  , nPIntDofs);
            Ljc = zeros(nPJumpDofs , this.nglp);
            Ljj = zeros(nPJumpDofs , nPJumpDofs);
            Ljd = zeros(nPJumpDofs , nPIntDofs);
            Ldc = zeros(nPIntDofs  , this.nglp);
            Ldj = zeros(nPIntDofs  , nPJumpDofs);
            Ldd = zeros(nPIntDofs  , nPIntDofs);

            % Condensation matrices
            Tdc = zeros(nPIntDofs,this.nglp);
            Tdj = zeros(nPIntDofs,nPJumpDofs);

            % Loop through the discontinuities
            for i = 1:nDiscontinuities

                % Internal pressure dofs associated with this discontinuity segment
                pint_dofs = 2*(i-1)+1 : 2*i;

                % Get the discontinuity data
                [Hddi, Sddi, Lcci, Lcji, Lcdi, Ljci, Ljji, Ljdi, Ldci, Ldji, Lddi,~,~,~] = this.discontinuity(i).elementData(this,i);

                % Assemble the contribution of this discontinuity
                Hdd(pint_dofs,pint_dofs) = Hdd(pint_dofs,pint_dofs) + Hddi;
                Sdd(pint_dofs,pint_dofs) = Sdd(pint_dofs,pint_dofs) + Sddi;
                Lcc = Lcc + Lcci;
                Lcj(:,i) = Lcj(:,i) + Lcji;
                Lcd(:,pint_dofs) = Lcd(:,pint_dofs) + Lcdi;
                Ljc(i,:) = Ljc(i,:) + Ljci;
                Ljj(i,i) = Ljj(i,i) + Ljji;
                Ljd(i,pint_dofs) = Ljd(i,pint_dofs) + Ljdi;
                Ldc(pint_dofs,:) = Ldc(pint_dofs,:) + Ldci;
                Ldj(pint_dofs,i) = Ldj(pint_dofs,i) + Ldji;
                Ldd(pint_dofs,pint_dofs) = Ldd(pint_dofs,pint_dofs) + Lddi;


                % Loop through the nodes of the discontinuity to fill the
                % condensation matrix
                for j = 1:2
                    X = this.discontinuity(i).node(j,:);
                    Xn = this.shape.coordCartesianToNatural(this.node,X);
                    Np = this.shape.shapeFncMtrx(Xn);
                    Tdc(pint_dofs(j),:) = Np;
                    Nenr_i = this.enrichedShapeFncValues(i, Np, X);
                    Tdj(pint_dofs(j),i) = 0.5 * (Nenr_i(2) + Nenr_i(3));
                end

            end
        end

        %------------------------------------------------------------------
        % Gets the number of enriched degrees of freedom
        function nEnrDof = getNumberEnrichedDofs(this)
            nEnrDof = this.getNumberOfDiscontinuities();
            nEnrDof = nEnrDof * this.getNumberOfDofPerDiscontinuity();
        end

        %------------------------------------------------------------------
        % Obtain the number of discontinuities
        function n = getNumberOfDiscontinuities(this)
            n = size(this.discontinuity,1);
        end

        %------------------------------------------------------------------
        % Calculates the number of degrees of freedom per discontinuity for
        % the enriched element
        function n = getNumberOfDofPerDiscontinuity(this)
            n = 2;
        end

        %------------------------------------------------------------------
        % Adds a discontinuity segment to the element
        function addDiscontinuitySegment(this,dseg)
            this.discontinuity = [this.discontinuity; dseg];
        end

        %------------------------------------------------------------------
        % Adds the discontinuities dofs to the element dof vector
        function addEnrichmentToDofVector(this)
            nDiscontinuities = this.getNumberOfDiscontinuities();
            for i = 1:nDiscontinuities
                this.gle = [this.gle, this.discontinuity(i).dof];
            end
            this.ngle = length(this.gle);
        end

        %------------------------------------------------------------------
        % Compute the enrichment shape function matrix
        function Nenr = enrichedShapeFncMtrx(this, N, Xcar)
            nDiscontinuities  = this.getNumberOfDiscontinuities();
            Nenr = zeros(1,nDiscontinuities);  % Each discontinuity has a pressure jump dof
            for i = 1:nDiscontinuities
                Nenr_i = this.enrichedShapeFncValues(i, N, Xcar);
                Nenr(i) = Nenr_i(1);
            end
        end

        %------------------------------------------------------------------
        % Compute the enrichment shape function values of a discontinuity
        function Nenr_i = enrichedShapeFncValues(this, id, N, Xcar)
            phi = 0.0;
            h = this.discontinuity(id).heaviside(Xcar);
            for j = 1:this.nnd_el
                Xj = this.node(j,:);
                hj = this.discontinuity(id).heaviside(Xj);
                if (hj > 0.0)
                    phi = phi + N(:, j);
                end
            end
            Nenr_i = [h-phi;
                       -phi;        % Nbot
                      1.0-phi];     % Ntop
        end

        %------------------------------------------------------------------
        % Compute the gradient enrichment matrix
        function G = Gmatrix(this, Bu)
            nDiscontinuities  = this.getNumberOfDiscontinuities();
            G = zeros(2,nDiscontinuities);  % Each discontinuity has a pressure jump dof
            for i = 1:nDiscontinuities
                for j = 1:this.nnd_el
                    Xj = this.node(j,:);
                    h = this.discontinuity(i).heaviside(Xj);
                    if (h > 0.0)
                        G(:,i) = G(:,i) - Bu(:, j);
                    end
                end
            end
        end
        %------------------------------------------------------------------

    end
end