!
! Large Scale Computing
! Stokes Flow in a Cavity
! ex32.f90
!
! Need Lapack and Blas Libraries
!
program StokesFlowInCavity
use stokeslet2d
implicit none
double precision :: t_cost
double precision,parameter :: EPSILON = 0.005 ! blob size
integer,parameter :: INTGRID = 51 ! # of x-grid lines for internal velocity
double precision :: dp,dm
integer :: numpdepth
integer :: numpwidth
integer :: numparticles
double precision,dimension(:),allocatable :: loc ! particle location
double precision,dimension(:),allocatable :: vel ! particle velocity
double precision,dimension(:),allocatable :: foc ! particle force
double precision,dimension(:),allocatable :: mat ! 2Nx2N dense matrix
double precision,dimension(:),allocatable :: cloc ! array for internal points
double precision,dimension(:),allocatable :: cvel; ! array for internal velocity
integer :: i,j
integer nyg
character(len=32) :: arg
! Newer version of Fortran can get commadline arguments
call get_command_argument(1,arg)
if (len_trim(arg) == 0) then
call get_command_argument(0,arg)
print *,arg," [Depth of Cavity]"
call exit(-1)
end if
! get inputed depth
read(arg,*) dp
! # of particles in depth
numpdepth = int(dp / EPSILON + 0.5)
! # of particles in width
numpwidth = int(1.0 / EPSILON + 0.5)
! total # od particles
numparticles = numpdepth * 2 + numpwidth * 2
print *,"Total # of Particles=",numparticles
! Allocate Space
! DIM=2 defined by 'stokeslet2d.f90'
allocate(loc(numparticles * DIM))
allocate(vel(numparticles * DIM))
allocate(foc(numparticles * DIM))
allocate(mat(numparticles * DIM * numparticles * DIM))
! set location & velocity of particles (blob)
do i = 0, numparticles-1
foc(i * DIM + 1) = 0.d0;
foc(i * DIM + 2) = 0.d0;
if ((i >= 0) .AND. (i <= numpwidth)) then ! top
loc(i * DIM + 1) = -0.5 + EPSILON * dble(i) ! x
loc(i * DIM + 2) = 0.d0 ! y
vel(i * DIM + 1) = 1.d0
vel(i * DIM + 2) = 0.d0
else
if (i <= (numpwidth + numpdepth)) then ! right wall
loc(i * DIM + 1) = 0.5 ! x
loc(i * DIM + 2) = -EPSILON * dble(i - numpwidth) ! y
vel(i * DIM + 1) = 0.d0
vel(i * DIM + 2) = 0.d0
else
if (i <= (2 * numpwidth + numpdepth)) then ! bottom
loc(i * DIM + 1) = 0.5 - EPSILON * dble(i - (numpwidth + numpdepth))! x
loc(i * DIM + 2) = -EPSILON * numpdepth ! y
vel(i * DIM + 1) = 0.d0
vel(i * DIM + 2) = 0.d0
else ! left wall
loc(i * DIM + 1) = -0.5 ! x
loc(i * DIM + 2) = -EPSILON * dble((2 * numpwidth + 2 * numpdepth) - i) ! y
vel(i * DIM + 1) = 0.d0
vel(i * DIM + 2) = 0.d0
end if
end if
end if
end do
! make 2Nx2N Matrix
dm=t_cost();
call slet2d_mkMatrix(numparticles,loc,EPSILON,mat)
print *,"setting matrix ",t_cost(),"(sec)"
! Sovle linear ststem
call slet2d_solve(numparticles,mat,vel,foc)
!call slet2d_solve_CG(numparticles,mat,vel,foc)
print *,"Sovle linear ststem",t_cost(),"(sec)"
! check the solution
call slet2d_mkMatrix(numparticles,loc,EPSILON,mat)
call check_solution(numparticles,mat,vel,foc)
! deallocate big matrix
deallocate(mat)
! out particle (blob) data
open(10,FILE='particle.dat')
do i = 0, numparticles-1
write(10,'(6e16.8)') loc(i * DIM + 1),loc(i * DIM + 2), &
vel(i * DIM + 1),vel(i * DIM + 2), &
foc(i * DIM + 1),foc(i * DIM + 2)
end do
close(10)
!
! compute internal velocity
!
nyg = int(EPSILON * dble(numpdepth * (INTGRID - 1)))
!nyg = numpdepth * (INTGRID - 1) + 1
allocate(cvel(INTGRID * nyg * DIM))
allocate(cloc(INTGRID * nyg * DIM))
!print *,"Internal Grid",INTGRID,"x",nyg
! setting location
do j = 0, nyg - 1
do i = 0,INTGRID - 1
cloc(DIM * (i + INTGRID * j) + 1) = -0.5 + dble(i) / dble(INTGRID - 1)
cloc(DIM * (i + INTGRID * j) + 2) = -dble(j) / dble(INTGRID - 1)
end do
end do
! compute velocities
dm=t_cost();
call slet2d_velocity(numparticles, loc, foc, EPSILON, INTGRID * nyg, cloc, cvel)
print *,"Compute internal velocity",t_cost(),"(sec)"
! out velocities
open(20,FILE='res.dat')
do j = 0, nyg - 1
do i = 0, INTGRID - 1
write(20,'(4e16.8)') cloc(DIM * (i + INTGRID * j) + 1), cloc(DIM * (i + INTGRID * j) + 2),&
cvel(DIM * (i + INTGRID * j) + 1), cvel(DIM * (i + INTGRID * j) + 2)
end do
end do
close(20)
! free
deallocate(cloc)
deallocate(cvel)
deallocate(loc)
deallocate(vel)
deallocate(foc)
end program StokesFlowInCavity
! for timing
double precision function t_cost()
real, save :: ptm
integer,save :: fl = 0
real :: tm,sec;
call cpu_time(tm);
if (fl == 0) then
ptm = tm
end if
fl = 1;
sec = tm - ptm
ptm = tm
t_cost = sec
return
end function t_cost
stokeslet2d.f90
!
! Large Scale Computing
! Stokeslet for 2D
!
! Ricardo Cortez,"The Method of Regularized Stokeslets",
! (2001), SIAM J. Sci. Comput., Vol.23, No.4, pp.1204
!
! assuming mu = 1
!
module stokeslet2d
implicit none
parameter DIM=2
REAL, PARAMETER :: PI = 3.141592653589793238462643383279502884197169399375
contains
! make Matrix
subroutine slet2d_mkMatrix(np,loc,ep,mat)
integer :: np
double precision, dimension(:), allocatable :: loc,mat
double precision :: ep
integer :: i,j
double precision :: r
double precision :: dx,dy
double precision tr1,tr2
!zeros mat
do i = 1, DIM * DIM * np * np
mat(i) = 0.d0
end do
! make mat
! Because of symmetric, we can loop over a half
do i = 0, np-1
do j = i, np-1
dx = loc(i * DIM + 1) - loc(j * DIM + 1)
dy = loc(i * DIM + 2) - loc(j * DIM + 2)
r = sqrt(dx * dx + dy * dy);
tr1 = term1(r,ep) / (4.d0 * PI);
tr2 = term2(r,ep) / (4.d0 * PI);
! diagoanl elements and upper half
mat(i * DIM + 1 + j * DIM * np * DIM) = &
mat(i * DIM + 1 + j * DIM * np * DIM) - tr1 + tr2 * dx * dx
mat(i * DIM + 1 + (j * DIM + 1) * np * DIM) = &
mat(i * DIM + 1 + (j * DIM + 1) * np * DIM) + tr2 * dx * dy
mat(i * DIM + 2 + j * DIM * np * DIM) = &
mat(i * DIM + 2 + j * DIM * np * DIM) + tr2 * dx * dy
mat(i * DIM + 2 + (j * DIM + 1) * np * DIM) = &
mat(i * DIM + 2 + (j * DIM + 1) * np * DIM) - tr1 + tr2 * dy * dy
if (i /= j) then
! lower half
mat(j * DIM + 1 + i * DIM * np * DIM) = &
mat(j * DIM + 1 + i * DIM * np * DIM) - tr1 + tr2 * dx * dx
mat(j * DIM + 1 + (i * DIM + 1) * np * DIM) = &
mat(j * DIM + 1 + (i * DIM + 1) * np * DIM) + tr2 * dx * dy
mat(j * DIM + 2 + i * DIM * np * DIM) = &
mat(j * DIM + 2 + i * DIM * np * DIM) + tr2 * dx * dy
mat(j * DIM + 2 + (i * DIM + 1) * np * DIM) = &
mat(j * DIM + 2 + (i * DIM + 1) * np * DIM) - tr1 + tr2 * dy * dy
end if
end do
end do
return
end subroutine slet2d_mkMatrix
! Sovle Liear ststem
! Use Lapack
subroutine slet2d_solve(np,mat,vel,foc)
external dgesv
integer :: np
double precision, dimension(:), allocatable :: mat,vel,foc
integer :: nrhs
integer :: n
integer :: lda
integer :: ldb
integer,dimension(:),allocatable :: ipiv;
integer :: i;
integer :: info;
! solve Ax=b
! A (amat) is n x n matrix
nrhs = 1 ! # of RHS is 1
n = DIM * np
lda = DIM * np
ldb = DIM * np
! The pivot indices that define the permutation matrix P
! row i of the matrix was interchanged with row IPIV(i).
allocate(ipiv(DIM * np))
! set RHS
do i = 1, n
foc(i) = vel(i)
end do
! solve with LAPACK
call dgesv(n, nrhs, mat, lda, ipiv, foc, ldb, info)
! check
! if (info == 0) printf("successfully done\n");
if (info < 0) then
print *,"the",-info,"-th argument had an illegal value"
call exit(-1)
end if
if (info > 0) then
print *,"U(",info,",",info,") is exactly zero."
call exit(-1)
end if
! free
deallocate(ipiv)
return
end subroutine slet2d_solve
! CG use blas
subroutine slet2d_solve_CG(np,mat,b,x)
external dnrm2,dcopy,dgemv,ddot,daxpy
double precision :: ddot, dnrm2
integer :: np
double precision,dimension(:),allocatable :: mat,b,x
double precision,parameter :: tol = 1.d-8
double precision,dimension(:),allocatable :: r
double precision,dimension(:),allocatable :: p
double precision,dimension(:),allocatable :: Ap
double precision :: rr,pAp,rr1,alpha,beta
integer :: i,j,count
double precision :: al,bt,normb
character(len=1) :: tr = "N"
integer :: inc,n
n = DIM * np
inc = 1
! Check if the solution is trivial.
normb = dnrm2(n, b, inc)
if (normb <= 0.0) then
do i = 1, n
x(i) = 0.d0
end do
return
end if
! Allocate Working Spaces
allocate(r(n))
allocate(p(n))
allocate(Ap(n))
! compute r0 = b - Ax
al = -1.d0
bt = 1.d0
call dcopy(n,b,inc,r,inc) ! r = b
call dgemv(tr,n,n,al,mat,n,x,inc,bt,r,inc) ! r=r-Ax
rr = 0.d0
call dcopy(n,r,inc,p,inc) ! p = r
rr = ddot(n,r,inc,r,inc) ! rr = r.r
print *,"rr=",rr
! cg iteration
count = 0
do while(rr > tol * tol * normb * normb)
! Ap = A*p
al = 1.d0
bt = 0.d0
call dgemv(tr,n,n,al,mat,n,p,inc,bt,Ap,inc)
! alpha = r.r / p.Ap
pAp = 0.d0
pAp = ddot(n,p,inc,Ap,inc) ! pAp = p.Ap
alpha = rr / pAp
! Beta
rr1 = 0.d0
call daxpy(n,alpha,p,inc,x,inc) ! x += alpha * p
al = -alpha
call daxpy(n,al,Ap,inc,r,inc) ! r -= alpha * Ap
rr1 = ddot(n,r,inc,r,inc) ! rr1 = r.r
beta = rr1 / rr
! p = r + beta * p no blas routine :(
do i = 1,n
p(i) = r(i) + beta * p(i)
end do
rr = rr1
count = count + 1
end do
! Deallocate Working Spaces
deallocate(r)
deallocate(p)
deallocate(Ap)
return
end subroutine slet2d_solve_CG
subroutine check_solution(np,mat,b,x)
external dcopy,dgemv,dnrm2
double precision :: dnrm2
integer :: np
double precision,dimension(:),allocatable :: mat,b,x
double precision,dimension(:),allocatable :: r
double precision :: al,bt,rr
character(len=1) :: tr = "N"
integer :: inc,n
n = DIM * np
inc = 1
! Allocate Working Spaces
allocate(r(n))
! compute r0 = b - Ax
al = -1.d0
bt = 1.d0
call dcopy(n,b,inc,r,inc) ! r = b
call dgemv(tr,n,n,al,mat,n,x,inc,bt,r,inc)
! rr = |r|
rr = dnrm2(n, r, inc)
print *,"|b - Ax|=",rr
deallocate(r)
return
end subroutine check_solution
!
! compute velocity
subroutine slet2d_velocity(np, loc, foc, ep, nump, cloc,cvel)
integer :: np
double precision,dimension(:),allocatable :: loc, foc
double precision :: ep
integer :: nump
double precision,dimension(:),allocatable :: cloc,cvel
integer :: i,p
double precision :: r
double precision :: dx,dy
double precision :: tr1,tr2
! loop for grid
do p = 0, nump-1
! zeros
cvel(p * DIM + 1) = 0.d0
cvel(p * DIM + 2) = 0.d0
! loop for partilces (blob)
do i = 0, np-1
dx = cloc(p * DIM + 1) - loc(i * DIM + 1)
dy = cloc(p * DIM + 2) - loc(i * DIM + 2)
r = sqrt(dx * dx + dy * dy)
tr1 = term1(r,ep) / (4.d0 * PI)
tr2 = term2(r,ep) / (4.d0 * PI)
tr2 = tr2 * (foc(i * DIM + 1) * dx + foc(i * DIM + 2) * dy)
cvel(p * DIM + 1) = cvel(p * DIM + 1) - foc(i * DIM + 1) * tr1 + tr2 * dx
cvel(p * DIM + 2) = cvel(p * DIM + 2) - foc(i * DIM + 2) * tr1 + tr2 * dy
end do
end do
return
end subroutine slet2d_velocity
double precision function term1(r,ep)
double precision :: r,ep
double precision ::sq
sq = sqrt(r * r + ep * ep)
term1 = log(sq + ep) - ep * (sq + 2.d0 * ep) / (sq + ep) / sq
return
end function term1
double precision function term2(r,ep)
double precision :: r,ep
double precision :: sq
sq = sqrt(r * r + ep * ep)
term2 = (sq + 2.d0 * ep) / (sq + ep) / (sq + ep) / sq
return
end function term2
!
end module stokeslet2d