BinKinematics_SphereWlin class

Contents

Description

This is a sub-class of the BinKinematics class for the implementation of the Sphere-Wall Line binary kinematics for particle-wall interactions of types Particle Sphere and Wall Line.

classdef BinKinematics_SphereWlin < BinKinematics

Constructor method

    methods
        function this = BinKinematics_SphereWlin()
            this = this@BinKinematics(BinKinematics.PARTICLE_WALL,BinKinematics.SPHERE_WALL_LINE);
        end
    end

Public methods: implementation of super-class declarations

    methods
        %------------------------------------------------------------------
        function setEffParams(~,int)
            p  = int.elem1;  w  = int.elem2;
            mp = p.material; mw = w.material;

            % Assumption: effective radius and mass consider particle only
            int.eff_radius = p.radius;
            int.eff_mass   = p.mass;

            % Wall with no material
            % Assumption: effective and average properties are the particle values
            if (isempty(mw))
                if (~isempty(mp.young) && ~isempty(mp.poisson))
                    int.eff_young = mp.young / (1 - mp.poisson^2);
                    if (~isempty(mp.young0))
                        int.eff_young0 = mp.young0 / (1 - mp.poisson^2);
                    end
                end
                if (~isempty(mp.shear) && ~isempty(mp.poisson))
                    int.eff_shear = mp.shear / (2 - mp.poisson);
                end
                if (~isempty(mp.poisson))
                    int.avg_poisson = mp.poisson;
                end
                if (~isempty(mp.conduct))
                    int.eff_conduct = mp.conduct/2;
                    int.avg_conduct = mp.conduct;
                end

            % Wall with material
            else
                if (~isempty(mp.young) && ~isempty(mp.poisson) && ~isempty(mw.young) && ~isempty(mw.poisson))
                    int.eff_young = 1 / ((1-mp.poisson^2)/mp.young + (1-mw.poisson^2)/mw.young);
                    if (~isempty(mp.young0) && ~isempty(mw.young0))
                        int.eff_young0 = 1 / ((1-mp.poisson^2)/mp.young0 + (1-mw.poisson^2)/mw.young0);
                    end
                end
                if (~isempty(mp.shear) && ~isempty(mp.poisson) && ~isempty(mw.shear) && ~isempty(mw.poisson))
                    int.eff_shear = 1 / ((2-mp.poisson)/mp.shear + (2-mw.poisson)/mw.shear);
                end
                if (~isempty(mp.poisson) && ~isempty(mw.poisson))
                    int.avg_poisson = (mp.poisson + mw.poisson) / 2;
                end
                if (~isempty(mp.conduct) && ~isempty(mw.conduct))
                    int.eff_conduct = mp.conduct * mw.conduct / (mp.conduct + mw.conduct);
                    int.avg_conduct = mp.conduct; % assumption: average conductivity considers particle only
                end
            end
        end

        %------------------------------------------------------------------
        function this = setRelPos(this,p,w)
            % Needed properties
            P = p.coord;
            A = w.coord_ini;
            B = w.coord_end;
            M = B - A;

            % Running parameter at the orthogonal intersection
            t = dot(M,P-A)/w.len^2;

            % Normal direction from particle to wall
            if (t <= 0)
                this.dir = A-P;
            elseif (t >= 1)
                this.dir = B-P;
            else
                this.dir = (A + t * M) - P;
            end

            % Distance between particle surface and line segment
            this.dist  = norm(this.dir);
            this.distc = this.dist;
            this.separ = this.dist - p.radius;
        end

        %------------------------------------------------------------------
        function this = setOverlaps(this,int,dt)
            p = int.elem1; w = int.elem2;

            % Normal overlap and unit vector
            % Assumption: the ends of the wall are treated as a flat surface
            this.ovlp_n = -this.separ;
            this.dir_n  =  this.dir / norm(this.dir);

            % Positions of contact point
            % Assumption: discount the full overlap from particle
            cp = (p.radius - this.ovlp_n) * this.dir_n;
            cw = (p.coord+cp) - (w.coord_ini+w.coord_end)/2;

            % Particle velocity at contact point (3D due to cross-product)
            wp  = cross([0;0;p.veloc_rot],[cp(1);cp(2);0]);
            vcp = p.veloc_trl + wp(1:2);

            % Wall velocity at contact point (3D due to cross-product)
            ww  = cross([0;0;w.veloc_rot],[cw(1);cw(2);0]);
            vcw = w.veloc_trl + ww(1:2);

            % Relative velocities
            % Assumption: rotation and angular velocities consider the particle only
            this.vel_trl = vcp - vcw;
            this.vel_rot = wp(1:2);       % particle only
            this.vel_ang = p.veloc_rot;   % particle only

            % Normal overlap rate of change
            this.vel_n = dot(this.vel_trl,this.dir_n);

            % Tangential relative velocity
            vt = this.vel_trl - this.vel_n * this.dir_n;

            % Tangential unit vector
            if (any(vt))
                this.dir_t = vt / norm(vt);
            else
                this.dir_t = [0;0];
            end

            % Tangential overlap rate of change
            this.vel_t = dot(this.vel_trl,this.dir_t);

            % Tangential overlap
            if (isempty(this.ovlp_t))
                this.ovlp_t = this.vel_t * dt;
            else
                this.ovlp_t = this.ovlp_t + this.vel_t * dt;
            end
        end

        %------------------------------------------------------------------
        function this = setContactArea(this,int)
            % Needed properties
            r = int.elem1.radius;
            d = this.dist;

            % Contact radius
            this.contact_radius = sqrt(r^2-d^2);

            % Contact correction
            if (~isempty(int.corarea))
                % Adjusted radius
                int.corarea.fixRadius(int);

                % Adjusted distance consistent with adjusted radius
                this.distc = sqrt(r^2-this.contact_radius^2);
            end
        end

        %------------------------------------------------------------------
        function this = setVoronoiEdge(this,~,int)
            % Assumption: same as the particle diameter
            this.vedge = 2*int.elem1.radius;
        end

        %------------------------------------------------------------------
        function addContactForceNormalToParticles(~,int)
            int.elem1.force = int.elem1.force + int.cforcen.total_force;
        end

        %------------------------------------------------------------------
        function addContactForceTangentToParticles(~,int)
            int.elem1.force = int.elem1.force + int.cforcet.total_force;
        end

        %------------------------------------------------------------------
        function addContactTorqueTangentToParticles(this,int)
            % Lever arm
            % Assumption: half of the overlap
            l = (int.elem1.radius-this.ovlp_n/2) * this.dir_n;

            % Torque from tangential contact force (3D due to cross-product)
            f = int.cforcet.total_force;
            torque = cross([l(1);l(2);0],[f(1);f(2);0]);

            % Add torque from tangential contact force to particle
            int.elem1.torque = int.elem1.torque + torque(3);
        end

        %------------------------------------------------------------------
        function addRollResistTorqueToParticles(~,int)
            int.elem1.torque = int.elem1.torque + int.rollres.torque;
        end

        %------------------------------------------------------------------
        function addDirectConductionToParticles(~,int)
            int.elem1.heat_rate = int.elem1.heat_rate + int.dconduc.total_hrate;
        end

        %------------------------------------------------------------------
        function addIndirectConductionToParticles(~,int)
            int.elem1.heat_rate = int.elem1.heat_rate + int.iconduc.total_hrate;
        end
    end
end