Simple MAC  1.0
A Marker and Cell Method Solver for the Navier Stokes Equations
 All Classes Files Functions Variables Pages
mac.f90
Go to the documentation of this file.
1 
6 
7 
12 module dim
13 
14  implicit none
15 
16  integer, parameter :: nx = 90
17  integer, parameter :: ny = 90
18 
19  double precision, parameter :: dx = 1.0d0/(nx-1.0d0)
20  double precision, parameter :: dy = 1.0d0/(ny-1.0d0)
21 
22  double precision, parameter :: wconst = 1.0d0/(4.0d0*dx)
23 
24  integer :: t
25  double precision :: dt
26 
27  double precision :: re
28  double precision :: r
29 end module dim
30 
33 module solver
34  use dim
35  implicit none
36  double precision, dimension(nx,ny) :: u
37  double precision, dimension(nx,ny) :: v
38  double precision, dimension(nx,ny) :: p
39  double precision, dimension(nx,ny) :: Fn
40  double precision, dimension(nx,ny) :: Gn
41  double precision, dimension(nx,ny) :: Q
42 
43  contains
44 
46  subroutine initzero()
47  u(:,:) = 0.0d0
48  v(:,:) = 0.0d0
49  p(:,:) = 10.0d0
50  fn(:,:) = 0.0d0
51  gn(:,:) = 0.0d0
52  q(:,:) = 0.0d0
53  end subroutine initzero
54 
56  subroutine returnu(array)
57  double precision, dimension(nx,ny), intent(out) :: array
58  array(:,:) = u(:,:)
59  end subroutine returnu
60 
62  subroutine returnv(array)
63  double precision, dimension(nx,ny), intent(out) :: array
64  array(:,:) = v(:,:)
65  end subroutine returnv
66 
68  subroutine returnp(array)
69  double precision, dimension(nx,ny), intent(out) :: array
70  array(:,:) = p(:,:)
71  end subroutine returnp
72 
83  subroutine ghostcondition()
84  use omp_lib
85  use dim
86  integer :: i,j
87 
88  !X Boundary condition
89  !$omp parallel do shared(u) private(i) schedule(dynamic)
90  do j=1,ny
91  u(1,j) = 0.0d0
92  u(nx,j) = 0.0d0
93  end do
94  !$omp end parallel do
95 
96  !Y Boundary condition
97  !$omp parallel do shared(v)
98  do i=1,nx
99  v(i,1) = 0.0d0
100  v(i,ny) = 0.0d0
101  end do
102  !$omp end parallel do
103  end subroutine ghostcondition
104 
114  subroutine lidcondition()
115  use omp_lib
116  use dim
117  integer :: i, j
118 
119  !U velocity condition
120  !$omp parallel do private(i) shared(u) schedule(dynamic)
121  do i=2,nx-1
122  u(i,1) = - u(i,2)
123  u(i,ny) = 2.0d0 - u(i,ny-1)
124  end do
125  !$omp end parallel do
126 
127  !V Velocity condition
128  !$omp parallel do private(j) shared(v) schedule(dynamic)
129  do j=2,ny-1
130  v(1,j) = - v(2,j)
131  v(nx,j) = - v(nx-1,j)
132  end do
133  !$omp end parallel do
134  end subroutine lidcondition
135 
143  subroutine calctstep()
144  use omp_lib
145  use dim
146  implicit none
147  double precision :: umax1(2),umax2,vmax1(2),vmax2,dtc,dtr
148 
149  !We use different step sizes depending on how long we've been running
150  if(t .gt. 10) then
151  !Calculate first stability condition
152  dtr = r*dx*dy*re
153 
154  !get the maximum value of u and v using worksharing
155  !$omp workshare
156  umax1 = maxval(u)
157  umax2 = maxval(umax1)
158  vmax1 = maxval(v)
159  vmax2 = maxval(vmax1)
160  !$omp end workshare
161 
162  !Calculate second stability condition
163  dtc = (1.0d0 / r) / (re * (abs(umax2) + abs(vmax2))**2 )
164 
165  !use the smaller of the two
166  dt = min(dtr,dtc)
167  else
168  !If first few steps then take a very small step
169  dt = (r/25.0d0)*dx*dy*re
170  end if
171  end subroutine calctstep
172 
197  subroutine calcfngn()
198  use dim
199  use omp_lib
200  implicit none
201  integer :: i, j, err
202 
203  !$omp parallel do private(i,j) schedule(dynamic)
204  do i=2,nx-1
205  do j=2,ny-1
206  fn(i,j) = u(i,j)+dt*(((u(i+1,j)-2*u(i,j)+u(i-1,j))/(re*dx*dx))+((u(i,j-1) &
207  -2.0d0*u(i,j)+u(i,j+1))/(re*dy*dy))-(((u(i,j)+u(i+1,j))*(u(i,j)+u(i+1,j)) &
208  -(u(i-1,j)+u(i,j))*(u(i-1,j)+u(i,j)))/(4.0d0*dx))-((((u(i,j)+u(i,j+1))*(v(i+1,j) &
209  +v(i,j)))-((u(i,j-1)+u(i,j))*(v(i+1,j-1)+v(i,j-1))))/(4.0d0*dy)))
210  gn(i,j) = v(i,j)+dt*(((v(i+1,j)-2.0d0*v(i,j)+v(i-1,j))/(re*dx*dx))+((v(i,j-1) &
211  -2.0d0*v(i,j)+v(i,j+1))/(re*dy*dy))-(((v(i,j+1)+v(i,j))*(v(i,j+1)+v(i,j)) &
212  -(v(i,j-1)+v(i,j))*(v(i,j-1)+v(i,j)))/(4.0d0*dy))-((((u(i,j)+u(i,j+1))*(v(i+1,j) &
213  +v(i,j)))-((u(i-1,j)+u(i-1,j+1))*(v(i,j)+v(i-1,j))))/(4.0d0*dx)))
214  end do
215  end do
216  !$omp end parallel do
217  end subroutine calcfngn
218 
235  subroutine calcqn()
236  use dim
237  use omp_lib
238  integer :: i, j, err
239 
240  !$omp parallel do private(i,j) schedule(dynamic)
241  do i=2,nx-1
242  do j=2,ny-1
243  q(i,j) =((fn(i,j)-fn(i-1,j)+gn(i,j)-gn(i,j-1))/(dt*dx))
244  end do
245  end do
246  !$omp end parallel do
247  end subroutine calcqn
248 
261  subroutine calcvel()
262  use dim
263  use omp_lib
264  integer :: i, j, err
265 
266  !$omp parallel do private(i,j) schedule(dynamic)
267  do i=2,nx-2
268  do j=2,ny-1
269  u(i,j) = fn(i,j) - ( p(i+1,j) - p(i,j) ) * (dt/dx)
270  end do
271  end do
272  !$omp end parallel do
273 
274  !$omp parallel do private(i,j) schedule(dynamic)
275  do i=2,nx-1
276  do j=2,ny-2
277  v(i,j) = gn(i,j) - ( p(i,j+1) - p(i,j) ) * (dt/dy)
278  end do
279  end do
280  !$omp end parallel do
281 
282  end subroutine calcvel
283 
290  subroutine vort(w)
291  use dim
292  implicit none
293  double precision, dimension(nx,ny), intent(out) :: w
294  integer :: i,j
295 
296  w(:,:) = 0.0d0
297  do j=2,ny-1
298  do i=2,nx-1
299  w(i,j) = wconst * (v(i+1,j) - v(i-1,j) - u(i,j+1) + u(i,j-1))
300  end do
301  end do
302  end subroutine vort
303 
319  subroutine poisson()
320  use dim
321  implicit none
322  double precision, parameter :: rf = 1.60d0
323  double precision, parameter :: conv = 0.00010d0
324  integer, parameter :: itmax = 200
325  double precision :: change, pold, po, ch
326  integer :: iter, im, jm, k
327  integer :: i,j
328 
329  iter = 0
330  change = 1.0d0
331  do while((change .ge. conv))
332  iter = iter + 1
333  change = 0.0d0
334 
335  do i=2,nx-1
336  do j=2,ny-1
337  pold=p(i,j)
338  p(i,j) = 0.250d0*((p(i-1,j)+p(i,j-1)+p(i+1,j)+p(i,j+1))-(q(i,j)*dx*dx))
339  p(i,j) = pold + rf*(p(i,j)-pold);
340 
341  !Calculates change
342  if(pold .ne. 0) ch = abs((p(i,j)-pold)/pold)
343 
344  !Stores greatest change value
345  if(ch .gt. change) then
346  change = ch
347  im = i
348  jm = j
349  po = pold
350  end if
351  end do
352  end do
353 
354  !update boundaries on poisson solver
355  do k=1,nx
356  p(k,1) = p(k,2) - ((2.0 * v(k,2)) / (re*dx))
357  p(k,ny) = p(k,ny-1) + ((2.0 * v(k,ny-2)) / (re*dx))
358  p(1,k) = p(2,k) - ((2.0 * u(2,k)) / (re*dx))
359  p(nx,k) = p(nx-1,k) + ((2.0 * u(nx-2,k)) / (re*dx))
360  end do
361 
362  if(iter .gt. itmax) then
363  goto 100
364  end if
365  end do
366 100 continue
367  end subroutine poisson
368 
373  subroutine parpoisson()
374  use omp_lib
375  use dim
376  implicit none
377 
378  double precision, parameter :: rf = 1.60d0
379  double precision, parameter :: conv = 0.00010d0
380  integer, parameter :: itmax = 500
381  double precision :: pold, po, ch
382  integer :: iter, im, jm, k
383  integer :: i,j,tstep
384  integer :: rowper, colper, numthreads, istart, iend, myid, kstart, kend
385  double precision :: change, changethread
386 
387  iter = 0
388  change = 1.0d0
389 
390  !For OpenMP
391  numthreads = 4
392  call omp_set_num_threads(numthreads)
393 
394  !calculate sizes of blocks
395  rowper = int(ny/numthreads)
396  colper = int(nx/numthreads)
397 
398  !Fork the threads
399  !$omp parallel private(myid, istart, iend, i, j, k,t, iter, pold, changeThread) shared(change)
400  myid = omp_get_thread_num()
401 
402  istart = myid*rowper + 1
403  if(myid == 0) istart = istart + 1
404  iend = (myid*rowper) + rowper
405  if(myid == numthreads-1) iend = iend - 1
406 
407  !Main iterative loop
408  do while(iter .lt. itmax)
409  iter = iter + 1
410 
411  !$omp single
412  change = 0.0d0
413  !$omp end single
414  !$omp barrier
415  !$omp flush
416 
417  changethread = 0.0d0
418  do j=istart,iend
419  do i=2,nx-1
420  pold=p(i,j)
421  p(i,j) = 0.250d0*((p(i-1,j)+p(i,j-1)+p(i+1,j)+p(i,j+1))-(q(i,j)*dx*dx))
422  p(i,j) = pold + rf*(p(i,j)-pold);
423 
424  !Calculates change
425  if(pold .ne. 0) changethread = max(changethread,abs((p(i,j)-pold)/pold))
426  end do
427  end do
428 
429  !calculates change
430  !$omp critical
431  change = max(change,changethread)
432  !$omp end critical
433  !$omp barrier
434 
435  if(change .lt. conv) exit
436 
437  !$omp barrier
438 
439  !update boundaries on poisson solver
440  !$omp master
441  do k=1,nx
442  p(k,1) = p(k,2) - ((2.0d0 * v(k,2)) / (re*dx))
443  p(k,ny) = p(k,ny-1) + ((2.0d0 * v(k,ny-2)) / (re*dx))
444  p(1,k) = p(2,k) - ((2.0d0 * u(2,k)) / (re*dx))
445  p(nx,k) = p(nx-1,k) + ((2.0d0 * u(nx-2,k)) / (re*dx))
446  end do
447  !$omp end master
448 
449  end do
450 100 continue
451  !$omp barrier
452  !$omp end parallel
453  end subroutine parpoisson
454 
455 end module solver