!>
!> @file two_grid.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 .
!>
!> @author
!> (in alphabetical order)
!> @author Trach-Minh Tran
!>
PROGRAM main
!
! Check some properties of grid transfer
!
USE multigrid
USE math_util, ONLY : root_bessj
IMPLICIT NONE
!
INTEGER :: nx=8, nidbas=1, ngauss=2, alpha=0
INTEGER :: modem=22, modep=10
INTEGER :: levels=2
INTEGER :: l, nrank
DOUBLE PRECISION :: sigma=1.0d0, kmode=10.0, pi=4.0d0*ATAN(1.0d0)
DOUBLE PRECISION, ALLOCATABLE :: v_prolong(:)
!
TYPE(grid1d) :: gridx(2)
!
NAMELIST /newrun/ nx, nidbas, ngauss, sigma, kmode, modem, modep, alpha
!--------------------------------------------------------------------------------
! 1. Prologue
! Inputs
!
READ(*,newrun)
WRITE(*,newrun)
!
! Create grids
!
CALL create_grid(nx, nidbas, ngauss, alpha, gridx)
WRITE(*,'(a/(20i6))') 'Number of intervals in grids', (gridx(l)%n, l=1,levels)
!
! Create FE matrice and set BC u(0)=u(1)=0
!
DO l=1,levels
CALL femat(gridx(l)%spl, gridx(l)%mata, coefeq)
!
! Left Dirichlet BC (only for Cartesian geometry)
IF(alpha .EQ. 0) THEN
CALL ibcmat(1, gridx(l)%mata)
END IF
!
! Right Dirichlet BC
CALL ibcmat(gridx(l)%mata%rank, gridx(l)%mata)
!
! BC on grid transfer operator
IF(l.GT.1) THEN
WHERE( ABS(gridx(l)%transf%val) < 1.d-8) gridx(l)%transf%val=0.0d0
IF(alpha .EQ. 0) gridx(l)%transf%val(2:,1)=0.0d0
gridx(l)%transf%val(1:gridx(l-1)%rank-1,gridx(l)%rank)=0.0d0
END IF
END DO
!
! Construct RHS and set BC only on the finest grid
!
nrank = gridx(1)%rank
CALL disrhs(gridx(1)%spl, gridx(1)%f, rhs)
!
! Left Dirichlet BC (only for Cartesian geometry)
IF(alpha .EQ. 0) THEN
gridx(1)%f(1) = 0.0d0
END IF
!
! Right Dirichlet BC
gridx(1)%f(nrank) = 0.0d0
!
! RHS on coarse grid by restriction
!
gridx(2)%f = restrict(gridx(2)%transf,gridx(1)%f)
!--------------------------------------------------------------------------------
! 2. Direct solutions
!
DO l=1,levels
CALL direct_solve(gridx(l), gridx(l)%v)
WRITE(*,'(a,i3/(10(1pe12.3)))') 'Sol at level', l, gridx(l)%v
END DO
!
! Prolongation of coarse solution
!
ALLOCATE(v_prolong(SIZE(gridx(1)%v)))
!
v_prolong = prolong(gridx(2)%transf, gridx(2)%v)
WRITE(*,'(a,i3/(10(1pe12.3)))') 'Prolong. sol.', l, v_prolong
WRITE(*,'(a,1pe12.3)') 'Error ||V_prolong-V_fine||', normf(gridx(1)%matm, v_prolong-gridx(1)%v)
!--------------------------------------------------------------------------------
! 9. Epilogue
!
! Creata HDF5 file
!
CALL h5file
!--------------------------------------------------------------------------------
CONTAINS
SUBROUTINE h5file
USE futils
CHARACTER(len=128) :: file='two_grid.h5'
INTEGER :: fid
INTEGER :: l
CHARACTER(len=64) :: dsname
CALL creatf(file, fid, real_prec='d')
CALL attach(fid, '/', 'NX', nx)
CALL attach(fid, '/', 'NIDBAS', nidbas)
CALL attach(fid, '/', 'SIGMA', sigma)
CALL attach(fid, '/', 'KMODE', kmode)
CALL attach(fid, '/', 'ALPHA', alpha)
CALL attach(fid, '/', 'LEVELS', levels)
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', gridx(l)%mata)
IF(l.GT.1) THEN
CALL putarr(fid, TRIM(dsname)//'/matp', gridx(l)%transf%val)
CALL attach(fid, TRIM(dsname)//'/matp', 'M', gridx(l)%transf%mrows)
CALL attach(fid, TRIM(dsname)//'/matp', 'N', gridx(l)%transf%ncols)
END IF
CALL putarr(fid, TRIM(dsname)//'/f', gridx(l)%f)
CALL putarr(fid, TRIM(dsname)//'/v', gridx(l)%v)
END DO
CALL putarr(fid, '/v_prolong', v_prolong)
END SUBROUTINE h5file
FUNCTION rhs(x)
DOUBLE PRECISION, INTENT(in) :: x
DOUBLE PRECISION :: rhs
DOUBLE PRECISION :: nump
SELECT CASE (alpha)
CASE(0) ! Cartesian geometry
rhs = SIN(pi*kmode*x)
CASE(1) ! Cylindrical
nump = root_bessj(modem, modep)
rhs = x * nump**2 * bessel_jn(modem, nump*x)
END SELECT
END FUNCTION rhs
FUNCTION sol(x)
DOUBLE PRECISION, INTENT(in) :: x(:)
DOUBLE PRECISION :: sol(SIZE(x))
DOUBLE PRECISION :: nump
SELECT CASE (alpha)
CASE(0) ! Cartesian geometry
sol(:) = 1.0d0/((pi*kmode)**2+sigma)*SIN(pi*kmode*x(:))
CASE(1) ! Cylindrical
nump = root_bessj(modem, modep)
sol(:) = bessel_jn(modem, nump*x(:))
END SELECT
END FUNCTION sol
SUBROUTINE coefeq(x, idt, idw, c)
DOUBLE PRECISION, INTENT(in) :: x
INTEGER, INTENT(out) :: idt(:), idw(:)
DOUBLE PRECISION, INTENT(out) :: c(:)
SELECT CASE (alpha)
CASE(0) ! Cartesian geometry
c(1) = 1.0d0
idt(1) = 1
idw(1) = 1
c(2) = sigma
idt(2) = 0
idw(2) = 0
CASE(1) ! Cylindrical
c(1) = x
idt(1) = 1
idw(1) = 1
c(2) = REAL(modem,8)**2/x
idt(2) = 0
idw(2) = 0
END SELECT
END SUBROUTINE coefeq
END PROGRAM main