!> !> @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 . !> !> @author !> (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