classdef EmSolver < handle
 %EMSOLVER Abstract class for enabling different solvers
    
    properties(SetObservable,AbortSet)
        % Electromagnetic solver type used to solve the structure
        SolverType char {mustBeMember(SolverType,{'MoM','MoM-PO','FMM','PO'})}='MoM'
    end
    
    methods
        function set.SolverType(obj,propVal)
            validatestring(propVal,{'MoM','MoM-PO','FMM','PO'});
            checkSolvervsObjType(obj,upper(propVal));
            checkSolvervsInfiniteGndPlane(obj,propVal)
            checkSolvervsDielectric(obj,propVal);
            checkSolvervsLoad(obj,propVal)
            if isPropertyChanged(obj,obj.SolverType,propVal)
                obj.SolverType = propVal;
                % Clean up solver object if the Solver object for fmm was
                % created
                 if ~isempty(obj.SolverStruct.Solver) && ~strcmpi(propVal,'FMM')
                     obj.SolverStruct.Solver = [];
                 end                     
            end
        end
        
        function s = solver(obj)
        % SOLVER Access the solver used for electromagnetic analysis
        %
        % s = solver (hobj) returns the solver being used for
        % electromagnetic analysis. Access to the solver is only available
        % when the 'SolverType' chosen is FMM. The returned object has the
        % following properties that can be modified to affect the solver
        % performance
        %
        % Iterations - Maximum number of iterations for the iterative
        % solver to achieve convergence. If convergence is achieved with
        % lesser iterations, the solver will terminate and provide the
        % solution. The default is set to 100.
        %
        % RelativeResidual - The error in solution to be achieved. The
        % default is set to 1e-4.
        %
        % Precision - The precision requested from the FMM solver. The
        % default is set to 2e-4.
        %
        % % Examples
        %
        % % Example1: Calculate and plot the convergence of the FMM solver 
        % % from an analysis of a parabolic reflector antenna
        %
        % m = reflectorParabolic;
        % m.SolverType = 'FMM';
        % Z = impedance(m,10e9);
        % s = solver(m);
        % convergence(s)

        % Copyright 2021 The MathWorks, Inc.
            if strcmpi(obj.SolverType, 'FMM')
                if ~isempty(obj.SolverStruct.Solver)
                    s = obj.SolverStruct.Solver;                    
                else
                    obj.SolverStruct.Solver = em.solvers.EFIE;
                    s = obj.SolverStruct.Solver;
                    addlistener(s,'IterativeSolver','PostSet',@(src, evt)obj.handleSolverPropEvents(src, evt));
                    addlistener(s,'Iterations','PostSet',@(src, evt)obj.handleSolverPropEvents(src, evt));
                    addlistener(s,'RelativeResidual','PostSet',@(src, evt)obj.handleSolverPropEvents(src, evt));
                    addlistener(s,'Precision','PostSet',@(src, evt)obj.handleSolverPropEvents(src, evt));
                end
            else
                error('This functionality is not supported for MoM and MoM-PO solvers')
            end
                
            
        end
    end
    
    methods(Hidden)
        function handleSolverPropEvents(obj,src,evnt)
            setHasSolverChanged(obj,true);
        end

        function  obj = superLoadSolver(obj,s)
            obj.SolverType = s.SolverType;
        end
    end
end

