!> !> @file test_stencil.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 !> MODULE mod USE iso_fortran_env, ONLY : real64 IMPLICIT NONE ! INTEGER, PARAMETER :: rkind = real64 LOGICAL, PARAMETER :: nldebug=.FALSE. REAL(rkind), PARAMETER :: PI=4.d0*ATAN(1.0d0) CONTAINS END MODULE mod !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ PROGRAM main USE mpi USE pputils2, ONLY : dist1d, exchange, norm2_vec=>ppnorm2 USE stencil, ONLY : stencil_2d, init, laplacian, vmx, putmat USE mod IMPLICIT NONE ! INTEGER, PARAMETER :: ndims=2 ! INTEGER :: me, neighs(4), npes, ierr INTEGER, DIMENSION(ndims) :: dims=[0,0] INTEGER, DIMENSION(ndims) :: coords, comm1d LOGICAL, DIMENSION(ndims) :: periods=[.FALSE.,.FALSE.] LOGICAL :: reorder =.FALSE. INTEGER :: comm_cart ! INTEGER :: nx=4, ny=4 ! Number of intervals INTEGER, DIMENSION(ndims) :: e, s, lb, ub, npt_glob, npt_loc ! REAL(rkind), ALLOCATABLE :: xgrid(:), ygrid(:) REAL(rkind), ALLOCATABLE :: arr(:,:), fexact(:,:) REAL(rkind), ALLOCATABLE :: barr1(:,:), barr2(:,:), barr3(:,:) REAL(rkind) :: dx, dy REAL(rkind) :: err INTEGER, DIMENSION(5,2) :: id ! 5-point stencil INTEGER :: npoints TYPE(stencil_2d) :: mat INTEGER :: i, j ! NAMELIST /in/ nx, ny !================================================================================ ! 1.0 Prologue ! ! 2D process grid CALL mpi_init(ierr) CALL mpi_comm_rank(MPI_COMM_WORLD, me, ierr) CALL mpi_comm_size(MPI_COMM_WORLD, npes, 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_comm_rank(comm_cart, me, ierr) CALL mpi_cart_coords(comm_cart, me, ndims, coords, ierr) CALL mpi_cart_shift(comm_cart, 0, 1, neighs(1), neighs(2), ierr) CALL mpi_cart_shift(comm_cart, 1, 1, neighs(3), neighs(4), ierr) ! CALL mpi_cart_sub(comm_cart, [.TRUE.,.FALSE.], comm1d(1), ierr) CALL mpi_cart_sub(comm_cart, [.FALSE.,.TRUE.], comm1d(2), ierr) ! ! Read problem inputs IF(me.EQ.0) THEN READ(*,in) WRITE(*,in) END IF CALL mpi_bcast(nx, 1, MPI_INTEGER, 0, comm_cart, ierr) CALL mpi_bcast(ny, 1, MPI_INTEGER, 0, comm_cart, ierr) !================================================================================ ! 2.0 2d Grid construction ! ! Partition 2D 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 END DO WRITE(*,'(a,i3.3,a,2(3i4,", "))') 'PE', me, ' coords, s,e:', & & (coords(i),s(i),e(i),i=1,ndims) ! ! Global mesh dx = 1.0d0/REAL(nx) dy = 1.0d0/REAL(ny) ALLOCATE(xgrid(0:nx)) ALLOCATE(ygrid(0:ny)) xgrid = [ (i*dx, i=0,nx) ] ygrid = [ (i*dy, i=0,ny) ] !================================================================================ ! 3.0 FD Laplacian ! id=RESHAPE([ 0, -1, 0, 1, 0, & 0, 0,-1, 0, 1], & [5,2]) npoints = 5 CALL init(s, e, id, .FALSE., mat, comm_cart) ! CALL laplacian(dx, dy, mat) !================================================================================ ! 4.0 Check matrice-vector product ! ! Local arrays with ghost cells lb = mat%s-1 ub = mat%e+1 ALLOCATE(arr(lb(1):ub(1),lb(2):ub(2))) ALLOCATE(fexact(lb(1):ub(1),lb(2):ub(2))) ALLOCATE(barr1(lb(1):ub(1),lb(2):ub(2))) ALLOCATE(barr2(lb(1):ub(1),lb(2):ub(2))) ALLOCATE(barr3(lb(1):ub(1),lb(2):ub(2))) ! ! Constant vector => Laplacian = 0 barr1 = 0 arr = 1.0 barr1 = vmx(mat,arr) IF(mat%s(1).EQ.0) barr1(0,:) = 0.0 ! discard boundary values IF(mat%e(1).EQ.nx) barr1(nx,:) = 0.0 IF(mat%s(2).EQ.0) barr1(:,0) = 0.0 IF(mat%e(2).EQ.ny) barr1(:,ny) = 0.0 err = norm2_vec(barr1,comm_cart,root=0,garea=[1,1]) IF(me.EQ.0) THEN WRITE(*,'(/a,1pe12.3)') 'Constant vector: ||B1|| =', err END IF ! ! Bilinear vector => Laplacian = 0 arr =0.0d0 barr2=0.0d0 DO j=mat%s(2),mat%e(2) DO i=mat%s(1),mat%e(1) arr(i,j) = xgrid(i)*ygrid(j) END DO END DO CALL exchange(comm_cart, arr) barr2 = vmx(mat,arr) IF(mat%s(1).EQ.0) barr2(0,:) = 0.0 ! discard boundary values IF(mat%e(1).EQ.nx) barr2(nx,:) = 0.0 IF(mat%s(2).EQ.0) barr2(:,0) = 0.0 IF(mat%e(2).EQ.ny) barr2(:,ny) = 0.0 err = norm2_vec(barr2, comm_cart,root=0,garea=[1,1]) IF(me.EQ.0) THEN WRITE(*,'(a,1pe12.3)') 'Bilinear vector: ||B2|| =', err END IF ! ! Biquadratic vector => Laplacian = fexact DO j=mat%s(2),mat%e(2) DO i=mat%s(1),mat%e(1) arr(i,j) = (xgrid(i)*ygrid(j))**2/4.0d0 fexact(i,j) = (xgrid(i)**2 + ygrid(j)**2)/2.0d0 END DO END DO CALL exchange(comm_cart, arr) CALL exchange(comm_cart, fexact) barr3 = vmx(mat,arr) - fexact IF(mat%s(1).EQ.0) barr3(0,:) = 0.0 ! discard boundary values IF(mat%e(1).EQ.nx) barr3(nx,:) = 0.0 IF(mat%s(2).EQ.0) barr3(:,0) = 0.0 IF(mat%e(2).EQ.ny) barr3(:,ny) = 0.0 err = norm2_vec(barr3,comm_cart,root=0,garea=[1,1]) IF(me.EQ.0) THEN WRITE(*,'(a,1pe12.3)') 'Biquadratic vector: ||B3|| =', err END IF !================================================================================ ! 9.0 Epilogue CALL h5file CALL MPI_FINALIZE(ierr) CONTAINS SUBROUTINE disp(str, arr) CHARACTER(len=*), INTENT(in) :: str REAL(rkind), INTENT(in) :: arr(:,:) INTEGER :: j WRITE(*,'(/a)') str DO j=1,SIZE(arr,2) WRITE(*,'(10f8.3)') arr(:,j) END DO END SUBROUTINE disp ! SUBROUTINE h5file USE futils CHARACTER(len=128) :: file='test_stencil.h5' INTEGER :: fid CALL creatf(file, fid, real_prec='d', mpicomm=comm_cart) CALL putarr(fid, '/xgrid', xgrid, ionode=0) ! only rank 0 does IO CALL putarr(fid, '/ygrid', ygrid, ionode=0) ! only rank 0 does IO CALL putarrnd(fid, '/barr1', barr1,(/1,2/), garea=(/1,1/)) CALL putarrnd(fid, '/barr2', barr2,(/1,2/), garea=(/1,1/)) CALL putarrnd(fid, '/barr3', barr3,(/1,2/), garea=(/1,1/)) CALL putmat(fid, '/MAT', mat) CALL closef(fid) END SUBROUTINE h5file ! FUNCTION outerprod(x, y) RESULT(r) ! ! outer product ! REAL(rkind), INTENT(in) :: x(:), y(:) REAL(rkind) :: r(SIZE(x),SIZE(y)) INTEGER :: i, j DO j=1,SIZE(y) DO i=1,SIZE(x) r(i,j) = x(i)*y(j) END DO END DO END FUNCTION outerprod ! FUNCTION rhs(x,y) REAL(rkind), INTENT(in) :: x(:), y(:) REAL(rkind) :: rhs(SIZE(x),SIZE(y)) rhs = -10.d0*pi**2 * outerprod(SIN(pi*x), SIN(3.d0*pi*y)) END FUNCTION rhs ! FUNCTION exact(x,y) REAL(rkind), INTENT(in) :: x(:), y(:) REAL(rkind) :: exact(SIZE(x),SIZE(y)) exact = outerprod(SIN(pi*x), SIN(3.d0*pi*y)) END FUNCTION exact END PROGRAM main