!>
!> @file test_intergrid1.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 implementation of (parallel) matrix-free
!
USE iso_fortran_env, ONLY : rkind => real64
USE parmg, ONLY : grid2_type, init_restrict, coarse, get_lmax, &
& exchange, prolong, restrict, disp, norm_vec
USE pputils2, ONLY : dist1d
USE gvector, ONLY : gvector_2d,OPERATOR(-)
USE futils
USE mpi
IMPLICIT NONE
!
INTEGER, PARAMETER :: ndims=2
INTEGER :: ierr, me, npes
INTEGER, DIMENSION(ndims) :: dims=[0,0]
INTEGER, DIMENSION(ndims) :: lmax, coords, comm1d
LOGICAL, DIMENSION(ndims) :: periods=[.FALSE.,.FALSE.]
LOGICAL :: reorder =.FALSE.
INTEGER :: comm_cart, comm_futils
!
INTEGER :: fin
CHARACTER(len=64) :: filein = 'test_intergrid0.h5'
CHARACTER(len=64) :: dsname
CHARACTER(len=4) :: prb
LOGICAL :: nldebug
!
INTEGER :: nx, ny, levels
TYPE(grid2_type), ALLOCATABLE :: grids(:), new_grids(:)
INTEGER, DIMENSION(ndims) :: e, s, npt_glob, npt_loc, npt_loc_min
!
CHARACTER(len=64) :: str
REAL(rkind) :: err
INTEGER :: i, k, l
!--------------------------------------------------------------------------------
! 1.0 Prologue
!
! Init MPI and setup 2D grid topology
!
CALL mpi_init(ierr)
CALL mpi_comm_size(MPI_COMM_WORLD, npes, ierr)
CALL mpi_comm_rank(MPI_COMM_WORLD, me, ierr)
CALL mpi_dims_create(npes, ndims, dims, ierr)
CALL mpi_cart_create(MPI_COMM_WORLD, ndims, dims, periods, reorder, comm_cart,&
& ierr)
CALL mpi_cart_coords(comm_cart, me, ndims, coords, ierr)
CALL mpi_cart_sub(comm_cart, [.TRUE.,.FALSE.], comm1d(1), ierr)
CALL mpi_cart_sub(comm_cart, [.FALSE.,.TRUE.], comm1d(2), ierr)
!
IF( me .EQ. 0 ) WRITE(*,'(a,i3,i3)') '2d processor grid', dims
!
! Get nx, ny, levels from h5 file created by test_intergrid0
!
IF( command_argument_count() > 0 ) THEN
CALL get_command_argument(1, filein)
END IF
IF(me.EQ.0) WRITE(*,'(a,a)') 'filein = ', TRIM(filein)
!
CALL mpi_comm_dup(comm_cart, comm_futils, ierr)
CALL openf(filein, fin, mpicomm=comm_futils)
CALL getatt(fin, '/', 'NX', nx, ierr)
CALL getatt(fin, '/', 'NY', ny, ierr)
CALL getatt(fin, '/', 'LEVELS', levels, ierr)
CALL getatt(fin, '/', 'PRB', prb, ierr)
CALL getatt(fin, '/', 'NLDEBUG', nldebug, ierr)
IF(me.EQ.0) WRITE(*,'(a,a,3i5,l3)') 'prb, nx, ny, levels: ', prb, nx, ny, &
& levels, nldebug
!--------------------------------------------------------------------------------
! 2.0 Read (f,v) from h5 file
!
ALLOCATE(grids(levels))
!
! Partition on finest grid
!
npt_glob(1) = nx+1
npt_glob(2) = ny+1
DO i=1,ndims
CALL dist1d(comm1d(i), 0, npt_glob(i), s(i), npt_loc(i))
e(i) = s(i) + npt_loc(i) - 1
lmax(i) = get_lmax(s(i), npt_loc(i), 1, comm1d(i))
END DO
npt_loc = e-s+1
IF(me.EQ.0) WRITE(*,'(a,2i4)') 'lmax', lmax
!
! Partition on coaser grids
!
DO l=1,levels
IF(l.GT.1) THEN
CALL coarse(s,e)
npt_loc = e-s+1
CALL mpi_allreduce(npt_loc, npt_loc_min, 2, MPI_INTEGER, &
& MPI_MIN, comm_cart, ierr)
CALL mpi_allreduce(e, npt_glob, 2, MPI_INTEGER, MPI_MAX, &
& comm_cart, ierr)
npt_glob = npt_glob+1
END IF
WRITE(str,'(a,i3,a)') 'Partition at level', l, ': start. index ='
CALL disp(TRIM(str), s, comm_cart)
IF(me.EQ.0) THEN
WRITE(*,'(a,2i6)') 'npt_glob ', npt_glob
WRITE(*,'(a,2i6)') 'npt_loc_min', npt_loc_min
END IF
grids(l)%s = s
grids(l)%e = e
grids(l)%npt = npt_glob
grids(l)%f = gvector_2d(s, e, [1,1])
grids(l)%v = gvector_2d(s, e, [1,1])
ALLOCATE(grids(l)%x(0:npt_glob(1)-1)) ! Global coords (x,y)
ALLOCATE(grids(l)%y(0:npt_glob(2)-1))
WRITE(dsname,'("/mglevels/level.",i2.2)') l
CALL getarr(fin, TRIM(dsname)//"/x", grids(l)%x)
CALL getarr(fin, TRIM(dsname)//"/y", grids(l)%y)
CALL getarrnd(fin, TRIM(dsname)//"/v", grids(l)%v%val, [1,2], garea=[1,1])
CALL getarrnd(fin, TRIM(dsname)//"/f", grids(l)%f%val, [1,2], garea=[1,1])
END DO
!--------------------------------------------------------------------------------
! 3.0 Parallel intergrid transfer
!
ALLOCATE(new_grids(levels))
CALL copy_grids(grids, new_grids)
!
! Set up restriction stencil
!
DO l=2,levels
CALL init_restrict(new_grids(l), prb, comm_cart)
END DO
!
! Prolongation of v
!
DO l=levels-1,1,-1
CALL exchange(comm_cart, grids(l+1)%v)
CALL prolong(grids(l+1)%v, new_grids(l)%v)
IF(nldebug) THEN
IF(me.EQ.0) WRITE(*,'(a)') '====='
DO k=0,npes
IF(me.EQ.k) THEN
s = grids(l+1)%f%s
e = grids(l+1)%f%e
WRITE(*,'(a,i2)') 'reference vbar on proc.', me
DO i=s(1),e(1)
WRITE(*,'(10f8.3)') grids(l+1)%v%val(i,s(2):e(2))
END DO
s = grids(l)%f%s
e = grids(l)%f%e
WRITE(*,'(a,i2)') 'reference v on proc.', me
DO i=s(1),e(1)
WRITE(*,'(10f8.3)') grids(l)%v%val(i,s(2):e(2))
END DO
WRITE(*,'(a,i2)') 'compute v on proc.', me
DO i=s(1),e(1)
WRITE(*,'(10f8.3)') new_grids(l)%v%val(i,s(2):e(2))
END DO
END IF
CALL mpi_barrier(comm_cart, ierr)
END DO
END IF
err = norm_vec(new_grids(l)%v-grids(l)%v, comm_cart, 0)
IF(me.EQ.0) WRITE(*,'(a,i3,1pe12.3)') 'Error of prolongation: ', l, err
END DO
!
! Restriction of f
!
DO l=2,levels
CALL exchange(comm_cart, grids(l-1)%f)
CALL restrict(new_grids(l)%restrict_mat, grids(l-1)%f, new_grids(l)%f)
IF(nldebug) THEN
IF(me.EQ.0) WRITE(*,'(a)') '====='
DO k=0,npes
IF(me.EQ.k) THEN
s = grids(l-1)%f%s
e = grids(l-1)%f%e
WRITE(*,'(a,i2)') 'reference f on proc.', me
DO i=s(1),e(1)
WRITE(*,'(10f8.3)') grids(l-1)%f%val(i,s(2):e(2))
END DO
s = grids(l)%f%s
e = grids(l)%f%e
WRITE(*,'(a,i2)') 'reference fbar on proc.', me
DO i=s(1),e(1)
WRITE(*,'(10f8.3)') grids(l)%f%val(i,s(2):e(2))
END DO
WRITE(*,'(a,i2)') 'compute fbar on proc.', me
DO i=s(1),e(1)
WRITE(*,'(10f8.3)') new_grids(l)%f%val(i,s(2):e(2))
END DO
END IF
CALL mpi_barrier(comm_cart, ierr)
END DO
END IF
err = norm_vec(new_grids(l)%f-grids(l)%f, comm_cart, 0)
IF(me.EQ.0) WRITE(*,'(a,i3,1pe12.3)') 'Error of restriction: ', l, err
END DO
!--------------------------------------------------------------------------------
! 9.0 Epilogue
!
CALL closef(fin)
CALL mpi_finalize(ierr)
!
CONTAINS
SUBROUTINE copy_grids(g1, g2)
TYPE(grid2_type), INTENT(in) :: g1(:)
TYPE(grid2_type), INTENT(out) :: g2(:)
INTEGER :: l
DO l=1,SIZE(g1)
g2(l)%s = g1(l)%s
g2(l)%e = g1(l)%e
g2(l)%npt_loc = g1(l)%npt_loc
g2(l)%npt = g1(l)%npt
ALLOCATE(g2(l)%x(0:g2(l)%npt(1)-1)); g2(l)%x = g1(l)%x
ALLOCATE(g2(l)%y(0:g2(l)%npt(2)-1)); g2(l)%y = g1(l)%y
g2(l)%v = gvector_2d(g1(l)%v%s, g1(l)%v%e, g1(l)%v%g); g2(l)%v%val = g1(l)%f%val
g2(l)%f = gvector_2d(g1(l)%f%s, g1(l)%f%e, g1(l)%f%g); g2(l)%f%val = g1(l)%f%val
END DO
END SUBROUTINE copy_grids
END PROGRAM main