Advertisement
Guest User

Untitled

a guest
Oct 9th, 2017
76
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Fortran 10.20 KB | None | 0 0
  1. program NaverStokesSolver
  2.   implicit none
  3.   integer :: i, j
  4.   integer, parameter :: nx = 60
  5.   integer, parameter :: ny = 30
  6.   double precision, parameter :: t_end = 0.5
  7.   double precision :: t
  8.   double precision, parameter :: dx = 4.0/(nx-1.0)
  9.   double precision, parameter :: dy = 1.0/(ny-1.0)
  10.   double precision, parameter :: nu = 0.025
  11.   double precision, parameter :: rho = 1.0
  12.   double precision, dimension(nx,ny) :: u, v, us, vs, un, vn, P
  13.   double precision, dimension(nx,ny) :: us1, vs1, us2, vs2
  14.   double precision, dimension(nx,ny) :: x, y
  15.   double precision :: dt = 0.003
  16.   double precision, dimension(nx,ny) :: uMtm, vMtm, uMtm1, vMtm1, uMtm2, vMtm2
  17.  
  18.   !Initial condition
  19.   call CartesianGrid(x,y,dx,dy)
  20.   call InitialCondition(u,v,P)
  21.  
  22.   t = 0.0
  23.   do while (t <= t_end)
  24.     call Momentum(u, v, uMtm, vMtm)
  25.  
  26.     ! TVD RK3 step 1
  27.     do j=2,ny-1
  28.         do i=2,nx-1
  29.             us1(i,j) = u(i,j) + dt*uMtm(i,j)
  30.             vs1(i,j) = v(i,j) + dt*vMtm(i,j)
  31.         end do
  32.     end do
  33.  
  34.     call IntermediateBC(us1,vs1,un,vn,P)
  35.     call Momentum(us1,vs1,uMtm1,vMtm1)
  36.  
  37.     ! TVD RK3 step 2
  38.     do j=2,ny-1
  39.         do i=2,nx-1
  40.             us2(i,j) = (3.0/4.0)*u(i,j) + (1.0/4.0)*us1(i,j) + (dt/4.0)*uMtm1(i,j)
  41.             vs2(i,j) = (3.0/4.0)*v(i,j) + (1.0/4.0)*vs1(i,j) + (dt/4.0)*vMtm1(i,j)
  42.         end do
  43.     end do
  44.  
  45.     call IntermediateBC(us2,vs2,un,vn,P)
  46.     call Momentum(us2,vs2,uMtm2,vMtm2)
  47.  
  48.     ! TVD RK3 step 3
  49.     do j=2,ny-1
  50.         do i=2,nx-1
  51.             us(i,j) = (1.0/3.0)*u(i,j) + (2.0/3.0)*us2(i,j) + ((2.0*dt)/3.0)*uMtm2(i,j)
  52.             vs(i,j) = (1.0/3.0)*v(i,j) + (2.0/3.0)*vs2(i,j) + ((2.0*dt)/3.0)*vMtm2(i,j)
  53.         end do
  54.     end do
  55.  
  56.     ! Solve for P
  57.     call IntermediateBC(us,vs,un,vn,P)
  58.     call PressureSolver(P,us,vs,un,vn)
  59.  
  60.     ! Corrector step
  61.     do j=2,ny-1
  62.       do i=2,nx-1
  63.         un(i,j) = us(i,j) - (dt/(2.0*dx*rho))*(P(i+1,j) - P(i-1,j))
  64.         vn(i,j) = vs(i,j) - (dt/(2.0*dy*rho))*(P(i,j+1) - P(i,j-1))
  65.       end do
  66.     end do
  67.  
  68.     call BoundaryConditions(un,vn)
  69.  
  70.     u = un
  71.     v = vn
  72.  
  73.     t = t + dt
  74.  
  75.     print *, "t = ", t
  76.   end do
  77.  
  78.   open(12,file='uvelocity.dat',status='replace')
  79.     do i=1,nx
  80.        write(12,'(1000F14.7)') (un(i,j),j=1,ny)
  81.     end do
  82.   close(12)
  83.  
  84.   open(10,file='pressure.dat',status='replace')
  85.   do i=1,nx
  86.      write(10,'(1000F14.7)') (P(i,j),j=1,ny)
  87.   end do
  88.   close(10)
  89.  
  90.   open(10,file='xcoord.dat',status='replace')
  91.   do i=1,nx
  92.      write(10,'(1000F14.7)') (x(i,j),j=1,ny)
  93.   end do
  94.   close(10)
  95.  
  96.   open(10,file='ycoord.dat',status='replace')
  97.   do i=1,nx
  98.      write(10,'(1000F14.7)') (y(i,j),j=1,ny)
  99.   end do
  100.   close(10)
  101.  
  102. contains
  103.  
  104. subroutine BoundaryConditions (u, v)
  105.       implicit none
  106.       double precision, dimension(nx,ny), intent(out) :: u, v
  107.       integer :: i, j
  108.  
  109.       do i=1,nx
  110.           u(i,1) = 0.0
  111.           u(i,ny) = 0.0
  112.           v(i,1) = 0.0
  113.           v(i,ny) = 0.0
  114.       end do
  115.  
  116.       do j=1,ny
  117.           u(nx,j) = u(nx-1,j)
  118.           v(1,j) = 0.0
  119.           v(nx,j) = v(nx-1,j)
  120.       end do
  121.  
  122.       do j=15,17
  123.           u(1,j) = y(1,j)*(2.0 - y(1,j))
  124.       end do
  125.       return
  126. end subroutine BoundaryConditions
  127.  
  128. !2nd-order BC as in Kim and Moin
  129. subroutine IntermediateBC (us, vs, un, vn, P)
  130.         implicit none
  131.         integer :: i, j
  132.         double precision, dimension(nx,ny), intent(out) :: un, vn, us, vs, P
  133.  
  134.         do j=1,ny
  135.             us(1,j) = un(1,j) + (dt/dx)*(P(2,j) - P(1,j))
  136.             us(nx,j) = un(nx,j) + (dt/dx)*(P(nx,j) - P(nx-1,j))
  137.  
  138.             vs(1,j) = vn(1,j) + (dt/dx)*(P(2,j) - P(1,j))
  139.             vs(nx,j) = vn(nx,j) + (dt/dx)*(P(nx,j) - P(nx-1,j))
  140.         end do
  141.  
  142.         do i=1,nx
  143.             us(i,1) = un(i,1) + (dt/dy)*(P(i,2) - P(i,1))
  144.             us(i,ny) = un(i,ny) + (dt/dy)*(P(i,ny) - P(i,ny-1))
  145.  
  146.             vs(i,1) = vn(i,1) + (dt/dy)*(P(i,2) - P(i,1))
  147.             vs(i,ny) = vn(i,ny) + (dt/dy)*(P(i,ny) - P(i,ny-1))
  148.         end do
  149.  
  150.         return
  151. end subroutine IntermediateBC
  152.  
  153. subroutine CartesianGrid (x, y, dx, dy)
  154.       implicit none
  155.       integer :: i, j
  156.       double precision, dimension(nx,ny), intent(out) :: x, y
  157.       double precision, intent(in) :: dx, dy
  158.  
  159.       do j=1,ny
  160.         do i=1,nx
  161.           x(i,j) = (i-1.0)*dx
  162.           y(i,j) = (j-1.0)*dy
  163.         end do
  164.       end do
  165. end subroutine CartesianGrid
  166.  
  167. subroutine InitialCondition (u, v, P)
  168.       implicit none
  169.       double precision, dimension(nx,ny), intent(out) :: u, v, P
  170.  
  171.       do j=1,ny
  172.         do i=1,nx
  173.           u(i,j) = 0.0
  174.           v(i,j) = 0.0
  175.           P(i,j) = 0.0
  176.         end do
  177.       end do
  178. end subroutine InitialCondition
  179.  
  180. ! 2nd-order central differencing for diffusion and advection
  181. subroutine Momentum (u, v, uMtm, vMtm)
  182.     implicit none
  183.     integer :: i, j
  184.     double precision, dimension(nx,ny), intent(out) :: uMtm, vMtm
  185.     double precision, dimension(nx,ny), intent(inout) :: u, v
  186.     double precision, dimension(nx,ny) :: Cx, Cy;
  187.     double precision, dimension(nx,ny) :: Vx, Vy
  188.     double precision, dimension(nx,ny) :: uf, vf
  189.  
  190.     call FaceVelocities(u,v,uf,vf)
  191.     call BoundaryConditions(uf,vf)
  192.  
  193.     do j=2,ny-1
  194.         do i=2,nx-1
  195.             Cx(i,j) = (1.0/dx)*(uf(i,j)*uf(i,j) - uf(i-1,j)*uf(i-1,j)) + (1.0/dy)*(uf(i,j)*vf(i,j) - uf(i,j-1)*vf(i,j-1))
  196.             Cy(i,j) = (1.0/dx)*(uf(i,j)*vf(i,j) - uf(i-1,j)*vf(i-1,j)) + (1.0/dy)*(vf(i,j)*vf(i,j) - vf(i,j-1)*vf(i,j-1))
  197.  
  198.             Vx(i,j) = nu*((1.0/dx**2)*(u(i-1,j) - 2.0*u(i,j) + u(i+1,j)) + (1.0/dy**2)*(u(i,j-1) - 2.0*u(i,j) + u(i,j+1)))
  199.             Vy(i,j) = nu*((1.0/dx**2)*(v(i-1,j) - 2.0*v(i,j) + v(i+1,j)) + (1.0/dy**2)*(v(i,j-1) - 2.0*v(i,j) + v(i,j+1)))
  200.  
  201.             uMtm(i,j) = -Cx(i,j) + Vx(i,j)
  202.             vMtm(i,j) = -Cy(i,j) + Vy(i,j)
  203.         end do
  204.     end do
  205.     return
  206. end subroutine
  207.  
  208. subroutine PressureSolver (P, us, vs, u, v)
  209.     implicit none
  210.     integer :: i, j
  211.     double precision, dimension(nx,ny), intent(out) :: P
  212.     double precision, dimension(nx,ny), intent(in) :: us, vs
  213.     double precision, dimension(nx,ny), intent(in) :: u, v
  214.     double precision, dimension(nx,ny) :: vfs, ufs
  215.     double precision, dimension(nx,ny) :: R, Res
  216.     double precision, parameter :: inv_dxx = 1.0/dx**2
  217.     double precision, parameter :: inv_dyy  = 1.0/dy**2
  218.     double precision, parameter :: inv_dx = 1.0/dx
  219.     double precision, parameter :: inv_dy = 1.0/dy
  220.     double precision, parameter :: tol = 1e-6
  221.     double precision, parameter :: iter_max = 16000
  222.     double precision, parameter :: omega = 1.96
  223.     double precision :: L2_Error
  224.     double precision :: iter
  225.  
  226.     call FaceVelocities(us,vs,ufs,vfs)
  227.     call BoundaryConditions(ufs,vfs)
  228.  
  229.     do j=3,ny-2
  230.         do i=3,nx-2
  231.             R(i,j) = (rho/dt)*(inv_dx*(ufs(i,j) - ufs(i-1,j)) + inv_dy*(vfs(i,j) - vfs(i,j-1)))
  232.         end do
  233.     end do
  234.  
  235.     Iter = 0
  236.  
  237.     do while (iter <= iter_max)
  238.         do j=3,ny-2
  239.             do i=3,nx-2
  240.                 P(i,j) = (1.0-omega)*P(i,j) + omega/(2.0*inv_dxx + 2.0*inv_dyy)*(inv_dxx*(P(i+1,j) + P(i-1,j)) + inv_dyy*(P(i,j+1) + P(i,j-1))- R(i,j))
  241.             end do
  242.         end do
  243.  
  244.         do j=3,ny-2
  245.             R(2,j) = (rho/dt)*(inv_dx*(ufs(2,j)- u(1,j)) + inv_dy*(vfs(2,j) - vfs(2,j-1)))
  246.             P(2,j) = (1.0-omega)*P(2,j) + omega/(inv_dxx + 2.0*inv_dyy)*(inv_dxx*P(3,j) + inv_dyy*(P(2,j+1) + P(2,j-1))-R(2,j))
  247.  
  248.             R(nx-1,j) = (rho/dt)*(inv_dx*(u(nx,j) - ufs(nx-2,j)) + inv_dy*(vfs(nx-1,j) - vfs(nx-1,j-1)))
  249.             P(nx-1,j) = (1.0-omega)*P(nx-1,j) + omega/(inv_dxx + 2.0*inv_dyy)*(inv_dxx*P(nx-2,j) + inv_dyy*(P(nx-1,j+1) + P(nx-1,j-1)) - R(nx-1,j))
  250.         end do
  251.  
  252.         do i=3,nx-2
  253.             R(i,2) = (rho/dt)*(inv_dx*(ufs(i,2) - ufs(i-1,2)) + inv_dy*(vfs(i,2)- v(i,1)))
  254.             P(i,2) = (1.0-omega)*P(i,2) + omega/(2.0*inv_dxx + inv_dyy)*(inv_dxx*(P(i+1,2) + P(i-1,2)) + inv_dyy*P(i,3) - R(i,2))
  255.  
  256.             R(i,ny-1) = (rho/dt)*(inv_dx*(ufs(i,ny-1)- ufs(i-1,ny-1)) + inv_dy*(v(i,ny) - vfs(i,ny-2)))
  257.             P(i,ny-1) = (1.0-omega)*P(i,ny-1) + omega/(2.0*inv_dxx + inv_dyy)*(inv_dxx*(P(i+1,ny-1) + P(i-1,ny-1)) + inv_dyy*P(i,ny-2) - R(i,ny-1))
  258.         end do
  259.  
  260.         R(2,ny-1) = (rho/dt)*(inv_dx*(ufs(2,ny-1) - u(1,ny-1)) + inv_dy*(v(2,ny) - vfs(2,ny-2)))
  261.         P(2,ny-1) = (1.0-omega)*P(2,ny-1) + omega/(inv_dxx + inv_dyy)*(inv_dxx*P(3,ny-1) + inv_dyy*P(2,ny-2) - R(2,ny-1))
  262.  
  263.         R(nx-1,2) = (rho/dt)*(inv_dx*(u(nx,2) - ufs(nx-2,2)) + inv_dy*(vfs(nx-1,2) - v(nx-1,1)))
  264.         P(nx-1,2) = (1.0-omega)*P(nx-1,2) + omega/(inv_dxx + inv_dyy)*(inv_dxx*P(nx-2,2) + inv_dyy*P(nx-1,3) - R(nx-1,2))
  265.  
  266.         R(nx-1,ny-1) = (rho/dt)*(inv_dx*(u(nx,ny-1) - ufs(nx-2,ny-1)) + inv_dy*(v(nx-1,ny) - vfs(nx-1,ny-2)))
  267.         P(nx-1,ny-1) = (1.0-omega)*P(nx-1,ny-1) + omega/(inv_dxx + inv_dyy)*(inv_dxx*P(nx-2,ny-1) + inv_dyy*P(nx-1,ny-2) - R(nx-1,ny-1))
  268.  
  269.         !R(2,2) = (rho/dt)*(inv_dx*(ufs(2,2) - u(1,2)) + inv_dy*(vfs(2,2) - v(2,1)))
  270.         !P(2,2) = (1.0-omega)*P(2,2) + omega/(inv_dxx + inv_dyy)*(inv_dxx*P(3,2) + inv_dyy*P(2,3) - R(2,2))
  271.         P(2,2) = 1.0
  272.         ! If I remove the P(2,2) BC and set P(2,2) = 1.0 then my simulation does not crash, however my soltuion does not satisfy the compatibility condition
  273.         do j=3,ny-2
  274.             do i=3,nx-2
  275.                     Res(i,j) = (inv_dxx*(P(i-1,j) - 2*P(i,j) + P(i+1,j)) + inv_dyy*(P(i,j-1) - 2*P(i,j) + P(i,j+1))) - R(i,j);
  276.             end do
  277.         end do
  278.  
  279.         L2_Error = sum(dx*dy*abs(Res))
  280.  
  281.         if (L2_Error >= tol) then
  282.           Iter = Iter + 1;
  283.         else
  284.             exit
  285.         end if
  286.     end do
  287.  
  288.     P(1,:) = P(2,:) + (dx/dt)*(us(1,:) - u(1,:))
  289.     P(nx,:) = P(nx-1,:) - (dx/dt)*(us(nx,:) - u(nx,:))
  290.     P(:,1) = P(:,2) + (dy/dt)*(vs(:,1) - v(:,1))
  291.     P(:,ny) = P(:,ny-1) - (dy/dt)*(vs(:,ny) - v(:,ny))
  292. end subroutine PressureSolver
  293.  
  294. subroutine FaceVelocities (u, v, uf, vf)
  295.         implicit none
  296.         double precision, dimension(nx,ny), intent(in) :: u, v
  297.         double precision, dimension(nx,ny), intent(out) :: uf, vf
  298.         integer :: i, j
  299.  
  300.         do j=1,ny
  301.             do i=1,nx-1
  302.                 uf(i,j) = 0.5*(u(i+1,j) + u(i,j))
  303.             end do
  304.         end do
  305.  
  306.         do j=1,ny-1
  307.             do i=1,nx
  308.                 vf(i,j) = 0.5*(v(i,j+1) + v(i,j))
  309.             end do
  310.         end do
  311. end subroutine FaceVelocities
  312.  
  313. end program
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement