!>
!> @file test_intergrid0.f90
!>
!> @brief
!>
!> @copyright
!> Copyright (©) 2021 EPFL (Ecole Polytechnique Fédérale de Lausanne)
!> SPC (Swiss Plasma Center)
!>
!> SPClibs is free software: you can redistribute it and/or modify it under
!> the terms of the GNU Lesser General Public License as published by the Free
!> Software Foundation, either version 3 of the License, or (at your option)
!> any later version.
!>
!> SPClibs is distributed in the hope that it will be useful, but WITHOUT ANY
!> WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
!> FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
!>
!> You should have received a copy of the GNU Lesser General Public License
!> along with this program. If not, see .
!>
!> @authors
!> (in alphabetical order)
!> @author Trach-Minh Tran
!>
PROGRAM main
!
! intergrid transfer using *serial* multigrid module:
! - restriction of rhs
! - prolongation of sol
!
USE multigrid, ONLY : grid2d, mg_info, &
& get_lmax, create_grid_fd, ibc_transf, &
& prolong, restrict
IMPLICIT NONE
DOUBLE PRECISION, PARAMETER :: pi=4.0d0*ATAN(1.0d0)
DOUBLE PRECISION :: Lx, Ly, kx, ky, icrosst, beta, miome
INTEGER :: nx, ny, levels
CHARACTER(len=4) :: prb
LOGICAL :: nldebug
!
DOUBLE PRECISION :: dx, dy
DOUBLE PRECISION, ALLOCATABLE :: x(:),y(:)
!
TYPE(mg_info) :: info ! info for MG
TYPE(grid2d), ALLOCATABLE :: grids(:)
!
INTEGER :: i, l
!
NAMELIST /parameters/ prb, nx, ny, levels, Lx, Ly, kx, ky, icrosst, beta, &
& miome, nldebug
!--------------------------------------------------------------------------------
!
! Default inputs
!
nx=32
ny=32
levels = 2
kx=1
ky=1
icrosst=1.0d0
Lx = 1.0D0
Ly = 1.0D0
miome = 200d0
beta = 0d0
prb = 'dddd'
nldebug = .FALSE.
!
READ(*,parameters)
WRITE(*,parameters)
!
! Fine grid
!
dx = lx/REAL(nx,8)
dy = ly/REAL(ny,8)
ALLOCATE(x(0:nx), y(0:ny))
x = dx * [(i,i=0,nx)]
y = dy * [(i,i=0,ny)]
WRITE(*,'(a/10(1pe12.3))') 'x =', x
WRITE(*,'(a/10(1pe12.3))') 'y =', y
!
! Create array of grids
!
levels = MIN(levels, get_lmax(nx), get_lmax(ny))
WRITE(*,'(a,i4)') 'Number of levels', levels
ALLOCATE(grids(levels))
info%nu1 = 1
info%nu2 = 1
info%mu = 1
info%nu0 = 1
info%levels = levels
info%relax = 'jac'
info%omega = 1
CALL create_grid_fd(x, y, grids, info, mat_type='cds', debug=nldebug)
!
! Set BC on grid transfer matrices
!
IF(prb.EQ.'dddd') CALL ibc_transf(grids,1,3) ! Direction X
CALL ibc_transf(grids,2,3) ! Direction Y
!
! Define RHS at l=1, compute RHS at l=2,...,levels by "restriction".
!
grids(1)%f(:,:) = frhs(grids(1)%x,grids(1)%y)
DO l=2,levels
grids(l)%f = restrict(grids(l)%matp, grids(l-1)%f)
grids(l)%f = 0.25d0*grids(l)%f ! Scaling for FD
END DO
!
! Define SOL at l=levels, compute SOL at l=levels-1,..,1 by "prolongation"
!
grids(levels)%v(:,:) = fsol(grids(levels)%x,grids(levels)%y)
DO l=levels-1,1,-1
grids(l)%v = prolong(grids(l+1)%matp, grids(l+1)%v)
END DO
!
IF(nldebug) THEN
DO l=1,levels
WRITE(*,'(a,i3)') '==== Level', l
WRITE(*,'(a)') 'f ='
DO i=0,grids(l)%n(1)
WRITE(*,'(10f8.3)') grids(l)%f(i,:)
END DO
WRITE(*,'(a)') 'v ='
DO i=0,grids(l)%n(1)
WRITE(*,'(10f8.3)') grids(l)%v(i,:)
END DO
END DO
END IF
!
! Epilogue
!
CALL h5file
!--------------------------------------------------------------------------------
CONTAINS
!+++
FUNCTION fdense(x)
!
! Return density
!
DOUBLE PRECISION, INTENT(in) :: x(:)
DOUBLE PRECISION :: fdense(SIZE(x))
fdense(:) = 0.5d0*beta*miome*EXP( -(x(:)-Lx/3d0)**2d0/(Lx/2d0)**2d0 );
END FUNCTION fdense
!+++
FUNCTION frhs(x,y)
!
! Return RHS
!
DOUBLE PRECISION, INTENT(in) :: x(:), y(:)
DOUBLE PRECISION :: frhs(SIZE(x),SIZE(y))
DOUBLE PRECISION :: c, s, d(SIZE(x))
DOUBLE PRECISION :: corr
INTEGER :: j
corr = 1.d0+icrosst**2/4.0d0
d(:) = fdense(x(:))
IF(prb.EQ.'dddd') THEN
DO j=1,SIZE(y)
c = COS(2.0d0*pi*ky*y(j)/Ly)
s = SIN(2.0d0*pi*ky*y(j)/Ly)
frhs(:,j) = -4.0d0*pi*pi*( (kx*kx/Lx/Lx+corr*ky*ky/Ly/Ly) * SIN(2.0d0*pi*kx*x(:)/Lx)*s &
& -icrosst*kx*ky/Lx/Ly * COS(2.0d0*pi*kx*x(:)/Lx)*c ) &
& + d(:) * SIN(2.0d0*pi*kx*x(:)/Lx)*s
END DO
ELSE IF (prb.EQ.'nndd') THEN
DO j=1,SIZE(y)
c = COS(2.0d0*pi*ky*y(j)/Ly)
s = SIN(2.0d0*pi*ky*y(j)/Ly)
frhs(:,j) = -4.0d0*pi*pi*( (kx*kx/Lx/Lx+corr*ky*ky/Ly/Ly) * COS(2.0d0*pi*kx*x(:)/Lx)*s &
& +icrosst*kx*ky/Lx/Ly * SIN(2.0d0*pi*kx*x(:)/Lx)*c ) &
& + d(:) * COS(2.0d0*pi*kx*x(:)/Lx)*s
END DO
END IF
END FUNCTION frhs
!+++
FUNCTION fsol(x,y)
!
! Return analytical solution
!
DOUBLE PRECISION, INTENT(in) :: x(:), y(:)
DOUBLE PRECISION :: fsol(SIZE(x),SIZE(y))
DOUBLE PRECISION :: c
INTEGER :: j
IF(prb.EQ.'dddd') THEN
DO j=1,SIZE(y)
c = SIN(2.0d0*pi*ky*y(j)/Ly)
fsol(:,j) = SIN(2.0d0*pi*kx*x(:)/Lx)*c
END DO
ELSE IF (prb.EQ.'nndd') THEN
DO j=1,SIZE(y)
c = SIN(2.0d0*pi*ky*y(j)/Ly)
fsol(:,j) = COS(2.0d0*pi*kx*x(:)/Lx)*c
END DO
END IF
END FUNCTION fsol
!+++
SUBROUTINE h5file
USE futils
USE csr, ONLY : putmat
CHARACTER(len=128) :: file='test_intergrid0.h5'
INTEGER :: fid
INTEGER :: l
CHARACTER(len=64) :: dsname
CALL creatf(file, fid, real_prec='d')
CALL attach(fid, '/', 'NX', nx)
CALL attach(fid, '/', 'NY', ny)
CALL attach(fid, '/', 'KX', kx)
CALL attach(fid, '/', 'KY', ky)
CALL attach(fid, '/', 'LX', Lx)
CALL attach(fid, '/', 'LY', Ly)
CALL attach(fid, '/', 'BETA', beta)
CALL attach(fid, '/', 'LEVELS', levels)
CALL attach(fid, '/', 'PRB', prb)
CALL attach(fid, '/', 'NLDEBUG', nldebug)
CALL creatg(fid, '/mglevels')
DO l=1,levels
WRITE(dsname,'("/mglevels/level.",i2.2)') l
CALL creatg(fid, TRIM(dsname))
IF(l.GT.1) THEN
CALL putmat(fid, TRIM(dsname)//'/matpx', grids(l)%matp(1))
CALL putmat(fid, TRIM(dsname)//'/matpy', grids(l)%matp(2))
END IF
CALL putarr(fid, TRIM(dsname)//'/x', grids(l)%x)
CALL putarr(fid, TRIM(dsname)//'/y', grids(l)%y)
CALL putarr(fid, TRIM(dsname)//'/f', grids(l)%f)
CALL putarr(fid, TRIM(dsname)//'/v', grids(l)%v)
END DO
CALL closef(fid)
END SUBROUTINE h5file
!+++
END PROGRAM main