├── Monday ├── Lectures │ ├── trt.pdf │ ├── lbnotes_jd.pdf │ ├── introduction.pdf │ └── 2011-08-22_Edmonton_scaling.pdf └── Coding │ ├── coding_taylorgreen.pdf │ ├── taylor_green_ex1.m │ ├── taylor_green.m │ ├── taylor_green_ex3.m │ ├── fourrows_ex1.m │ ├── taylor_green_ex2.m │ ├── fourrows.m │ ├── fourrows_ex2.m │ ├── taylor_green_trt.m │ └── fourrows_trt.m ├── Tuesday ├── Coding │ ├── labs.pdf │ ├── Poiseuille_BB_exercise.m │ ├── Poiseuille_BB_solution.m │ ├── PoiseuilleZouHe_solution.m │ ├── PoiseuilleZouHe_exercise.m │ ├── PoiseuilleDeveloping_exercise.m │ ├── Cylinder_flow.m │ ├── PoiseuilleDeveloping_solution.m │ ├── Backstep_exercise.m │ └── Backstep_solution.m └── Lectures │ ├── Corners.pdf │ ├── Curved_boundaries.pdf │ └── Straight_boundaries.pdf ├── Wednesday ├── Lectures │ ├── shanchen.pdf │ ├── binaryliquid.pdf │ ├── VisualizationSession.pdf │ └── Examples_for_visualization.zip └── Coding │ ├── coding_liquids.pdf │ ├── visualize.m │ ├── ellipse.m │ ├── contactangle.m │ ├── shanchen_ex1.m │ ├── shanchen_ex2.m │ ├── shanchen.m │ ├── binaryliquid_ex1.m │ ├── binaryliquid.m │ ├── shanchen_walls.m │ ├── shanchen_ex1.cpp │ ├── shanchen-walls.cpp │ ├── binary_ex3.cpp │ └── binary_ex2.cpp ├── Thursday ├── Coding │ ├── 2011-08-25_IBM_code.pdf │ ├── LBMWorkshop-vecAdd.zip │ └── IBLBM_2D_example1.cc └── Lectures │ ├── 2011-08-25_Edmonton_IBM.pdf │ └── OrestShardt-GPUComputing1.pdf └── README.md /Monday/Lectures/trt.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shurikkuzmin/LBMWorkshop/HEAD/Monday/Lectures/trt.pdf -------------------------------------------------------------------------------- /Tuesday/Coding/labs.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shurikkuzmin/LBMWorkshop/HEAD/Tuesday/Coding/labs.pdf -------------------------------------------------------------------------------- /Tuesday/Lectures/Corners.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shurikkuzmin/LBMWorkshop/HEAD/Tuesday/Lectures/Corners.pdf -------------------------------------------------------------------------------- /Monday/Lectures/lbnotes_jd.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shurikkuzmin/LBMWorkshop/HEAD/Monday/Lectures/lbnotes_jd.pdf -------------------------------------------------------------------------------- /Wednesday/Lectures/shanchen.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shurikkuzmin/LBMWorkshop/HEAD/Wednesday/Lectures/shanchen.pdf -------------------------------------------------------------------------------- /Monday/Lectures/introduction.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shurikkuzmin/LBMWorkshop/HEAD/Monday/Lectures/introduction.pdf -------------------------------------------------------------------------------- /Monday/Coding/coding_taylorgreen.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shurikkuzmin/LBMWorkshop/HEAD/Monday/Coding/coding_taylorgreen.pdf -------------------------------------------------------------------------------- /Wednesday/Coding/coding_liquids.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shurikkuzmin/LBMWorkshop/HEAD/Wednesday/Coding/coding_liquids.pdf -------------------------------------------------------------------------------- /Wednesday/Lectures/binaryliquid.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shurikkuzmin/LBMWorkshop/HEAD/Wednesday/Lectures/binaryliquid.pdf -------------------------------------------------------------------------------- /Thursday/Coding/2011-08-25_IBM_code.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shurikkuzmin/LBMWorkshop/HEAD/Thursday/Coding/2011-08-25_IBM_code.pdf -------------------------------------------------------------------------------- /Thursday/Coding/LBMWorkshop-vecAdd.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shurikkuzmin/LBMWorkshop/HEAD/Thursday/Coding/LBMWorkshop-vecAdd.zip -------------------------------------------------------------------------------- /Tuesday/Lectures/Curved_boundaries.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shurikkuzmin/LBMWorkshop/HEAD/Tuesday/Lectures/Curved_boundaries.pdf -------------------------------------------------------------------------------- /Tuesday/Lectures/Straight_boundaries.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shurikkuzmin/LBMWorkshop/HEAD/Tuesday/Lectures/Straight_boundaries.pdf -------------------------------------------------------------------------------- /Wednesday/Lectures/VisualizationSession.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shurikkuzmin/LBMWorkshop/HEAD/Wednesday/Lectures/VisualizationSession.pdf -------------------------------------------------------------------------------- /Thursday/Lectures/2011-08-25_Edmonton_IBM.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shurikkuzmin/LBMWorkshop/HEAD/Thursday/Lectures/2011-08-25_Edmonton_IBM.pdf -------------------------------------------------------------------------------- /Monday/Lectures/2011-08-22_Edmonton_scaling.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shurikkuzmin/LBMWorkshop/HEAD/Monday/Lectures/2011-08-22_Edmonton_scaling.pdf -------------------------------------------------------------------------------- /Thursday/Lectures/OrestShardt-GPUComputing1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shurikkuzmin/LBMWorkshop/HEAD/Thursday/Lectures/OrestShardt-GPUComputing1.pdf -------------------------------------------------------------------------------- /Wednesday/Lectures/Examples_for_visualization.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shurikkuzmin/LBMWorkshop/HEAD/Wednesday/Lectures/Examples_for_visualization.zip -------------------------------------------------------------------------------- /Wednesday/Coding/visualize.m: -------------------------------------------------------------------------------- 1 | %% The construction of movie from data files 2 | clear all 3 | clc 4 | 5 | a=dir('height*.dat') 6 | for counter=1:size(a) 7 | file_name=a(counter).name; 8 | rho=dlmread(file_name); 9 | %surf(rho) 10 | %zlim([0,3.0]); 11 | imagesc(rho) 12 | F(counter)=getframe; 13 | end 14 | movie(F) 15 | -------------------------------------------------------------------------------- /Wednesday/Coding/ellipse.m: -------------------------------------------------------------------------------- 1 | %% Contour plotting 2 | clc 3 | clear all 4 | 5 | phase=dlmread('phase020000.dat',' '); 6 | %imagesc(phase) 7 | figure(1) 8 | [c,h]=contour(phase,1) 9 | hold on 10 | 11 | aver=mean(c,2) 12 | 13 | c=c(:,2:end) 14 | crel=sqrt((c(1,:)-aver(1)).^2+(c(2,:)-aver(2)).^2) 15 | rmin=min(crel) 16 | rmax=max(crel) 17 | 18 | x0=aver(1); 19 | y0=aver(2); 20 | 21 | xaxis=find(phase(round(x0),:)>0) 22 | yaxis=find(phase(:,round(y0))>0) 23 | 24 | radx=max(yaxis)-y0; 25 | rady=max(xaxis)-x0; 26 | theta=-atan(rady/radx) 27 | 28 | a=rmin; 29 | b=rmax; 30 | alpha=0:pi/180:2*pi; 31 | x=a*cos(alpha); 32 | y=b*sin(alpha); 33 | 34 | xprime=x0+x.*cos(theta)+y.*sin(theta); 35 | yprime=y0-x.*sin(theta)+y.*cos(theta); 36 | %plot(xprime,yprime,'r+') 37 | 38 | d=abs(rmax-rmin)/(rmax+rmin) 39 | %% Postprocessing with the Matlab 40 | 41 | 42 | %plot(phase(dims(1)/2,:),'r+') 43 | %hold on 44 | %plot(phase(:,(dims(2)-1)/2),'bo') -------------------------------------------------------------------------------- /Wednesday/Coding/contactangle.m: -------------------------------------------------------------------------------- 1 | %% Visualization (uncomment for nice movie) 2 | %a=dir('phase*.dat') 3 | %figure(1) 4 | %for counter=1:size(a) 5 | % file_name=a(counter).name; 6 | % rho=dlmread(file_name); 7 | % %surf(rho) 8 | % imagesc(rho) 9 | % zlim([-1.1,1.1]); 10 | % F(counter)=getframe; 11 | %end 12 | 13 | %% Getting countour (wait until the second figure appears) 14 | figure(2) 15 | rho=dlmread('phase020000.dat'); 16 | rho=flipud(rho); 17 | [c,h]=contour(rho,1); 18 | c=c(:,2:end); 19 | 20 | %[coormax,indmax]=max(c(1,:)) 21 | %[coormin,indmin]=min(c(1,:)) 22 | 23 | coeff=(c(2,2)-c(2,1))/(c(1,2)-c(1,1)) 24 | theta=atan(coeff) 25 | atan(coeff)*180/pi 26 | 27 | wall_gradient=0.15 28 | a=0.04 29 | k=0.04 30 | x = fzero(@(x) sqrt(2)*sqrt(cos(acos(sin(x)^2)/3)*(1-cos(acos(sin(x)^2)/3)))-wall_gradient,theta) 31 | 32 | param=cos(acos(sin(theta)^2)/3); 33 | wall_gradient_computed=sqrt(2)*sqrt(param*(1-param)) 34 | 35 | Sim=theta*180/pi 36 | Theor=x*180/pi -------------------------------------------------------------------------------- /Monday/Coding/taylor_green_ex1.m: -------------------------------------------------------------------------------- 1 | %% periodic flow my version 2 | clear all; 3 | clc; 4 | 5 | % Macroscopic density and velocities 6 | NX=16; 7 | NY=16; 8 | NPOP=9; 9 | NSTEPS=2500; 10 | 11 | rho0=1; 12 | umax=0.001; 13 | 14 | rho=ones(NX,NY); 15 | ux=zeros(NX,NY); 16 | uy=zeros(NX,NY); 17 | 18 | uxinit=zeros(NX,NY); 19 | uyinit=zeros(NX,NY); 20 | 21 | feq=zeros(NPOP); 22 | f1=zeros(NPOP,NX,NY); 23 | f2=zeros(NPOP,NX,NY); 24 | 25 | weights=[4/9 1/9 1/9 1/9 1/9 1/36 1/36 1/36 1/36]; 26 | cx=[0 1 0 -1 0 1 -1 -1 1]; 27 | cy=[0 0 1 0 -1 1 1 -1 -1]; 28 | omega=1.0; 29 | 30 | for y=1:NY 31 | for x=1:NX 32 | rho(x,y)=rho0+3*0.25*umax^2*... 33 | (cos(4*pi*(x-1)/NX)-cos(4*pi*(y-1)/NY)); 34 | ux(x,y)=umax*sin(2*pi*(x-1)/NX)*sin(2*pi*(y-1)/NY); 35 | uy(x,y)=umax*cos(2*pi*(x-1)/NX)*cos(2*pi*(y-1)/NY); 36 | vx=ux(x,y); 37 | vy=uy(x,y); 38 | 39 | %Please initialize it with the equilibrium function 40 | end 41 | end 42 | 43 | for counter=1:NSTEPS 44 | for y=1:NY 45 | for x=1:NX 46 | dense=0; 47 | vx=0; 48 | vy=0; 49 | 50 | %Construct densitie and velocities by summation 51 | rho(x,y)=dense; 52 | vx = vx/dense; 53 | vy = vy/dense; 54 | ux(x,y)=vx; 55 | uy(x,y)=vy; 56 | 57 | for k=1:NPOP 58 | %Equilibrium distribution construction 59 | %newx,newy is for streaming 60 | 61 | newx=1+mod(x-1+cx(k)+NX,NX); 62 | newy=1+mod(y-1+cy(k)+NY,NY); 63 | 64 | %Collsion 65 | %Streaming from f1 to f2 66 | end 67 | 68 | end 69 | end 70 | 71 | track(counter)=ux(NX/4+1,NY/4+1); 72 | decay(counter)=umax*exp(-1/3*(1/omega-0.5)*counter*2*(2*pi/NX)^2); 73 | f1=f2; 74 | end 75 | 76 | plot(1:NSTEPS,track,'+') 77 | xlim([0 200]) 78 | hold on 79 | plot(1:NSTEPS,decay,'o') 80 | -------------------------------------------------------------------------------- /Monday/Coding/taylor_green.m: -------------------------------------------------------------------------------- 1 | %% periodic flow my version 2 | clear all; 3 | clc; 4 | 5 | % Macroscopic density and velocities 6 | NX=16; 7 | NY=16; 8 | NPOP=9; 9 | NSTEPS=100; 10 | 11 | rho0=1; 12 | umax=0.001; 13 | 14 | rho=ones(NX,NY); 15 | ux=zeros(NX,NY); 16 | uy=zeros(NX,NY); 17 | 18 | uxinit=zeros(NX,NY); 19 | uyinit=zeros(NX,NY); 20 | 21 | feq=zeros(NPOP); 22 | f1=zeros(NPOP,NX,NY); 23 | f2=zeros(NPOP,NX,NY); 24 | 25 | weights=[4/9 1/9 1/9 1/9 1/9 1/36 1/36 1/36 1/36]; 26 | cx=[0 1 0 -1 0 1 -1 -1 1]; 27 | cy=[0 0 1 0 -1 1 1 -1 -1]; 28 | omega=1.0; 29 | 30 | for y=1:NY 31 | for x=1:NX 32 | rho(x,y)=rho0+3*0.25*umax^2*... 33 | (cos(4*pi*(x-1)/NX)-cos(4*pi*(y-1)/NY)); 34 | ux(x,y)=umax*sin(2*pi*(x-1)/NX)*sin(2*pi*(y-1)/NY); 35 | uy(x,y)=umax*cos(2*pi*(x-1)/NX)*cos(2*pi*(y-1)/NY); 36 | vx=ux(x,y); 37 | vy=uy(x,y); 38 | 39 | for k=1:NPOP 40 | feq(k)=weights(k)*rho(x,y)*(1+3*(vx*cx(k)+vy*cy(k)) ... 41 | + 9/2*((cx(k)*cx(k)-1/3)*vx*vx+2*cx(k)*cy(k)*vx*vy+(cy(k)*cy(k)-1/3)*vy*vy)); 42 | f1(k,x,y)=feq(k); 43 | f2(k,x,y)=feq(k); 44 | end 45 | 46 | end 47 | end 48 | 49 | for counter=1:NSTEPS 50 | for y=1:NY 51 | for x=1:NX 52 | dense=0; 53 | vx=0; 54 | vy=0; 55 | for k=1:NPOP 56 | dense=dense+f1(k,x,y); 57 | vx=vx+cx(k)*f1(k,x,y); 58 | vy=vy+cy(k)*f1(k,x,y); 59 | end 60 | 61 | rho(x,y)=dense; 62 | vx = vx/dense; 63 | vy = vy/dense; 64 | ux(x,y)=vx; 65 | uy(x,y)=vy; 66 | 67 | for k=1:NPOP 68 | feq(k)=weights(k)*rho(x,y)*(1+3*(vx*cx(k)+vy*cy(k)) ... 69 | +9/2*((cx(k)*cx(k)-1/3)*vx*vx+2*cx(k)*cy(k)*vx*vy+(cy(k)*cy(k)-1/3)*vy*vy)); 70 | 71 | newx=1+mod(x-1+cx(k)+NX,NX); 72 | newy=1+mod(y-1+cy(k)+NY,NY); 73 | 74 | f1(k,x,y)=f1(k,x,y)*(1-omega)+feq(k)*omega; 75 | f2(k,newx,newy)=f1(k,x,y); 76 | end 77 | 78 | end 79 | end 80 | 81 | track(counter)=ux(NX/4+1,NY/4+1); 82 | decay(counter)=umax*exp(-1/3*(1/omega-0.5)*counter*2*(2*pi/NX)^2); 83 | f1=f2; 84 | end 85 | 86 | %% Calculation of L2 error 87 | sum=0 88 | for y=1:NX 89 | for x=1:NX 90 | ux_value=umax*sin(2*pi*(x-1)/NX)*sin(2*pi*(y-1)/NY); 91 | uy_value=umax*cos(2*pi*(x-1)/NX)*cos(2*pi*(y-1)/NY); 92 | 93 | sum=sum+(ux(x,y)-ux_value)^2+(uy(x,y)-uy_value)^2; 94 | end 95 | end 96 | error=sqrt(sum/(NX*NY)) 97 | -------------------------------------------------------------------------------- /Monday/Coding/taylor_green_ex3.m: -------------------------------------------------------------------------------- 1 | %% periodic flow my version 2 | clear all; 3 | clc; 4 | 5 | % Macroscopic density and velocities 6 | NX=64; 7 | NY=64; 8 | NPOP=9; 9 | NSTEPS=400; 10 | 11 | rho0=1; 12 | umax=0.001; 13 | 14 | rho=ones(NX,NY); 15 | ux=zeros(NX,NY); 16 | uy=zeros(NX,NY); 17 | 18 | uxinit=zeros(NX,NY); 19 | uyinit=zeros(NX,NY); 20 | 21 | feq=zeros(NPOP); 22 | f1=zeros(NPOP,NX,NY); 23 | f2=zeros(NPOP,NX,NY); 24 | 25 | weights=[4/9 1/9 1/9 1/9 1/9 1/36 1/36 1/36 1/36]; 26 | cx=[0 1 0 -1 0 1 -1 -1 1]; 27 | cy=[0 0 1 0 -1 1 1 -1 -1]; 28 | omega=1.0/10.0; 29 | 30 | for y=1:NY 31 | for x=1:NX 32 | rho(x,y)=rho0+3*0.25*umax^2*... 33 | (cos(4*pi*(x-1)/NX)-cos(4*pi*(y-1)/NY)); 34 | ux(x,y)=umax*sin(2*pi*(x-1)/NX)*sin(2*pi*(y-1)/NY); 35 | uy(x,y)=umax*cos(2*pi*(x-1)/NX)*cos(2*pi*(y-1)/NY); 36 | vx=ux(x,y); 37 | vy=uy(x,y); 38 | 39 | for k=1:NPOP 40 | feq(k)=weights(k)*rho(x,y)*(1+3*(vx*cx(k)+vy*cy(k)) ... 41 | + 9/2*((cx(k)*cx(k)-1/3)*vx*vx+2*cx(k)*cy(k)*vx*vy+(cy(k)*cy(k)-1/3)*vy*vy)); 42 | f1(k,x,y)=feq(k); 43 | f2(k,x,y)=feq(k); 44 | end 45 | 46 | end 47 | end 48 | 49 | for counter=1:NSTEPS 50 | for y=1:NY 51 | for x=1:NX 52 | dense=0; 53 | vx=0; 54 | vy=0; 55 | for k=1:NPOP 56 | dense=dense+f1(k,x,y); 57 | vx=vx+cx(k)*f1(k,x,y); 58 | vy=vy+cy(k)*f1(k,x,y); 59 | end 60 | 61 | rho(x,y)=dense; 62 | vx = vx/dense; 63 | vy = vy/dense; 64 | ux(x,y)=vx; 65 | uy(x,y)=vy; 66 | 67 | for k=1:NPOP 68 | feq(k)=weights(k)*rho(x,y)*(1+3*(vx*cx(k)+vy*cy(k)) ... 69 | +9/2*((cx(k)*cx(k)-1/3)*vx*vx+2*cx(k)*cy(k)*vx*vy+(cy(k)*cy(k)-1/3)*vy*vy)); 70 | 71 | newx=1+mod(x-1+cx(k)+NX,NX); 72 | newy=1+mod(y-1+cy(k)+NY,NY); 73 | 74 | f1(k,x,y)=f1(k,x,y)*(1-omega)+feq(k)*omega; 75 | f2(k,newx,newy)=f1(k,x,y); 76 | end 77 | 78 | end 79 | end 80 | 81 | track(counter)=ux(NX/4+1,NY/4+1); 82 | decay(counter)=umax*exp(-1/3*(1/omega-0.5)*(counter-1)*2*(2*pi/NX)^2); 83 | f1=f2; 84 | end 85 | 86 | plot(1:NSTEPS,track,'+') 87 | xlim([0 NSTEPS]) 88 | hold on 89 | plot(1:NSTEPS,decay,'o') 90 | 91 | 92 | %% Calculation of L2 error 93 | sum=0 94 | for y=1:NX 95 | for x=1:NX 96 | ux_value=umax*sin(2*pi*(x-1)/NX)*sin(2*pi*(y-1)/NY)*exp(-1/3*(1/omega-0.5)*(NSTEPS-1)*2*(2*pi/NX)^2); 97 | uy_value=umax*cos(2*pi*(x-1)/NX)*cos(2*pi*(y-1)/NY)*exp(-1/3*(1/omega-0.5)*(NSTEPS-1)*2*(2*pi/NX)^2); 98 | 99 | sum=sum+(ux(x,y)-ux_value)^2+(uy(x,y)-uy_value)^2; 100 | end 101 | end 102 | error=sqrt(sum/(NX*NY)) 103 | -------------------------------------------------------------------------------- /Monday/Coding/fourrows_ex1.m: -------------------------------------------------------------------------------- 1 | %% periodic flow my version 2 | clear all; 3 | clc; 4 | 5 | % Macroscopic density and velocities 6 | NX=64; 7 | NY=64; 8 | NPOP=9; 9 | NSTEPS=400; 10 | 11 | rho0=1; 12 | umax=0.001; 13 | 14 | rho=ones(NX,NY); 15 | ux=zeros(NX,NY); 16 | uy=zeros(NX,NY); 17 | 18 | uxinit=zeros(NX,NY); 19 | uyinit=zeros(NX,NY); 20 | 21 | feq=zeros(NPOP); 22 | f1=zeros(NPOP,NX,NY); 23 | f2=zeros(NPOP,NX,NY); 24 | 25 | weights=[4/9 1/9 1/9 1/9 1/9 1/36 1/36 1/36 1/36]; 26 | cx=[0 1 0 -1 0 1 -1 -1 1]; 27 | cy=[0 0 1 0 -1 1 1 -1 -1]; 28 | omega=0.1; 29 | 30 | for y=1:NY 31 | for x=1:NX 32 | rho(x,y)=rho0+3*0.25*umax^2*... 33 | (cos(4*pi*(x-1)/NX)-cos(4*pi*(y-1)/NY)); 34 | ux(x,y)=umax*sin(2*pi*(x-1)/NX)*sin(2*pi*(y-1)/NY); 35 | uy(x,y)=umax*cos(2*pi*(x-1)/NX)*cos(2*pi*(y-1)/NY); 36 | uxinit(x,y)=umax*sin(2*pi*(x-1)/NX)*sin(2*pi*(y-1)/NY); 37 | uyinit(x,y)=umax*cos(2*pi*(x-1)/NX)*cos(2*pi*(y-1)/NY); 38 | 39 | vx=ux(x,y); 40 | vy=uy(x,y); 41 | for k=1:NPOP 42 | feq(k)=weights(k)*(rho(x,y)+3*(vx*cx(k)+vy*cy(k)) ... 43 | + 9/2*((cx(k)*cx(k)-1/3)*vx*vx+2*cx(k)*cy(k)*vx*vy+(cy(k)*cy(k)-1/3)*vy*vy)); 44 | f1(k,x,y)=feq(k); 45 | f2(k,x,y)=feq(k); 46 | end 47 | end 48 | end 49 | 50 | track=zeros(1,NSTEPS); 51 | 52 | %this value we need to obtain - it should be constant over the simulation 53 | %umax*sin(2*pi*(NX/4-1)/NX)*sin(2*pi*(NY/4-1)/NY) 54 | 55 | for counter=1:NSTEPS 56 | for y=1:NY 57 | for x=1:NX 58 | dense=0; 59 | vx=0; 60 | vy=0; 61 | for k=1:NPOP 62 | dense=dense+f1(k,x,y); 63 | vx=vx+cx(k)*f1(k,x,y); 64 | vy=vy+cy(k)*f1(k,x,y); 65 | end 66 | vx=vx/dense; 67 | vy=vy/dense; 68 | 69 | % Collision 70 | forcex=(2*pi/NX)^2*2*1/3*(1/omega-1/2)*umax*sin(2*pi*(x-1)/NX)*sin(2*pi*(y-1)/NY); 71 | forcey=(2*pi/NX)^2*2*1/3*(1/omega-1/2)*umax*cos(2*pi*(x-1)/NX)*cos(2*pi*(y-1)/NY); 72 | 73 | 74 | rho(x,y)=dense; 75 | % Modify macroscopic variables 76 | 77 | for k=1:NPOP 78 | feq(k)=weights(k)*dense*(1+3*(vx*cx(k)+vy*cy(k)) ... 79 | +9/2*((cx(k)*cx(k)-1/3)*vx*vx+2*cx(k)*cy(k)*vx*vy+(cy(k)*cy(k)-1/3)*vy*vy)); 80 | 81 | newx=1+mod(x-1+cx(k)+NX,NX); 82 | newy=1+mod(y-1+cy(k)+NY,NY); 83 | 84 | %Implement force population here 85 | f1(k,x,y)=f1(k,x,y)*(1-omega)+feq(k)*omega+forcepop; 86 | f2(k,newx,newy)=f1(k,x,y); 87 | end 88 | 89 | end 90 | end 91 | track(counter)=ux(NX/4+1,NY/4+1); 92 | %decay(counter)=umax*exp(-1/3*(1/omega-0.5)*counter*4*pi/NX); 93 | f1=f2; 94 | end 95 | figure(1) 96 | surf(ux-uxinit) 97 | figure(2) 98 | plot(1:NSTEPS,track) 99 | 100 | max(max(ux)) 101 | -------------------------------------------------------------------------------- /Monday/Coding/taylor_green_ex2.m: -------------------------------------------------------------------------------- 1 | %% periodic flow my version 2 | clear all; 3 | clc; 4 | 5 | % Macroscopic density and velocities 6 | NX=64; 7 | NY=64; 8 | NPOP=9; 9 | NSTEPS=100*(NX/16)^2; 10 | 11 | rho0=1; 12 | umax=0.001; 13 | 14 | rho=ones(NX,NY); 15 | ux=zeros(NX,NY); 16 | uy=zeros(NX,NY); 17 | 18 | uxinit=zeros(NX,NY); 19 | uyinit=zeros(NX,NY); 20 | 21 | feq=zeros(NPOP); 22 | f1=zeros(NPOP,NX,NY); 23 | f2=zeros(NPOP,NX,NY); 24 | 25 | weights=[4/9 1/9 1/9 1/9 1/9 1/36 1/36 1/36 1/36]; 26 | cx=[0 1 0 -1 0 1 -1 -1 1]; 27 | cy=[0 0 1 0 -1 1 1 -1 -1]; 28 | omega=1.0; 29 | 30 | for y=1:NY 31 | for x=1:NX 32 | rho(x,y)=rho0+3*0.25*umax^2*... 33 | (cos(4*pi*(x-1)/NX)-cos(4*pi*(y-1)/NY)); 34 | ux(x,y)=umax*sin(2*pi*(x-1)/NX)*sin(2*pi*(y-1)/NY); 35 | uy(x,y)=umax*cos(2*pi*(x-1)/NX)*cos(2*pi*(y-1)/NY); 36 | vx=ux(x,y); 37 | vy=uy(x,y); 38 | 39 | for k=1:NPOP 40 | feq(k)=weights(k)*rho(x,y)*(1+3*(vx*cx(k)+vy*cy(k)) ... 41 | + 9/2*((cx(k)*cx(k)-1/3)*vx*vx+2*cx(k)*cy(k)*vx*vy+(cy(k)*cy(k)-1/3)*vy*vy)); 42 | f1(k,x,y)=feq(k); 43 | f2(k,x,y)=feq(k); 44 | end 45 | 46 | end 47 | end 48 | 49 | for counter=1:NSTEPS 50 | for y=1:NY 51 | for x=1:NX 52 | dense=0; 53 | vx=0; 54 | vy=0; 55 | for k=1:NPOP 56 | dense=dense+f1(k,x,y); 57 | vx=vx+cx(k)*f1(k,x,y); 58 | vy=vy+cy(k)*f1(k,x,y); 59 | end 60 | 61 | rho(x,y)=dense; 62 | vx = vx/dense; 63 | vy = vy/dense; 64 | ux(x,y)=vx; 65 | uy(x,y)=vy; 66 | 67 | for k=1:NPOP 68 | feq(k)=weights(k)*rho(x,y)*(1+3*(vx*cx(k)+vy*cy(k)) ... 69 | +9/2*((cx(k)*cx(k)-1/3)*vx*vx+2*cx(k)*cy(k)*vx*vy+(cy(k)*cy(k)-1/3)*vy*vy)); 70 | 71 | newx=1+mod(x-1+cx(k)+NX,NX); 72 | newy=1+mod(y-1+cy(k)+NY,NY); 73 | 74 | f1(k,x,y)=f1(k,x,y)*(1-omega)+feq(k)*omega; 75 | f2(k,newx,newy)=f1(k,x,y); 76 | end 77 | 78 | end 79 | end 80 | 81 | track(counter)=ux(NX/4+1,NY/4+1); 82 | decay(counter)=umax*exp(-1/3*(1/omega-0.5)*(counter-1)*2*(2*pi/NX)^2); 83 | f1=f2; 84 | end 85 | 86 | plot(1:NSTEPS,track,'+') 87 | xlim([0 NSTEPS]) 88 | hold on 89 | plot(1:NSTEPS,decay,'o') 90 | 91 | 92 | %% Calculation of L2 error 93 | sum=0 94 | for y=1:NX 95 | for x=1:NX 96 | ux_value=umax*sin(2*pi*(x-1)/NX)*sin(2*pi*(y-1)/NY)*exp(-1/3*(1/omega-0.5)*(NSTEPS-1)*2*(2*pi/NX)^2); 97 | uy_value=umax*cos(2*pi*(x-1)/NX)*cos(2*pi*(y-1)/NY)*exp(-1/3*(1/omega-0.5)*(NSTEPS-1)*2*(2*pi/NX)^2); 98 | 99 | sum=sum+(ux(x,y)-ux_value)^2+(uy(x,y)-uy_value)^2; 100 | end 101 | end 102 | error=sqrt(sum/(NX*NY)) 103 | 104 | %% Log-log plot (uncomment it when is needed) 105 | 106 | %grid=[16,32,64] 107 | %curve=[1e-7,1e-7/4,1e-7/16] 108 | %figure(2) 109 | %loglog(grid,err,grid,curve) 110 | -------------------------------------------------------------------------------- /Monday/Coding/fourrows.m: -------------------------------------------------------------------------------- 1 | %% periodic flow my version 2 | clear all; 3 | clc; 4 | 5 | % Macroscopic density and velocities 6 | NX=64; 7 | NY=64; 8 | NPOP=9; 9 | NSTEPS=400; 10 | 11 | rho0=1; 12 | umax=0.001; 13 | 14 | rho=ones(NX,NY); 15 | ux=zeros(NX,NY); 16 | uy=zeros(NX,NY); 17 | 18 | uxinit=zeros(NX,NY); 19 | uyinit=zeros(NX,NY); 20 | 21 | feq=zeros(NPOP); 22 | f1=zeros(NPOP,NX,NY); 23 | f2=zeros(NPOP,NX,NY); 24 | 25 | weights=[4/9 1/9 1/9 1/9 1/9 1/36 1/36 1/36 1/36]; 26 | cx=[0 1 0 -1 0 1 -1 -1 1]; 27 | cy=[0 0 1 0 -1 1 1 -1 -1]; 28 | omega=0.1; 29 | 30 | for y=1:NY 31 | for x=1:NX 32 | rho(x,y)=rho0+3*0.25*umax^2*... 33 | (cos(4*pi*(x-1)/NX)-cos(4*pi*(y-1)/NY)); 34 | ux(x,y)=umax*sin(2*pi*(x-1)/NX)*sin(2*pi*(y-1)/NY); 35 | uy(x,y)=umax*cos(2*pi*(x-1)/NX)*cos(2*pi*(y-1)/NY); 36 | uxinit(x,y)=umax*sin(2*pi*(x-1)/NX)*sin(2*pi*(y-1)/NY); 37 | uyinit(x,y)=umax*cos(2*pi*(x-1)/NX)*cos(2*pi*(y-1)/NY); 38 | 39 | vx=ux(x,y); 40 | vy=uy(x,y); 41 | for k=1:NPOP 42 | feq(k)=weights(k)*(rho(x,y)+3*(vx*cx(k)+vy*cy(k)) ... 43 | + 9/2*((cx(k)*cx(k)-1/3)*vx*vx+2*cx(k)*cy(k)*vx*vy+(cy(k)*cy(k)-1/3)*vy*vy)); 44 | f1(k,x,y)=feq(k); 45 | f2(k,x,y)=feq(k); 46 | end 47 | end 48 | end 49 | 50 | track=zeros(1,NSTEPS); 51 | 52 | %this value we need to obtain - it should be constant over the simulation 53 | %umax*sin(2*pi*(NX/4-1)/NX)*sin(2*pi*(NY/4-1)/NY) 54 | 55 | for counter=1:NSTEPS 56 | for y=1:NY 57 | for x=1:NX 58 | dense=0; 59 | vx=0; 60 | vy=0; 61 | for k=1:NPOP 62 | dense=dense+f1(k,x,y); 63 | vx=vx+cx(k)*f1(k,x,y); 64 | vy=vy+cy(k)*f1(k,x,y); 65 | end 66 | vx=vx/dense; 67 | vy=vy/dense; 68 | 69 | % Collision 70 | %forcex=tempx(x,y); 71 | %forcey=tempy(x,y); 72 | forcex=(2*pi/NX)^2*2*1/3*(1/omega-1/2)*umax*sin(2*pi*(x-1)/NX)*sin(2*pi*(y-1)/NY); 73 | forcey=(2*pi/NX)^2*2*1/3*(1/omega-1/2)*umax*cos(2*pi*(x-1)/NX)*cos(2*pi*(y-1)/NY); 74 | 75 | 76 | rho(x,y)=dense; 77 | ux(x,y)=vx+forcex/(2.0*dense); 78 | uy(x,y)=vy+forcey/(2.0*dense); 79 | 80 | vx=vx+forcex/2.0; 81 | vy=vy+forcey/2.0; 82 | 83 | 84 | for k=1:NPOP 85 | feq(k)=weights(k)*dense*(1+3*(vx*cx(k)+vy*cy(k)) ... 86 | +9/2*((cx(k)*cx(k)-1/3)*vx*vx+2*cx(k)*cy(k)*vx*vy+(cy(k)*cy(k)-1/3)*vy*vy)); 87 | 88 | newx=1+mod(x-1+cx(k)+NX,NX); 89 | newy=1+mod(y-1+cy(k)+NY,NY); 90 | 91 | 92 | forcepop=weights(k)*(1-0.5*omega)*(forcex*(3.0*(cx(k)-vx)+9.0*cx(k)*(cx(k)*vx+cy(k)*vy))+... 93 | forcey*(3.0*(cy(k)-vy)+9.0*cy(k)*(cx(k)*vx+cy(k)*vy))); 94 | f1(k,x,y)=f1(k,x,y)*(1-omega)+feq(k)*omega+forcepop; 95 | f2(k,newx,newy)=f1(k,x,y); 96 | end 97 | 98 | end 99 | end 100 | track(counter)=ux(NX/4+1,NY/4+1); 101 | %decay(counter)=umax*exp(-1/3*(1/omega-0.5)*counter*4*pi/NX); 102 | f1=f2; 103 | end 104 | figure(1) 105 | surf(ux-uxinit) 106 | figure(2) 107 | plot(1:NSTEPS,track) 108 | 109 | max(max(ux)) 110 | -------------------------------------------------------------------------------- /Wednesday/Coding/shanchen_ex1.m: -------------------------------------------------------------------------------- 1 | %% periodic flow my version 2 | clear all; 3 | clc; 4 | 5 | % Macroscopic density and velocities 6 | NX=128; 7 | NY=128; 8 | NPOP=9; 9 | NSTEPS=300; 10 | NOUTPUT=10; 11 | 12 | % Parameters of the Shan-Chen model 13 | rho_crit=log(2) 14 | rho_liq=1.95 15 | rho_gas=0.15 16 | radius=20 17 | G=-5.0 18 | 19 | % Initialization 20 | rho=ones(NX,NY); 21 | ux=zeros(NX,NY); 22 | uy=zeros(NX,NY); 23 | 24 | feq=zeros(NPOP); 25 | f1=zeros(NPOP,NX,NY); 26 | f2=zeros(NPOP,NX,NY); 27 | forcex=zeros(NX,NY); 28 | forcey=zeros(NY,NY); 29 | 30 | % Parameters of the lattice 31 | weights=[4/9 1/9 1/9 1/9 1/9 1/36 1/36 1/36 1/36]; 32 | cx=[0 1 0 -1 0 1 -1 -1 1]; 33 | cy=[0 0 1 0 -1 1 1 -1 -1]; 34 | omega=1.0; 35 | 36 | 37 | for y=1:NY 38 | for x=1:NX 39 | %Initialize density here 40 | ux(x,y)=0; 41 | uy(x,y)=0; 42 | vx=ux(x,y); 43 | vy=uy(x,y); 44 | 45 | for k=1:NPOP 46 | feq(k)=weights(k)*rho(x,y)*(1+3*(vx*cx(k)+vy*cy(k)) ... 47 | + 9/2*((cx(k)*cx(k)-1/3)*vx*vx+2*cx(k)*cy(k)*vx*vy+(cy(k)*cy(k)-1/3)*vy*vy)); 48 | f1(k,x,y)=feq(k); 49 | f2(k,x,y)=feq(k); 50 | end 51 | 52 | end 53 | end 54 | 55 | counter_frame=1; 56 | for counter=1:NSTEPS 57 | 58 | % Calculation of the macroscopic quantities 59 | for y=1:NY 60 | for x=1:NX 61 | dense=0; 62 | vx=0; 63 | vy=0; 64 | for k=1:NPOP 65 | dense=dense+f1(k,x,y); 66 | vx=vx+cx(k)*f1(k,x,y); 67 | vy=vy+cy(k)*f1(k,x,y); 68 | end 69 | 70 | rho(x,y)=dense; 71 | ux(x,y)=vx/dense; 72 | uy(x,y)=vy/dense; 73 | end 74 | end 75 | 76 | % Calculation of the force 77 | for y=1:NY 78 | for x=1:NX 79 | 80 | force_sum_x=0.0; 81 | force_sum_y=0.0; 82 | 83 | for k=2:NPOP 84 | newx=1+mod(x-1+cx(k)+NX,NX); 85 | newy=1+mod(y-1+cy(k)+NY,NY); 86 | psi=1-exp(-rho(newx,newy)); 87 | %Implement force here 88 | end 89 | 90 | end 91 | end 92 | % main loop 93 | for y=1:NY 94 | for x=1:NX 95 | 96 | dense=rho(x,y); 97 | vx=ux(x,y)+0.5*forcex(x,y)/dense; 98 | vy=uy(x,y)+0.5*forcey(x,y)/dense; 99 | for k=1:NPOP 100 | feq(k)=weights(k)*dense*(1+3*(vx*cx(k)+vy*cy(k)) ... 101 | +9/2*((cx(k)*cx(k)-1/3)*vx*vx+2*cx(k)*cy(k)*vx*vy+(cy(k)*cy(k)-1/3)*vy*vy)); 102 | 103 | 104 | forcepop=weights(k)*(1-0.5*omega)*((3*(cx(k)-vx)+9*cx(k)*(cx(k)*vx+cy(k)*vy))*forcex(x,y)... 105 | +(3*(cy(k)-vy)+9*cy(k)*(cx(k)*vx+cy(k)*vy))*forcey(x,y)); 106 | 107 | newx=1+mod(x-1+cx(k)+NX,NX); 108 | newy=1+mod(y-1+cy(k)+NY,NY); 109 | 110 | f1(k,x,y)=f1(k,x,y)*(1-omega)+feq(k)*omega+forcepop; 111 | f2(k,newx,newy)=f1(k,x,y); 112 | end 113 | 114 | end 115 | end 116 | 117 | f1=f2; 118 | counter 119 | 120 | if mod(counter,NOUTPUT)==0 121 | surf(rho); 122 | F(counter_frame) = getframe; 123 | counter_frame=counter_frame+1; 124 | end 125 | end 126 | 127 | movie(F,10) 128 | 129 | disp('Rho_liq=') 130 | disp(mean(mean(rho(NX/2-5:NX/2+5,NY/2-5:NY/2+5)))) 131 | disp('Rho_gas=') 132 | disp(mean(mean(rho(1:10,1:10)))) 133 | -------------------------------------------------------------------------------- /Monday/Coding/fourrows_ex2.m: -------------------------------------------------------------------------------- 1 | %% periodic flow my version 2 | clear all; 3 | clc; 4 | 5 | % Macroscopic density and velocities 6 | NX=64; 7 | NY=64; 8 | NPOP=9; 9 | NSTEPS=400; 10 | 11 | rho0=1; 12 | umax=0.001; 13 | 14 | rho=ones(NX,NY); 15 | ux=zeros(NX,NY); 16 | uy=zeros(NX,NY); 17 | 18 | uxinit=zeros(NX,NY); 19 | uyinit=zeros(NX,NY); 20 | 21 | feq=zeros(NPOP); 22 | f1=zeros(NPOP,NX,NY); 23 | f2=zeros(NPOP,NX,NY); 24 | 25 | weights=[4/9 1/9 1/9 1/9 1/9 1/36 1/36 1/36 1/36]; 26 | cx=[0 1 0 -1 0 1 -1 -1 1]; 27 | cy=[0 0 1 0 -1 1 1 -1 -1]; 28 | 29 | %Parameters of the TRT model 30 | omega=1.0/10.0; 31 | omega_plus=omega 32 | lambda=1/4; 33 | omega_minus=1/(lambda/(1/omega_plus-0.5)+0.5) 34 | 35 | compliment=[1 4 5 2 3 8 9 6 7]; 36 | %Additional memory for TRT 37 | feq_plus=zeros(NPOP); 38 | feq_minus=zeros(NPOP); 39 | f_plus=zeros(NPOP); 40 | f_minus=zeros(NPOP); 41 | 42 | 43 | 44 | for y=1:NY 45 | for x=1:NX 46 | rho(x,y)=rho0+3*0.25*umax^2*... 47 | (cos(4*pi*(x-1)/NX)-cos(4*pi*(y-1)/NY)); 48 | ux(x,y)=umax*sin(2*pi*(x-1)/NX)*sin(2*pi*(y-1)/NY); 49 | uy(x,y)=umax*cos(2*pi*(x-1)/NX)*cos(2*pi*(y-1)/NY); 50 | uxinit(x,y)=umax*sin(2*pi*(x-1)/NX)*sin(2*pi*(y-1)/NY); 51 | uyinit(x,y)=umax*cos(2*pi*(x-1)/NX)*cos(2*pi*(y-1)/NY); 52 | 53 | vx=ux(x,y); 54 | vy=uy(x,y); 55 | for k=1:NPOP 56 | feq(k)=weights(k)*(rho(x,y)+3*(vx*cx(k)+vy*cy(k)) ... 57 | + 9/2*((cx(k)*cx(k)-1/3)*vx*vx+2*cx(k)*cy(k)*vx*vy+(cy(k)*cy(k)-1/3)*vy*vy)); 58 | f1(k,x,y)=feq(k); 59 | f2(k,x,y)=feq(k); 60 | end 61 | end 62 | end 63 | 64 | track=zeros(1,NSTEPS); 65 | 66 | %this value we need to obtain - it should be constant over the simulation 67 | %umax*sin(2*pi*(NX/4-1)/NX)*sin(2*pi*(NY/4-1)/NY) 68 | 69 | for counter=1:NSTEPS 70 | for y=1:NY 71 | for x=1:NX 72 | dense=0; 73 | vx=0; 74 | vy=0; 75 | for k=1:NPOP 76 | dense=dense+f1(k,x,y); 77 | vx=vx+cx(k)*f1(k,x,y); 78 | vy=vy+cy(k)*f1(k,x,y); 79 | end 80 | vx=vx/dense; 81 | vy=vy/dense; 82 | 83 | % Collision 84 | %forcex=tempx(x,y); 85 | %forcey=tempy(x,y); 86 | forcex=(2*pi/NX)^2*2*1/3*(1/omega-1/2)*umax*sin(2*pi*(x-1)/NX)*sin(2*pi*(y-1)/NY); 87 | forcey=(2*pi/NX)^2*2*1/3*(1/omega-1/2)*umax*cos(2*pi*(x-1)/NX)*cos(2*pi*(y-1)/NY); 88 | 89 | 90 | rho(x,y)=dense; 91 | ux(x,y)=vx+forcex/(2.0*dense); 92 | uy(x,y)=vy+forcey/(2.0*dense); 93 | 94 | vx=vx+forcex/2.0; 95 | vy=vy+forcey/2.0; 96 | 97 | for k=1:NPOP 98 | feq(k)=weights(k)*rho(x,y)*(1+3*(vx*cx(k)+vy*cy(k)) ... 99 | +9/2*((cx(k)*cx(k)-1/3)*vx*vx+2*cx(k)*cy(k)*vx*vy+(cy(k)*cy(k)-1/3)*vy*vy)); 100 | 101 | end 102 | %Do projection on symmetric and antisymmetric parts 103 | 104 | for k=1:NPOP 105 | 106 | newx=1+mod(x-1+cx(k)+NX,NX); 107 | newy=1+mod(y-1+cy(k)+NY,NY); 108 | 109 | %Implement force population and collision here 110 | f2(k,newx,newy)=f1(k,x,y); 111 | end 112 | 113 | 114 | end 115 | end 116 | track(counter)=ux(NX/4+1,NY/4+1); 117 | f1=f2; 118 | end 119 | figure(1) 120 | surf(ux-uxinit) 121 | figure(2) 122 | plot(1:NSTEPS,track) 123 | 124 | max(max(ux)) 125 | -------------------------------------------------------------------------------- /Monday/Coding/taylor_green_trt.m: -------------------------------------------------------------------------------- 1 | %% periodic flow my version 2 | clear all; 3 | clc; 4 | 5 | % Macroscopic density and velocities 6 | NX=64; 7 | NY=64; 8 | NPOP=9; 9 | NSTEPS=400; 10 | 11 | rho0=1; 12 | umax=0.001; 13 | 14 | rho=ones(NX,NY); 15 | ux=zeros(NX,NY); 16 | uy=zeros(NX,NY); 17 | 18 | uxinit=zeros(NX,NY); 19 | uyinit=zeros(NX,NY); 20 | 21 | feq=zeros(NPOP); 22 | f1=zeros(NPOP,NX,NY); 23 | f2=zeros(NPOP,NX,NY); 24 | 25 | weights=[4/9 1/9 1/9 1/9 1/9 1/36 1/36 1/36 1/36]; 26 | cx=[0 1 0 -1 0 1 -1 -1 1]; 27 | cy=[0 0 1 0 -1 1 1 -1 -1]; 28 | 29 | %Parameters of the TRT model 30 | omega=1.0/10.0; 31 | omega_plus=omega 32 | lambda=130; 33 | omega_minus=1/(lambda/(1/omega_plus-0.5)+0.5) 34 | 35 | compliment=[1 4 5 2 3 8 9 6 7]; 36 | %Additional memory for TRT 37 | feq_plus=zeros(NPOP); 38 | feq_minus=zeros(NPOP); 39 | f_plus=zeros(NPOP); 40 | f_minus=zeros(NPOP); 41 | 42 | for y=1:NY 43 | for x=1:NX 44 | rho(x,y)=rho0+3*0.25*umax^2*... 45 | (cos(4*pi*(x-1)/NX)-cos(4*pi*(y-1)/NY)); 46 | ux(x,y)=umax*sin(2*pi*(x-1)/NX)*sin(2*pi*(y-1)/NY); 47 | uy(x,y)=umax*cos(2*pi*(x-1)/NX)*cos(2*pi*(y-1)/NY); 48 | vx=ux(x,y); 49 | vy=uy(x,y); 50 | 51 | for k=1:NPOP 52 | feq(k)=weights(k)*rho(x,y)*(1+3*(vx*cx(k)+vy*cy(k)) ... 53 | + 9/2*((cx(k)*cx(k)-1/3)*vx*vx+2*cx(k)*cy(k)*vx*vy+(cy(k)*cy(k)-1/3)*vy*vy)); 54 | f1(k,x,y)=feq(k); 55 | f2(k,x,y)=feq(k); 56 | end 57 | 58 | end 59 | end 60 | 61 | for counter=1:NSTEPS 62 | for y=1:NY 63 | for x=1:NX 64 | dense=0; 65 | vx=0; 66 | vy=0; 67 | for k=1:NPOP 68 | dense=dense+f1(k,x,y); 69 | vx=vx+cx(k)*f1(k,x,y); 70 | vy=vy+cy(k)*f1(k,x,y); 71 | end 72 | 73 | rho(x,y)=dense; 74 | vx = vx/dense; 75 | vy = vy/dense; 76 | ux(x,y)=vx; 77 | uy(x,y)=vy; 78 | 79 | for k=1:NPOP 80 | feq(k)=weights(k)*rho(x,y)*(1+3*(vx*cx(k)+vy*cy(k)) ... 81 | +9/2*((cx(k)*cx(k)-1/3)*vx*vx+2*cx(k)*cy(k)*vx*vy+(cy(k)*cy(k)-1/3)*vy*vy)); 82 | end 83 | 84 | for k=1:NPOP 85 | f_plus(k)=0.5*(f1(k,x,y)+f1(compliment(k),x,y)); 86 | f_minus(k)=0.5*(f1(k,x,y)-f1(compliment(k),x,y)); 87 | feq_plus(k)=0.5*(feq(k)+feq(compliment(k))); 88 | feq_minus(k)=0.5*(feq(k)-feq(compliment(k))); 89 | 90 | end 91 | for k=1:NPOP 92 | 93 | newx=1+mod(x-1+cx(k)+NX,NX); 94 | newy=1+mod(y-1+cy(k)+NY,NY); 95 | 96 | f1(k,x,y)=f1(k,x,y)-omega_plus*(f_plus(k)-feq_plus(k))-omega_minus*(f_minus(k)-feq_minus(k)); 97 | f2(k,newx,newy)=f1(k,x,y); 98 | end 99 | 100 | end 101 | end 102 | 103 | track(counter)=ux(NX/4+1,NY/4+1); 104 | decay(counter)=umax*exp(-1/3*(1/omega-0.5)*(counter-1)*2*(2*pi/NX)^2); 105 | f1=f2; 106 | end 107 | 108 | plot(1:NSTEPS,track,'+') 109 | xlim([0 NSTEPS]) 110 | hold on 111 | plot(1:NSTEPS,decay,'o') 112 | 113 | 114 | %% Calculation of L2 error 115 | sum=0 116 | for y=1:NX 117 | for x=1:NX 118 | ux_value=umax*sin(2*pi*(x-1)/NX)*sin(2*pi*(y-1)/NY)*exp(-1/3*(1/omega-0.5)*(NSTEPS-1)*2*(2*pi/NX)^2); 119 | uy_value=umax*cos(2*pi*(x-1)/NX)*cos(2*pi*(y-1)/NY)*exp(-1/3*(1/omega-0.5)*(NSTEPS-1)*2*(2*pi/NX)^2); 120 | 121 | sum=sum+(ux(x,y)-ux_value)^2+(uy(x,y)-uy_value)^2; 122 | end 123 | end 124 | error=sqrt(sum/(NX*NY)) 125 | -------------------------------------------------------------------------------- /Wednesday/Coding/shanchen_ex2.m: -------------------------------------------------------------------------------- 1 | %% periodic flow my version 2 | clear all; 3 | clc; 4 | 5 | % Macroscopic density and velocities 6 | NX=64; 7 | NY=64; 8 | NPOP=9; 9 | NSTEPS=500; 10 | NOUTPUT=10; 11 | 12 | % Parameters of the Shan-Chen model 13 | rho_crit=log(2) 14 | rho_liq=2.7 15 | rho_gas=0.05 16 | G=-6.0 17 | 18 | % Initialization 19 | rho=ones(NX,NY); 20 | ux=zeros(NX,NY); 21 | uy=zeros(NX,NY); 22 | 23 | feq=zeros(NPOP); 24 | f1=zeros(NPOP,NX,NY); 25 | f2=zeros(NPOP,NX,NY); 26 | forcex=zeros(NX,NY); 27 | forcey=zeros(NY,NY); 28 | 29 | % Parameters of the lattice 30 | weights=[4/9 1/9 1/9 1/9 1/9 1/36 1/36 1/36 1/36]; 31 | cx=[0 1 0 -1 0 1 -1 -1 1]; 32 | cy=[0 0 1 0 -1 1 1 -1 -1]; 33 | omega=1.0; 34 | 35 | 36 | for y=1:NY 37 | for x=1:NX 38 | if (y>=NY/2) 39 | rho(x,y)=rho_gas; 40 | else 41 | rho(x,y)=rho_liq; 42 | end 43 | 44 | ux(x,y)=0; 45 | uy(x,y)=0; 46 | vx=ux(x,y); 47 | vy=uy(x,y); 48 | 49 | for k=1:NPOP 50 | feq(k)=weights(k)*rho(x,y)*(1+3*(vx*cx(k)+vy*cy(k)) ... 51 | + 9/2*((cx(k)*cx(k)-1/3)*vx*vx+2*cx(k)*cy(k)*vx*vy+(cy(k)*cy(k)-1/3)*vy*vy)); 52 | f1(k,x,y)=feq(k); 53 | f2(k,x,y)=feq(k); 54 | end 55 | 56 | end 57 | end 58 | 59 | counter_frame=1; 60 | for counter=1:NSTEPS 61 | 62 | % Calculation of the macroscopic quantities 63 | for y=1:NY 64 | for x=1:NX 65 | dense=0; 66 | vx=0; 67 | vy=0; 68 | for k=1:NPOP 69 | dense=dense+f1(k,x,y); 70 | vx=vx+cx(k)*f1(k,x,y); 71 | vy=vy+cy(k)*f1(k,x,y); 72 | end 73 | 74 | rho(x,y)=dense; 75 | ux(x,y)=vx/dense; 76 | uy(x,y)=vy/dense; 77 | end 78 | end 79 | 80 | % Calculation of the force 81 | for y=1:NY 82 | for x=1:NX 83 | 84 | force_sum_x=0.0; 85 | force_sum_y=0.0; 86 | 87 | for k=2:NPOP 88 | newx=1+mod(x-1+cx(k)+NX,NX); 89 | newy=1+mod(y-1+cy(k)+NY,NY); 90 | psi=1-exp(-rho(newx,newy)); 91 | force_sum_x=force_sum_x-G*weights(k)*psi*cx(k); 92 | force_sum_y=force_sum_y-G*weights(k)*psi*cy(k); 93 | end 94 | forcex(x,y)=(1-exp(-rho(x,y)))*force_sum_x; 95 | forcey(x,y)=(1-exp(-rho(x,y)))*force_sum_y; 96 | 97 | end 98 | end 99 | % main loop 100 | for y=1:NY 101 | for x=1:NX 102 | 103 | dense=rho(x,y); 104 | vx=ux(x,y)+0.5*forcex(x,y)/dense; 105 | vy=uy(x,y)+0.5*forcey(x,y)/dense; 106 | for k=1:NPOP 107 | feq(k)=weights(k)*dense*(1+3*(vx*cx(k)+vy*cy(k)) ... 108 | +9/2*((cx(k)*cx(k)-1/3)*vx*vx+2*cx(k)*cy(k)*vx*vy+(cy(k)*cy(k)-1/3)*vy*vy)); 109 | 110 | 111 | forcepop=weights(k)*(1-0.5*omega)*((3*(cx(k)-vx)+9*cx(k)*(cx(k)*vx+cy(k)*vy))*forcex(x,y)... 112 | +(3*(cy(k)-vy)+9*cy(k)*(cx(k)*vx+cy(k)*vy))*forcey(x,y)); 113 | 114 | newx=1+mod(x-1+cx(k)+NX,NX); 115 | newy=1+mod(y-1+cy(k)+NY,NY); 116 | 117 | f1(k,x,y)=f1(k,x,y)*(1-omega)+feq(k)*omega+forcepop; 118 | f2(k,newx,newy)=f1(k,x,y); 119 | end 120 | 121 | end 122 | end 123 | 124 | f1=f2; 125 | counter 126 | 127 | if mod(counter,NOUTPUT)==0 128 | imagesc(rho); 129 | F(counter_frame) = getframe; 130 | counter_frame=counter_frame+1; 131 | end 132 | end 133 | 134 | movie(F,1) 135 | 136 | disp('Rho_gas=') 137 | disp(mean(mean(rho(NX/2-5:NX/2+5,(3*NY)/4-5:(3*NY)/4+5)))) 138 | disp('Rho_liq=') 139 | disp(mean(mean(rho(NX/2-5:NX/2+5,NY/4-5:NY/4+5)))) 140 | -------------------------------------------------------------------------------- /Wednesday/Coding/shanchen.m: -------------------------------------------------------------------------------- 1 | %% periodic flow my version 2 | clear all; 3 | clc; 4 | 5 | % Macroscopic density and velocities 6 | NX=128; 7 | NY=128; 8 | NPOP=9; 9 | NSTEPS=300; 10 | NOUTPUT=10; 11 | 12 | % Parameters of the Shan-Chen model 13 | rho_crit=log(2) 14 | rho_liq=1.95 15 | rho_gas=0.15 16 | radius=20 17 | G=-5.0 18 | 19 | % Initialization 20 | rho=ones(NX,NY); 21 | ux=zeros(NX,NY); 22 | uy=zeros(NX,NY); 23 | 24 | feq=zeros(NPOP); 25 | f1=zeros(NPOP,NX,NY); 26 | f2=zeros(NPOP,NX,NY); 27 | forcex=zeros(NX,NY); 28 | forcey=zeros(NY,NY); 29 | 30 | % Parameters of the lattice 31 | weights=[4/9 1/9 1/9 1/9 1/9 1/36 1/36 1/36 1/36]; 32 | cx=[0 1 0 -1 0 1 -1 -1 1]; 33 | cy=[0 0 1 0 -1 1 1 -1 -1]; 34 | omega=1.0; 35 | 36 | 37 | for y=1:NY 38 | for x=1:NX 39 | %if (x-NX/2)^2+(y-NY/2)^2<=radius*radius 40 | % rho(x,y)=rho_liq; 41 | %else 42 | % rho(x,y)=rho_gas; 43 | %end 44 | rho(x,y)=rho_crit+0.1*rand(); 45 | ux(x,y)=0; 46 | uy(x,y)=0; 47 | vx=ux(x,y); 48 | vy=uy(x,y); 49 | 50 | for k=1:NPOP 51 | feq(k)=weights(k)*rho(x,y)*(1+3*(vx*cx(k)+vy*cy(k)) ... 52 | + 9/2*((cx(k)*cx(k)-1/3)*vx*vx+2*cx(k)*cy(k)*vx*vy+(cy(k)*cy(k)-1/3)*vy*vy)); 53 | f1(k,x,y)=feq(k); 54 | f2(k,x,y)=feq(k); 55 | end 56 | 57 | end 58 | end 59 | 60 | counter_frame=1; 61 | for counter=1:NSTEPS 62 | 63 | % Calculation of the macroscopic quantities 64 | for y=1:NY 65 | for x=1:NX 66 | dense=0; 67 | vx=0; 68 | vy=0; 69 | for k=1:NPOP 70 | dense=dense+f1(k,x,y); 71 | vx=vx+cx(k)*f1(k,x,y); 72 | vy=vy+cy(k)*f1(k,x,y); 73 | end 74 | 75 | rho(x,y)=dense; 76 | ux(x,y)=vx/dense; 77 | uy(x,y)=vy/dense; 78 | end 79 | end 80 | 81 | % Calculation of the force 82 | for y=1:NY 83 | for x=1:NX 84 | 85 | force_sum_x=0.0; 86 | force_sum_y=0.0; 87 | 88 | for k=2:NPOP 89 | newx=1+mod(x-1+cx(k)+NX,NX); 90 | newy=1+mod(y-1+cy(k)+NY,NY); 91 | psi=1-exp(-rho(newx,newy)); 92 | force_sum_x=force_sum_x-G*weights(k)*psi*cx(k); 93 | force_sum_y=force_sum_y-G*weights(k)*psi*cy(k); 94 | end 95 | forcex(x,y)=(1-exp(-rho(x,y)))*force_sum_x; 96 | forcey(x,y)=(1-exp(-rho(x,y)))*force_sum_y; 97 | 98 | end 99 | end 100 | % main loop 101 | for y=1:NY 102 | for x=1:NX 103 | 104 | dense=rho(x,y); 105 | vx=ux(x,y)+0.5*forcex(x,y)/dense; 106 | vy=uy(x,y)+0.5*forcey(x,y)/dense; 107 | for k=1:NPOP 108 | feq(k)=weights(k)*dense*(1+3*(vx*cx(k)+vy*cy(k)) ... 109 | +9/2*((cx(k)*cx(k)-1/3)*vx*vx+2*cx(k)*cy(k)*vx*vy+(cy(k)*cy(k)-1/3)*vy*vy)); 110 | 111 | 112 | forcepop=weights(k)*(1-0.5*omega)*((3*(cx(k)-vx)+9*cx(k)*(cx(k)*vx+cy(k)*vy))*forcex(x,y)... 113 | +(3*(cy(k)-vy)+9*cy(k)*(cx(k)*vx+cy(k)*vy))*forcey(x,y)); 114 | 115 | newx=1+mod(x-1+cx(k)+NX,NX); 116 | newy=1+mod(y-1+cy(k)+NY,NY); 117 | 118 | f1(k,x,y)=f1(k,x,y)*(1-omega)+feq(k)*omega+forcepop; 119 | f2(k,newx,newy)=f1(k,x,y); 120 | end 121 | 122 | end 123 | end 124 | 125 | f1=f2; 126 | counter 127 | 128 | if mod(counter,NOUTPUT)==0 129 | %surf(rho); 130 | imagesc(rho); 131 | F(counter_frame) = getframe; 132 | counter_frame=counter_frame+1; 133 | end 134 | end 135 | 136 | movie(F,10) 137 | 138 | disp('Rho_liq=') 139 | disp(mean(mean(rho(NX/2-5:NX/2+5,NY/2-5:NY/2+5)))) 140 | disp('Rho_gas=') 141 | disp(mean(mean(rho(1:10,1:10)))) 142 | -------------------------------------------------------------------------------- /Monday/Coding/fourrows_trt.m: -------------------------------------------------------------------------------- 1 | %% periodic flow my version 2 | clear all; 3 | clc; 4 | 5 | % Macroscopic density and velocities 6 | NX=64; 7 | NY=64; 8 | NPOP=9; 9 | NSTEPS=400; 10 | 11 | rho0=1; 12 | umax=0.001; 13 | 14 | rho=ones(NX,NY); 15 | ux=zeros(NX,NY); 16 | uy=zeros(NX,NY); 17 | 18 | uxinit=zeros(NX,NY); 19 | uyinit=zeros(NX,NY); 20 | 21 | feq=zeros(NPOP); 22 | f1=zeros(NPOP,NX,NY); 23 | f2=zeros(NPOP,NX,NY); 24 | 25 | weights=[4/9 1/9 1/9 1/9 1/9 1/36 1/36 1/36 1/36]; 26 | cx=[0 1 0 -1 0 1 -1 -1 1]; 27 | cy=[0 0 1 0 -1 1 1 -1 -1]; 28 | 29 | %Parameters of the TRT model 30 | omega=1.0/10.0; 31 | omega_plus=omega 32 | lambda=1/4; 33 | omega_minus=1/(lambda/(1/omega_plus-0.5)+0.5) 34 | 35 | compliment=[1 4 5 2 3 8 9 6 7]; 36 | %Additional memory for TRT 37 | feq_plus=zeros(NPOP); 38 | feq_minus=zeros(NPOP); 39 | f_plus=zeros(NPOP); 40 | f_minus=zeros(NPOP); 41 | 42 | 43 | 44 | for y=1:NY 45 | for x=1:NX 46 | rho(x,y)=rho0+3*0.25*umax^2*... 47 | (cos(4*pi*(x-1)/NX)-cos(4*pi*(y-1)/NY)); 48 | ux(x,y)=umax*sin(2*pi*(x-1)/NX)*sin(2*pi*(y-1)/NY); 49 | uy(x,y)=umax*cos(2*pi*(x-1)/NX)*cos(2*pi*(y-1)/NY); 50 | uxinit(x,y)=umax*sin(2*pi*(x-1)/NX)*sin(2*pi*(y-1)/NY); 51 | uyinit(x,y)=umax*cos(2*pi*(x-1)/NX)*cos(2*pi*(y-1)/NY); 52 | 53 | vx=ux(x,y); 54 | vy=uy(x,y); 55 | for k=1:NPOP 56 | feq(k)=weights(k)*(rho(x,y)+3*(vx*cx(k)+vy*cy(k)) ... 57 | + 9/2*((cx(k)*cx(k)-1/3)*vx*vx+2*cx(k)*cy(k)*vx*vy+(cy(k)*cy(k)-1/3)*vy*vy)); 58 | f1(k,x,y)=feq(k); 59 | f2(k,x,y)=feq(k); 60 | end 61 | end 62 | end 63 | 64 | track=zeros(1,NSTEPS); 65 | 66 | %this value we need to obtain - it should be constant over the simulation 67 | %umax*sin(2*pi*(NX/4-1)/NX)*sin(2*pi*(NY/4-1)/NY) 68 | 69 | for counter=1:NSTEPS 70 | for y=1:NY 71 | for x=1:NX 72 | dense=0; 73 | vx=0; 74 | vy=0; 75 | for k=1:NPOP 76 | dense=dense+f1(k,x,y); 77 | vx=vx+cx(k)*f1(k,x,y); 78 | vy=vy+cy(k)*f1(k,x,y); 79 | end 80 | vx=vx/dense; 81 | vy=vy/dense; 82 | 83 | % Collision 84 | %forcex=tempx(x,y); 85 | %forcey=tempy(x,y); 86 | forcex=(2*pi/NX)^2*2*1/3*(1/omega-1/2)*umax*sin(2*pi*(x-1)/NX)*sin(2*pi*(y-1)/NY); 87 | forcey=(2*pi/NX)^2*2*1/3*(1/omega-1/2)*umax*cos(2*pi*(x-1)/NX)*cos(2*pi*(y-1)/NY); 88 | 89 | 90 | rho(x,y)=dense; 91 | ux(x,y)=vx+forcex/(2.0*dense); 92 | uy(x,y)=vy+forcey/(2.0*dense); 93 | 94 | %vx=vx+forcex/2.0; 95 | %vy=vy+forcey/2.0; 96 | 97 | for k=1:NPOP 98 | feq(k)=weights(k)*rho(x,y)*(1+3*(vx*cx(k)+vy*cy(k)) ... 99 | +9/2*((cx(k)*cx(k)-1/3)*vx*vx+2*cx(k)*cy(k)*vx*vy+(cy(k)*cy(k)-1/3)*vy*vy)); 100 | 101 | end 102 | 103 | for k=1:NPOP 104 | f_plus(k)=0.5*(f1(k,x,y)+f1(compliment(k),x,y)); 105 | f_minus(k)=0.5*(f1(k,x,y)-f1(compliment(k),x,y)); 106 | feq_plus(k)=0.5*(feq(k)+feq(compliment(k))); 107 | feq_minus(k)=0.5*(feq(k)-feq(compliment(k))); 108 | 109 | end 110 | for k=1:NPOP 111 | 112 | newx=1+mod(x-1+cx(k)+NX,NX); 113 | newy=1+mod(y-1+cy(k)+NY,NY); 114 | forcepop=weights(k)*(3.0*forcex*cx(k)+3.0*forcey*cy(k)); 115 | 116 | f1(k,x,y)=f1(k,x,y)-omega_plus*(f_plus(k)-feq_plus(k))-omega_minus*(f_minus(k)-feq_minus(k))+forcepop; 117 | f2(k,newx,newy)=f1(k,x,y); 118 | end 119 | 120 | 121 | end 122 | end 123 | track(counter)=ux(NX/4+1,NY/4+1); 124 | %decay(counter)=umax*exp(-1/3*(1/omega-0.5)*counter*4*pi/NX); 125 | f1=f2; 126 | end 127 | figure(1) 128 | surf(ux-uxinit) 129 | figure(2) 130 | plot(1:NSTEPS,track) 131 | 132 | max(max(ux)) 133 | -------------------------------------------------------------------------------- /Tuesday/Coding/Poiseuille_BB_exercise.m: -------------------------------------------------------------------------------- 1 | clear all 2 | clc 3 | tic 4 | % Poiseuille flow driven by constant body force 5 | 6 | % Lattice parameters 7 | weights=[4/9 1/9 1/9 1/9 1/9 1/36 1/36 1/36 1/36]; 8 | cx=[0 1 0 -1 0 1 -1 -1 1]; 9 | cy=[0 0 1 0 -1 1 1 -1 -1]; 10 | 11 | % Numerical parameters 12 | NX=3; % Number of grids points along x 13 | NY=16; % Number of grid points along y 14 | NPOP=9; % Number of populations used in velocity space discretization 15 | NSTEPS=10000; % Number of time steps/iterations 16 | 17 | 18 | % Simulation parameters 19 | y_bottom=0.5; % location of bottom wall 20 | y_top=NY+0.5; % location of top wall 21 | 22 | Re=10; % Reynolds number 23 | omega=32/(20+sqrt(208)); % Relaxation frequency 24 | kvisc=1/3*(1/omega-0.5); % Kinematic viscosity 25 | umax=Re*kvisc/((y_top-y_bottom)) ;% umax=0.001; % Mach number (can be understood as a CFL number) 26 | 27 | 28 | % Macroscopic parameters 29 | rho=ones(NX,NY); 30 | ux=zeros(NX,NY); 31 | uy=zeros(NX,NY); 32 | 33 | forcex=8.*umax*kvisc./((y_top-y_bottom).^2); 34 | forcey=0; 35 | 36 | 37 | 38 | % Initialize populations with rho=1 and (ux,uy)=(0,0) 39 | feq=zeros(NPOP); 40 | f1=zeros(NPOP,NX,NY); 41 | f2=zeros(NPOP,NX,NY); 42 | forcepop=zeros(NPOP); 43 | for y=1:NY 44 | for x=1:NX 45 | dense=rho(x,y); 46 | vx=ux(x,y); 47 | vy=uy(x,y); 48 | for k=1:NPOP 49 | feq(k)=weights(k)*(dense+(3*(vx*cx(k)+vy*cy(k)) ... 50 | +9/2*(cx(k)*vx+cy(k)*vy)^2-3/2*(vx^2+vy^2))); 51 | f1(k,x,y)=feq(k); 52 | f2(k,x,y)=feq(k); 53 | end 54 | end 55 | end 56 | 57 | % Main algorithm 58 | for counter=1:NSTEPS 59 | 60 | % Macroscopic parameters computed through velocity moments of 61 | % populations f1 62 | for y=1:NY 63 | for x=1:NX 64 | 65 | dense=0; 66 | vx=0; 67 | vy=0; 68 | for k=1:NPOP 69 | dense=dense+f1(k,x,y); 70 | vx=vx+cx(k)*f1(k,x,y); 71 | vy=vy+cy(k)*f1(k,x,y); 72 | end 73 | 74 | rho(x,y)=dense; 75 | ux(x,y)=vx; 76 | uy(x,y)=vy; 77 | 78 | 79 | for k=1:NPOP 80 | 81 | % Compute the populations equilibrium value 82 | feq(k)=weights(k).*(dense+3*(vx*cx(k)+vy*cy(k)) ... 83 | +9/2*((cx(k)*cx(k)-1/3)*vx*vx+2*cx(k)*cy(k)*vx*vy+(cy(k)*cy(k)-1/3)*vy*vy)); 84 | 85 | % Compute external forcing term 86 | forcepop(k)=weights(k).*3.*(cx(k).*forcex+cy(k).*forcey); 87 | 88 | 89 | % Collision step 90 | f1(k,x,y)=f1(k,x,y)*(1-omega)+feq(k)*omega+forcepop(k); 91 | 92 | % Streaming step 93 | newx=1+mod(x-1+cx(k)+NX,NX); 94 | newy=1+mod(y-1+cy(k)+NY,NY); 95 | f2(k,newx,newy)=f1(k,x,y); 96 | end 97 | end 98 | end 99 | 100 | 101 | % Bounceback Boundary Conditions 102 | 103 | for y=1:NY 104 | for x=1:NX 105 | if y==1 % Bottom wall 106 | 107 | % Introduce here the BB boundary conditions! 108 | 109 | end 110 | if y==NY % Top wall 111 | 112 | % Introduce here the BB boundary conditions! 113 | 114 | end 115 | end 116 | end 117 | 118 | % Assign new state f1, i.e. f(t+1) to previous state f2, i.e. f(t) 119 | f1=f2; 120 | end 121 | 122 | ux_plot=zeros(NX,NY+2); 123 | ux_plot(:,2:NY+1)=ux; 124 | % Analytical solution 125 | y_plot=[y_bottom,1:NY,y_top]; 126 | ux_analy=-1/(2*kvisc).*forcex.*(y_plot-y_bottom).*(y_plot-y_top); 127 | 128 | 129 | % % Compare LBM and Analytical solution velocity profiles 130 | % 131 | % figure('color',[1 1 1]) 132 | % hold on 133 | % plot(y_plot./(y_top),ux_analy./umax,'ko--'); 134 | % xlabel('y/y_{top}'); 135 | % ylabel('u/umax'); 136 | % plot(y_plot./(y_top),ux_plot(round(NX/2),:)./umax,'rs-.'); 137 | % legend('ux analy','ux LBM'); 138 | % axis tight 139 | % box on 140 | 141 | 142 | % Calculation of L2 error 143 | sum_num=0; 144 | sum_denom=0; 145 | for y=1:NY+2 146 | for x=1:NX 147 | sum_num=sum_num+(ux_plot(x,y)-ux_analy(y)).^2; 148 | sum_denom=sum_denom+ux_analy(y).^2; 149 | end 150 | end 151 | 152 | error=sqrt((sum_num)/(sum_denom)); 153 | 154 | disp(['L2 relative error = ',num2str(error)]); 155 | 156 | toc % Stop time counter 157 | 158 | -------------------------------------------------------------------------------- /Tuesday/Coding/Poiseuille_BB_solution.m: -------------------------------------------------------------------------------- 1 | clear all 2 | clc 3 | tic 4 | % Poiseuille flow driven by constant body force 5 | 6 | % Lattice parameters 7 | weights=[4/9 1/9 1/9 1/9 1/9 1/36 1/36 1/36 1/36]; 8 | cx=[0 1 0 -1 0 1 -1 -1 1]; 9 | cy=[0 0 1 0 -1 1 1 -1 -1]; 10 | 11 | % Numerical parameters 12 | NX=3; % Number of grids points along x 13 | NY=16; % Number of grid points along y 14 | NPOP=9; % Number of populations used in velocity space discretization 15 | NSTEPS=10000; % Number of time steps/iterations 16 | 17 | 18 | % Simulation parameters 19 | y_bottom=0.5; % location of bottom wall 20 | y_top=NY+0.5; % location of top wall 21 | 22 | Re=10; % Reynolds number 23 | omega=32/(20+sqrt(208)); % Relaxation frequency 24 | kvisc=1/3*(1/omega-0.5); % Kinematic viscosity 25 | umax=Re*kvisc/((y_top-y_bottom)) ;% umax=0.001; % Mach number (can be understood as a CFL number) 26 | 27 | forcex=8.*umax*kvisc./((y_top-y_bottom).^2); 28 | forcey=0; 29 | 30 | % Macroscopic parameters 31 | rho0=1; 32 | rho=ones(NX,NY); 33 | ux=zeros(NX,NY); 34 | uy=zeros(NX,NY); 35 | 36 | 37 | 38 | 39 | 40 | % Initialize populations with rho=1 and (ux,uy)=(0,0) 41 | feq=zeros(NPOP); 42 | f1=zeros(NPOP,NX,NY); 43 | f2=zeros(NPOP,NX,NY); 44 | forcepop=zeros(NPOP); 45 | for y=1:NY 46 | for x=1:NX 47 | dense=rho(x,y); 48 | vx=ux(x,y); 49 | vy=uy(x,y); 50 | for k=1:NPOP 51 | feq(k)=weights(k)*(dense+rho0*(3*(vx*cx(k)+vy*cy(k)) ... 52 | +9/2*(cx(k)*vx+cy(k)*vy)^2-3/2*(vx^2+vy^2))); 53 | f1(k,x,y)=feq(k); 54 | f2(k,x,y)=feq(k); 55 | end 56 | end 57 | end 58 | 59 | % Main algorithm 60 | for counter=1:NSTEPS 61 | 62 | % Macroscopic parameters computed through velocity moments of 63 | % populations f1 64 | for y=1:NY 65 | for x=1:NX 66 | 67 | dense=0; 68 | vx=0; 69 | vy=0; 70 | for k=1:NPOP 71 | dense=dense+f1(k,x,y); 72 | vx=vx+cx(k)*f1(k,x,y); 73 | vy=vy+cy(k)*f1(k,x,y); 74 | end 75 | 76 | rho(x,y)=dense; 77 | ux(x,y)=vx; 78 | uy(x,y)=vy; 79 | 80 | 81 | for k=1:NPOP 82 | 83 | % Compute the populations equilibrium value 84 | feq(k)=weights(k).*(dense+3*(vx*cx(k)+vy*cy(k)) ... 85 | +9/2*((cx(k)*cx(k)-1/3)*vx*vx+2*cx(k)*cy(k)*vx*vy+(cy(k)*cy(k)-1/3)*vy*vy)); 86 | 87 | % Compute external forcing term 88 | forcepop(k)=weights(k).*3.*(cx(k).*forcex+cy(k).*forcey); 89 | 90 | 91 | % Collision step 92 | f1(k,x,y)=f1(k,x,y)*(1-omega)+feq(k)*omega+forcepop(k); 93 | 94 | % Streaming step 95 | newx=1+mod(x-1+cx(k)+NX,NX); 96 | newy=1+mod(y-1+cy(k)+NY,NY); 97 | f2(k,newx,newy)=f1(k,x,y); 98 | end 99 | end 100 | end 101 | 102 | 103 | % Bounceback Boundary Conditions 104 | 105 | for y=1:NY 106 | for x=1:NX 107 | if y==1 % Bottom wall 108 | f2(3,x,y)=f1(5,x,y); 109 | f2(6,x,y)=f1(8,x,y); 110 | f2(7,x,y)=f1(9,x,y); 111 | end 112 | if y==NY % Top wall 113 | f2(5,x,y)=f1(3,x,y); 114 | f2(8,x,y)=f1(6,x,y); 115 | f2(9,x,y)=f1(7,x,y); 116 | end 117 | end 118 | end 119 | 120 | % Assign new state f1, i.e. f(t+1) to previous state f2, i.e. f(t) 121 | f1=f2; 122 | end 123 | 124 | ux_plot=zeros(NX,NY+2); 125 | ux_plot(:,2:NY+1)=ux; 126 | % Analytical solution 127 | y_plot=[y_bottom,1:NY,y_top]; 128 | ux_analy=-1/(2*kvisc).*forcex.*(y_plot-y_bottom).*(y_plot-y_top); 129 | 130 | 131 | % % Compare LBM and Analytical solution velocity profiles 132 | % 133 | % figure('color',[1 1 1]) 134 | % hold on 135 | % plot(y_plot./(y_top),ux_analy./umax,'ko--'); 136 | % xlabel('y/y_{top}'); 137 | % ylabel('u/umax'); 138 | % plot(y_plot./(y_top),ux_plot(round(NX/2),:)./umax,'rs-.'); 139 | % legend('ux analy','ux LBM'); 140 | % axis tight 141 | % box on 142 | 143 | 144 | % Calculation of L2 error 145 | sum_num=0; 146 | sum_denom=0; 147 | for y=1:NY+2 148 | for x=1:NX 149 | sum_num=sum_num+(ux_plot(x,y)-ux_analy(y)).^2; 150 | sum_denom=sum_denom+ux_analy(y).^2; 151 | end 152 | end 153 | 154 | error=sqrt((sum_num)/(sum_denom)); 155 | 156 | disp(['L2 relative error = ',num2str(error)]); 157 | 158 | toc % Stop time counter 159 | 160 | -------------------------------------------------------------------------------- /Tuesday/Coding/PoiseuilleZouHe_solution.m: -------------------------------------------------------------------------------- 1 | clear all 2 | clc 3 | tic 4 | % Poiseuille flow driven by constant body force 5 | 6 | % Lattice parameters 7 | weights=[4/9 1/9 1/9 1/9 1/9 1/36 1/36 1/36 1/36]; 8 | cx=[0 1 0 -1 0 1 -1 -1 1]; 9 | cy=[0 0 1 0 -1 1 1 -1 -1]; 10 | 11 | % Numerical parameters 12 | NX=3; % Number of grids points along x 13 | NY=16; % Number of grid points along y 14 | NPOP=9; % Number of populations used in velocity space discretization 15 | NSTEPS=5000; % Number of time steps/iterations 16 | 17 | 18 | % Simulation parameters 19 | y_bottom=1; % location of bottom wall 20 | y_top=NY; % location of top wall 21 | Re=10; % Reynolds number 22 | omega=0.9; % Relaxation frequency 23 | kvisc=1/3*(1/omega-0.5); % Kinematic viscosity 24 | umax=Re*kvisc/((y_top-y_bottom)) ;% umax=0.001; % Mach number (can be understood as a CFL number) 25 | 26 | 27 | % Macroscopic parameters 28 | rho=ones(NX,NY); 29 | ux=zeros(NX,NY); 30 | uy=zeros(NX,NY); 31 | 32 | forcex=8.*umax*kvisc./((y_top-y_bottom).^2); 33 | forcey=0; 34 | 35 | 36 | 37 | % Initialize populations with rho=1 and (ux,uy)=(0,0) 38 | feq=zeros(NPOP); 39 | f1=zeros(NPOP,NX,NY); 40 | f2=zeros(NPOP,NX,NY); 41 | forcepop=zeros(NPOP); 42 | for y=1:NY 43 | for x=1:NX 44 | dense=rho(x,y); 45 | vx=ux(x,y); 46 | vy=uy(x,y); 47 | for k=1:NPOP 48 | feq(k)=weights(k)*(dense+(3*(vx*cx(k)+vy*cy(k)) ... 49 | +9/2*(cx(k)*vx+cy(k)*vy)^2-3/2*(vx^2+vy^2))); 50 | f1(k,x,y)=feq(k); 51 | f2(k,x,y)=feq(k); 52 | end 53 | end 54 | end 55 | 56 | % Main algorithm 57 | for counter=1:NSTEPS 58 | 59 | % Macroscopic parameters computed through velocity moments of 60 | % populations f1 61 | for y=1:NY 62 | for x=1:NX 63 | 64 | dense=0; 65 | vx=0; 66 | vy=0; 67 | for k=1:NPOP 68 | dense=dense+f1(k,x,y); 69 | vx=vx+cx(k)*f1(k,x,y); 70 | vy=vy+cy(k)*f1(k,x,y); 71 | end 72 | 73 | rho(x,y)=dense; 74 | ux(x,y)=vx; 75 | uy(x,y)=vy; 76 | 77 | 78 | for k=1:NPOP 79 | 80 | % Compute the populations equilibrium value 81 | feq(k)=weights(k).*(dense+3*(vx*cx(k)+vy*cy(k)) ... 82 | +9/2*((cx(k)*cx(k)-1/3)*vx*vx+2*cx(k)*cy(k)*vx*vy+(cy(k)*cy(k)-1/3)*vy*vy)); 83 | 84 | % Compute external forcing term 85 | forcepop(k)=weights(k).*3.*(cx(k).*forcex+cy(k).*forcey); 86 | 87 | 88 | % Collision step 89 | f1(k,x,y)=f1(k,x,y)*(1-omega)+feq(k)*omega+forcepop(k); 90 | 91 | % Streaming step 92 | newx=1+mod(x-1+cx(k)+NX,NX); 93 | newy=1+mod(y-1+cy(k)+NY,NY); 94 | f2(k,newx,newy)=f1(k,x,y); 95 | end 96 | end 97 | end 98 | 99 | 100 | % Zou He Boundary Conditions 101 | 102 | for y=1:NY 103 | for x=1:NX 104 | if y==1 % Bottom wall 105 | ux(x,y)=0; 106 | uy(x,y)=0; 107 | rho(x,y)=uy(x,y)+(f2(1,x,y)+f2(2,x,y)+f2(4,x,y)+2*(f2(5,x,y)+... 108 | f2(8,x,y)+f2(9,x,y))); 109 | 110 | 111 | f2(3,x,y)=f2(5,x,y)+2/3*uy(x,y); 112 | f2(6,x,y)=f2(8,x,y)+1/6*uy(x,y)+0.5*(f2(4,x,y)-f2(2,x,y))+1/2.*ux(x,y); 113 | f2(7,x,y)=f2(9,x,y)+1/6*uy(x,y)-0.5*(f2(4,x,y)-f2(2,x,y))-1/2.*ux(x,y); 114 | 115 | end 116 | 117 | 118 | if y==NY % Top wall 119 | ux(x,y)=0; 120 | uy(x,y)=0; 121 | rho(x,y)=-uy(x,y)+(f2(1,x,y)+f2(2,x,y)+f2(4,x,y)+2*(f2(3,x,y)+... 122 | f2(6,x,y)+f2(7,x,y))); 123 | 124 | 125 | f2(5,x,y)=f2(3,x,y)-2/3*uy(x,y); 126 | f2(8,x,y)=f2(6,x,y)-1/6*uy(x,y)+0.5*(f2(2,x,y,1)-f2(4,x,y))-1/2*ux(x,y); 127 | f2(9,x,y)=f2(7,x,y)-1/6*uy(x,y)-0.5*(f2(2,x,y)-f2(4,x,y))+1/2*ux(x,y); 128 | 129 | end 130 | end 131 | end 132 | % Assign new state f1, i.e. f(t+1) to previous state f2, i.e. f(t) 133 | f1=f2; 134 | end 135 | 136 | ux_plot=ux; 137 | % Analytical solution 138 | y_plot=y_bottom:y_top; 139 | ux_analy=-1/(2*kvisc).*forcex.*(y_plot-y_bottom).*(y_plot-y_top); 140 | 141 | 142 | % % Compare LBM and Analytical solution velocity profiles 143 | % figure('color',[1 1 1]) 144 | % hold on 145 | % plot(y_plot./(y_top),ux_analy./umax,'ko--'); 146 | % xlabel('y/y_{top}'); 147 | % ylabel('u/umax'); 148 | % plot(y_plot./(y_top),ux_plot(round(NX/2),:)./umax,'rs-.'); 149 | % legend('ux analy','ux LBM'); 150 | % axis tight 151 | % box on 152 | 153 | 154 | % Calculation of L2 error 155 | sum_num=0; 156 | sum_denom=0; 157 | for y=1:NY 158 | for x=1:NX 159 | sum_num=sum_num+(ux_plot(x,y)-ux_analy(y)).^2; 160 | sum_denom=sum_denom+ux_analy(y).^2; 161 | end 162 | end 163 | 164 | error=sqrt((sum_num)/(sum_denom)); 165 | 166 | disp(['L2 relative error = ',num2str(error)]); 167 | 168 | toc % Stop time counter 169 | 170 | -------------------------------------------------------------------------------- /Tuesday/Coding/PoiseuilleZouHe_exercise.m: -------------------------------------------------------------------------------- 1 | clear all 2 | clc 3 | tic 4 | % Poiseuille flow driven by constant body force 5 | 6 | % Lattice parameters 7 | weights=[4/9 1/9 1/9 1/9 1/9 1/36 1/36 1/36 1/36]; 8 | cx=[0 1 0 -1 0 1 -1 -1 1]; 9 | cy=[0 0 1 0 -1 1 1 -1 -1]; 10 | 11 | % Numerical parameters 12 | NX=3; % Number of grids points along x 13 | NY=16; % Number of grid points along y 14 | NPOP=9; % Number of populations used in velocity space discretization 15 | NSTEPS=5000; % Number of time steps/iterations 16 | 17 | 18 | % Simulation parameters 19 | y_bottom=1; % location of bottom wall 20 | y_top=NY; % location of top wall 21 | Re=10; % Reynolds number 22 | omega=0.9; % Relaxation frequency 23 | kvisc=1/3*(1/omega-0.5); % Kinematic viscosity 24 | umax=Re*kvisc/((y_top-y_bottom)) ;% umax=0.001; % Mach number (can be understood as a CFL number) 25 | 26 | 27 | % Macroscopic parameters 28 | rho=ones(NX,NY); 29 | ux=zeros(NX,NY); 30 | uy=zeros(NX,NY); 31 | 32 | forcex=8.*umax*kvisc./((y_top-y_bottom).^2); 33 | forcey=0; 34 | 35 | 36 | 37 | % Initialize populations with rho=1 and (ux,uy)=(0,0) 38 | feq=zeros(NPOP); 39 | f1=zeros(NPOP,NX,NY); 40 | f2=zeros(NPOP,NX,NY); 41 | forcepop=zeros(NPOP); 42 | for y=1:NY 43 | for x=1:NX 44 | dense=rho(x,y); 45 | vx=ux(x,y); 46 | vy=uy(x,y); 47 | for k=1:NPOP 48 | feq(k)=weights(k)*(dense+(3*(vx*cx(k)+vy*cy(k)) ... 49 | +9/2*(cx(k)*vx+cy(k)*vy)^2-3/2*(vx^2+vy^2))); 50 | f1(k,x,y)=feq(k); 51 | f2(k,x,y)=feq(k); 52 | end 53 | end 54 | end 55 | 56 | % Main algorithm 57 | for counter=1:NSTEPS 58 | 59 | % Macroscopic parameters computed through velocity moments of 60 | % populations f1 61 | for y=1:NY 62 | for x=1:NX 63 | 64 | dense=0; 65 | vx=0; 66 | vy=0; 67 | for k=1:NPOP 68 | dense=dense+f1(k,x,y); 69 | vx=vx+cx(k)*f1(k,x,y); 70 | vy=vy+cy(k)*f1(k,x,y); 71 | end 72 | 73 | rho(x,y)=dense; 74 | ux(x,y)=vx; 75 | uy(x,y)=vy; 76 | 77 | 78 | for k=1:NPOP 79 | 80 | % Compute the populations equilibrium value 81 | feq(k)=weights(k).*(dense+3*(vx*cx(k)+vy*cy(k)) ... 82 | +9/2*((cx(k)*cx(k)-1/3)*vx*vx+2*cx(k)*cy(k)*vx*vy+(cy(k)*cy(k)-1/3)*vy*vy)); 83 | 84 | % Compute external forcing term 85 | forcepop(k)=weights(k).*3.*(cx(k).*forcex+cy(k).*forcey); 86 | 87 | 88 | % Collision step 89 | f1(k,x,y)=f1(k,x,y)*(1-omega)+feq(k)*omega+forcepop(k); 90 | 91 | % Streaming step 92 | newx=1+mod(x-1+cx(k)+NX,NX); 93 | newy=1+mod(y-1+cy(k)+NY,NY); 94 | f2(k,newx,newy)=f1(k,x,y); 95 | end 96 | end 97 | end 98 | 99 | 100 | % Zou He Boundary Conditions 101 | 102 | for y=1:NY 103 | for x=1:NX 104 | if y==1 % Bottom wall 105 | ux(x,y)=0; 106 | uy(x,y)=0; 107 | rho(x,y)=uy(x,y)+(f2(1,x,y)+f2(2,x,y)+f2(4,x,y)+2*(f2(5,x,y)+... 108 | f2(8,x,y)+f2(9,x,y))); 109 | 110 | 111 | f2(3,x,y)=f2(5,x,y)+2/3*uy(x,y); 112 | f2(6,x,y)=f2(8,x,y)+1/6*uy(x,y)+0.5*(f2(4,x,y)-f2(2,x,y))+1/2.*ux(x,y); 113 | f2(7,x,y)=f2(9,x,y)+1/6*uy(x,y)-0.5*(f2(4,x,y)-f2(2,x,y))-1/2.*ux(x,y); 114 | 115 | end 116 | 117 | 118 | if y==NY % Top wall 119 | ux(x,y)=0; 120 | uy(x,y)=0; 121 | rho(x,y)=-uy(x,y)+(f2(1,x,y)+f2(2,x,y)+f2(4,x,y)+2*(f2(3,x,y)+... 122 | f2(6,x,y)+f2(7,x,y))); 123 | 124 | 125 | f2(5,x,y)=f2(3,x,y)-2/3*uy(x,y); 126 | f2(8,x,y)=f2(6,x,y)-1/6*uy(x,y)+0.5*(f2(2,x,y,1)-f2(4,x,y))-1/2*ux(x,y); 127 | f2(9,x,y)=f2(7,x,y)-1/6*uy(x,y)-0.5*(f2(2,x,y)-f2(4,x,y))+1/2*ux(x,y); 128 | 129 | end 130 | end 131 | end 132 | % Assign new state f1, i.e. f(t+1) to previous state f2, i.e. f(t) 133 | f1=f2; 134 | end 135 | 136 | ux_plot=ux; 137 | % Analytical solution 138 | y_plot=y_bottom:y_top; 139 | ux_analy=-1/(2*kvisc).*forcex.*(y_plot-y_bottom).*(y_plot-y_top); 140 | 141 | 142 | % % Compare LBM and Analytical solution velocity profiles 143 | % figure('color',[1 1 1]) 144 | % hold on 145 | % plot(y_plot./(y_top),ux_analy./umax,'ko--'); 146 | % xlabel('y/y_{top}'); 147 | % ylabel('u/umax'); 148 | % plot(y_plot./(y_top),ux_plot(round(NX/2),:)./umax,'rs-.'); 149 | % legend('ux analy','ux LBM'); 150 | % axis tight 151 | % box on 152 | 153 | 154 | % Calculation of L2 error 155 | sum_num=0; 156 | sum_denom=0; 157 | for y=1:NY 158 | for x=1:NX 159 | sum_num=sum_num+(ux_plot(x,y)-ux_analy(y)).^2; 160 | sum_denom=sum_denom+ux_analy(y).^2; 161 | end 162 | end 163 | 164 | error=sqrt((sum_num)/(sum_denom)); 165 | 166 | disp(['L2 relative error = ',num2str(error)]); 167 | 168 | toc % Stop time counter 169 | 170 | -------------------------------------------------------------------------------- /Wednesday/Coding/binaryliquid_ex1.m: -------------------------------------------------------------------------------- 1 | %% periodic flow my version 2 | clear all; 3 | clc; 4 | 5 | % Macroscopic parameters 6 | NX=128; 7 | NY=128; 8 | NPOP=9; 9 | NSTEPS=200; 10 | NOUTPUT=10; 11 | 12 | % Parameters of the binary-liquid model 13 | ksurf=0.04; 14 | gamma=1.0; 15 | a=0.04; 16 | tau_gas=0.7; 17 | tau_liq=2.5; 18 | radius=20; 19 | tau_phi=1.0; 20 | 21 | % Stencils parameters 22 | wxx=[0.0, 1.0/3.0, -1.0/6.0, 1.0/3.0, -1.0/6.0, -1.0/24.0, -1.0/24.0, -1.0/24.0, -1.0/24.0]; 23 | wyy=[0.0, -1.0/6.0, 1.0/3.0, -1.0/6.0, 1.0/3.0, -1.0/24.0, -1.0/24.0, -1.0/24.0, -1.0/24.0]; 24 | wxy=[0.0, 0.0, 0.0, 0.0, 0.0, 1.0/4.0, -1.0/4.0, 1.0/4.0, -1.0/4.0]; 25 | 26 | gradstencilx=[0.0,4.0/12.0,0.0,-4.0/12.0,0.0,1.0/12.0,-1.0/12.0,-1.0/12.0,1.0/12.0]; 27 | gradstencily=[0.0,0.0,4.0/12.0,0.0,-4.0/12.0,1.0/12.0,1.0/12.0,-1.0/12.0,-1.0/12.0]; 28 | laplacestencil=[-20.0/6.0,4.0/6.0,4.0/6.0,4.0/6.0,4.0/6.0,1.0/6.0,1.0/6.0,1.0/6.0,1.0/6.0]; 29 | 30 | % Initialization 31 | rho=ones(NX,NY); 32 | phi=zeros(NX,NY); 33 | ux=zeros(NX,NY); 34 | uy=zeros(NX,NY); 35 | 36 | feq=zeros(NPOP); 37 | geq=zeros(NPOP); 38 | f1=zeros(NPOP,NX,NY); 39 | f2=zeros(NPOP,NX,NY); 40 | g1=zeros(NPOP,NX,NY); 41 | g2=zeros(NPOP,NX,NY); 42 | 43 | % Parameters of the lattice 44 | weights=[4/9 1/9 1/9 1/9 1/9 1/36 1/36 1/36 1/36]; 45 | cx=[0 1 0 -1 0 1 -1 -1 1]; 46 | cy=[0 0 1 0 -1 1 1 -1 -1]; 47 | 48 | % Initialization 49 | for y=1:NY 50 | for x=1:NX 51 | if (x-NX/2)^2+(y-NY/2)^2<=radius*radius 52 | phi(x,y)=1; 53 | else 54 | phi(x,y)=-1; 55 | end 56 | 57 | end 58 | end 59 | 60 | 61 | for y=1:NY 62 | for x=1:NX 63 | rho(x,y)=1; 64 | ux(x,y)=0; 65 | uy(x,y)=0; 66 | vx=ux(x,y); 67 | vy=uy(x,y); 68 | 69 | gradx=0.0; 70 | grady=0.0; 71 | laplace=0.0; 72 | 73 | for k=1:NPOP 74 | newx=1+mod(x-1+cx(k)+NX,NX); 75 | newy=1+mod(y-1+cy(k)+NY,NY); 76 | gradx=gradx+gradstencilx(k)*phi(newx,newy); 77 | grady=grady+gradstencily(k)*phi(newx,newy); 78 | laplace=laplace+laplacestencil(k)*phi(newx,newy); 79 | end 80 | 81 | phase=phi(x,y); 82 | dense=rho(x,y); 83 | vx=ux(x,y); 84 | vy=uy(x,y); 85 | 86 | 87 | sum_dense=0.0; 88 | sum_phase=0.0; 89 | phase_square=phi(x,y)*phi(x,y); 90 | pressure_bulk=dense/3.0+a*(-0.5*phase_square+3.0/4.0*phase_square*phase_square)-ksurf*phase*laplace; 91 | chemical=gamma*(a*(-phase+phase*phase*phase)-ksurf*laplace); 92 | 93 | for k=2:NPOP 94 | 95 | feq(k)=weights(k)*(3.0*pressure_bulk+3.0*dense*(cx(k)*vx+cy(k)*vy) ... 96 | +4.5*dense*((cx(k)*cx(k)-1.0/3.0)*vx*vx+(cy(k)*cy(k)-1.0/3.0)*vy*vy ... 97 | +2.0*vx*vy*cx(k)*cy(k)))... 98 | +ksurf*(wxx(k)*gradx*gradx+wyy(k)*grady*grady+wxy(k)*gradx*grady); 99 | geq(k)=weights(k)*(3.0*chemical+3.0*phase*(cx(k)*vx+cy(k)*vy) ... 100 | +4.5*phase*((cx(k)*cx(k)-1.0/3.0)*vx*vx+(cy(k)*cy(k)-1.0/3.0)*vy*vy ... 101 | +2.0*vx*vy*cx(k)*cy(k))); 102 | sum_dense=sum_dense+feq(k); 103 | sum_phase=sum_phase+geq(k); 104 | 105 | f1(k,x,y)=feq(k); 106 | g1(k,x,y)=geq(k); 107 | end 108 | 109 | f1(1,x,y)=dense-sum_dense; 110 | g1(1,x,y)=phase-sum_phase; 111 | 112 | 113 | end 114 | end 115 | 116 | %% Main iteration loop 117 | counter_frame=1; 118 | for counter=1:NSTEPS 119 | 120 | % Calculation of the macroscopic quantities 121 | for y=1:NY 122 | for x=1:NX 123 | dense=0; 124 | phase=0; 125 | vx=0; 126 | vy=0; 127 | for k=1:NPOP 128 | dense=dense+f1(k,x,y); 129 | phase=phase+g1(k,x,y); 130 | vx=vx+cx(k)*f1(k,x,y); 131 | vy=vy+cy(k)*f1(k,x,y); 132 | end 133 | 134 | rho(x,y)=dense; 135 | ux(x,y)=vx/dense; 136 | uy(x,y)=vy/dense; 137 | 138 | phi(x,y)=phase; 139 | end 140 | end 141 | 142 | % main loop 143 | for y=1:NY 144 | for x=1:NX 145 | 146 | % Calculation of the laplacians and gradients and equilibrium 147 | % functions 148 | 149 | 150 | % Change tau_rho depending on phase and tau_liq with tau_gas 151 | 152 | for k=1:NPOP 153 | 154 | %forcepop=weights(k)*(1-0.5*omega)*((3*(cx(k)-vx)+9*cx(k)*(cx(k)*vx+cy(k)*vy))*forcex(x,y)... 155 | % +(3*(cy(k)-vy)+9*cy(k)*(cx(k)*vx+cy(k)*vy))*forcey(x,y)); 156 | 157 | newx=1+mod(x-1+cx(k)+NX,NX); 158 | newy=1+mod(y-1+cy(k)+NY,NY); 159 | 160 | f1(k,x,y)=f1(k,x,y)*(1.0-1.0/tau_rho)+feq(k)*1.0/tau_rho; 161 | f2(k,newx,newy)=f1(k,x,y); 162 | 163 | g1(k,x,y)=g1(k,x,y)*(1.0-1.0/tau_phi)+geq(k)*1.0/tau_phi; 164 | g2(k,newx,newy)=g1(k,x,y); 165 | end 166 | 167 | end 168 | end 169 | 170 | f1=f2; 171 | g1=g2; 172 | counter 173 | 174 | if mod(counter,NOUTPUT)==0 175 | imagesc(phi); 176 | %surf(phi); 177 | %sum(sum(phi)) 178 | %zlim([-1.1 1.1]) 179 | F(counter_frame) = getframe; 180 | counter_frame=counter_frame+1; 181 | end 182 | end 183 | 184 | movie(F,10) 185 | -------------------------------------------------------------------------------- /Tuesday/Coding/PoiseuilleDeveloping_exercise.m: -------------------------------------------------------------------------------- 1 | clear all 2 | clc 3 | tic 4 | % Developing Poiseuille flow 5 | 6 | % Lattice parameters 7 | weights=[4/9 1/9 1/9 1/9 1/9 1/36 1/36 1/36 1/36]; 8 | cx=[0 1 0 -1 0 1 -1 -1 1]; 9 | cy=[0 0 1 0 -1 1 1 -1 -1]; 10 | 11 | % Numerical parameters 12 | NX=52; % Number of grids points along x 13 | NY=52; % Number of grid points along y 14 | NPOP=9; % Number of populations used in velocity space discretization 15 | NSTEPS=2000; % Number of time steps/iterations 16 | 17 | 18 | % Simulation parameters 19 | y_bottom=1; % location of bottom wall 20 | y_top=NY; % location of top wall 21 | Re=10; % Reynolds number 22 | omega=0.9; % Relaxation frequency 23 | kvisc=1/3*(1/omega-0.5); % Kinematic viscosity 24 | umax=Re*kvisc/((y_top-y_bottom)) ;% umax=0.001; % Mach number (can be understood as a CFL number) 25 | 26 | 27 | % Macroscopic parameters 28 | rho=ones(NX,NY); 29 | ux=zeros(NX,NY); 30 | uy=zeros(NX,NY); 31 | 32 | forcex=8.*umax*kvisc./((y_top-y_bottom).^2); 33 | forcey=0; 34 | 35 | % Analytical solution 36 | y_plot=y_bottom:y_top; 37 | ux_analy=-1/(2*kvisc).*forcex.*(y_plot-y_bottom).*(y_plot-y_top); 38 | ux_in=1/12*(y_bottom^2-2*y_bottom*y_top+y_top^2)*forcex/kvisc; 39 | 40 | 41 | 42 | % Initialize populations with rho=1 and (ux,uy)=(0,0) 43 | feq=zeros(NPOP); 44 | f1=zeros(NPOP,NX,NY); 45 | f2=zeros(NPOP,NX,NY); 46 | forcepop=zeros(NPOP); 47 | for y=1:NY 48 | for x=1:NX 49 | dense=rho(x,y); 50 | vx=ux(x,y); 51 | vy=uy(x,y); 52 | for k=1:NPOP 53 | feq(k)=weights(k)*(dense+(3*(vx*cx(k)+vy*cy(k)) ... 54 | +9/2*(cx(k)*vx+cy(k)*vy)^2-3/2*(vx^2+vy^2))); 55 | f1(k,x,y)=feq(k); 56 | f2(k,x,y)=feq(k); 57 | end 58 | end 59 | end 60 | 61 | % Main algorithm 62 | for counter=1:NSTEPS 63 | 64 | % Macroscopic parameters computed through velocity moments of 65 | % populations f1 66 | for y=1:NY 67 | for x=1:NX 68 | 69 | dense=0; 70 | vx=0; 71 | vy=0; 72 | for k=1:NPOP 73 | dense=dense+f1(k,x,y); 74 | vx=vx+cx(k)*f1(k,x,y); 75 | vy=vy+cy(k)*f1(k,x,y); 76 | end 77 | 78 | rho(x,y)=dense; 79 | ux(x,y)=vx; 80 | uy(x,y)=vy; 81 | 82 | 83 | for k=1:NPOP 84 | 85 | % Compute the populations equilibrium value 86 | feq(k)=weights(k).*(dense+3*(vx*cx(k)+vy*cy(k)) ... 87 | +9/2*((cx(k)*cx(k)-1/3)*vx*vx+2*cx(k)*cy(k)*vx*vy+(cy(k)*cy(k)-1/3)*vy*vy)); 88 | 89 | 90 | % Collision step 91 | f1(k,x,y)=f1(k,x,y)*(1-omega)+feq(k)*omega; 92 | 93 | % Streaming step 94 | newx=1+mod(x-1+cx(k)+NX,NX); 95 | newy=1+mod(y-1+cy(k)+NY,NY); 96 | f2(k,newx,newy)=f1(k,x,y); 97 | end 98 | end 99 | end 100 | 101 | 102 | % Zou He Boundary Conditions 103 | 104 | x=1; % inlet 105 | for y=2:NY-1 106 | 107 | % Introduce here the Zou He inlet boundary condition! 108 | end 109 | 110 | x=NX; % outlet 111 | for y=2:NY-1 112 | 113 | % Introduce here the Zou He outlet boundary condition! 114 | 115 | end 116 | 117 | 118 | y=1; %bottom wall 119 | for x=2:NX-1 120 | ux(x,y)=0; 121 | uy(x,y)=0; 122 | rho(x,y)=uy(x,y)+(f2(1,x,y)+f2(2,x,y)+f2(4,x,y)+2*(f2(5,x,y)+... 123 | f2(8,x,y)+f2(9,x,y))); 124 | 125 | 126 | f2(3,x,y)=f2(5,x,y)+2/3*uy(x,y); 127 | f2(6,x,y)=f2(8,x,y)+1/6*uy(x,y)+0.5*(f2(4,x,y)-f2(2,x,y))+1/2.*ux(x,y); 128 | f2(7,x,y)=f2(9,x,y)+1/6*uy(x,y)-0.5*(f2(4,x,y)-f2(2,x,y))-1/2.*ux(x,y); 129 | 130 | end 131 | 132 | y=NY; % Top wall 133 | for x=2:NX-1 134 | 135 | ux(x,y)=0; 136 | uy(x,y)=0; 137 | rho(x,y)=-uy(x,y)+(f2(1,x,y)+f2(2,x,y)+f2(4,x,y)+2*(f2(3,x,y)+... 138 | f2(6,x,y)+f2(7,x,y))); 139 | 140 | 141 | f2(5,x,y)=f2(3,x,y)-2/3*uy(x,y); 142 | f2(8,x,y)=f2(6,x,y)-1/6*uy(x,y)+0.5*(f2(2,x,y,1)-f2(4,x,y))-1/2*ux(x,y); 143 | f2(9,x,y)=f2(7,x,y)-1/6*uy(x,y)-0.5*(f2(2,x,y)-f2(4,x,y))+1/2*ux(x,y); 144 | 145 | 146 | end 147 | 148 | 149 | % Corners 150 | %================================================================== 151 | %Bottom left corner 152 | x=1; y=1; 153 | rho(x,y)=rho(x,y+1); %Extrapolation (1st order) 154 | ux(x,y)=0; 155 | uy(x,y)=0; 156 | f2(2,x,y)=f2(4,x,y)+2/3*ux(x,y); 157 | f2(3,x,y)=f2(5,x,y)+2/3*uy(x,y); 158 | f2(6,x,y)=f2(8,x,y)+1/6*(ux(x,y)+uy(x,y)); 159 | f2(7,x,y)=1/12*(-ux(x,y)+uy(x,y)); 160 | f2(9,x,y)=1/12*(ux(x,y)-uy(x,y)); 161 | f2(1,x,y)=0; 162 | f2(1,x,y)=rho(x,y)-sum(f2(:,x,y)); 163 | 164 | %Top left corner 165 | x=1; y=NY; 166 | rho(x,y)=rho(x,y-1); %Extrapolation (1st order) 167 | ux(x,y)=0; 168 | uy(x,y)=0; 169 | f2(2,x,y)=f2(4,x,y)+2/3*ux(x,y); 170 | f2(5,x,y)=f2(3,x,y)-2/3*uy(x,y); 171 | f2(9,x,y)=f2(7,x,y)+1/6*(ux(x,y)-uy(x,y)); 172 | f2(6,x,y)=1/12*(ux(x,y)+uy(x,y)); 173 | f2(8,x,y)=-1/12*(ux(x,y)+uy(x,y)); 174 | f2(1,x,y)=0; 175 | f2(1,x,y)=rho(x,y)-sum(f2(:,x,y)); 176 | 177 | %Bottom right corner 178 | x=NX; y=1; 179 | rho(x,y)=rho(x,y+1); %Extrapolation (1st order) 180 | ux(x,y)=0; 181 | uy(x,y)=0; 182 | f2(4,x,y)=f2(2,x,y)-2/3*ux(x,y); 183 | f2(3,x,y)=f2(5,x,y)+2/3*uy(x,y); 184 | f2(7,x,y)=f2(9,x,y)+1/6*(-ux(x,y)+uy(x,y)); 185 | f2(6,x,y)=1/12*(ux(x,y)+uy(x,y)); 186 | f2(8,x,y)=-1/12*(ux(x,y)+uy(x,y)); 187 | f2(1,x,y)=0; 188 | f2(1,x,y)=rho(x,y)-sum(f2(:,x,y)); 189 | 190 | %Top right corner 191 | x=NX; y=NY; 192 | rho(x,y)=rho(x,y-1); %Extrapolation (1st order) 193 | ux(x,y)=0; 194 | uy(x,y)=0; 195 | f2(4,x,y)=f2(2,x,y)-2/3*ux(x,y); 196 | f2(5,x,y)=f2(3,x,y)-2/3*uy(x,y); 197 | f2(8,x,y)=f2(6,x,y)-1/6*(ux(x,y)+uy(x,y)); 198 | f2(7,x,y)=1/12*(-ux(x,y)+uy(x,y)); 199 | f2(9,x,y)=1/12*(ux(x,y)-uy(x,y)); 200 | f2(1,x,y)=0; 201 | f2(1,x,y)=rho(x,y)-sum(f2(:,x,y)); 202 | 203 | % Assign new state f1, i.e. f(t+1) to previous state f2, i.e. f(t) 204 | f1=f2; 205 | end 206 | 207 | ux_plot=ux; 208 | 209 | 210 | 211 | % % Compare LBM and Analytical solution velocity profiles 212 | % figure('color',[1 1 1]) 213 | % hold on 214 | % plot(y_plot./(y_top),ux_analy./umax,'ko--'); 215 | % xlabel('y/y_{top}'); 216 | % ylabel('u/umax'); 217 | % plot(y_plot./(y_top),ux_plot(round(NX),:)./umax,'rs-.'); 218 | % legend('ux analy','ux LBM'); 219 | % axis tight 220 | % box on 221 | 222 | 223 | % Calculation of L2 error 224 | sum_num=0; 225 | sum_denom=0; 226 | x=NX; 227 | for y=1:NY 228 | 229 | sum_num=sum_num+(ux_plot(x,y)-ux_analy(y)).^2; 230 | sum_denom=sum_denom+ux_analy(y).^2; 231 | end 232 | 233 | error=sqrt((sum_num)/(sum_denom)); 234 | 235 | disp(['L2 relative error = ',num2str(error)]); 236 | 237 | toc % Stop time counter 238 | 239 | -------------------------------------------------------------------------------- /Wednesday/Coding/binaryliquid.m: -------------------------------------------------------------------------------- 1 | %% periodic flow my version 2 | clear all; 3 | clc; 4 | 5 | % Macroscopic parameters 6 | NX=128; 7 | NY=128; 8 | NPOP=9; 9 | NSTEPS=200; 10 | NOUTPUT=10; 11 | 12 | % Parameters of the binary-liquid model 13 | ksurf=0.04; 14 | gamma=1.0; 15 | a=0.04; 16 | tau_gas=0.7; 17 | tau_liq=2.5; 18 | radius=20; 19 | tau_phi=1.0; 20 | 21 | % Stencils parameters 22 | wxx=[0.0, 1.0/3.0, -1.0/6.0, 1.0/3.0, -1.0/6.0, -1.0/24.0, -1.0/24.0, -1.0/24.0, -1.0/24.0]; 23 | wyy=[0.0, -1.0/6.0, 1.0/3.0, -1.0/6.0, 1.0/3.0, -1.0/24.0, -1.0/24.0, -1.0/24.0, -1.0/24.0]; 24 | wxy=[0.0, 0.0, 0.0, 0.0, 0.0, 1.0/4.0, -1.0/4.0, 1.0/4.0, -1.0/4.0]; 25 | 26 | gradstencilx=[0.0,4.0/12.0,0.0,-4.0/12.0,0.0,1.0/12.0,-1.0/12.0,-1.0/12.0,1.0/12.0]; 27 | gradstencily=[0.0,0.0,4.0/12.0,0.0,-4.0/12.0,1.0/12.0,1.0/12.0,-1.0/12.0,-1.0/12.0]; 28 | laplacestencil=[-20.0/6.0,4.0/6.0,4.0/6.0,4.0/6.0,4.0/6.0,1.0/6.0,1.0/6.0,1.0/6.0,1.0/6.0]; 29 | 30 | % Initialization 31 | rho=ones(NX,NY); 32 | phi=zeros(NX,NY); 33 | ux=zeros(NX,NY); 34 | uy=zeros(NX,NY); 35 | 36 | feq=zeros(NPOP); 37 | geq=zeros(NPOP); 38 | f1=zeros(NPOP,NX,NY); 39 | f2=zeros(NPOP,NX,NY); 40 | g1=zeros(NPOP,NX,NY); 41 | g2=zeros(NPOP,NX,NY); 42 | 43 | % Parameters of the lattice 44 | weights=[4/9 1/9 1/9 1/9 1/9 1/36 1/36 1/36 1/36]; 45 | cx=[0 1 0 -1 0 1 -1 -1 1]; 46 | cy=[0 0 1 0 -1 1 1 -1 -1]; 47 | 48 | % Initialization 49 | for y=1:NY 50 | for x=1:NX 51 | if (x-NX/2)^2+(y-NY/2)^2<=radius*radius 52 | phi(x,y)=1; 53 | else 54 | phi(x,y)=-1; 55 | end 56 | 57 | end 58 | end 59 | 60 | 61 | for y=1:NY 62 | for x=1:NX 63 | rho(x,y)=1; 64 | ux(x,y)=0; 65 | uy(x,y)=0; 66 | vx=ux(x,y); 67 | vy=uy(x,y); 68 | 69 | gradx=0.0; 70 | grady=0.0; 71 | laplace=0.0; 72 | 73 | for k=1:NPOP 74 | newx=1+mod(x-1+cx(k)+NX,NX); 75 | newy=1+mod(y-1+cy(k)+NY,NY); 76 | gradx=gradx+gradstencilx(k)*phi(newx,newy); 77 | grady=grady+gradstencily(k)*phi(newx,newy); 78 | laplace=laplace+laplacestencil(k)*phi(newx,newy); 79 | end 80 | 81 | phase=phi(x,y); 82 | dense=rho(x,y); 83 | vx=ux(x,y); 84 | vy=uy(x,y); 85 | 86 | 87 | sum_dense=0.0; 88 | sum_phase=0.0; 89 | phase_square=phi(x,y)*phi(x,y); 90 | pressure_bulk=dense/3.0+a*(-0.5*phase_square+3.0/4.0*phase_square*phase_square)-ksurf*phase*laplace; 91 | chemical=gamma*(a*(-phase+phase*phase*phase)-ksurf*laplace); 92 | 93 | for k=2:NPOP 94 | 95 | feq(k)=weights(k)*(3.0*pressure_bulk+3.0*dense*(cx(k)*vx+cy(k)*vy) ... 96 | +4.5*dense*((cx(k)*cx(k)-1.0/3.0)*vx*vx+(cy(k)*cy(k)-1.0/3.0)*vy*vy ... 97 | +2.0*vx*vy*cx(k)*cy(k)))... 98 | +ksurf*(wxx(k)*gradx*gradx+wyy(k)*grady*grady+wxy(k)*gradx*grady); 99 | geq(k)=weights(k)*(3.0*chemical+3.0*phase*(cx(k)*vx+cy(k)*vy) ... 100 | +4.5*phase*((cx(k)*cx(k)-1.0/3.0)*vx*vx+(cy(k)*cy(k)-1.0/3.0)*vy*vy ... 101 | +2.0*vx*vy*cx(k)*cy(k))); 102 | sum_dense=sum_dense+feq(k); 103 | sum_phase=sum_phase+geq(k); 104 | 105 | f1(k,x,y)=feq(k); 106 | g1(k,x,y)=geq(k); 107 | end 108 | 109 | f1(1,x,y)=dense-sum_dense; 110 | g1(1,x,y)=phase-sum_phase; 111 | 112 | 113 | end 114 | end 115 | 116 | %% Main iteration loop 117 | counter_frame=1; 118 | for counter=1:NSTEPS 119 | 120 | % Calculation of the macroscopic quantities 121 | for y=1:NY 122 | for x=1:NX 123 | dense=0; 124 | phase=0; 125 | vx=0; 126 | vy=0; 127 | for k=1:NPOP 128 | dense=dense+f1(k,x,y); 129 | phase=phase+g1(k,x,y); 130 | vx=vx+cx(k)*f1(k,x,y); 131 | vy=vy+cy(k)*f1(k,x,y); 132 | end 133 | 134 | rho(x,y)=dense; 135 | ux(x,y)=vx/dense; 136 | uy(x,y)=vy/dense; 137 | 138 | phi(x,y)=phase; 139 | end 140 | end 141 | 142 | % main loop 143 | for y=1:NY 144 | for x=1:NX 145 | 146 | % Calculation of the laplacians and gradients 147 | gradx=0.0; 148 | grady=0.0; 149 | laplace=0.0; 150 | for k=1:NPOP 151 | newx=1+mod(x-1+cx(k)+NX,NX); 152 | newy=1+mod(y-1+cy(k)+NY,NY); 153 | gradx=gradx+gradstencilx(k)*phi(newx,newy); 154 | grady=grady+gradstencily(k)*phi(newx,newy); 155 | laplace=laplace+laplacestencil(k)*phi(newx,newy); 156 | end 157 | 158 | phase=phi(x,y); 159 | dense=rho(x,y); 160 | vx=ux(x,y); 161 | vy=uy(x,y); 162 | 163 | 164 | sum_dense=0.0; 165 | sum_phase=0.0; 166 | phase_square=phi(x,y)*phi(x,y); 167 | pressure_bulk=dense/3.0+a*(-0.5*phase_square+3.0/4.0*phase_square*phase_square)-ksurf*phase*laplace; 168 | chemical=gamma*(a*(-phase+phase*phase*phase)-ksurf*laplace); 169 | 170 | for k=2:NPOP 171 | 172 | feq(k)=weights(k)*(3.0*pressure_bulk+3.0*dense*(cx(k)*vx+cy(k)*vy) ... 173 | +4.5*dense*((cx(k)*cx(k)-1.0/3.0)*vx*vx+(cy(k)*cy(k)-1.0/3.0)*vy*vy ... 174 | +2.0*vx*vy*cx(k)*cy(k)))... 175 | +ksurf*(wxx(k)*gradx*gradx+wyy(k)*grady*grady+wxy(k)*gradx*grady); 176 | geq(k)=weights(k)*(3.0*chemical+3.0*phase*(cx(k)*vx+cy(k)*vy) ... 177 | +4.5*phase*((cx(k)*cx(k)-1.0/3.0)*vx*vx+(cy(k)*cy(k)-1.0/3.0)*vy*vy ... 178 | +2.0*vx*vy*cx(k)*cy(k))); 179 | sum_dense=sum_dense+feq(k); 180 | sum_phase=sum_phase+geq(k); 181 | 182 | f1(k,x,y)=feq(k); 183 | g1(k,x,y)=geq(k); 184 | end 185 | 186 | feq(1)=dense-sum_dense; 187 | geq(1)=phase-sum_phase; 188 | 189 | 190 | tau_rho=tau_gas+(phase+1.0)/2.0*(tau_liq-tau_gas); 191 | 192 | for k=1:NPOP 193 | 194 | %forcepop=weights(k)*(1-0.5*omega)*((3*(cx(k)-vx)+9*cx(k)*(cx(k)*vx+cy(k)*vy))*forcex(x,y)... 195 | % +(3*(cy(k)-vy)+9*cy(k)*(cx(k)*vx+cy(k)*vy))*forcey(x,y)); 196 | 197 | newx=1+mod(x-1+cx(k)+NX,NX); 198 | newy=1+mod(y-1+cy(k)+NY,NY); 199 | 200 | f1(k,x,y)=f1(k,x,y)*(1.0-1.0/tau_rho)+feq(k)*1.0/tau_rho; 201 | f2(k,newx,newy)=f1(k,x,y); 202 | 203 | g1(k,x,y)=g1(k,x,y)*(1.0-1.0/tau_phi)+geq(k)*1.0/tau_phi; 204 | g2(k,newx,newy)=g1(k,x,y); 205 | end 206 | 207 | end 208 | end 209 | 210 | f1=f2; 211 | g1=g2; 212 | counter 213 | 214 | if mod(counter,NOUTPUT)==0 215 | imagesc(phi); 216 | %surf(phi); 217 | %sum(sum(phi)) 218 | %zlim([-1.1 1.1]) 219 | F(counter_frame) = getframe; 220 | counter_frame=counter_frame+1; 221 | end 222 | end 223 | 224 | movie(F,10) 225 | -------------------------------------------------------------------------------- /Wednesday/Coding/shanchen_walls.m: -------------------------------------------------------------------------------- 1 | %% periodic flow my version 2 | clear all; 3 | clc; 4 | 5 | % Macroscopic density and velocities 6 | NX=128; 7 | NY=128; 8 | NPOP=9; 9 | NSTEPS=1000; 10 | NOUTPUT=10; 11 | 12 | % Parameters of the Shan-Chen model 13 | rho_crit=log(2) 14 | rho_liq=1.95 15 | rho_gas=0.15 16 | radius=20 17 | G=-5.0 18 | gravity=0.0001 19 | rho_wall=0.1 20 | 21 | % Initialization 22 | rho=ones(NX,NY); 23 | ux=zeros(NX,NY); 24 | uy=zeros(NX,NY); 25 | 26 | feq=zeros(NPOP); 27 | f1=zeros(NPOP,NX,NY); 28 | f2=zeros(NPOP,NX,NY); 29 | forcex=zeros(NX,NY); 30 | forcey=zeros(NY,NY); 31 | 32 | % Parameters of the lattice 33 | weights=[4/9 1/9 1/9 1/9 1/9 1/36 1/36 1/36 1/36]; 34 | cx=[0 1 0 -1 0 1 -1 -1 1]; 35 | cy=[0 0 1 0 -1 1 1 -1 -1]; 36 | omega=1.0; 37 | 38 | %% Initialization section 39 | for y=1:NY 40 | for x=1:NX 41 | %if abs(x-NX/2)NY-2*radius && y<============ 191 | 192 | 193 | %Top left corner 194 | x=1; y=NY; 195 | rho(x,y)=rho(x,y-1); %Extrapolation (1st order) 196 | ux(x,y)=0; 197 | uy(x,y)=0; 198 | f2(2,x,y)=f2(4,x,y)+2/3*ux(x,y); 199 | f2(5,x,y)=f2(3,x,y)-2/3*uy(x,y); 200 | f2(9,x,y)=f2(7,x,y)+1/6*(ux(x,y)-uy(x,y)); 201 | f2(6,x,y)=1/12*(ux(x,y)+uy(x,y)); 202 | f2(8,x,y)=-1/12*(ux(x,y)+uy(x,y)); 203 | f2(1,x,y)=0; 204 | f2(1,x,y)=rho(x,y)-sum(f2(:,x,y)); 205 | 206 | %Bottom right corner 207 | x=NX; y=1; 208 | rho(x,y)=rho(x,y+1); %Extrapolation (1st order) 209 | ux(x,y)=0; 210 | uy(x,y)=0; 211 | f2(4,x,y)=f2(2,x,y)-2/3*ux(x,y); 212 | f2(3,x,y)=f2(5,x,y)+2/3*uy(x,y); 213 | f2(7,x,y)=f2(9,x,y)+1/6*(-ux(x,y)+uy(x,y)); 214 | f2(6,x,y)=1/12*(ux(x,y)+uy(x,y)); 215 | f2(8,x,y)=-1/12*(ux(x,y)+uy(x,y)); 216 | f2(1,x,y)=0; 217 | f2(1,x,y)=rho(x,y)-sum(f2(:,x,y)); 218 | 219 | %Top right corner 220 | x=NX; y=NY; 221 | % Introduce here the Top-right corner! 222 | 223 | %===========================><============ 224 | 225 | 226 | % Assign new state f1, i.e. f(t+1) to previous state f2, i.e. f(t) 227 | f1=f2; 228 | end 229 | 230 | 231 | 232 | 233 | % % Compare LBM and Analytical solution velocity profiles 234 | % figure('color',[1 1 1]) 235 | % hold on 236 | % plot(y_plot,ux_analy_outlet,'ko--'); 237 | % plot(y_plot,ux(NX,:),'rs-.'); 238 | % legend('ux analy','ux LBM'); 239 | % box on 240 | % hold off 241 | 242 | % figure('color',[1 1 1]) 243 | % hold on 244 | % [X,Y]=meshgrid(1:NX,1:NY); 245 | % x_stream=linspace(1,NX,7); 246 | % y_stream=linspace(1,NY,25)/1; 247 | % % y_stream=(log(linspace(1,NY,10))).^4; 248 | % [sx,sy] = meshgrid(x_stream,y_stream); 249 | % contourf(ux); 250 | % h=streamline(X,Y,uy,ux,sy,sx); 251 | % set(h,'Color','white') 252 | % toc 253 | % Plot velocity field 254 | % [x_plot,y_plot]=meshgrid(1:NX,1:NY); 255 | % 256 | % figure('color',[1 1 1]); 257 | % set(gcf,'Position',[50 120 910 550]); clf; 258 | % quiver(x_plot,y_plot,uy,ux,'r'); 259 | % hold on; 260 | % set(gca,'Color','k'); 261 | % axis equal tight 262 | % xlabel('\it{y}');ylabel('\it{x}'); 263 | % % Streamlines 264 | % sx=linspace(1,NX,40); 265 | % sy=linspace(1,NY,4); % Nice view: 2 266 | % [sx sy]=meshgrid(sx, sy); 267 | % verts=stream2(x_plot,y_plot,uy,ux,sx,sy); 268 | % streamline(verts); 269 | % % Particles animation 270 | % nparts=150; 271 | % streamparticles(verts, nparts,'Animate',10,'Framerate',50,'MarkerFaceColor','g','ParticleAlignment','off'); 272 | 273 | % Calculation of L2 error 274 | sum_num=0; 275 | sum_denom=0; 276 | x=NX; 277 | for y=1:NY 278 | 279 | sum_num=sum_num+(ux(x,y)-ux_analy_outlet(y)).^2; 280 | sum_denom=sum_denom+ux_analy_outlet(y).^2; 281 | end 282 | 283 | error=sqrt((sum_num)/(sum_denom)); 284 | 285 | disp(['L2 relative error = ',num2str(error)]); 286 | 287 | 288 | toc % Stop time counter 289 | 290 | -------------------------------------------------------------------------------- /Tuesday/Coding/Backstep_solution.m: -------------------------------------------------------------------------------- 1 | clear all 2 | clc 3 | tic 4 | % Flow over a backward facing step 5 | 6 | % Lattice parameters 7 | weights=[4/9 1/9 1/9 1/9 1/9 1/36 1/36 1/36 1/36]; 8 | cx=[0 1 0 -1 0 1 -1 -1 1]; 9 | cy=[0 0 1 0 -1 1 1 -1 -1]; 10 | 11 | % Numerical parameters 12 | NX=52; % Number of grids points along x 13 | NY=52; % Number of grid points along y 14 | NPOP=9; % Number of populations used in velocity space discretization 15 | NSTEPS=2000; % Number of time steps/iterations 16 | 17 | 18 | % Simulation parameters 19 | y_bottom=1; % location of bottom wall 20 | y_top=NY; % location of top wall 21 | Re=10; % Reynolds number 22 | omega=0.9; % Relaxation frequency 23 | kvisc=1/3*(1/omega-0.5); % Kinematic viscosity 24 | influx_ratio=1/1.2; 25 | y_top_influx=round((y_top-y_bottom)*influx_ratio)+y_bottom; 26 | 27 | umax=Re*kvisc/((y_top_influx-y_bottom)) ;% umax=0.001; % Mach number (can be understood as a CFL number) 28 | 29 | 30 | 31 | % Macroscopic parameters 32 | rho0=1; 33 | rho=ones(NX,NY); 34 | ux=zeros(NX,NY); 35 | uy=zeros(NX,NY); 36 | 37 | forcex_inlet=8.*umax*kvisc./((y_top_influx-y_bottom).^2); 38 | 39 | % Inlet analytical solution 40 | y_plot=y_bottom:y_top_influx; 41 | ux_analy_inlet=-1/(2*kvisc).*forcex_inlet.*(y_plot-y_bottom).*(y_plot-y_top_influx); 42 | 43 | % Outlet analytical solution 44 | forcex_outlet=8.*umax*kvisc./((y_top-y_bottom).^2); 45 | y_plot=y_bottom:y_top; 46 | ux_analy_outlet=-1/(2*kvisc).*forcex_outlet.*(y_plot-y_bottom).*(y_plot-y_top); 47 | 48 | % Initialize populations with rho=1 and (ux,uy)=(0,0) 49 | feq=zeros(NPOP); 50 | f1=zeros(NPOP,NX,NY); 51 | f2=zeros(NPOP,NX,NY); 52 | forcepop=zeros(NPOP); 53 | for y=1:NY 54 | for x=1:NX 55 | dense=rho(x,y); 56 | vx=ux(x,y); 57 | vy=uy(x,y); 58 | for k=1:NPOP 59 | feq(k)=weights(k)*(dense+rho0*(3*(vx*cx(k)+vy*cy(k)) ... 60 | +9/2*(cx(k)*vx+cy(k)*vy)^2-3/2*(vx^2+vy^2))); 61 | f1(k,x,y)=feq(k); 62 | f2(k,x,y)=feq(k); 63 | end 64 | end 65 | end 66 | 67 | % Main algorithm 68 | for counter=1:NSTEPS 69 | 70 | % Macroscopic parameters computed through velocity moments of 71 | % populations f1 72 | for y=1:NY 73 | for x=1:NX 74 | 75 | dense=0; 76 | vx=0; 77 | vy=0; 78 | for k=1:NPOP 79 | dense=dense+f1(k,x,y); 80 | vx=vx+cx(k)*f1(k,x,y); 81 | vy=vy+cy(k)*f1(k,x,y); 82 | end 83 | 84 | rho(x,y)=dense; 85 | ux(x,y)=vx; 86 | uy(x,y)=vy; 87 | 88 | 89 | for k=1:NPOP 90 | 91 | % Compute the populations equilibrium value 92 | feq(k)=weights(k).*(dense+3*(vx*cx(k)+vy*cy(k)) ... 93 | +9/2*((cx(k)*cx(k)-1/3)*vx*vx+2*cx(k)*cy(k)*vx*vy+(cy(k)*cy(k)-1/3)*vy*vy)); 94 | 95 | % Collision step 96 | f1(k,x,y)=f1(k,x,y)*(1-omega)+feq(k)*omega; 97 | 98 | % Streaming step 99 | newx=1+mod(x-1+cx(k)+NX,NX); 100 | newy=1+mod(y-1+cy(k)+NY,NY); 101 | f2(k,newx,newy)=f1(k,x,y); 102 | end 103 | end 104 | end 105 | 106 | 107 | % Boundaries (Zou He) 108 | %================================================================== 109 | 110 | x=1; % Inlet 111 | for y=2:y_top_influx 112 | 113 | ux(x,y)=ux_analy_inlet(y); 114 | uy(x,y)=0; 115 | rho(x,y)=ux(x,y)+(f2(1,x,y)+f2(3,x,y)+f2(5,x,y)+2*(f2(4,x,y)+f2(7,x,y)+f2(8,x,y))); 116 | 117 | f2(2,x,y)=f2(4,x,y)+2/3*ux(x,y); 118 | f2(6,x,y)=f2(8,x,y)+1/6*ux(x,y)+0.5*(f2(5,x,y)-f2(3,x,y))+1/2*uy(x,y); 119 | f2(9,x,y)=f2(7,x,y)+1/6*ux(x,y)-0.5*(f2(5,x,y)-f2(3,x,y))-1/2*uy(x,y); 120 | 121 | end 122 | 123 | x=1; % Inlet 124 | for y=y_top_influx+1:NY-1 125 | 126 | ux(x,y)=0; 127 | uy(x,y)=0; 128 | rho(x,y)=ux(x,y)+(f2(1,x,y)+f2(3,x,y)+f2(5,x,y)+2*(f2(4,x,y)+f2(7,x,y)+f2(8,x,y))); 129 | 130 | f2(2,x,y)=f2(4,x,y)+2/3*ux(x,y); 131 | f2(6,x,y)=f2(8,x,y)+1/6*ux(x,y)+0.5*(f2(5,x,y)-f2(3,x,y))+1/2*uy(x,y); 132 | f2(9,x,y)=f2(7,x,y)+1/6*ux(x,y)-0.5*(f2(5,x,y)-f2(3,x,y))-1/2*uy(x,y); 133 | 134 | end 135 | 136 | 137 | 138 | x=NX; % Outlet 139 | for y=2:NY-1 140 | 141 | 142 | ux(x,y)=ux(x-1,y); %Extrapolation (1st order) 143 | uy(x,y)=0; 144 | rho(x,y)=-ux(x,y)+(f2(1,x,y)+f2(3,x,y)+f2(5,x,y)+2*(f2(2,x,y)+f2(6,x,y)+f2(9,x,y))); 145 | 146 | f2(4,x,y)=f2(2,x,y)-2/3*ux(x,y); 147 | f2(8,x,y)=f2(6,x,y)-1/6*ux(x,y)-0.5*(f2(5,x,y)-f2(3,x,y))-1/2*uy(x,y); 148 | f2(7,x,y)=f2(9,x,y)-1/6*ux(x,y)+0.5*(f2(5,x,y)-f2(3,x,y))+1/2*uy(x,y); 149 | 150 | end 151 | 152 | y=1; % Bottom wall 153 | for x=2:NX-1 154 | ux(x,y)=0; 155 | uy(x,y)=0; 156 | rho(x,y)=uy(x,y)+(f2(1,x,y)+f2(2,x,y)+f2(4,x,y)+2*(f2(5,x,y)+... 157 | f2(8,x,y)+f2(9,x,y))); 158 | 159 | 160 | f2(3,x,y)=f2(5,x,y)+2/3*uy(x,y); 161 | f2(6,x,y)=f2(8,x,y)+1/6*uy(x,y)+0.5*(f2(4,x,y)-f2(2,x,y))+1/2.*ux(x,y); 162 | f2(7,x,y)=f2(9,x,y)+1/6*uy(x,y)-0.5*(f2(4,x,y)-f2(2,x,y))-1/2.*ux(x,y); 163 | 164 | end 165 | 166 | y=NY; % Top wall 167 | for x=2:NX-1 168 | ux(x,y)=0; 169 | uy(x,y)=0; 170 | rho(x,y)=-uy(x,y)+(f2(1,x,y)+f2(2,x,y)+f2(4,x,y)+2*(f2(3,x,y)+... 171 | f2(6,x,y)+f2(7,x,y))); 172 | 173 | 174 | f2(5,x,y)=f2(3,x,y)-2/3*uy(x,y); 175 | f2(8,x,y)=f2(6,x,y)-1/6*uy(x,y)+0.5*(f2(2,x,y,1)-f2(4,x,y))-1/2*ux(x,y); 176 | f2(9,x,y)=f2(7,x,y)-1/6*uy(x,y)-0.5*(f2(2,x,y)-f2(4,x,y))+1/2*ux(x,y); 177 | 178 | end 179 | %================================================================== 180 | 181 | % Corners 182 | %================================================================== 183 | %Bottom left corner 184 | x=1; y=1; 185 | rho(x,y)=rho(x,y+1); %Extrapolation (1st order) 186 | ux(x,y)=0; 187 | uy(x,y)=0; 188 | f2(2,x,y)=f2(4,x,y)+2/3*ux(x,y); 189 | f2(3,x,y)=f2(5,x,y)+2/3*uy(x,y); 190 | f2(6,x,y)=f2(8,x,y)+1/6*(ux(x,y)+uy(x,y)); 191 | f2(7,x,y)=1/12*(-ux(x,y)+uy(x,y)); 192 | f2(9,x,y)=1/12*(ux(x,y)-uy(x,y)); 193 | f2(1,x,y)=0; 194 | f2(1,x,y)=rho(x,y)-sum(f2(:,x,y)); 195 | 196 | %Top left corner 197 | x=1; y=NY; 198 | rho(x,y)=rho(x,y-1); %Extrapolation (1st order) 199 | ux(x,y)=0; 200 | uy(x,y)=0; 201 | f2(2,x,y)=f2(4,x,y)+2/3*ux(x,y); 202 | f2(5,x,y)=f2(3,x,y)-2/3*uy(x,y); 203 | f2(9,x,y)=f2(7,x,y)+1/6*(ux(x,y)-uy(x,y)); 204 | f2(6,x,y)=1/12*(ux(x,y)+uy(x,y)); 205 | f2(8,x,y)=-1/12*(ux(x,y)+uy(x,y)); 206 | f2(1,x,y)=0; 207 | f2(1,x,y)=rho(x,y)-sum(f2(:,x,y)); 208 | 209 | %Bottom right corner 210 | x=NX; y=1; 211 | rho(x,y)=rho(x,y+1); %Extrapolation (1st order) 212 | ux(x,y)=0; 213 | uy(x,y)=0; 214 | f2(4,x,y)=f2(2,x,y)-2/3*ux(x,y); 215 | f2(3,x,y)=f2(5,x,y)+2/3*uy(x,y); 216 | f2(7,x,y)=f2(9,x,y)+1/6*(-ux(x,y)+uy(x,y)); 217 | f2(6,x,y)=1/12*(ux(x,y)+uy(x,y)); 218 | f2(8,x,y)=-1/12*(ux(x,y)+uy(x,y)); 219 | f2(1,x,y)=0; 220 | f2(1,x,y)=rho(x,y)-sum(f2(:,x,y)); 221 | 222 | %Top right corner 223 | x=NX; y=NY; 224 | rho(x,y)=rho(x,y-1); %Extrapolation (1st order) 225 | ux(x,y)=0; 226 | uy(x,y)=0; 227 | f2(4,x,y)=f2(2,x,y)-2/3*ux(x,y); 228 | f2(5,x,y)=f2(3,x,y)-2/3*uy(x,y); 229 | f2(8,x,y)=f2(6,x,y)-1/6*(ux(x,y)+uy(x,y)); 230 | f2(7,x,y)=1/12*(-ux(x,y)+uy(x,y)); 231 | f2(9,x,y)=1/12*(ux(x,y)-uy(x,y)); 232 | f2(1,x,y)=0; 233 | f2(1,x,y)=rho(x,y)-sum(f2(:,x,y)); 234 | 235 | % Assign new state f1, i.e. f(t+1) to previous state f2, i.e. f(t) 236 | f1=f2; 237 | end 238 | 239 | 240 | 241 | 242 | % % Compare LBM and Analytical solution velocity profiles 243 | % figure('color',[1 1 1]) 244 | % hold on 245 | % plot(y_plot,ux_analy_outlet,'ko--'); 246 | % plot(y_plot,ux(NX,:),'rs-.'); 247 | % legend('ux analy','ux LBM'); 248 | % box on 249 | % hold off 250 | 251 | % figure('color',[1 1 1]) 252 | % hold on 253 | % [X,Y]=meshgrid(1:NX,1:NY); 254 | % x_stream=linspace(1,NX,7); 255 | % y_stream=linspace(1,NY,25)/1; 256 | % % y_stream=(log(linspace(1,NY,10))).^4; 257 | % [sx,sy] = meshgrid(x_stream,y_stream); 258 | % contourf(ux); 259 | % h=streamline(X,Y,uy,ux,sy,sx); 260 | % set(h,'Color','white') 261 | % toc 262 | % Plot velocity field 263 | % [x_plot,y_plot]=meshgrid(1:NX,1:NY); 264 | % 265 | % figure('color',[1 1 1]); 266 | % set(gcf,'Position',[50 120 910 550]); clf; 267 | % quiver(x_plot,y_plot,uy,ux,'r'); 268 | % hold on; 269 | % set(gca,'Color','k'); 270 | % axis equal tight 271 | % xlabel('\it{y}');ylabel('\it{x}'); 272 | % % Streamlines 273 | % sx=linspace(1,NX,40); 274 | % sy=linspace(1,NY,4); % Nice view: 2 275 | % [sx sy]=meshgrid(sx, sy); 276 | % verts=stream2(x_plot,y_plot,uy,ux,sx,sy); 277 | % streamline(verts); 278 | % % Particles animation 279 | % nparts=150; 280 | % streamparticles(verts, nparts,'Animate',10,'Framerate',50,'MarkerFaceColor','g','ParticleAlignment','off'); 281 | 282 | % Calculation of L2 error 283 | sum_num=0; 284 | sum_denom=0; 285 | x=NX; 286 | for y=1:NY 287 | 288 | sum_num=sum_num+(ux(x,y)-ux_analy_outlet(y)).^2; 289 | sum_denom=sum_denom+ux_analy_outlet(y).^2; 290 | end 291 | 292 | error=sqrt((sum_num)/(sum_denom)); 293 | 294 | disp(['L2 relative error = ',num2str(error)]); 295 | 296 | 297 | toc % Stop time counter 298 | 299 | -------------------------------------------------------------------------------- /Wednesday/Coding/shanchen-walls.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | //Parameters of the grid 11 | const int nx=128; 12 | const int ny=128; 13 | const int npop=9; 14 | const int nsteps=2000; 15 | const int noutput=100; 16 | 17 | //Parameters of the LBM 18 | const int cx[]={0,1,0,-1,0,1,-1,-1,1}; 19 | const int cy[]={0,0,1,0,-1,1,1,-1,-1}; 20 | const double weights[]={4.0/9.0,1.0/9.0,1.0/9.0,1.0/9.0,1.0/9.0,1.0/36.0,1.0/36.0,1.0/36.0,1.0/36.0}; 21 | double tau=1.0; 22 | 23 | //Parameters of the Shan-Chen model 24 | double rhol=1.95; 25 | double rhog=0.15; 26 | int radius=20; 27 | double g=-5.0; 28 | double gravity=0.00001; 29 | double rho_wall=0.05; 30 | //Arrays 31 | double rho[nx*ny]; 32 | double u1[nx*ny]; 33 | double u2[nx*ny]; 34 | double f_mem[nx*ny*npop]; 35 | double f2_mem[nx*ny*npop]; 36 | double feq[npop]; 37 | 38 | void writeFile(std::string name, double* f, int n) 39 | { 40 | //name="tmp/"+name; 41 | std::ofstream fout(name.c_str()); 42 | for(int counterX=0;counterX 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | //Domain size 12 | const int NY=128; 13 | const int NX=128; 14 | 15 | int radius=20; 16 | //Time steps 17 | int N=20000; 18 | int NOUTPUT=100; 19 | int NSIGNAL=100; 20 | double force_y; 21 | double force_x; 22 | 23 | //Fields and populations 24 | double f[NX][NY][9], f2[NX][NY][9], g[NX][NY][9], g2[NX][NY][9]; 25 | double rho[NX][NY],ux[NX][NY],uy[NX][NY],phase[NX][NY]; 26 | 27 | 28 | //Binary-liquid parameters 29 | double aconst=0.04; 30 | double kconst=0.04; 31 | double gammaconst=1.0; 32 | double wall_gradient=-0.15; 33 | 34 | //double tau_gas=0.7; 35 | //double tau_liq=2.5; 36 | double tau_gas=1.0; 37 | double tau_liq=1.0; 38 | 39 | //BGK relaxation parameter 40 | double omega_rho=1.0; 41 | double omega_phi=1.0; 42 | 43 | //Underlying lattice parameters 44 | double weights[]={4.0/9.0,1.0/9.0,1.0/9.0,1.0/9.0,1.0/9.0,1.0/36.0,1.0/36.0,1.0/36.0,1.0/36.0}; 45 | int cx[]={0,1,0,-1,0,1,-1,-1,1}; 46 | int cy[]={0,0,1,0,-1,1,1,-1,-1}; 47 | int compliment[]={0,3,4,1,2,7,8,5,6}; 48 | float wxx[] = {0.0, 1.0/3.0, -1.0/6.0, 1.0/3.0, -1.0/6.0, -1.0/24.0, -1.0/24.0, -1.0/24.0, -1.0/24.0}; 49 | float wyy[] = {0.0, -1.0/6.0, 1.0/3.0, -1.0/6.0, 1.0/3.0, -1.0/24.0, -1.0/24.0, -1.0/24.0, -1.0/24.0}; 50 | float wxy[] = {0.0, 0.0, 0.0, 0.0, 0.0, 1.0/4.0, -1.0/4.0, 1.0/4.0, -1.0/4.0}; 51 | 52 | float gradstencilx[9]={0.0,4.0/12.0,0.0,-4.0/12.0,0.0, 53 | 1.0/12.0,-1.0/12.0,-1.0/12.0,1.0/12.0}; 54 | 55 | float gradstencily[9]={0.0,0.0,4.0/12.0,0.0,-4.0/12.0, 56 | 1.0/12.0,1.0/12.0,-1.0/12.0,-1.0/12.0}; 57 | 58 | float laplacestencil[9]={-20.0/6.0,4.0/6.0,4.0/6.0,4.0/6.0,4.0/6.0, 59 | 1.0/6.0,1.0/6.0,1.0/6.0,1.0/6.0}; 60 | 61 | void writedensity(std::string const & fName) 62 | { 63 | std::string fullName = "./tmp/" + fName+ ".dat"; 64 | std::ofstream fout(fullName.c_str()); 65 | fout.precision(10); 66 | 67 | for (int iY=NY-1; iY>=0; --iY) 68 | { 69 | for (int iX=0; iX=0; --iY) 83 | { 84 | for (int iX=0; iX=0; --iY) 99 | { 100 | for (int iX=0; iX=0; --iY) 114 | { 115 | for (int iX=0; iX=1)) 130 | phase[iX][iY]=1.0; 131 | else 132 | phase[iX][iY]=-1.0; 133 | 134 | //Walls initialization 135 | 136 | for(int iX=0;iX 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | //Domain size 12 | const int NY=128; 13 | const int NX=128; 14 | 15 | int radius=20; 16 | //Time steps 17 | int N=20000; 18 | int NOUTPUT=100; 19 | int NSIGNAL=100; 20 | int NFORCE=3000; 21 | double force_y; 22 | double force_x; 23 | const double u_wall=0.025; 24 | 25 | //Fields and populations 26 | double f[NX][NY][9], f2[NX][NY][9], g[NX][NY][9], g2[NX][NY][9]; 27 | double rho[NX][NY],ux[NX][NY],uy[NX][NY],phase[NX][NY]; 28 | 29 | 30 | //Binary-liquid parameters 31 | double aconst=0.04; 32 | double kconst=0.04; 33 | double gammaconst=1.0; 34 | double wall_gradient=0.0; 35 | 36 | //double tau_gas=0.7; 37 | //double tau_liq=2.5; 38 | double tau_gas=1.0; 39 | double tau_liq=1.0; 40 | 41 | //BGK relaxation parameter 42 | double omega_rho=1.0; 43 | double omega_phi=1.0; 44 | 45 | //Underlying lattice parameters 46 | double weights[]={4.0/9.0,1.0/9.0,1.0/9.0,1.0/9.0,1.0/9.0,1.0/36.0,1.0/36.0,1.0/36.0,1.0/36.0}; 47 | int cx[]={0,1,0,-1,0,1,-1,-1,1}; 48 | int cy[]={0,0,1,0,-1,1,1,-1,-1}; 49 | int compliment[]={0,3,4,1,2,7,8,5,6}; 50 | float wxx[] = {0.0, 1.0/3.0, -1.0/6.0, 1.0/3.0, -1.0/6.0, -1.0/24.0, -1.0/24.0, -1.0/24.0, -1.0/24.0}; 51 | float wyy[] = {0.0, -1.0/6.0, 1.0/3.0, -1.0/6.0, 1.0/3.0, -1.0/24.0, -1.0/24.0, -1.0/24.0, -1.0/24.0}; 52 | float wxy[] = {0.0, 0.0, 0.0, 0.0, 0.0, 1.0/4.0, -1.0/4.0, 1.0/4.0, -1.0/4.0}; 53 | 54 | float gradstencilx[9]={0.0,4.0/12.0,0.0,-4.0/12.0,0.0, 55 | 1.0/12.0,-1.0/12.0,-1.0/12.0,1.0/12.0}; 56 | 57 | float gradstencily[9]={0.0,0.0,4.0/12.0,0.0,-4.0/12.0, 58 | 1.0/12.0,1.0/12.0,-1.0/12.0,-1.0/12.0}; 59 | 60 | float laplacestencil[9]={-20.0/6.0,4.0/6.0,4.0/6.0,4.0/6.0,4.0/6.0, 61 | 1.0/6.0,1.0/6.0,1.0/6.0,1.0/6.0}; 62 | 63 | void writedensity(std::string const & fName) 64 | { 65 | std::string fullName = "./tmp/" + fName+ ".dat"; 66 | std::ofstream fout(fullName.c_str()); 67 | fout.precision(10); 68 | 69 | for (int iY=NY-1; iY>=0; --iY) 70 | { 71 | for (int iX=0; iX=0; --iY) 85 | { 86 | for (int iX=0; iX=0; --iY) 101 | { 102 | for (int iX=0; iX=0; --iY) 116 | { 117 | for (int iX=0; iXNFORCE) 242 | { 243 | for(int iX=0;iXNFORCE) 254 | { 255 | y_top=NY-2; 256 | y_bottom=1; 257 | } 258 | 259 | for(int iX=0;iXNFORCE) 356 | update_bounce_back(); 357 | 358 | //Streaming 359 | int y_top=NY-1; 360 | int y_bottom=0; 361 | 362 | if (counter>NFORCE) 363 | { 364 | y_top=NY-2; 365 | y_bottom=1; 366 | } 367 | 368 | for(int iX=0;iX 20 | // /|\ 21 | // 6 4 7 22 | 23 | /// ********************* 24 | /// PREPROCESSOR COMMANDS 25 | /// ********************* 26 | 27 | #include // vector containers 28 | #include // mathematical library 29 | #include // for the use of 'cout' 30 | #include // file streams 31 | #include // string streams 32 | #include // standard library 33 | #define SQ(x) ((x) * (x)) // square function; replaces SQ(x) by ((x) * (x)) in the code 34 | 35 | using namespace std; // permanently use the standard namespace 36 | 37 | /// ********************* 38 | /// SIMULATION PARAMETERS 39 | /// ********************* 40 | 41 | // These are the relevant simulation parameters. 42 | // They can be changed by the user. 43 | // If a bottom or top wall shall move in negative x-direction, a negative velocity has to be specified. 44 | // Moving walls and gravity can be switched on simultaneously. 45 | 46 | /// Simulation types 47 | // Exactly one of the following options has to be defined. 48 | // RIGID_CYLINDER 49 | // - for simulation of, e.g., Karman vortex street 50 | // - the cylinder is kept in space, it does not move 51 | // DEFORMABLE_CYLINDER 52 | // - for simulation of a deformable cylinder 53 | // - the cylinder moves along with the flow 54 | // DEFORMABLE_RBC 55 | // - for simulation of a deformable red blood cell 56 | // - the cell moves along with the flow 57 | 58 | //#define RIGID_CYLINDER 59 | //#define DEFORMABLE_CYLINDER 60 | #define DEFORMABLE_RBC 61 | 62 | /// Fluid/lattice properties 63 | 64 | #ifdef RIGID_CYLINDER 65 | const int Nx = 300; // number of lattice nodes along the x-axis (periodic) 66 | const int Ny = 62; // number of lattice nodes along the y-axis (including two wall nodes) 67 | const double tau = 0.53; // relaxation time 68 | const int t_num = 100000; // number of time steps (running from 1 to t_num) 69 | const int t_disk = 200; // disk write time step (data will be written to the disk every t_disk step) 70 | const int t_info = 5000; // info time step (screen message will be printed every t_info step) 71 | const double gravity = 0.000005; // force density due to gravity (in positive x-direction) 72 | const double wall_vel_bottom = 0; // velocity of the bottom wall (in positive x-direction) 73 | const double wall_vel_top = 0; // velocity of the top wall (in positive x-direction) 74 | #else 75 | const int Nx = 30; // number of lattice nodes along the x-axis (periodic) 76 | const int Ny = 32; // number of lattice nodes along the y-axis (including two wall nodes) 77 | const double tau = 1; // relaxation time 78 | const int t_num = 50000; // number of time steps (running from 1 to t_num) 79 | const int t_disk = 200; // disk write time step (data will be written to the disk every t_disk step) 80 | const int t_info = 1000; // info time step (screen message will be printed every t_info step) 81 | const double gravity = 0; // force density due to gravity (in positive x-direction) 82 | const double wall_vel_bottom = -0.02; // velocity of the bottom wall (in positive x-direction) 83 | const double wall_vel_top = 0.02; // velocity of the top wall (in positive x-direction) 84 | #endif 85 | 86 | /// Particle properties 87 | 88 | #ifdef RIGID_CYLINDER 89 | const int particle_num_nodes = 36; // number of surface nodes 90 | const double particle_radius = 8; // radius 91 | const double particle_stiffness = 0.3; // stiffness modulus 92 | const double particle_center_x = 15; // center position (x-component) 93 | const double particle_center_y = 29; // center position (y-component) 94 | #else 95 | const int particle_num_nodes = 32; // number of surface nodes 96 | const double particle_radius = 6; // radius 97 | const double particle_stiffness = 0.1; // stiffness modulus 98 | const double particle_bending = 0.001; // stiffness modulus 99 | const double particle_center_x = 15; // center position (x-component) 100 | const double particle_center_y = 15; // center position (y-component) 101 | #endif 102 | 103 | /// ***************** 104 | /// DECLARE VARIABLES 105 | /// ***************** 106 | 107 | // The following code should not be modified when it is first used. 108 | 109 | const double omega = 1. / tau; // relaxation frequency (inverse of relaxation time) 110 | double ***pop, ***pop_old; // LBM populations (old and new) 111 | double **density; // fluid density 112 | double **velocity_x; // fluid velocity (x-component) 113 | double **velocity_y; // fluid velocity (y-component) 114 | double **force_x; // fluid force (x-component) 115 | double **force_y; // fluid force (y-component) 116 | double force_latt[9]; // lattice force term entering the lattice Boltzmann equation 117 | double pop_eq[9]; // equilibrium populations 118 | const double weight[9] = {4./9., 1./9., 1./9., 1./9., 1./9., 1./36., 1./36., 1./36., 1./36.}; // lattice weights 119 | 120 | /// ****************** 121 | /// PARTICLE STRUCTURE 122 | /// ****************** 123 | 124 | // The following code handles the object immersed in the flow. 125 | // In the present implementation, only a single object can be put into the flow. 126 | 127 | /// Structure for surface nodes 128 | // Each node has a current x- and y-position and a reference x- and y-position. 129 | 130 | struct node_struct { 131 | 132 | /// Constructor 133 | 134 | node_struct() { 135 | x = 0; 136 | y = 0; 137 | x_ref = 0; 138 | y_ref = 0; 139 | vel_x = 0; 140 | vel_y = 0; 141 | force_x = 0; 142 | force_y = 0; 143 | } 144 | 145 | /// Elements 146 | 147 | double x; // current x-position 148 | double y; // current y-position 149 | double x_ref; // reference x-position 150 | double y_ref; // reference y-position 151 | double vel_x; // node velocity (x-component) 152 | double vel_y; // node velocity (y-component) 153 | double force_x; // node force (x-component) 154 | double force_y; // node force (y-component) 155 | }; 156 | 157 | /// Structure for object (either cylinder or red blood cell) 158 | 159 | struct particle_struct { 160 | 161 | /// Constructor 162 | 163 | particle_struct() { 164 | num_nodes = particle_num_nodes; 165 | radius = particle_radius; 166 | stiffness = particle_stiffness; 167 | center.x = particle_center_x; 168 | center.y = particle_center_y; 169 | center.x_ref = particle_center_x; 170 | center.y_ref = particle_center_y; 171 | node = new node_struct[num_nodes]; 172 | 173 | // The initial shape of the object is set in the following. 174 | // For a cylinder (rigid or deformable), the nodes define a circle. 175 | // For a red blood cell, the y-position has to be changed in order to describe a red blood cell. 176 | // Initially, the current node positions and reference node positions are identical. 177 | // During the simulation, only the current positions are updated, 178 | // the reference node positions are fixed. 179 | 180 | for(int n = 0; n < num_nodes; ++n) { 181 | #if defined RIGID_CYLINDER || defined DEFORMABLE_CYLINDER 182 | node[n].x = center.x + radius * sin(2. * M_PI * (double) n / num_nodes); 183 | node[n].x_ref = center.x + radius * sin(2. * M_PI * (double) n / num_nodes); 184 | node[n].y = center.y + radius * cos(2. * M_PI * (double) n / num_nodes); 185 | node[n].y_ref = center.y + radius * cos(2. * M_PI * (double) n / num_nodes); 186 | #endif 187 | 188 | #ifdef DEFORMABLE_RBC 189 | node[n].x = center.x + radius * sin(2. * M_PI * (double) n / num_nodes); 190 | node[n].x_ref = center.x + radius * sin(2. * M_PI * (double) n / num_nodes); 191 | node[n].y = radius * cos(2. * M_PI * (double) n / num_nodes); 192 | 193 | // Parametrization of the red blood cell shape in 2D 194 | 195 | if(node[n].y > 0) { 196 | node[n].y = center.y + sqrt(1 - SQ((center.x - node[n].x) / radius)) * (0.207 + 2.00 * SQ((center.x - node[n].x) / radius) - 1.12 * SQ(SQ((center.x - node[n].x) / radius))) * radius / 2; 197 | node[n].y_ref = center.y + sqrt(1 - SQ((center.x - node[n].x) / radius)) * (0.207 + 2.00 * SQ((center.x - node[n].x) / radius) - 1.12 * SQ(SQ((center.x - node[n].x) / radius))) * radius / 2; 198 | } 199 | else { 200 | node[n].y = center.y - sqrt(1 - SQ((center.x - node[n].x) / radius)) * (0.207 + 2.00 * SQ((center.x - node[n].x) / radius) - 1.12 * SQ(SQ((center.x - node[n].x) / radius))) * radius / 2; 201 | node[n].y_ref = center.y - sqrt(1 - SQ((center.x - node[n].x) / radius)) * (0.207 + 2.00 * SQ((center.x - node[n].x) / radius) - 1.12 * SQ(SQ((center.x - node[n].x) / radius))) * radius / 2; 202 | } 203 | #endif 204 | } 205 | } 206 | 207 | /// Elements 208 | 209 | int num_nodes; // number of surface nodes 210 | double radius; // object radius 211 | double stiffness; // stiffness modulus 212 | node_struct center; // center node 213 | node_struct *node; // list of nodes 214 | }; 215 | 216 | /// ***************** 217 | /// DECLARE FUNCTIONS 218 | /// ***************** 219 | 220 | // The following functions are used in the simulation code. 221 | 222 | void initialize(); // allocate memory and initialize variables 223 | void LBM(); // perform LBM operations 224 | void momenta(); // compute fluid density and velocity from the populations 225 | void equilibrium(double, double, double); // compute the equilibrium populations from the fluid density and velocity 226 | void compute_particle_forces(particle_struct); // compute the forces acting on the object nodes 227 | void spread(particle_struct); // spread node forces to fluid lattice 228 | void interpolate(particle_struct); // interpolate node velocities from fluid velocity 229 | void update_particle_position(particle_struct); // update object center position 230 | void write_fluid_vtk(int); // write the fluid state to the disk as VTK file 231 | void write_particle_vtk(int, particle_struct); // write the particle state to the disk as VTK file 232 | void write_data(int, particle_struct); // write data to the disk (drag/lift, center position) 233 | 234 | /// ************* 235 | /// MAIN FUNCTION 236 | /// ************* 237 | 238 | // This is the main function, containing the simulation initialization and the simulation loop. 239 | 240 | int main() { 241 | 242 | /// ************ 243 | /// PREPARATIONS 244 | /// ************ 245 | 246 | initialize(); // allocate memory and initialize variables 247 | particle_struct particle; // create immersed object 248 | 249 | /// Compute derived quantities 250 | 251 | const double D = Ny - 2; // inner channel diameter 252 | const double nu = (tau - 0.5) / 3; // lattice viscosity 253 | const double umax = gravity / (2 * nu) * SQ(0.5 * D); // expected maximum velocity for Poiseuille flow without immersed object 254 | const double Re = D * umax / nu; // Reynolds number for Poiseuille flow without immersed object 255 | 256 | /// Report derived parameters 257 | 258 | cout << "simulation parameters" << endl; 259 | cout << "=====================" << endl; 260 | cout << "D = " << D << endl; 261 | cout << "nu = " << nu << endl; 262 | cout << "umax = " << umax << endl; 263 | cout << "Re = " << Re << endl; 264 | cout << endl; 265 | 266 | /// *************** 267 | /// SIMULATION LOOP 268 | /// *************** 269 | 270 | // Overview of simulation algorithm: 271 | // 1) compute the node forces based on the object's deformation 272 | // 2) spread the node forces to the fluid lattice 273 | // 3) update the fluid state via LBM 274 | // 4) interpolate the fluid velocity to the object nodes 275 | // 5) update node positions and object's center 276 | // 6) if desired, write data to disk and report status 277 | 278 | cout << "starting simulation" << endl; 279 | 280 | for(int t = 1; t <= t_num; ++t) { // run over all times between 1 and t_num 281 | 282 | compute_particle_forces(particle); // compute particle forces 283 | spread(particle); // spread forces from the Lagrangian to the Eulerian mesh 284 | LBM(); // perform collision, propagation, and bounce-back 285 | interpolate(particle); // interpolate velocity 286 | update_particle_position(particle); // update particle position 287 | 288 | /// Write fluid and particle to VTK files 289 | // The data is only written each t_info time step. 290 | 291 | if(t % t_disk == 0) { 292 | write_fluid_vtk(t); 293 | write_particle_vtk(t, particle); 294 | write_data(t, particle); 295 | } 296 | 297 | /// Report end of time step 298 | 299 | if(t % t_info == 0) { 300 | cout << "completed time step " << t << " in [1, " << t_num << "]" << endl; 301 | } 302 | } 303 | 304 | /// Report successful end of simulation 305 | 306 | cout << "simulation complete" << endl; 307 | 308 | return 0; 309 | } // end of main function 310 | 311 | /// **************************************** 312 | /// ALLOCATE MEMORY AND INITIALIZE VARIABLES 313 | /// **************************************** 314 | 315 | // The memory for lattice variables (populations, density, velocity, forces) is allocated. 316 | // The variables are initialized. 317 | 318 | void initialize() { 319 | 320 | /// Create folders, delete data file 321 | // Make sure that the VTK folders exist. 322 | // Old file data.dat is deleted, if existing. 323 | 324 | int ignore; // ignore return value of system calls 325 | ignore = system("mkdir -p vtk_fluid"); // create folder if not existing 326 | ignore = system("mkdir -p vtk_particle"); // create folder if not existing 327 | ignore = system("rm -f data.dat"); // delete file if existing 328 | 329 | /// Allocate memory for the fluid density, velocity, and force 330 | 331 | density = new double*[Nx]; 332 | velocity_x = new double*[Nx]; 333 | velocity_y = new double*[Nx]; 334 | force_x = new double*[Nx]; 335 | force_y = new double*[Nx]; 336 | 337 | for(int X = 0; X < Nx; ++X) { 338 | density[X] = new double[Ny]; 339 | velocity_x[X] = new double[Ny]; 340 | velocity_y[X] = new double[Ny]; 341 | force_x[X] = new double[Ny]; 342 | force_y[X] = new double[Ny]; 343 | } 344 | 345 | /// Initialize the fluid density and velocity 346 | // Start with unit density and zero velocity. 347 | 348 | for(int X = 0; X < Nx; ++X) { 349 | for(int Y = 0; Y < Ny; ++Y) { 350 | density[X][Y] = 1; 351 | velocity_x[X][Y] = 0; 352 | velocity_y[X][Y] = 0; 353 | force_x[X][Y] = 0; 354 | force_y[X][Y] = 0; 355 | } 356 | } 357 | 358 | /// Allocate memory for the populations 359 | 360 | pop = new double**[9]; 361 | pop_old = new double**[9]; 362 | 363 | for(int c_i = 0; c_i < 9; ++c_i) { 364 | pop[c_i] = new double*[Nx]; 365 | pop_old[c_i] = new double*[Nx]; 366 | 367 | for(int X = 0; X < Nx; ++X) { 368 | pop[c_i][X] = new double[Ny]; 369 | pop_old[c_i][X] = new double[Ny]; 370 | 371 | for(int Y = 0; Y < Ny; ++Y) { 372 | pop[c_i][X][Y] = 0; 373 | pop_old[c_i][X][Y] = 0; 374 | } 375 | } 376 | } 377 | 378 | /// Initialize the populations 379 | // Use the equilibrium populations corresponding to the initialized fluid density and velocity. 380 | 381 | for(int X = 0; X < Nx; ++X) { 382 | for(int Y = 0; Y < Ny; ++Y) { 383 | equilibrium(density[X][Y], velocity_x[X][Y], velocity_y[X][Y]); 384 | 385 | for(int c_i = 0; c_i < 9; ++c_i) { 386 | pop_old[c_i][X][Y] = pop_eq[c_i]; 387 | pop[c_i][X][Y] = pop_eq[c_i]; 388 | } 389 | } 390 | } 391 | 392 | return; 393 | } 394 | 395 | /// ******************* 396 | /// COMPUTE EQUILIBRIUM 397 | /// ******************* 398 | 399 | // This function computes the equilibrium populations from the fluid density and velocity. 400 | // It computes the equilibrium only at a specific lattice node: Function has to be called at each lattice node. 401 | // The standard quadratic euilibrium is used. 402 | // reminder: SQ(x) = x * x 403 | 404 | void equilibrium(double den, double vel_x, double vel_y) { 405 | pop_eq[0] = weight[0] * den * (1 - 1.5 * (SQ(vel_x) + SQ(vel_y))); 406 | pop_eq[1] = weight[1] * den * (1 + 3 * ( vel_x ) + 4.5 * SQ( vel_x ) - 1.5 * (SQ(vel_x) + SQ(vel_y))); 407 | pop_eq[2] = weight[2] * den * (1 + 3 * (- vel_x ) + 4.5 * SQ(- vel_x ) - 1.5 * (SQ(vel_x) + SQ(vel_y))); 408 | pop_eq[3] = weight[3] * den * (1 + 3 * ( vel_y) + 4.5 * SQ( vel_y) - 1.5 * (SQ(vel_x) + SQ(vel_y))); 409 | pop_eq[4] = weight[4] * den * (1 + 3 * ( - vel_y) + 4.5 * SQ( - vel_y) - 1.5 * (SQ(vel_x) + SQ(vel_y))); 410 | pop_eq[5] = weight[5] * den * (1 + 3 * ( vel_x + vel_y) + 4.5 * SQ( vel_x + vel_y) - 1.5 * (SQ(vel_x) + SQ(vel_y))); 411 | pop_eq[6] = weight[6] * den * (1 + 3 * (- vel_x - vel_y) + 4.5 * SQ(- vel_x - vel_y) - 1.5 * (SQ(vel_x) + SQ(vel_y))); 412 | pop_eq[7] = weight[7] * den * (1 + 3 * ( vel_x - vel_y) + 4.5 * SQ( vel_x - vel_y) - 1.5 * (SQ(vel_x) + SQ(vel_y))); 413 | pop_eq[8] = weight[8] * den * (1 + 3 * (- vel_x + vel_y) + 4.5 * SQ(- vel_x + vel_y) - 1.5 * (SQ(vel_x) + SQ(vel_y))); 414 | 415 | return; 416 | } 417 | 418 | /// ********************** 419 | /// PERFORM LBM OPERATIONS 420 | /// ********************** 421 | 422 | void LBM() { 423 | 424 | /// Swap populations 425 | // The present code used old and new populations which are swapped at the beginning of each time step. 426 | // This is sometimes called 'double-buffered' or 'ping-pong' algorithm. 427 | // This way, the old populations are not overwritten during propagation. 428 | // The resulting code is easier to write and to debug. 429 | // The memory requirement for the populations is twice as large. 430 | 431 | double ***swap_temp = pop_old; 432 | pop_old = pop; 433 | pop = swap_temp; 434 | 435 | /// Lattice Boltzmann equation 436 | // The lattice Boltzmann equation is solved in the following. 437 | // The algorithm includes 438 | // - computation of the lattice force 439 | // - combined collision and propagation (faster than first collision and then propagation) 440 | 441 | for(int X = 0; X < Nx; ++X) { 442 | for(int Y = 1; Y < Ny - 1; ++Y) { 443 | 444 | /// Compute lattice force 445 | // The following code corresponds to Guo's forcing scheme. 446 | // Gravity is always along the x-axis. 447 | 448 | force_latt[0] = (1 - 0.5 * omega) * weight[0] * (3 * (( - velocity_x[X][Y]) * (force_x[X][Y] + gravity) + ( - velocity_y[X][Y]) * force_y[X][Y])); 449 | force_latt[1] = (1 - 0.5 * omega) * weight[1] * (3 * (( 1 - velocity_x[X][Y]) * (force_x[X][Y] + gravity) + ( - velocity_y[X][Y]) * force_y[X][Y]) + 9 * (velocity_x[X][Y]) * (force_x[X][Y] + gravity)); 450 | force_latt[2] = (1 - 0.5 * omega) * weight[2] * (3 * ((-1 - velocity_x[X][Y]) * (force_x[X][Y] + gravity) + ( - velocity_y[X][Y]) * force_y[X][Y]) + 9 * (velocity_x[X][Y]) * (force_x[X][Y] + gravity)); 451 | force_latt[3] = (1 - 0.5 * omega) * weight[3] * (3 * (( - velocity_x[X][Y]) * (force_x[X][Y] + gravity) + ( 1 - velocity_y[X][Y]) * force_y[X][Y]) + 9 * (velocity_y[X][Y]) * force_y[X][Y]); 452 | force_latt[4] = (1 - 0.5 * omega) * weight[4] * (3 * (( - velocity_x[X][Y]) * (force_x[X][Y] + gravity) + (-1 - velocity_y[X][Y]) * force_y[X][Y]) + 9 * (velocity_y[X][Y]) * force_y[X][Y]); 453 | force_latt[5] = (1 - 0.5 * omega) * weight[5] * (3 * (( 1 - velocity_x[X][Y]) * (force_x[X][Y] + gravity) + ( 1 - velocity_y[X][Y]) * force_y[X][Y]) + 9 * (velocity_x[X][Y] + velocity_y[X][Y]) * (force_x[X][Y] + gravity + force_y[X][Y])); 454 | force_latt[6] = (1 - 0.5 * omega) * weight[6] * (3 * ((-1 - velocity_x[X][Y]) * (force_x[X][Y] + gravity) + (-1 - velocity_y[X][Y]) * force_y[X][Y]) + 9 * (velocity_x[X][Y] + velocity_y[X][Y]) * (force_x[X][Y] + gravity + force_y[X][Y])); 455 | force_latt[7] = (1 - 0.5 * omega) * weight[7] * (3 * (( 1 - velocity_x[X][Y]) * (force_x[X][Y] + gravity) + (-1 - velocity_y[X][Y]) * force_y[X][Y]) + 9 * (velocity_x[X][Y] - velocity_y[X][Y]) * (force_x[X][Y] + gravity - force_y[X][Y])); 456 | force_latt[8] = (1 - 0.5 * omega) * weight[8] * (3 * ((-1 - velocity_x[X][Y]) * (force_x[X][Y] + gravity) + ( 1 - velocity_y[X][Y]) * force_y[X][Y]) + 9 * (velocity_x[X][Y] - velocity_y[X][Y]) * (force_x[X][Y] + gravity - force_y[X][Y])); 457 | 458 | /// Compute equilibrium 459 | // The equilibrium populations are computed. 460 | 461 | equilibrium(density[X][Y], velocity_x[X][Y], velocity_y[X][Y]); 462 | 463 | /// Compute new populations 464 | // This is the lattice Boltzmann equation (combined collision and propagation) including external forcing. 465 | // Periodicity of the lattice in x-direction is taken into account by the %-operator. 466 | 467 | pop[0][X] [Y] = pop_old[0][X][Y] * (1 - omega) + pop_eq[0] * omega + force_latt[ 0]; 468 | pop[1][(X + 1) % Nx] [Y] = pop_old[1][X][Y] * (1 - omega) + pop_eq[1] * omega + force_latt[ 1]; 469 | pop[2][(X - 1 + Nx) % Nx][Y] = pop_old[2][X][Y] * (1 - omega) + pop_eq[2] * omega + force_latt[ 2]; 470 | pop[3][X] [Y + 1] = pop_old[3][X][Y] * (1 - omega) + pop_eq[3] * omega + force_latt[ 3]; 471 | pop[4][X] [Y - 1] = pop_old[4][X][Y] * (1 - omega) + pop_eq[4] * omega + force_latt[ 4]; 472 | pop[5][(X + 1) % Nx] [Y + 1] = pop_old[5][X][Y] * (1 - omega) + pop_eq[5] * omega + force_latt[ 5]; 473 | pop[6][(X - 1 + Nx) % Nx][Y - 1] = pop_old[6][X][Y] * (1 - omega) + pop_eq[6] * omega + force_latt[ 6]; 474 | pop[7][(X + 1) % Nx] [Y - 1] = pop_old[7][X][Y] * (1 - omega) + pop_eq[7] * omega + force_latt[ 7]; 475 | pop[8][(X - 1 + Nx) % Nx][Y + 1] = pop_old[8][X][Y] * (1 - omega) + pop_eq[8] * omega + force_latt[ 8]; 476 | } 477 | } 478 | 479 | /// Bounce-back 480 | // Due to the presence of the rigid walls at y = 0 and y = Ny - 1, the populations have to be bounced back. 481 | // Ladd's momentum correction term is included for moving walls (wall velocity parallel to x-axis). 482 | // Periodicity of the lattice in x-direction is taken into account via the %-operator. 483 | 484 | for(int X = 0; X < Nx; ++X) { 485 | 486 | /// Bottom wall (y = 0) 487 | 488 | pop[3][X][1] = pop[4][X] [0]; 489 | pop[5][X][1] = pop[6][(X - 1 + Nx) % Nx][0] + 6 * weight[6] * density[X][1] * wall_vel_bottom; 490 | pop[8][X][1] = pop[7][(X + 1) % Nx] [0] - 6 * weight[7] * density[X][1] * wall_vel_bottom; 491 | 492 | /// Top wall (y = Ny - 1) 493 | 494 | pop[4][X][Ny - 2] = pop[3][X] [Ny - 1]; 495 | pop[6][X][Ny - 2] = pop[5][(X + 1) % Nx] [Ny - 1] - 6 * weight[5] * density[X][Ny - 2] * wall_vel_top; 496 | pop[7][X][Ny - 2] = pop[8][(X - 1 + Nx) % Nx][Ny - 1] + 6 * weight[8] * density[X][Ny - 2] * wall_vel_top; 497 | } 498 | 499 | /// Compute fluid density and velocity 500 | // The fluid density and velocity are obtained from the populations. 501 | 502 | momenta(); 503 | 504 | return; 505 | } 506 | 507 | /// ********************************** 508 | /// COMPUTE FLUID DENSITY AND VELOCITY 509 | /// ********************************** 510 | 511 | // This function computes the fluid density and velocity from the populations. 512 | // The velocity correction due to body force is included (Guo's forcing). 513 | 514 | void momenta() { 515 | for(int X = 0; X < Nx; ++X) { 516 | for(int Y = 1; Y < Ny - 1; ++Y) { 517 | density[X][Y] = pop[0][X][Y] + pop[1][X][Y] + pop[2][X][Y] + pop[3][X][Y] + pop[4][X][Y] + pop[5][X][Y] + pop[6][X][Y] + pop[7][X][Y] + pop[8][X][Y]; 518 | velocity_x[X][Y] = (pop[1][X][Y] - pop[2][X][Y] + pop[5][X][Y] - pop[6][X][Y] + pop[7][X][Y] - pop[8][X][Y] + 0.5 * (force_x[X][Y] + gravity)) / density[X][Y]; 519 | velocity_y[X][Y] = (pop[3][X][Y] - pop[4][X][Y] + pop[5][X][Y] - pop[6][X][Y] - pop[7][X][Y] + pop[8][X][Y] + 0.5 * force_y[X][Y]) / density[X][Y]; 520 | } 521 | } 522 | 523 | return; 524 | } 525 | 526 | /// *********************** 527 | /// COMPUTE PARTICLE FORCES 528 | /// *********************** 529 | 530 | // The forces acting on the object nodes are computed. 531 | // Depending on the simulation type (rigid/deformable cylinder or red blood cell), 532 | // the force computation is different. 533 | 534 | void compute_particle_forces(particle_struct particle) { 535 | 536 | /// Reset forces 537 | // This way, the force from the previous time step is deleted. 538 | // This is necessary whenever forces are computed using '+='. 539 | 540 | for(int n = 0; n < particle.num_nodes; ++n) { 541 | particle.node[n].force_x = 0; 542 | particle.node[n].force_y = 0; 543 | } 544 | 545 | /// Compute strain forces 546 | // The strain forces are proportional to the relative displacement of a node with respect to its two neighbors. 547 | // This force is invariant under displacements and rotations, 548 | // i.e., it is only sensitive to deformations. 549 | // Newton's law is fulfilled: sum of forces is zero. 550 | // In order to make the force distribution smoother, each node is assigned an equivalent area. 551 | // This area is the circumference of the cylinder divided by the number of surface nodes. 552 | 553 | #if defined DEFORMABLE_CYLINDER || defined DEFORMABLE_RBC 554 | const double area = 2 * M_PI * particle.radius / particle.num_nodes; // area belonging to a node 555 | 556 | for(int n = 0; n < particle.num_nodes; ++n) { 557 | const double distance = sqrt(SQ(particle.node[n].x - particle.node[(n + 1) % particle.num_nodes].x) + SQ(particle.node[n].y - particle.node[(n + 1) % particle.num_nodes].y)); // current distance between neighboring nodes 558 | const double distance_ref = sqrt(SQ(particle.node[n].x_ref - particle.node[(n + 1) % particle.num_nodes].x_ref) + SQ(particle.node[n].y_ref - particle.node[(n + 1) % particle.num_nodes].y_ref)); // reference distance between neighboring nodes 559 | const double f_x = particle.stiffness * (distance - distance_ref) * (particle.node[n].x - particle.node[(n + 1) % particle.num_nodes].x); 560 | const double f_y = particle.stiffness * (distance - distance_ref) * (particle.node[n].y - particle.node[(n + 1) % particle.num_nodes].y); 561 | particle.node[n].force_x += -f_x; 562 | particle.node[n].force_y += -f_y; 563 | particle.node[(n + 1) % particle.num_nodes].force_x += f_x; 564 | particle.node[(n + 1) % particle.num_nodes].force_y += f_y; 565 | } 566 | #endif 567 | 568 | /// Compute bending forces 569 | 570 | #if defined DEFORMABLE_CYLINDER || defined DEFORMABLE_RBC 571 | for(int n = 0; n < particle.num_nodes; ++n) { 572 | 573 | /// Get node coordinates for bending 574 | 575 | const double x_l = particle.node[(n - 1 + particle.num_nodes) % particle.num_nodes].x; 576 | const double y_l = particle.node[(n - 1 + particle.num_nodes) % particle.num_nodes].y; 577 | const double x_m = particle.node[n].x; 578 | const double y_m = particle.node[n].y; 579 | const double x_r = particle.node[(n + 1) % particle.num_nodes].x; 580 | const double y_r = particle.node[(n + 1) % particle.num_nodes].y; 581 | const double x_l_ref = particle.node[(n - 1 + particle.num_nodes) % particle.num_nodes].x_ref; 582 | const double y_l_ref = particle.node[(n - 1 + particle.num_nodes) % particle.num_nodes].y_ref; 583 | const double x_m_ref = particle.node[n].x_ref; 584 | const double y_m_ref = particle.node[n].y_ref; 585 | const double x_r_ref = particle.node[(n + 1) % particle.num_nodes].x_ref; 586 | const double y_r_ref = particle.node[(n + 1) % particle.num_nodes].y_ref; 587 | 588 | /// Compute normal vector direction 589 | 590 | const double tang_x_ref = x_r_ref - x_l_ref; 591 | const double tang_y_ref = y_r_ref - y_l_ref; 592 | double normal_x_ref; 593 | double normal_y_ref; 594 | 595 | if(abs(tang_x_ref) < abs(tang_y_ref)) { 596 | normal_x_ref = 1; 597 | normal_y_ref = -tang_x_ref / tang_y_ref; 598 | } 599 | else { 600 | normal_y_ref = 1; 601 | normal_x_ref = -tang_y_ref / tang_x_ref; 602 | } 603 | 604 | const double tang_x = x_r - x_l; 605 | const double tang_y = y_r - y_l; 606 | double normal_x; 607 | double normal_y; 608 | 609 | if(abs(tang_x) < abs(tang_y)) { 610 | normal_x = 1; 611 | normal_y = -tang_x / tang_y; 612 | } 613 | else { 614 | normal_y = 1; 615 | normal_x = -tang_y / tang_x; 616 | } 617 | 618 | /// Normalize normal vector to unit length and outward direction 619 | 620 | const double normal_length_ref = sqrt(SQ(normal_x_ref) + SQ(normal_y_ref)); 621 | normal_x_ref /= normal_length_ref; 622 | normal_y_ref /= normal_length_ref; 623 | 624 | if(normal_x_ref * tang_y_ref - normal_y_ref * tang_x_ref > 0) { 625 | normal_x_ref *= -1; 626 | normal_y_ref *= -1; 627 | } 628 | 629 | const double normal_length = sqrt(SQ(normal_x) + SQ(normal_y)); 630 | normal_x /= normal_length; 631 | normal_y /= normal_length; 632 | 633 | if(normal_x * tang_y - normal_y * tang_x > 0) { 634 | normal_x *= -1; 635 | normal_y *= -1; 636 | } 637 | 638 | /// Compute bending angles 639 | 640 | double angle_cos = (x_l - x_m) * (x_m - x_r) + (y_l - y_m) * (y_m - y_r); 641 | angle_cos /= (sqrt(SQ(x_l - x_m) + SQ(y_l - y_m)) * sqrt(SQ(x_m - x_r) + SQ(y_m - y_r))); 642 | double angle = acos(angle_cos); 643 | double angle_ref_cos = (x_l_ref - x_m_ref) * (x_m_ref - x_r_ref) + (y_l_ref - y_m_ref) * (y_m_ref - y_r_ref); 644 | angle_ref_cos /= (sqrt(SQ(x_l_ref - x_m_ref) + SQ(y_l_ref - y_m_ref)) * sqrt(SQ(x_m_ref - x_r_ref) + SQ(y_m_ref - y_r_ref))); 645 | double angle_ref = acos(angle_ref_cos); 646 | 647 | const double convex_x_ref = (x_l_ref + x_r_ref) / 2 - x_m_ref; 648 | const double convex_y_ref = (y_l_ref + y_r_ref) / 2 - y_m_ref; 649 | 650 | if(convex_x_ref * normal_x_ref + convex_y_ref * normal_y_ref > 0) { 651 | angle_ref *= -1; 652 | } 653 | 654 | const double convex_x = (x_l + x_r) / 2 - x_m; 655 | const double convex_y = (y_l + y_r) / 2 - y_m; 656 | 657 | if(convex_x * normal_x + convex_y * normal_y > 0) { 658 | angle *= -1; 659 | } 660 | 661 | /// Compute force magnitude 662 | 663 | const double force_mag = particle_bending * (angle - angle_ref); 664 | const double length_l = abs(tang_x * (x_m - x_l) + tang_y * (y_m - y_l)); 665 | const double length_r = abs(tang_x * (x_m - x_r) + tang_y * (y_m - y_r)); 666 | 667 | particle.node[(n - 1 + particle.num_nodes) % particle.num_nodes].force_x += normal_x * force_mag * length_l / (length_l + length_r); 668 | particle.node[(n - 1 + particle.num_nodes) % particle.num_nodes].force_y += normal_y * force_mag * length_l / (length_l + length_r); 669 | particle.node[n].force_x += -normal_x * force_mag; 670 | particle.node[n].force_y += -normal_y * force_mag; 671 | particle.node[(n + 1) % particle.num_nodes].force_x += normal_x * force_mag * length_r / (length_l + length_r); 672 | particle.node[(n + 1) % particle.num_nodes].force_y += normal_y * force_mag * length_r / (length_l + length_r); 673 | } 674 | #endif 675 | 676 | /// Compute rigid forces 677 | // Here, the node forces are proportional to the displacement with respect to the reference position. 678 | 679 | #ifdef RIGID_CYLINDER 680 | const double area = 2 * M_PI * particle.radius / particle.num_nodes; // area belonging to a node 681 | 682 | for(int n = 0; n < particle.num_nodes; ++n) { 683 | particle.node[n].force_x = -particle.stiffness * (particle.node[n].x - particle.node[n].x_ref) * area; 684 | particle.node[n].force_y = -particle.stiffness * (particle.node[n].y - particle.node[n].y_ref) * area; 685 | } 686 | #endif 687 | 688 | return; 689 | } 690 | 691 | /// ************* 692 | /// SPREAD FORCES 693 | /// ************* 694 | 695 | // The node forces are spread to the fluid nodes via IBM. 696 | // The two-point interpolation stencil (bi-linear interpolation) is used in the present code. 697 | // It may be replaced by a higher-order interpolation. 698 | 699 | void spread(particle_struct particle) { 700 | 701 | /// Reset forces 702 | // This is necessary since '+=' is used afterwards. 703 | 704 | for(int X = 0; X < Nx; ++X) { 705 | for(int Y = 1; Y < Ny - 1; ++Y) { 706 | force_x[X][Y] = 0; 707 | force_y[X][Y] = 0; 708 | } 709 | } 710 | 711 | /// Spread forces 712 | // Run over all object nodes. 713 | 714 | for(int n = 0; n < particle.num_nodes; ++n) { 715 | 716 | // Identify the lowest fluid lattice node in interpolation range. 717 | // 'Lowest' means: its x- and y-values are the smallest. 718 | // The other fluid nodes in range have coordinates 719 | // (x_int + 1, y_int), (x_int, y_int + 1), and (x_int + 1, y_int + 1). 720 | 721 | int x_int = (int) (particle.node[n].x - 0.5 + Nx) - Nx; 722 | int y_int = (int) (particle.node[n].y + 0.5); 723 | 724 | // Run over all neighboring fluid nodes. 725 | // In the case of the two-point interpolation, it is 2x2 fluid nodes. 726 | 727 | for(int X = x_int; X <= x_int + 1; ++X) { 728 | for(int Y = y_int; Y <= y_int + 1; ++Y) { 729 | 730 | // Compute distance between object node and fluid lattice node. 731 | 732 | const double dist_x = particle.node[n].x - 0.5 - X; 733 | const double dist_y = particle.node[n].y + 0.5 - Y; 734 | 735 | // Compute interpolation weights for x- and y-direction based on the distance. 736 | 737 | const double weight_x = 1 - abs(dist_x); 738 | const double weight_y = 1 - abs(dist_y); 739 | 740 | // Compute lattice force. 741 | 742 | force_x[(X + Nx) % Nx][Y] += (particle.node[n].force_x * weight_x * weight_y); 743 | force_y[(X + Nx) % Nx][Y] += (particle.node[n].force_y * weight_x * weight_y); 744 | } 745 | } 746 | } 747 | 748 | return; 749 | } 750 | 751 | /// ********************** 752 | /// INTERPOLATE VELOCITIES 753 | /// ********************** 754 | 755 | // The node velocities are interpolated from the fluid nodes via IBM. 756 | // The two-point interpolation stencil (bi-linear interpolation) is used in the present code. 757 | // It may be replaced by a higher-order interpolation. 758 | 759 | void interpolate(particle_struct particle) { 760 | 761 | // Run over all object nodes. 762 | 763 | for(int n = 0; n < particle.num_nodes; ++n) { 764 | 765 | // Reset node velocity first since '+=' is used. 766 | 767 | particle.node[n].vel_x = 0; 768 | particle.node[n].vel_y = 0; 769 | 770 | // Identify the lowest fluid lattice node in interpolation range (see spreading). 771 | 772 | int x_int = (int) (particle.node[n].x - 0.5 + Nx) - Nx; 773 | int y_int = (int) (particle.node[n].y + 0.5); 774 | 775 | // Run over all neighboring fluid nodes. 776 | // In the case of the two-point interpolation, it is 2x2 fluid nodes. 777 | 778 | for(int X = x_int; X <= x_int + 1; ++X) { 779 | for(int Y = y_int; Y <= y_int + 1; ++Y) { 780 | 781 | // Compute distance between object node and fluid lattice node. 782 | 783 | const double dist_x = particle.node[n].x - 0.5 - X; 784 | const double dist_y = particle.node[n].y + 0.5 - Y; 785 | 786 | // Compute interpolation weights for x- and y-direction based on the distance. 787 | 788 | const double weight_x = 1 - abs(dist_x); 789 | const double weight_y = 1 - abs(dist_y); 790 | 791 | // Compute node velocities. 792 | 793 | particle.node[n].vel_x += (velocity_x[(X + Nx) % Nx][Y] * weight_x * weight_y); 794 | particle.node[n].vel_y += (velocity_y[(X + Nx) % Nx][Y] * weight_x * weight_y); 795 | } 796 | } 797 | } 798 | 799 | return; 800 | } 801 | 802 | /// ************************ 803 | /// UPDATE PARTICLE POSITION 804 | /// ************************ 805 | 806 | // The position of the particle nodes are updated according to their velocity. 807 | // The center position is updated as well. 808 | // The new node position is its old position plus its current velocity (Euler integration). 809 | // The center position is the arithmetic mean of all node positions. 810 | // Periodicity is taken into account: 811 | // If the particle center leaves the system domain (x < 0 or x >= Nx), it reenters from the other side. 812 | 813 | void update_particle_position(particle_struct particle) { 814 | 815 | /// Reset center position 816 | 817 | particle.center.x = 0; 818 | particle.center.y = 0; 819 | 820 | /// Update node and center positions 821 | 822 | for(int n = 0; n < particle.num_nodes; ++n) { 823 | particle.node[n].x += particle.node[n].vel_x; 824 | particle.node[n].y += particle.node[n].vel_y; 825 | particle.center.x += particle.node[n].x / particle.num_nodes; 826 | particle.center.y += particle.node[n].y / particle.num_nodes; 827 | } 828 | 829 | /// Check for periodicity along the x-axis 830 | 831 | if(particle.center.x < 0) { 832 | particle.center.x += Nx; 833 | 834 | for(int n = 0; n < particle.num_nodes; ++n) { 835 | particle.node[n].x += Nx; 836 | } 837 | } 838 | else if(particle.center.x >= Nx) { 839 | particle.center.x -= Nx; 840 | 841 | for(int n = 0; n < particle.num_nodes; ++n) { 842 | particle.node[n].x -= Nx; 843 | } 844 | } 845 | 846 | return; 847 | } 848 | 849 | /// ***************************** 850 | /// WRITE FLUID STATE TO VTK FILE 851 | /// ***************************** 852 | 853 | // The fluid state is writen to a VTK file at each t_disk step. 854 | // The following data is written: 855 | // - density difference (density - 1) 856 | // - x-component of velocity 857 | // - y-component of velocity 858 | // The following code is designed in such a way that the file can be read by ParaView. 859 | 860 | void write_fluid_vtk(int time) { 861 | 862 | /// Create filename 863 | 864 | stringstream output_filename; 865 | output_filename << "vtk_fluid/fluid_t" << time << ".vtk"; 866 | ofstream output_file; 867 | 868 | /// Open file 869 | 870 | output_file.open(output_filename.str().c_str()); 871 | 872 | /// Write VTK header 873 | 874 | output_file << "# vtk DataFile Version 3.0\n"; 875 | output_file << "fluid_state\n"; 876 | output_file << "ASCII\n"; 877 | output_file << "DATASET RECTILINEAR_GRID\n"; 878 | output_file << "DIMENSIONS " << Nx << " " << Ny - 2 << " 1" << "\n"; 879 | output_file << "X_COORDINATES " << Nx << " float\n"; 880 | 881 | for(int X = 0; X < Nx; ++X) { 882 | output_file << X + 0.5 << " "; 883 | } 884 | 885 | output_file << "\n"; 886 | output_file << "Y_COORDINATES " << Ny - 2 << " float\n"; 887 | 888 | for(int Y = 1; Y < Ny - 1; ++Y) { 889 | output_file << Y - 0.5 << " "; 890 | } 891 | 892 | output_file << "\n"; 893 | output_file << "Z_COORDINATES " << 1 << " float\n"; 894 | output_file << 0 << "\n"; 895 | output_file << "POINT_DATA " << Nx * (Ny - 2) << "\n"; 896 | 897 | /// Write density difference 898 | 899 | output_file << "SCALARS density_difference float 1\n"; 900 | output_file << "LOOKUP_TABLE default\n"; 901 | 902 | for(int Y = 1; Y < Ny - 1; ++Y) { 903 | for(int X = 0; X < Nx; ++X) { 904 | output_file << density[X][Y] - 1 << "\n"; 905 | } 906 | } 907 | 908 | /// Write velocity 909 | 910 | output_file << "VECTORS velocity_vector float\n"; 911 | 912 | for(int Y = 1; Y < Ny - 1; ++Y) { 913 | for(int X = 0; X < Nx; ++X) { 914 | output_file << velocity_x[X][Y] << " " << velocity_y[X][Y] << " 0\n"; 915 | } 916 | } 917 | 918 | /// Close file 919 | 920 | output_file.close(); 921 | 922 | return; 923 | } 924 | 925 | /// ******************************** 926 | /// WRITE PARTICLE STATE TO VTK FILE 927 | /// ******************************** 928 | 929 | // The particle state (node positions) is writen to a VTK file at each t_disk step. 930 | // The following code is designed in such a way that the file can be read by ParaView. 931 | 932 | void write_particle_vtk(int time, particle_struct particle) { 933 | 934 | /// Create filename 935 | 936 | stringstream output_filename; 937 | output_filename << "vtk_particle/particle_t" << time << ".vtk"; 938 | ofstream output_file; 939 | 940 | /// Open file 941 | 942 | output_file.open(output_filename.str().c_str()); 943 | 944 | /// Write VTK header 945 | 946 | output_file << "# vtk DataFile Version 3.0\n"; 947 | output_file << "particle_state\n"; 948 | output_file << "ASCII\n"; 949 | output_file << "DATASET POLYDATA\n"; 950 | 951 | /// Write node positions 952 | 953 | output_file << "POINTS " << particle_num_nodes << " float\n"; 954 | 955 | for(int n = 0; n < particle_num_nodes; ++n) { 956 | output_file << particle.node[n].x << " " << particle.node[n].y << " 0\n"; 957 | } 958 | 959 | /// Write lines between neighboring nodes 960 | 961 | output_file << "LINES " << particle_num_nodes << " " << 3 * particle_num_nodes << "\n"; 962 | 963 | for(int n = 0; n < particle_num_nodes; ++n) { 964 | output_file << "2 " << n << " " << (n + 1) % particle_num_nodes << "\n"; 965 | } 966 | 967 | /// Write vertices 968 | 969 | output_file << "VERTICES 1 " << particle_num_nodes + 1 << "\n"; 970 | output_file << particle_num_nodes << " "; 971 | 972 | for(int n = 0; n < particle_num_nodes; ++n) { 973 | output_file << n << " "; 974 | } 975 | 976 | /// Close file 977 | 978 | output_file.close(); 979 | 980 | return; 981 | } 982 | 983 | /// ************************ 984 | /// WRITE DATA TO ASCII FILE 985 | /// ************************ 986 | 987 | // The following quantities are written to the disk at each t_disk step: 988 | // - drag and lift forces (x- and y-components of the force) 989 | // - object center position (x- and y-components) 990 | // - object center velocity (x- and y-components) 991 | // The data file is readable by gnuplot 992 | 993 | void write_data(int time, particle_struct particle) { 994 | 995 | /// Create filename 996 | 997 | string output_filename("data.dat"); 998 | ofstream output_file; 999 | 1000 | /// Open file 1001 | 1002 | output_file.open(output_filename.c_str(), fstream::app); 1003 | 1004 | /// Compute quantities 1005 | 1006 | double force_tot_x = 0; 1007 | double force_tot_y = 0; 1008 | double vel_center_x = 0; 1009 | double vel_center_y = 0; 1010 | 1011 | for(int i = 0; i < particle.num_nodes; ++i) { 1012 | force_tot_x += particle.node[i].force_x; 1013 | force_tot_y += particle.node[i].force_y; 1014 | vel_center_x += particle.node[i].vel_x; 1015 | vel_center_y += particle.node[i].vel_y; 1016 | } 1017 | 1018 | /// Write data 1019 | 1020 | output_file << time << " "; // time step 1021 | output_file << force_tot_x << " "; // drag force 1022 | output_file << force_tot_y << " "; // lift force 1023 | output_file << particle.center.x << " "; // center position (x-component) 1024 | output_file << particle.center.y << " "; // center position (y-component) 1025 | output_file << vel_center_x << " "; // center velocity (x-component) 1026 | output_file << vel_center_y << "\n"; // center velocity (y-component) 1027 | 1028 | /// Close file 1029 | 1030 | output_file.close(); 1031 | 1032 | return; 1033 | } 1034 | --------------------------------------------------------------------------------