!> !> @file test_mgp.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 multigrid V-cycle for periodic problems ! USE multigrid IMPLICIT NONE ! INTEGER :: nx=8, nidbas=1, ngauss=2, nits=40 INTEGER :: levels=2, nu1=1, nu2=1, mu=1, nu0=1 CHARACTER(len=4) :: relax='jac ' LOGICAL :: nlfixed = .FALSE. DOUBLE PRECISION :: sigma=1.0d0, kmode=10.0, pi=4.0d0*ATAN(1.0d0) DOUBLE PRECISION :: omega=2.0d0/3.0d0 INTEGER :: l, nrank, dim, its DOUBLE PRECISION :: errdisc_dir DOUBLE PRECISION, ALLOCATABLE :: u_direct(:), u_exact(:), u_calc(:) DOUBLE PRECISION, ALLOCATABLE :: sol_direct(:), sol_calc(:), sol_grid(:) DOUBLE PRECISION, ALLOCATABLE :: err(:), resid(:), errdisc(:) DOUBLE PRECISION, ALLOCATABLE :: errdisc_fmg(:) ! TYPE(grid1d), ALLOCATABLE :: gridx(:) TYPE(mg_info) :: info ! NAMELIST /newrun/ nx, nidbas, ngauss, sigma, kmode, & & relax, nits, nlfixed, levels, nu1, nu2, mu, nu0 !-------------------------------------------------------------------------------- ! 1. Prologue ! Inputs ! READ(*,newrun) WRITE(*,newrun) ! levels = MIN(levels, get_lmax(nx)) ! info%nu1 = nu1 info%nu2 = nu2 info%mu = mu info%nu0 = nu0 info%levels = levels info%relax = relax info%omega = omega ! ! Create grids ! ALLOCATE(gridx(levels)) CALL create_grid(nx, nidbas, ngauss, 0, gridx, period=.TRUE.) 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)%matap, coefeq) END DO ! ! Construct RHS only on the finest grid ! nrank = gridx(1)%rank ! Rank of the system (number of unknowns) dim = nrank+nidbas ! Dimension of Splines space CALL disrhs(gridx(1)%spl, gridx(1)%f, rhs) !-------------------------------------------------------------------------------- ! 2. Direct solution ! WRITE(*,'(//a)') 'Direct solution for the finest grid problem' ALLOCATE(u_direct(0:nx)) ALLOCATE(sol_direct(nrank)) ALLOCATE(sol_grid(dim)) ! Required by GRIDVAL ! CALL direct_solve(gridx(1), sol_direct) sol_grid(1:nrank) = sol_direct(1:nrank) sol_grid(nrank+1:dim) = sol_direct(1:nidbas) CALL gridval(gridx(1)%spl, gridx(1)%x, u_direct, 0, sol_grid) ! errdisc_dir = disc_err(gridx(1)%spl, sol_grid, sol) WRITE(*,'(a,1pe12.3)') 'Discretization error', errdisc_dir !-------------------------------------------------------------------------------- ! 3. Solution from MG V-cycles ! WRITE(*,'(//a)') 'Multigrid MG V-cycles' ALLOCATE(sol_calc(nrank)) ALLOCATE(err(0:nits)) ALLOCATE(errdisc(0:nits)) ALLOCATE(resid(0:nits)) ! ! Initial guess ! sol_calc(:) = 0.0d0 sol_grid(:) = 0.0d0 IF(nlfixed) THEN sol_calc(:) = sol_direct(:) sol_grid(1:nrank) = sol_calc(1:nrank) sol_grid(nrank+1:dim) = sol_calc(1:nidbas) END IF gridx(1)%v(:) = sol_calc(:) err(0) = normf(gridx(1)%matmp, sol_calc-sol_direct) errdisc(0) = disc_err(gridx(1)%spl, sol_grid, sol) resid(0) = residue(gridx(1)%matap, gridx(1)%f, sol_calc) ! ! Iterations ! DO its=1,nits ! CALL mg(gridx, info, 1) sol_calc(:) = gridx(1)%v(:) sol_grid(1:nrank) = sol_calc(1:nrank) sol_grid(nrank+1:dim) = sol_calc(1:nidbas) ! err(its) = normf(gridx(1)%matmp, sol_calc-sol_direct) errdisc(its) = disc_err(gridx(1)%spl, sol_grid, sol) ! will call GRIDVAL resid(its) = residue(gridx(1)%matap, gridx(1)%f, sol_calc) END DO ! WRITE(*,'(a4,3(a12,a8))') 'its', 'error', 'ratio', 'residue', 'ratio', & & 'disc. err', 'ratio' WRITE(*,'(i4,3(1pe12.3,8x))') 0, err(0), resid(0), errdisc(0) WRITE(*,'((i4,3(1pe12.3,0pf8.2)))') (its, err(its), err(its)/err(its-1), & & resid(its), resid(its)/resid(its-1), & & errdisc(its), errdisc(its)/errdisc(its-1), its=1,nits) !-------------------------------------------------------------------------------- ! 4. Solution from FMG ! WRITE(*,'(//a)') 'Full Multigrid' ALLOCATE(errdisc_fmg(nits)) DO its=1,nits info%nu0 = its ! CALL fmg(gridx, info, 1) sol_calc(:) = gridx(1)%v(:) sol_grid(1:nrank) = sol_calc(1:nrank) sol_grid(nrank+1:dim) = sol_calc(1:nidbas) ! errdisc_fmg(its) = disc_err(gridx(1)%spl, sol_grid, sol) ! will call GRIDVAL resid(its) = residue(gridx(1)%matap, gridx(1)%f, sol_calc) END DO WRITE(*,'(a4,2(a12,a8))') 'nu0', 'residue', 'ratio','disc. err', 'ratio' WRITE(*,'((i4,2(1pe12.3,0pf8.3)))') (its, resid(its), resid(its)/resid(its-1), & & errdisc_fmg(its),errdisc_fmg(its)/errdisc_dir, its=1,nits) ! ! Grid values at final iteration ! ALLOCATE(u_exact(0:nx)) ALLOCATE(u_calc(0:nx)) u_exact = sol(gridx(1)%x) CALL gridval(gridx(1)%spl, gridx(1)%x, u_calc, 0, sol_grid) !-------------------------------------------------------------------------------- ! 9. Epilogue ! ! Creata HDF5 file ! CALL h5file !-------------------------------------------------------------------------------- CONTAINS FUNCTION rhs(x) DOUBLE PRECISION, INTENT(in) :: x DOUBLE PRECISION :: rhs rhs = SIN(pi*kmode*x) END FUNCTION rhs FUNCTION sol(x) DOUBLE PRECISION, INTENT(in) :: x(:) DOUBLE PRECISION :: sol(SIZE(x)) sol(:) = 1.0d0/((pi*kmode)**2+sigma)*SIN(pi*kmode*x(:)) END FUNCTION sol SUBROUTINE coefeq(x, idt, idw, c) DOUBLE PRECISION, INTENT(in) :: x INTEGER, INTENT(out) :: idt(:), idw(:) DOUBLE PRECISION, INTENT(out) :: c(:) c(1) = 1.0d0 idt(1) = 1 idw(1) = 1 c(2) = sigma idt(2) = 0 idw(2) = 0 END SUBROUTINE coefeq SUBROUTINE h5file USE futils CHARACTER(len=128) :: file='test_mgp.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, '/', 'RELAX', relax) CALL attach(fid, '/', 'NITS', nits) CALL attach(fid, '/', 'NLFIXED', nlfixed) CALL attach(fid, '/', 'LEVELS', levels) CALL attach(fid, '/', 'NU1', nu1) CALL attach(fid, '/', 'NU2', nu2) CALL attach(fid, '/', 'NU0', nu0) CALL attach(fid, '/', 'MU', mu) CALL creatg(fid, '/mglevels') DO l=1,levels WRITE(dsname,'("/mglevels/level.",i2.2)') l CALL creatg(fid, TRIM(dsname)) CALL putarr(fid, TRIM(dsname)//'/mata', gridx(l)%matap%val) 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 creatg(fid, '/Iterations') CALL putarr(fid, '/Iterations/errors', err) CALL putarr(fid, '/Iterations/residues', resid) CALL putarr(fid, '/Iterations/disc_errors', errdisc) CALL putarr(fid, '/Iterations/disc_errors_fmg', errdisc_fmg) CALL putarr(fid, '/Iterations/xgrid', gridx(1)%x) CALL putarr(fid, '/Iterations/u_direct', u_direct) CALL putarr(fid, '/Iterations/u_exact', u_exact) CALL putarr(fid, '/Iterations/u_calc', u_calc) CALL closef(fid) END SUBROUTINE h5file END PROGRAM main