classdef (Sealed) HeatSourceAssignmentRecords < handle & matlab.mixin.internal.CompactDisplay
% HeatSourceAssignmentRecords  Assignments of the internal heat generation/source
%    The HeatSourceAssignmentRecords holds a record of all the assignments
%    of internal heat generation across the geometric domain. This may be a
%    single assignment throughout the domain or multiple assignments that
%    vary across various subdomains. This object cannot be created
%    directly, it can only be created by the ThermalModel class.
%
% HeatSourceAssignmentRecords methods:
%    findHeatSource - Find heat source for a geometric region
%
% HeatSourceAssignmentRecords properties:
%    HeatSourceAssignments - Vector of heat source assignments
%
% See also pde.ThermalModel, pde.ThermalModel/internalHeatSource

% Copyright 2016-2020 The MathWorks, Inc.

properties
    % HeatSourceAssignments - Vector of heat source assignments
    %    A vector containing the heat source assignments to the geometric
    %    domain or subdomains. Each entry in the vector is a
    %    pde.HeatSourceAssignment object. This object defines the internal
    %    heat generation or source in a designated domain or subdomain of a
    %    thermal model. Heat source values and host domains are defined
    %    using the internalHeatSource method of the ThermalModel.
    HeatSourceAssignments;
end

methods
    % Method declaration
    mp = findHeatSource(self, varargin)
    tf = heatSourceSpecified(self, varargin)
    tf = globalHeatSource(self, varargin)
end

methods
    function self = HeatSourceAssignmentRecords(tpdem)
        self.HeatSourceAssignments = [];
        self.ParentModel = tpdem;
    end

    function tf = allHeatSourceNumeric(self)
        tf = true;
        for i = 1:self.nRegion
            hs = self.findHeatSource(self.qregiontype,i);
            if isa(hs,'pde.HeatSourceAssignment') && ~numericHeatSource(hs)
                tf = false;
                return
            end
        end
    end

    function performSolverPrechecks(self)
        syssize = 1;
        nf = self.ParentModel.Geometry.NumFaces;
        nc = self.ParentModel.Geometry.NumCells;
        for i = 1:self.nRegion
            ca = self.findHeatSource(self.qregiontype,i);
            if ~isempty(ca)
            ca.performSolverPrecheck(syssize, nf, nc);
            end
        end

    end

    function coefstruct = packHeatSource(self)
        msh = self.ParentModel.Mesh;
        ma = msh.MeshAssociation;
        numelems = size(msh.Elements,2);
        if self.globalHeatSource()
            [loc, state] = self.ParentModel.getSampleLocState(1);
            coefstruct.ElementsInSubdomain = (1:numelems)';
            coefstruct.NumElementsInSubdomain = numelems;
            ca = self.HeatSourceAssignments(end);
            thisstruct.f{1} = pde.HeatSourceAssignmentRecords.heatSource(ca.HeatSource,self.ParentModel.AnalysisType);
            coefstruct.Coefficients = thisstruct;
            coefstruct.IsComplex = hasComplexCoefficient(ca, loc, state);
        else
            eIDtocellID = ma.SubdomainAssociativity;
            coefstruct.ElementsInSubdomain = zeros(numelems,1)';
            coefstruct.NumElementsInSubdomain = zeros(self.nRegion,1);
            complexcoef = false;
            endidx = 0;
            for i = 1:self.nRegion
                [loc, state] = self.ParentModel.getSampleLocState(i);
                celems = eIDtocellID(2,i)-eIDtocellID(1,i)+1;
                numcelems = celems;
                startidx = endidx;
                endidx = startidx+numcelems;
                startidx = startidx+1;
                coefstruct.NumElementsInSubdomain(i) = numcelems;
                coefstruct.ElementsInSubdomain(startidx:endidx)=eIDtocellID(1,i):eIDtocellID(2,i);
                ca = self.findHeatSource(self.qregiontype,i);
                if isempty(ca)
                    thisstruct.f{i}  = 0;
                    complexcoef = false;
                else
                    thisstruct.f{i} = pde.HeatSourceAssignmentRecords.heatSource(ca.HeatSource,self.ParentModel.AnalysisType);
                    complexcoef = complexcoef | hasComplexCoefficient(ca, loc, state);
                end
            end
            
            coefstruct.Coefficients = thisstruct;
            coefstruct.IsComplex = complexcoef;
        end
    end
    
    
end

methods(Static, Hidden=true, Access=private)
    function q = heatSource(qin,analysisType)
        if contains(analysisType,'axisymmetric')
            q = pde.HeatSourceAssignmentRecords.axisymmHeatSource(qin);
        else
            q = qin;
        end
    end
    
    function q = axisymmHeatSource(qin)
        if isa(qin,'function_handle')
            q = @axisymmetricQFcn;
        else
            q = @(region,state) 2*pi*region.x.*qin;
        end
        function q = axisymmetricQFcn(region,state)
            regionAxsym = region;
            regionAxsym.r = region.x;
            regionAxsym.z = region.y;
            
            stateAxsym = state;
            stateAxsym.ur = state.ux;
            stateAxsym.uz = state.uy;
            
            q = 2*pi*region.x.*qin(regionAxsym,stateAxsym);
        end
        
    end
end

methods(Hidden=true, Access=private)
    
    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
end

methods(Hidden=true, Access={?pde.HeatSourceAssignment})
    function delistHeatSourceAssignments(self, hstodelete)
        numhs = numel(self.HeatSourceAssignments);
        for i = 1:numhs
            thishs = self.HeatSourceAssignments(i);
            if thishs == hstodelete
                self.HeatSourceAssignments(i) = [];
                break
            end
        end
        numhs = numel(self.HeatSourceAssignments);
        if numhs == 0 && isvalid(self.ParentModel)
            self.ParentModel.delistHeatSources();
        end
    end

end

properties (Hidden = true, SetAccess='private')
    ParentModel;
end

end
