classdef (Sealed) BodyLoadAssignmentRecords < handle & matlab.mixin.internal.CompactDisplay
    % BodyLoadAssignmentRecords - Assignments of structural body loads
    % BodyLoadAssignmentRecords holds a record of all the assignments of
    % external influences that act on the domain. This can be a single
    % assignment throughout the domain (for example, gravity) or multiple
    % assignments that vary across subdomains. This object cannot be created
    % directly; it can only be created by the StructuralModel class.
    %
    % BodyLoadAssignmentRecords methods:
    %    findBodyLoad - Find body load for a geometric region
    %
    % BodyLoadAssignmentRecords properties:
    %    BodyLoadAssignments - Vector of body load assignments
    %
    % See also pde.StructuralModel, pde.StructuralModel/structuralBodyLoad
    
    % Copyright 2017-2020 The MathWorks, Inc.
    
    properties
        % BodyLoadAssignments - Vector of body load assignments
        % A vector containing the body load assignments to the geometric
        % domain or subdomains. Each entry in the vector is a
        % pde.BodyLoadAssignment object. This object defines the load per
        % unit volume for the entire domain or subdomain of a structural
        % model. Body load values and host domains are defined using the
        % structuralBodyLoad method of the StructuralModel object.
        BodyLoadAssignments;
    end
    
    methods
        % Method declaration
        mp = findBodyLoad(self, varargin)
        tf = bodyLoadSpecified(self, varargin)
        tf = globalBodyLoad(self, varargin)
    end
    
    methods(Hidden=true, Access={?pde.EquationModel, ?pde.StructuralResults})
        function self = BodyLoadAssignmentRecords(spdem)
            self.BodyLoadAssignments = [];
            self.ParentModel = spdem;
        end
        
        function performSolverPrechecks(self)
            syssize = self.ParentModel.PDESystemSize;
            for i = 1:self.nRegion
                ca = self.findBodyLoad(self.qregiontype,i);
                ca.performSolverPrecheck(syssize);
            end
        end
        
        function bodyloadstruct = packBodyLoad(self,varargin)
            if ~isempty(varargin)
                massDensity = varargin{1};
            end
            
            isMaterialPropertiesGlobal=true;
            if ~isempty(self.ParentModel.MaterialProperties)
                isMaterialPropertiesGlobal = self.ParentModel.MaterialProperties.globalMaterialProperties();
            end
            
            numdim = self.ParentModel.Dim;
            numTrueSubdomain = self.nRegion;
            
            if self.globalBodyLoad() && isMaterialPropertiesGlobal
                numTrueSubdomain = 1;
                bodyloadstruct.IsGlobal  = true;
            end
            
            for i = 1:numTrueSubdomain
                ca = self.findBodyLoad(self.qregiontype,i);
                blcoefs.f{i} = self.formulateBodyLoad(massDensity{i},ca.GravitationalAcceleration,ca.AngularVelocity,numdim);
                blcoefs.Temperature{i} = ca.Temperature;
                blcoefs.TimeStep{i} = ca.TimeStep;
                blcoefs.needsInterpolation{i} = ca.needsInterpolation;
            end
            
            bodyloadstruct.Coefficients = blcoefs;
            bodyloadstruct.IsComplex = false;
        end
    end
    
    
    methods(Hidden=true, Access=private)
        function f = formulateBodyLoad(self,m,g,omega,ndim)
            if isempty(g)
                g = zeros(ndim,1);
            end
            
            if isempty(omega)
                omega = 0;
            end
            
            if isempty(m)
                m = 0;
            end
            
            % Revise this when functional form of mass density is supported.
            if contains(self.ParentModel.AnalysisType,'axisymmetric')
                 f = @(region,state) 2*pi*region.x.*g(:)*m + ... 
                       [2*pi*region.x.^2.*m*omega.^2; zeros(size(region.x))];
            else
                 f = g(:)*m; %omega is supported only for axisymmetric case.
            end
         end
    end
    
    
    methods(Hidden=true, Access={?pde.BodyLoadAssignment})
        function rType = qregiontype(self)
            if self.ParentModel.IsTwoD
                rType = 'Face';
            else
                rType = 'Cell';
            end
        end
        
        function n = nRegion(self)
            if self.ParentModel.IsTwoD
                n = self.ParentModel.Geometry.NumFaces;
            else
                n = self.ParentModel.Geometry.NumCells;
            end
        end
        
        function delistBodyLoadAssignments(self, bltodelete)
            numhs = numel(self.BodyLoadAssignments);
            for i = 1:numhs
                thishs = self.BodyLoadAssignments(i);
                if thishs == bltodelete
                    self.BodyLoadAssignments(i) = [];
                    break
                end
            end
            numhs = numel(self.BodyLoadAssignments);
            if numhs == 0 && isvalid(self.ParentModel)
                self.ParentModel.delistBodyLoads();
            end
        end
    end
    
    properties (Hidden = true, SetAccess='private')
        ParentModel;
    end
end
