sandbox/easystab/free_surface_navier_stokes.m

    This is a viscous flow described with the Navier-Stokes equation. The top is a free surface that can deform accordingly to the pressure jump through the interface due to surface tension, and the normal and tangential stress in the flow. At the inflow we impose a profile that looks like a boundary layer.

    clear all; clf; format compact
    
    %paramvec=linspace(5,1,7);
    paramvec=linspace(1,0.85,10);
    %paramvec=0.95
    
    for tre=1:length(paramvec);
        
        disp('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%')
        param=paramvec(tre)
        
        % parameters
        Re=500; % Reynolds number
        Nx=100;  % number of grid nodes in z
        Ny=50;  %number of grid nodes in r
        Lx=10;  % domain length
        Ly=1;   % domain height
        sig=5;  % surface tension
        V=Lx*Ly*param; % desired volume
        umax=1; % max inflow velocity
        mu=1/Re;
        
        % differentiation
        [d.x,d.xx,d.wx,x]=dif1D('fd',0,Lx,Nx,5);
        [d.y,d.yy,d.wy,y]=dif1D('fd',0,Ly,Ny,5);
        [Dc,l,X,Y,Z,I,NN]=dif2D(d,x,y);
        
        % useful
        l.top=[l.ctl; l.top; l.ctr]; % include the corners to the top
        l.u=(1:NN)'; l.v=l.u+NN; l.p=l.v+NN; l.e=l.p(end)+(1:Nx)'; l.p0=l.e(end)+1; % location vectors
        l.ue=[l.u;l.e]; l.ve=[l.v;l.e]; l.pe=[l.p;l.e]; % compound location vectors
        
        p0loc=2*Ny; % where to impose pressure=p0
        t=l.top; % a shortcut because its often used
        
        n=3*NN+Nx+1; % numbers of degrees of freedom
        ZZ=spalloc(n,n,0);    zx=spalloc(Nx,Nx,0);
        II=speye(n);        ix=speye(Nx);
        Iu=II(l.u,:); Iv=II(l.v,:); Ip=II(l.p,:); Ie=II(l.e,:); Ip0=II(l.p0,:);
        T=kron(speye(Nx,Nx),ones(Ny,1)); % transformation operator from 1D x to 2D grid
        yy=Y(:);
        
        % initial guess
        v=zeros(NN,1);
        %u=umax*Y(:).*(2-Y(:));
        u=umax*tanh(Y/0.1);
        p=-mu*X*umax; p=p-p(p0loc);
        e=Ly+0*sin(pi*x);
        p0=0;
        q0=[u(:);v(:);p(:);e;p0];
        
        % Newton iterations
        disp('Newton loop'); tlu=0;
        if tre==1; q=q0; end
        quit=0;count=0;
        while ~quit
            tic
            %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
            % the present solution and its computational-space derivatives
            e=q(l.e); ex=d.x*e; exx=d.xx*e; E=T*e; Ex=T*ex; Exx=T*exx; a=1+ex.^2;
            u=q(l.u); v=q(l.v); p=q(l.p); p0=q(l.p0);
            ux=Dc.x*u; uy=Dc.y*u; uxy=Dc.y*ux; uyy=Dc.yy*u;
            vx=Dc.x*v; vy=Dc.y*v; vxy=Dc.y*vx; vyy=Dc.yy*v;
            px=Dc.x*p; py=Dc.y*p;
    

    Physical space differentiation matrices

    This is just like we did in stretching_formula.m.

            % physical-space differentation matrices
            D.lap=Dc.xx ...
                +spd(-2*yy.*E.^-1.*Ex)*(Dc.x*Dc.y) ...
                +spd(yy.^2.*E.^-2.*Ex.^2+E.^-2)*Dc.yy ...
                +spd(yy.*(2*E.^-2.*Ex.^2-E.^-1.*Exx))*Dc.y;
            D.x=Dc.x+spd(-yy.*E.^-1.*Ex)*Dc.y;
            D.y=spd(E.^-1)*Dc.y;
    

    Jacobians of the differentiation matrices

    Since the domain deformation is one of the unknown of th system, the differentiation is no longer a linear operation (because it depends nonlinearly on the domain stretching \eta). We do just like we did in the test case jacobian_formula.m.

            % jacobians of the physical-space differentiation operators
            AA=-2*spd(yy)*T*(diag(e.^-1)*d.x-diag(e.^-2.*ex));
            BB=2*(spd(yy.^2)*T*(diag(e.^-2.*ex)*d.x-diag(e.^-3.*ex.^2))-T*diag(e.^-3));
            CC=spd(yy)*T*(diag(4*e.^-2.*ex)*d.x-diag(e.^-1)*d.xx+diag(-4*e.^-3.*ex.^2+e.^-2.*exx));
            DD=T*(diag(-e.^-1)*d.x+diag(e.^-2.*ex));
            EE=T*diag(-e.^-2);
            
            D.xue=spd(yy.*uy)*DD;  D.yue=spd(uy)*EE;  D.lapue=spd(uxy)*AA+spd(uyy)*BB+spd(uy)*CC;
            D.xve=spd(yy.*vy)*DD;  D.yve=spd(vy)*EE;  D.lapve=spd(vxy)*AA+spd(vyy)*BB+spd(vy)*CC;
            D.xpe=spd(yy.*py)*DD;  D.ype=spd(py)*EE;
            
            Iux=[D.x,D.xue]*II(l.ue,:);  Iuy=[D.y,D.yue]*II(l.ue,:);  Iulap=[D.lap,D.lapue]*II(l.ue,:);
            Ivx=[D.x,D.xve]*II(l.ve,:);  Ivy=[D.y,D.yve]*II(l.ve,:);  Ivlap=[D.lap,D.lapve]*II(l.ve,:);
            Ipx=[D.x,D.xpe]*II(l.pe,:);  Ipy=[D.y,D.ype]*II(l.pe,:);
            
            % physical-space derivatives
            ux=D.x*u; uy=D.y*u;
            vx=D.x*v; vy=D.y*v;
            px=D.x*p; py=D.y*p;
    

    The nonlinear function

    The first thing we do is to compute the expression of the normal and tangential stresses at the free surface. The stress tensor in a viscous Newtonian fluid is \displaystyle \sigma= \begin{pmatrix} 2\mu u_x-p & \mu(u_y+v_x) \\ \mu(u_y+v_x) & 2\mu v_y-p \end{pmatrix} We are interested at the components of the stress along our free-surface. We first need to find the expresion of its normal and tangent vectors. We can say that the normal is along the gradient of a function for which the free-surface is an iso-line. For instance take \displaystyle F(x,y)=y-\eta(x) then its gradient, normalized to unit one is the normal to the interface \displaystyle \overrightarrow{n}= \begin{pmatrix} -\frac{\eta_x}{\sqrt{1+\eta_x^2}}\\ \frac{1}{\sqrt{1+\eta_x^2}}\\ \end{pmatrix} and the tangent vector is \displaystyle \overrightarrow{t}= \begin{pmatrix} \frac{1}{\sqrt{1+\eta_x^2}}\\ \frac{\eta_x}{\sqrt{1+\eta_x^2}}\\ \end{pmatrix} Then, the normal stress is \displaystyle \sigma_n=\overrightarrow{n}\sigma \overrightarrow{n} =\frac{\eta_x^2(2\mu u_x-p)-2\mu\eta_x(u_y+v_x)+2\mu v_y-p}{1+\eta_x^2} and the tangential stress is \displaystyle \sigma_t=\overrightarrow{t}\sigma \overrightarrow{n} =\mu\frac{(1-\eta_x^2)(u_y+v_x)+2\mu\eta_x(v_y-u_x)}{1+\eta_x^2} The conditions at the interface are that the normal stress has a jump equal to the pressure jump through a curved interface with surface tension, and the tangential stress is zero.

    We have then Navier-Stokes in the flow domain. And the last equation imposes the value of the fluid volume.

            % nonlinear function
            stressn=-sig*(exx.*a.^-1.5)+(ex.^2.*(2*mu*ux(t)-p(t))-2*mu*ex.*(uy(t)+vx(t))+2*mu*vy(t)-p(t))./a; % normal stress
            stresst=mu*((1-ex.^2).*(uy(t)+vx(t))+2*ex.*(vy(t)-ux(t)))./a; % tangential stress
            
            f=[-(u.*ux+v.*uy)+D.lap*u/Re-px; ...
                -(u.*vx+v.*vy)+D.lap*v/Re-py; ...
                ux+vy; ...
                stressn; ... % jump in normal stress
                d.wx*Ly*e-V]; % volume

    The Jacobian

    We build here the expression of the Jacobian of f.

            % analytical Jacobian
            Astressn=-sig*(spd(a.^-1.5)*d.xx-spd(3*ex.*exx.*a.^-2.5)*d.x)*Ie ...
                +diag(2*mu*ex.^2./a)*Iux(t,:)-diag(2*mu*ex./a)*Iuy(t,:) ...
                -diag(2*mu*ex./a)*Ivx(t,:)+diag(2*mu./a)*Ivy(t,:) ...
                -Ip(t,:);
            
            Astresst=mu*(diag((1-ex.^2)./a)*Iuy(t,:)-diag(2*ex./a)*Iux(t,:) ...
                +diag((1-ex.^2)./a)*Ivx(t,:)+diag(2*ex./a)*Ivy(t,:));
            
            A=[-(spd(u)*Iux+spd(ux)*Iu+spd(v)*Iuy+spd(uy)*Iv)+Iulap/Re-Ipx; ...
                -(spd(u)*Ivx+spd(vx)*Iu+spd(v)*Ivy+spd(vy)*Iv)+Ivlap/Re-Ipy; ...
                Iux+Ivy; ...
                Astressn; ...
                d.wx*Ly*Ie];

    Boundary conditions

    They are:

    • Dirichlet for u and v at inflow (imposed inflow profile set by the initial guess) and bottom (no-slip)
    • Neumann for u and v at outflow (x derivative is zero)
    • The pressure must equal the reference pressure p_0 close to the bottom left corner
    • The Neumann condition on pressure to avoid spurious pressure modes
    • The height of the interface is imposed at x=0 and x=L_x.
    • The free surface is a streamline, or said differently: no penetration through the interface: \displaystyle v-u\eta_x=0
    • The tangential stress is zero
            % Boundary conditions
            dir=[l.u([l.left;l.bot]); l.v([l.left;l.bot])]; % where to put Dirichlet on u and v
            neuploc=[l.ctl;l.ctr;l.ctr-Ny];  % where to impose the neumann condition on the pressure
            
            loc=[dir; ...
                l.u(l.right); ...
                l.v(l.right); ...
                l.p(p0loc); ...
                l.p(neuploc); ...
                l.e([1,Nx]); ...
                l.u(t);
                l.v(t)];
            
            f(loc)=[q(dir)-q0(dir); ... % all Dirichlet
                ux(l.right); ... % Homogeneous Neuman on u at outflow
                vx(l.right); ...
                p(p0loc)-p0; % pressure equal to p0 at p0loc
                D.lap(neuploc,:)*v/Re-px(neuploc); ... % neumann constraint on pressure
                e(1)-Ly; ... % free-surface pinned at both ends
                e(Nx)-Ly; ...
                v(t)-u(t).*ex; ... % free-surface is a streamline
                stresst];
            
            C=[II(dir,:); ...     % all Dirichlet
                Iux(l.right,:); ...
                Ivx(l.right,:); ...
                Ip(p0loc,:)-Ip0;  % pressure equal to p0 at p0loc
                Ivlap(neuploc,:)/Re-Ipx(neuploc,:); ... % Neumann constraint on pressure
                ix(1,:)*Ie; ... % free-surface pinned at both ends
                ix(Nx,:)*Ie; ...
                Iv(t,:)-diag(ex)*Iu(t,:)-spd(u(t))*d.x*Ie; ... % free-surface is a streamline
                Astresst];
            
            A(loc,:)=C;
            tjac=toc;
            %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
            
            % plotting
            Yp=Y.*reshape(E,Ny,Nx); % physical mesh
            ww=reshape(u,Ny,Nx); vv=reshape(v,Ny,Nx);
            vo=vx-uy; % vorticity
            surf(X,Yp,reshape(vo,Ny,Nx)-10,'facealpha',1); view(2); shading interp; hold on
            sely=1:2:Ny; selx=round(linspace(1,Nx,10));
            quiver(X(sely,selx),Yp(sely,selx),ww(sely,selx),vv(sely,selx),'k','MaxHeadSize',0.01);
            plot(x,Ly+0*x,'b--',Lx+y*0,y,'b--');
            axis([0,1.1*Lx,0,1.2*Ly]);
            xlabel('x'); ylabel('y'); title('Vorticity and velocity field'); grid off;hold off
            %caxis([-30,0]-10)
            drawnow
            
            % convergence test
            res=norm(f);
            disp([num2str(count) '  ' sprintf('%9.3g',res) '  tjac:' sprintf('%7.3g',tjac) '  tlu:' sprintf('%7.3g',tlu)]);
            if count>50||res>1e5; disp('no convergence');break; end
            if res<1e-5; quit=1; disp('converged'); continue; end
            
            % Newton step
            tic; q=q-A\f; tlu=toc;
            count=count+1;
        end
        
    end
    set(gcf,'paperpositionmode','auto')
    print('-dpng','-r80','free_surface_navier_stokes.png')
    

    Here is the final figure:

    The figure

    The figure