classdef FEStruct <matlab.mixin.CustomDisplay
%FEStruct class for structural results data
%
% This undocumented function may be changed or removed in a future release.

% Copyright 2019 The MathWorks, Inc.
    
    properties
        % Tensor components
        xx, yy, zz; hoop
        yz, xz, xy;
        
        % Vector components and magnitude
        x,y,z;
        Magnitude;
    end
    
    properties (Dependent,Hidden = true)
        % Displacement
        ux,uy,uz;
        
        % Velocity
        vx,vy,vz;
        
        % Acceleration
        ax,ay,az;
        
        % Axisymmetric radial components
        ur,vr,ar;
        
        % Stress components
        sxx, syy, szz; sh
        syz, sxz, sxy;
        
        %Strain components
        exx, eyy, ezz; eh
        eyz, exz, exy;
        
        %Axisymmetric stress comonents
        srr, srz;
        
        %Axisymmetric strain comonents
        err, erz;
        
        %Symmetric components
        szy, szx, syx; szr;
        
        %Symmetric components
        ezy, ezx, eyx; ezr;
    end
    
    properties (Hidden = true,SetAccess=private)
        elasticityType;
        tensorID
    end
    
    methods
        function self = FEStruct(tensorID,elasticity,varargin)
            self.tensorID = tensorID;
            self.elasticityType = elasticity;
            if contains(tensorID,["Stress", "Strain"])
                cgardX = varargin{1};
                cgardY = varargin{2};
                cgardZ = varargin{3};
                if contains(tensorID,"Stress")
                    self.xx = squeeze(cgardX(:,1,:));
                    self.yy = squeeze(cgardY(:,2,:));
                    self.xy = squeeze(cgardX(:,2,:));
                    if ~isempty(cgardZ)
                        self.zz = squeeze(cgardZ(:,3,:));
                        self.yz = squeeze(cgardY(:,3,:));
                        self.xz = squeeze(cgardX(:,3,:));
                        self.hoop = squeeze(cgardZ(:,3,:));
                    end
                elseif contains(tensorID,"Strain")
                    self.xx = squeeze(cgardX(:,1,:));
                    self.yy = squeeze(cgardY(:,2,:));
                    self.xy = squeeze(cgardX(:,2,:)+cgardY(:,1,:));
                    if ~isempty(cgardZ)
                        self.zz = squeeze(cgardZ(:,3,:));
                        self.hoop = squeeze(cgardZ(:,3,:));
                        self.yz = squeeze(cgardY(:,3,:)+cgardZ(:,2,:));
                        self.xz = squeeze(cgardX(:,3,:)+cgardZ(:,1,:));
                    end
                end
            else
                umatrix = varargin{1};
                self.x = squeeze(umatrix(:,1,:));
                self.y = squeeze(umatrix(:,2,:));
                mag = squeeze(sqrt(umatrix(:,1,:).^2+umatrix(:,2,:).^2));
                if contains(elasticity,'3D')
                    self.z = squeeze(umatrix(:,3,:));
                    mag = squeeze(sqrt(umatrix(:,1,:).^2+umatrix(:,2,:).^2+umatrix(:,3,:).^2));
                end
                self.Magnitude = mag;
            end
        end
        
        %%%% Displacement, Velocity, and Acceleration components.
        function ur  = get.ur(self)
            validateAccess(self.tensorID,'Displacement','ur')
            ur = self.ux;
        end
        
        function vr  = get.vr(self)
            validateAccess(self.tensorID,'Velocity','vr')
            vr = self.vx;
        end
        
        function ar  = get.ar(self)
            validateAccess(self.tensorID,'Acceleration','ar')
            ar = self.ax;
        end
        
        function ux  = get.ux(self)
            validateAccess(self.tensorID,'Displacement','ux')
            ux = self.x;
        end
        
        function uy  = get.uy(self)
            validateAccess(self.tensorID,'Displacement','uy')
            uy = self.y;
        end
        
        function uz  = get.uz(self)
            validateAccess(self.tensorID,'Displacement','uz')
            if contains(self.elasticityType,'as')
                uz = self.y;
            else
                uz = self.z;
            end
        end
        
        function vx  = get.vx(self)
            validateAccess(self.tensorID,'Velocity','vx')
            vx = self.x;
        end
        
        function vy  = get.vy(self)
            validateAccess(self.tensorID,'Velocity','vy')
            vy = self.y;
        end
        
        function vz  = get.vz(self)
            validateAccess(self.tensorID,'Velocity','vz')
            if contains(self.elasticityType,'as')
                vz = self.y;
            else
                vz = self.z;
            end
        end
        
        
        function ax  = get.ax(self)
            validateAccess(self.tensorID,'Acceleration','ax')
            ax = self.x;
        end
        
        function ay  = get.ay(self)
            validateAccess(self.tensorID,'Acceleration','ay')
            ay = self.y;
        end
        
        function az  = get.az(self)
            validateAccess(self.tensorID,'Acceleration','az')
            if contains(self.elasticityType,'as')
                az = self.y;
            else
                az = self.z;
            end
        end
        
        %%%%%%%%%%%%%%%%%%%%% Stress components %%%%%%%%%%%%%%%%
        function sxx  = get.sxx(self)
            validateAccess(self.tensorID,'Stress','sxx')
            sxx = self.xx;
        end
        
        function syy  = get.syy(self)
            validateAccess(self.tensorID,'Stress','syy')
            syy = self.yy;
        end
        
        function szz  = get.szz(self)
            validateAccess(self.tensorID,'Stress','szz')
            if contains(self.elasticityType,'as')
                szz = self.yy;
            else
                szz = self.zz;
            end
        end
        
        function syz  = get.syz(self)
            validateAccess(self.tensorID,'Stress','syz')
            syz = self.yz;
        end
        
        function sxz  = get.sxz(self)
            validateAccess(self.tensorID,'Stress','sxz')
            sxz = self.xz;
        end
        
        function sxy  = get.sxy(self)
            validateAccess(self.tensorID,'Stress','sxy')
            sxy = self.xy;
        end
        
        function szy  = get.szy(self)
            validateAccess(self.tensorID,'Stress','szy')
            szy = self.yz;
        end
        
        function szx  = get.szx(self)
            validateAccess(self.tensorID,'Stress','szx')
            szx = self.xz;
        end
        
        function syx  = get.syx(self)
            validateAccess(self.tensorID,'Stress','syx')
            syx = self.xy;
        end
        
        function srr  = get.srr(self)
            validateAccess(self.tensorID,'Stress','srr')
            srr = self.sxx;
        end
        
        function srz  = get.srz(self)
            validateAccess(self.tensorID,'Stress','srz')
            srz = self.sxy;
        end
        
        function szr  = get.szr(self)
            validateAccess(self.tensorID,'Stress','szr')
            szr = self.sxy;
        end
        
        function sh  = get.sh(self)
            validateAccess(self.tensorID,'Stress','sh')
            sh = self.hoop;
        end
        
        %%%%%%%%%%%%%%%%%%%%% Strain components %%%%%%%%%%%%%%%%
        function exx  = get.exx(self)
            validateAccess(self.tensorID,'Strain','exx')
            exx = self.xx;
        end
        
        function eyy  = get.eyy(self)
            validateAccess(self.tensorID,'Strain','eyy')
            eyy = self.yy;
        end
        
        function ezz  = get.ezz(self)
            validateAccess(self.tensorID,'Strain','ezz')
            if contains(self.elasticityType,'as')
                ezz = self.yy;
            else
                ezz = self.zz;
            end
        end
        
        function eyz  = get.eyz(self)
            validateAccess(self.tensorID,'Strain','eyz')
            eyz = self.yz;
        end
        
        function exz  = get.exz(self)
            validateAccess(self.tensorID,'Strain','exz')
            exz = self.xz;
        end
        
        function exy  = get.exy(self)
            validateAccess(self.tensorID,'Strain','exy')
            exy = self.xy;
        end
        
        function ezy  = get.ezy(self)
            validateAccess(self.tensorID,'Strain','ezy')
            ezy = self.yz;
        end
        
        function ezx  = get.ezx(self)
            validateAccess(self.tensorID,'Strain','ezx')
            ezx = self.xz;
        end
        
        function eyx  = get.eyx(self)
            validateAccess(self.tensorID,'Strain','eyx')
            eyx = self.xy;
        end        
        
        function err  = get.err(self)
            validateAccess(self.tensorID,'Strain','err')
            err = self.exx;
        end
        
        function erz  = get.erz(self)
            validateAccess(self.tensorID,'Strain','erz')
            erz = self.xy;
        end
        
        function ezr  = get.ezr(self)
            validateAccess(self.tensorID,'Strain','ezr')
            ezr = self.xy;
        end
        
        function eh  = get.eh(self)
            validateAccess(self.tensorID,'Strain','eh')
            eh = self.hoop;
        end
        
    end
    
    methods (Access = protected,Hidden = true)
        
        function group = getPropertyGroups(self)
            
            switch self.tensorID
                case 'Displacement'
                    if contains(self.elasticityType,'as')
                        group = {'ur','uz','Magnitude'};
                    elseif contains(self.elasticityType,'pn') || contains(self.elasticityType,'ps')
                        group = {'ux','uy','Magnitude'};
                    else
                        group = {'ux','uy','uz','Magnitude'};
                    end
                case 'Velocity'
                    if contains(self.elasticityType,'as')
                        group = {'vr','vz','Magnitude'};
                    elseif contains(self.elasticityType,'pn') || contains(self.elasticityType,'ps')
                        group = {'vx','vy','Magnitude'};
                    else
                        group = {'vx','vy','vz','Magnitude'};
                    end
                case 'Acceleration'
                    if contains(self.elasticityType,'as')
                        group = {'ar','az','Magnitude'};
                    elseif contains(self.elasticityType,'pn') || contains(self.elasticityType,'ps')
                        group = {'ax','ay','Magnitude'};
                    else
                        group = {'ax','ay','az','Magnitude'};
                    end
                case 'Stress'
                    if contains(self.elasticityType,'ps')
                        group = {'sxx','syy','sxy'};
                    elseif contains(self.elasticityType,'pn')
                        group = {'sxx','syy','sxy','szz'};
                    elseif contains(self.elasticityType,'as')
                        group = {'srr','szz','srz','sh'};
                    else
                        group = {'sxx','syy','szz','syz','sxz','sxy'};
                    end
                case 'Strain'
                    if contains(self.elasticityType,'ps')
                        group = {'exx','eyy','exy','ezz'};
                    elseif contains(self.elasticityType,'pn')
                        group = {'exx','eyy','exy'};
                    elseif contains(self.elasticityType,'as')
                        group = {'err','ezz','erz','eh'};
                    else
                        group = {'exx','eyy','ezz','eyz','exz','exy'};
                    end
            end
            group = matlab.mixin.util.PropertyGroup(group);
        end
    end
end

% Helper function to valiate access to only right set of fields for a given
% tensor, e.g., Displacement can only access ux, uy, uz, ur.
function validateAccess(objTensorID, accessTensorID, fieldName)
if ~contains(objTensorID,accessTensorID)
    error(message('pde:StructuralResults:accessIncorrectField',fieldName,objTensorID))
end
end
        