!>
!> @file test_relax2d.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
!
! Test 2d direcxt solve and relaxation methods
!
USE multigrid
USE csr
IMPLICIT NONE
INCLUDE 'mpif.h'
!
DOUBLE PRECISION, PARAMETER :: PI=4.0d0*ATAN(1.0d0)
INTEGER, DIMENSION(2) :: n, nidbas, ngauss, alpha
DOUBLE PRECISION :: kx=4.d0, ky=3.d0, sigma=10.0d0
INTEGER :: levels=1, nits=1000
CHARACTER(len=4) :: relax='jac '
DOUBLE PRECISION :: omega=2.0d0/3.0d0
DOUBLE PRECISION :: t0
!
DOUBLE PRECISION, ALLOCATABLE :: x(:), y(:)
DOUBLE PRECISION :: dx, dy
INTEGER :: ix, iy
!
DOUBLE PRECISION, ALLOCATABLE, TARGET :: sol_direct(:,:), sol_relax(:,:)
DOUBLE PRECISION, POINTER :: sol_direct_1d(:), sol_relax_1d(:)
DOUBLE PRECISION, ALLOCATABLE :: sol_direct_grid(:,:)
DOUBLE PRECISION, ALLOCATABLE :: sol_anal_grid(:,:)
DOUBLE PRECISION, ALLOCATABLE :: resid(:), errdisc(:)
!
INTEGER :: ierr, me
INTEGER :: l, nterms
INTEGER :: its
!
TYPE(grid2d), ALLOCATABLE :: grids(:)
!
NAMELIST /newrun/ n, nidbas, ngauss, kx, ky, sigma, alpha, levels, nits, relax
!--------------------------------------------------------------------------------
! 1. Prologue
!
CALL mpi_init(ierr)
CALL mpi_comm_rank(MPI_COMM_WORLD, me, ierr)
!
! Inputs
!
n = (/8, 8/)
nidbas=(/3,3/)
ngauss=(/2,2/)
alpha = (/0,0/)
kx=4
ky=3
sigma=10.0d0
levels=2
relax='jac'
nits=100
!
IF(me.EQ.0) THEN
READ(*,newrun)
WRITE(*,newrun)
END IF
CALL mpi_bcast(n, 2, MPI_INTEGER, 0, MPI_COMM_WORLD, ierr)
CALL mpi_bcast(nidbas, 2, MPI_INTEGER, 0, MPI_COMM_WORLD, ierr)
CALL mpi_bcast(ngauss, 2, MPI_INTEGER, 0, MPI_COMM_WORLD, ierr)
CALL mpi_bcast(alpha, 2, MPI_DOUBLE_PRECISION, 0, MPI_COMM_WORLD, ierr)
CALL mpi_bcast(kx, 1, MPI_DOUBLE_PRECISION, 0, MPI_COMM_WORLD, ierr)
CALL mpi_bcast(ky, 1, MPI_DOUBLE_PRECISION, 0, MPI_COMM_WORLD, ierr)
CALL mpi_bcast(sigma, 1, MPI_DOUBLE_PRECISION, 0, MPI_COMM_WORLD, ierr)
CALL mpi_bcast(levels, 1, MPI_INTEGER, 0, MPI_COMM_WORLD, ierr)
CALL mpi_bcast(nits, 1, MPI_INTEGER, 0, MPI_COMM_WORLD, ierr)
CALL mpi_bcast(relax, LEN(relax), MPI_INTEGER, 0, MPI_COMM_WORLD, ierr)
!
! Adjust number of levels
!
levels = MIN(levels, get_lmax(n(1)), get_lmax(n(2)))
!
! Create grids
!
dx = 1.0d0/REAL(n(1),8)
dy = 1.0d0/REAL(n(2),8)
ALLOCATE(x(0:n(1)), y(0:n(2)))
DO ix=0,n(1)
x(ix) = ix*dx
END DO
DO iy=0,n(2)
y(iy) = iy*dy
END DO
!
ALLOCATE(grids(levels))
CALL create_grid(x, y, nidbas, ngauss, alpha, grids)
WRITE(*,'(5a6)') 'l', 'nx', 'ny', 'rx', 'ry'
WRITE(*,'(5i6)') (l, grids(l)%n, grids(l)%rank, l=1,levels)
!
! Construct RHS and set BC only on the finest grid
!
CALL disrhs(grids(1)%spl, grids(1)%f, rhs)
CALL ibcrhs(grids(1), grids(1)%f)
!!$ CALL printmat('** RHS **', grids(1)%f)
!
! Build FE matrices and set BC
!
nterms = 3
DO l=1,levels
CALL femat(grids(l)%spl, grids(l)%mata, coefeq, nterms)
CALL ibcmat(grids(l), grids(l)%mata)
CALL to_mat(grids(l)%mata)
END DO
!--------------------------------------------------------------------------------
! 1. Direct solution (at the finest grid, l=1)
!
WRITE(*,'(//a)') 'Direct solution for the finest grid problem'
ALLOCATE(sol_direct(SIZE(grids(1)%v,1), SIZE(grids(1)%v,2)), &
& source=grids(1)%f)
sol_direct_1d(1:SIZE(grids(1)%v1d)) => sol_direct
PRINT*, 'shape of sol_direct', SHAPE(sol_direct)
PRINT*, 'shape of sol_direct_1d', SHAPE(sol_direct_1d)
!
t0 = mpi_wtime()
CALL direct_solve(grids(1), sol_direct_1d, debug=.FALSE.)
WRITE(*,'(a,1pe12.3)') 'Fact. + solve time (s) =', mpi_wtime()-t0
!
sol_direct = grids(1)%f
t0 = mpi_wtime()
CALL direct_solve(grids(1), sol_direct_1d, debug=.FALSE.)
WRITE(*,'(a,1pe12.3)') 'Solve time (s) =', mpi_wtime()-t0
!
ALLOCATE(sol_direct_grid(0:n(1),0:n(2)))
ALLOCATE(sol_anal_grid(0:n(1),0:n(2)))
CALL gridval(grids(1)%spl, grids(1)%x, grids(1)%y, sol_direct_grid, &
& [0,0], sol_direct)
sol_anal_grid = sol(grids(1)%x, grids(1)%y)
WRITE(*,'(a,2(1pe12.3))') 'Discretization error and residue =', &
& disc_err(grids(1)%spl, sol_direct, sol), &
& residue(grids(1)%mata, grids(1)%f1d, sol_direct_1d)
!--------------------------------------------------------------------------------
! 2. Relaxation (at the finest grid, l=1)
!
ALLOCATE(errdisc(0:nits))
ALLOCATE(resid(0:nits))
ALLOCATE(sol_relax(SIZE(grids(1)%v,1), SIZE(grids(1)%v,2)))
sol_relax_1d(1:SIZE(grids(1)%v1d)) => sol_relax
!
sol_relax_1d = 0.0d0
errdisc(0) = disc_err(grids(1)%spl, sol_relax, sol)
resid(0) = residue(grids(1)%mata, grids(1)%f1d, sol_relax_1d)
t0 = mpi_wtime()
DO its=1,nits
SELECT CASE (TRIM(relax))
CASE('jac')
CALL jacobi(grids(1)%mata, omega, 1, sol_relax_1d, grids(1)%f1d)
CASE('gs')
CALL gs(grids(1)%mata, 1, sol_relax_1d, grids(1)%f1d)
END SELECT
errdisc(its) = disc_err(grids(1)%spl, sol_relax, sol)
resid(its) = residue(grids(1)%mata, grids(1)%f1d, sol_relax_1d)
END DO
WRITE(*,'(a,1pe12.3)') 'Iterative solve time (s/iteration) =', (mpi_wtime()-t0)/REAL(nits,8)
!
WRITE(*,'(/a4,3a12)') 'its', 'residue', 'disc. err'
WRITE(*,'(i4,3(1pe12.3))') 0, resid(0), errdisc(0)
WRITE(*,'((i4,4(1pe12.3)))') (its, resid(its), errdisc(its), &
& resid(its)/resid(its-1), &
& errdisc(its)/errdisc(its-1), its=1,nits,MAX(1,nits/10))
!--------------------------------------------------------------------------------
! 9. Epilogue
!
! Creata HDF5 file
!
IF(me.EQ.0) CALL h5file
!
CALL mpi_finalize(ierr)
!--------------------------------------------------------------------------------
CONTAINS
!+++
FUNCTION rhs(x, y)
!
! Return problem RHS
!
DOUBLE PRECISION, INTENT(in) :: x, y
DOUBLE PRECISION :: rhs
rhs = SIN(PI*kx*x)*SIN(PI*ky*y)
END FUNCTION rhs
!+++
FUNCTION sol(x, y)
!
! Return exact problem solution
!
DOUBLE PRECISION, INTENT(in) :: x(:), y(:)
DOUBLE PRECISION :: sol(SIZE(x),SIZE(y))
DOUBLE PRECISION :: c
INTEGER :: j
DO j=1,SIZE(y)
c = SIN(PI*ky*y(j)) / (PI**2*(kx**2+ky**2) + sigma**2)
sol(:,j) = c * SIN(PI*kx*x(:))
END DO
END FUNCTION sol
!+++
SUBROUTINE coefeq(x, y, idt, idw, c)
!
! Weak form = Int( \nabla(w).\nabla(t) + \sigma.t.w) dV)
!
DOUBLE PRECISION, INTENT(in) :: x, y
INTEGER, INTENT(out) :: idt(:,:), idw(:,:)
DOUBLE PRECISION, INTENT(out) :: c(:)
!
c(1) = 1.0d0
idt(1,1) = 1
idt(1,2) = 0
idw(1,1) = 1
idw(1,2) = 0
!
c(2) = 1.0d0
idt(2,1) = 0
idt(2,2) = 1
idw(2,1) = 0
idw(2,2) = 1
!
c(3) = sigma
idt(3,1) = 0
idt(3,2) = 0
idw(3,1) = 0
idw(3,2) = 0
END SUBROUTINE coefeq
!+++
SUBROUTINE h5file
USE futils
CHARACTER(len=128) :: file='test_relax2d.h5'
INTEGER :: fid
INTEGER :: l
CHARACTER(len=64) :: dsname
CALL creatf(file, fid, real_prec='d')
CALL attach(fid, '/', 'NX', n(1))
CALL attach(fid, '/', 'NY', n(2))
CALL attach(fid, '/', 'NIDBAS1', nidbas(1))
CALL attach(fid, '/', 'NIDBAS2', nidbas(2))
CALL attach(fid, '/', 'KX', kx)
CALL attach(fid, '/', 'KY', ky)
CALL attach(fid, '/', 'SIGMA', sigma)
CALL attach(fid, '/', 'ALPHA1', alpha(1))
CALL attach(fid, '/', 'ALPHA2', alpha(2))
CALL attach(fid, '/', 'LEVELS', levels)
CALL attach(fid, '/', 'RELAX', relax)
CALL attach(fid, '/', 'NITS', nits)
CALL creatg(fid, '/mglevels')
DO l=1,levels
WRITE(dsname,'("/mglevels/level.",i2.2)') l
CALL creatg(fid, TRIM(dsname))
CALL putmat(fid, TRIM(dsname)//'/mata', grids(l)%mata)
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)
CALL putarr(fid, TRIM(dsname)//'/f1d', grids(l)%f1d)
CALL putarr(fid, TRIM(dsname)//'/v1d', grids(l)%v1d)
END DO
!
! Solutions at finest grid
!
CALL creatg(fid, '/solutions')
CALL putarr(fid, '/solutions/xg', grids(1)%x)
CALL putarr(fid, '/solutions/yg', grids(1)%y)
CALL putarr(fid, '/solutions/direct', sol_direct_grid)
CALL putarr(fid, '/solutions/anal', sol_anal_grid)
!
CALL creatg(fid, '/relaxation')
CALL putarr(fid, '/relaxation/errdisc', errdisc)
CALL putarr(fid, '/relaxation/resid', resid)
!
IF(ALLOCATED(grids(1)%mata%mumps)) THEN
CALL myputmat(fid, '/MUMPS', grids(1)%mata%mumps)
END IF
!
CALL closef(fid)
END SUBROUTINE h5file
!+++
SUBROUTINE myputmat(fid, label, mat, str)
!
! Write matrix to hdf5 file
!
USE futils
!
INTEGER, INTENT(in) :: fid
CHARACTER(len=*), INTENT(in) :: label
TYPE(mumps_mat) :: mat
CHARACTER(len=*), OPTIONAL, INTENT(in) :: str
CHARACTER(len=128) :: mumps_grp
!
IF(PRESENT(str)) THEN
CALL creatg(fid, label, str)
ELSE
CALL creatg(fid, label)
END IF
CALL attach(fid, label, 'RANK', mat%rank)
CALL attach(fid, label, 'NNZ', mat%nnz)
CALL attach(fid, label, 'NLSYM', mat%nlsym)
CALL attach(fid, label, 'NLPOS', mat%nlpos)
CALL putarr(fid, TRIM(label)//'/irow', mat%irow)
CALL putarr(fid, TRIM(label)//'/cols', mat%mumps_par%JCN_loc)
CALL putarr(fid, TRIM(label)//'/val', mat%mumps_par%A_loc)
!
mumps_grp = TRIM(label)//'/mumps_par'
CALL creatg(fid, mumps_grp)
CALL attach(fid, mumps_grp, 'PAR', mat%mumps_par%PAR)
CALL attach(fid, mumps_grp, 'SYM', mat%mumps_par%SYM)
CALL putarr(fid, TRIM(mumps_grp)//'/IRN', mat%mumps_par%IRN_loc)
!
END SUBROUTINE myputmat
END PROGRAM