Search_SimpleLoop class

Contents

Description

This is a sub-class of the Search class for the implementation of the search algorithm Simple Loop.

This algorithm performs an outer loop over all particles and searches for their interactions through inner loops over all particles with a higher ID number and all walls.

The reference element of each interaction (element 1) is the particle with smaller ID number.

For each interaction found, a binary Interaction object is created to manage the mechanical and / or thermal interaction between both elements.

classdef Search_SimpleLoop < Search

Public properties

    properties (SetAccess = public, GetAccess = public)
        % Base objects for kinematics
        kinpp_sph      BinKinematics = BinKinematics.empty;   % sphere particle - sphere particle
        kinpw_sph_line BinKinematics = BinKinematics.empty;   % sphere particle - line wall
        kinpw_sph_circ BinKinematics = BinKinematics.empty;   % sphere particle - circle wall
        kinpp_cyl      BinKinematics = BinKinematics.empty;   % cylinder particle - sphere particle
        kinpw_cyl_line BinKinematics = BinKinematics.empty;   % cylinder particle - line wall
        kinpw_cyl_circ BinKinematics = BinKinematics.empty;   % cylinder particle - circle wall
    end

Constructor method

    methods
        function this = Search_SimpleLoop()
            this = this@Search(Search.SIMPLE_LOOP);
            this.setDefaultProps();
        end
    end

Public methods: implementation of super-class declarations

    methods
        %------------------------------------------------------------------
        function setDefaultProps(this)
            this.freq           = 1;
            this.done           = false;
            this.cutoff         = 0;
            this.kinpp_sph      = BinKinematics_SphereSphere();
            this.kinpw_sph_line = BinKinematics_SphereWlin();
            this.kinpw_sph_circ = BinKinematics_SphereWcirc();
            this.kinpp_cyl      = BinKinematics_CylinderCylinder();
            this.kinpw_cyl_line = BinKinematics_CylinderWlin();
            this.kinpw_cyl_circ = BinKinematics_CylinderWcirc();
        end

        %------------------------------------------------------------------
        function initialize(~,~)

        end

        %------------------------------------------------------------------
        function execute(this,drv)
            % Set flags
            this.done = true;
            rmv       = false;

            % Outer loop over reference particles
            for i = 1:drv.n_particles
                p1 = drv.particles(i);

                % Inner loop over all other particles with higher ID
                for j = 1:drv.n_particles
                    p2 = drv.particles(j);
                    if (p1.id >= p2.id)
                        continue;
                    end

                    % Check for existing interaction
                    if (any(p1.neigh_pid == p2.id))
                        % Get interaction object
                        int = findobj(p1.interacts,'elem2',p2);

                        % Compute separation between elements
                        int.kinemat = int.kinemat.setRelPos(p1,p2);

                        % Check if separation is greater than cutoff distance
                        % Assumption: cutoff ratio applies to maximum radius
                        if (int.kinemat.separ >= this.cutoff * max(p1.radius,p2.radius))
                            % Remove interaction references from elements
                            p1.interacts(p1.interacts==int)   = [];
                            p1.neigh_p(p1.neigh_p==p2)        = [];
                            p1.neigh_pid(p1.neigh_pid==p2.id) = [];
                            p2.interacts(p2.interacts==int)   = [];
                            p2.neigh_p(p2.neigh_p==p1)        = [];
                            p2.neigh_pid(p2.neigh_pid==p1.id) = [];

                            % Delete interaction object
                            delete(int);
                            rmv = true;
                        end
                    else
                        % Create new particle-particle interaction if needed
                        this.createInteractPP(drv,p1,p2);
                    end
                end

                % Inner loop over all walls
                for j = 1:drv.n_walls
                    w = drv.walls(j);

                    % Check for existing interaction
                    if (any(p1.neigh_wid == w.id))
                        % Get interaction object
                        int = findobj(p1.interacts,'elem2',w);

                        % Compute separation between elements
                        int.kinemat = int.kinemat.setRelPos(p1,w);

                        % Check if separation is greater than cutoff distance
                        % Assumption: cutoff ratio applies to particle radius
                        if (int.kinemat.separ >= this.cutoff * p1.radius)
                            % Remove interaction references from particle
                            % (neigh_w is cleaned by searching the id
                            %  to avoid error when it is heterogeneous:
                            %  i.e. different wall types)
                            p1.interacts(p1.interacts==int)   = [];
                            p1.neigh_w([p1.neigh_w.id]==w.id) = [];
                            p1.neigh_wid(p1.neigh_wid==w.id)  = [];

                            % Delete interaction object
                            delete(int);
                            rmv = true;
                        end
                    else
                        % Create new particle-wall interaction if needed
                        this.createInteractPW(drv,p1,w);
                    end
                end
            end

            % Erase handles to removed interactions from global list
            if (rmv)
                drv.interacts(~isvalid(drv.interacts)) = [];
            end

            % Update total number of interactions
            drv.n_interacts = length(drv.interacts);
        end
    end

Public methods: sub-class specifics

    methods
        %------------------------------------------------------------------
        function createInteractPP(this,drv,p1,p2)
            % Compute separation between particles surfaces
            % PS: This is exclusive for round particles to avoid calling the
            %     base kinematic object (a bit slower).
            %     For other shapes, the base kinematic object will be used.
            dir   = p2.coord - p1.coord;
            dist  = norm(dir);
            separ = dist - p1.radius - p2.radius;

            % Check if interaction exists
            % Assumption: cutoff ratio applies to maximum radius
            if (separ >= this.cutoff * max(p1.radius,p2.radius))
                return;
            end

            % Create new interaction object by copying base object
            int = copy(this.b_interact);

            % Set handles to interecting elements
            int.elem1 = p1;
            int.elem2 = p2;

            % Create binary kinematic object
            kin = this.createPPKinematic(p1,dir,dist,separ);
            kin.setEffParams(int);
            int.kinemat = kin;

            % Add references of new interaction to both elements and global list
            p1.interacts(end+1)  = int;
            p1.neigh_p(end+1)    = p2;
            p1.neigh_pid(end+1)  = p2.id;
            p2.interacts(end+1)  = int;
            p2.neigh_p(end+1)    = p1;
            p2.neigh_pid(end+1)  = p1.id;
            drv.interacts(end+1) = int;
        end

        %------------------------------------------------------------------
        function createInteractPW(this,drv,p,w)
            % Check elements separation and copy kinematics object from base object
            % Assumption: cutoff ratio applies to particle radius
            switch (this.pwInteractionType(p,w))
                case 1
                    this.kinpw_sph_line.setRelPos(p,w);
                    if (this.kinpw_sph_line.separ >= this.cutoff * p.radius)
                        return;
                    end
                    kin = copy(this.kinpw_sph_line);
                case 2
                    this.kinpw_sph_circ.setRelPos(p,w);
                    if (this.kinpw_sph_circ.separ >= this.cutoff * p.radius)
                        return;
                    end
                    kin = copy(this.kinpw_sph_circ);
                case 3
                    this.kinpw_cyl_line.setRelPos(p,w);
                    if (this.kinpw_cyl_line.separ >= this.cutoff * p.radius)
                        return;
                    end
                    kin = copy(this.kinpw_cyl_line);
                case 4
                    this.kinpw_cyl_circ.setRelPos(p,w);
                    if (this.kinpw_cyl_circ.separ >= this.cutoff * p.radius)
                        return;
                    end
                    kin = copy(this.kinpw_cyl_circ);
            end

            % Create new interaction object by copying base object
            int = copy(this.b_interact);

            % Set handles to interecting elements
            int.elem1 = p;
            int.elem2 = w;

            % Set binary kinematic object
            kin.setEffParams(int);
            int.kinemat = kin;

            % Set flag for insulated interaction
            int.insulated = w.insulated;

            % Add references of new interaction to particle and global list
            p.interacts(end+1)   = int;
            p.neigh_w(end+1)     = w;
            p.neigh_wid(end+1)   = w.id;
            drv.interacts(end+1) = int;
        end
    end
end