!>
!> @file gyro.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
!
! Gyro-average using splines.
! F(x)=cos(x) => \bar F(x,rho) = J_0(rho) cos(x)
!
USE bsplines
USE futils
!
IMPLICIT NONE
INTEGER, PARAMETER :: nx=10, nidbas=3, dim=nx+nidbas, npt=100, &
& nrho=21, nnq=5
DOUBLE PRECISION :: xgrid(0:nx), fgrid(0:nx), coefs(dim)
DOUBLE PRECISION :: xpt(npt), fcalc(npt), fexact(npt)
DOUBLE PRECISION :: averf(0:nx), averfexact(0:nx)
DOUBLE PRECISION, POINTER :: splines(:,:)
TYPE(spline1d) :: spl
DOUBLE PRECISION :: pi, twopi, dx, lperiod, dth
DOUBLE PRECISION :: drho, rho(nrho), erraver(nrho,nnq)
INTEGER :: i, j, nq(nnq)
DOUBLE PRECISION :: dbesj0
!
CHARACTER(len=128) :: file='gyro.h5'
INTEGER :: fid
!
INTERFACE
SUBROUTINE gyro(spl, xgrid, coefs, rho, nq, averf)
USE bsplines
TYPE(spline1d) :: spl
DOUBLE PRECISION, INTENT(in) :: xgrid(0:), coefs(:), rho
INTEGER, INTENT(in) :: nq
DOUBLE PRECISION, INTENT(out) :: averf(0:)
END SUBROUTINE gyro
END INTERFACE
!
pi = 4.0d0*ATAN(1.0d0)
twopi = 2.0d0*pi
!
! Create hdf5 file
CALL creatf(file, fid, 'gyro Result File')
CALL attach(fid, '/', 'NX', nx)
CALL attach(fid, '/', 'NIDBAS', nidbas)
!
! Grid and function values
dx = twopi/nx
xgrid(0) = 0.0d0
DO i=1,nx
xgrid(i) = xgrid(0) + i*dx
END DO
lperiod = xgrid(nx)-xgrid(0)
fgrid = func(xgrid)
!
! Spline interpolation
CALL set_splcoef(nidbas, xgrid, spl, period=.TRUE.)
CALL get_splcoef(spl, fgrid, coefs)
WRITE(*,'(a)') 'Spline coefficients'
WRITE(*,'(i5,f12.4)') (i-1, coefs(i), i=1,dim)
!
! Error of interpolation
CALL RANDOM_NUMBER(xpt)
xpt = twopi*xpt
CALL gridval(spl, xpt, fcalc, 0, coefs)
fexact = func(xpt)
!!$ WRITE(*,'(a)') 'Interpolated and exact f'
!!$ WRITE(*,'(3(1pe12.3))') (xpt(i), fcalc(i), fexact(i), i=1,npt)
WRITE(*,'(a,1pe12.3)') 'Interpolation error', norm2(fcalc-fexact)
CALL putarr(fid, '/X', xpt)
CALL putarr(fid, '/FEXACT', fexact, 'Exact values')
CALL putarr(fid, '/FCALC', fcalc, 'Interpolated values')
!
! Gyro-averaged of F at grid points xgrid(0:nx-1)
drho = 5.0d0/nrho
DO i=1,nrho
rho(i) = i*drho
DO j=1,nnq
nq(j) = 2**(j+1)
CALL gyro(spl, xgrid, coefs, rho(i), nq(j), averf)
averfexact = dbesj0(rho(i))*COS(xgrid)
erraver(i,j) = norm2(averfexact-averf)
END DO
END DO
!
WRITE(*,'(a,f8.3,i5)') 'averaged f at rho, nq =', rho(nrho), nq(nnq)
WRITE(*,'(3(1pe12.3))') (xgrid(i),averf(i),averfexact(i), i=0,nx)
CALL putarr(fid, '/XGRID', xgrid)
CALL putarr(fid, '/AVERF', averf, 'Averaged F')
CALL putarr(fid, '/AVERFEXACT', averfexact, 'Averaged F exact')
!
CALL putarr(fid, '/RHO', rho)
CALL putarr(fid, '/NQ', nq)
CALL putarr(fid, '/ERRAVER', erraver)
!
! Clean up
CALL destroy_sp(spl)
CALL closef(fid)
CONTAINS
FUNCTION func(x)
DOUBLE PRECISION, INTENT(in) :: x(:)
DOUBLE PRECISION :: func(SIZE(x))
func = COS(x)
END FUNCTION func
FUNCTION norm2(x)
DOUBLE PRECISION :: norm2
DOUBLE PRECISION, INTENT(in) :: x(:)
norm2 = SQRT(DOT_PRODUCT(x,x))
END FUNCTION norm2
END PROGRAM main
!
SUBROUTINE gyro(spl, xgrid, coefs, rho, nq, averf)
!
! Gyro-average using spline SPL and NQ point quadratire for
! theta-integration.
!
USE bsplines
IMPLICIT NONE
TYPE(spline1d) :: spl
DOUBLE PRECISION, INTENT(in) :: xgrid(0:), coefs(:), rho
INTEGER, INTENT(in) :: nq
DOUBLE PRECISION, INTENT(out) :: averf(0:)
!
DOUBLE PRECISION :: th(nq), wth(nq), xq(nq)
DOUBLE PRECISION, ALLOCATABLE :: avermat(:,:)
DOUBLE PRECISION :: pi, twopi, lperiod, dth
DOUBLE PRECISION, POINTER :: splines(:,:)
INTEGER :: i, j, iq, nx, dim
!
pi = 4.0d0*ATAN(1.0d0)
twopi = 2.0d0*pi
!
! Quadrature in theta
dth = twopi/nq
th(1) = -pi + dth/2.0d0
DO iq=2,nq
th(iq) = th(iq-1)+dth
END DO
wth = dth
!
! Gyro-averaging matrix
CALL get_dim(spl, dim, nx)
lperiod = xgrid(nx)-xgrid(0)
ALLOCATE(avermat(0:nx,dim))
DO i=0,nx
xq = xgrid(i) + rho*COS(th)
xq = xgrid(0) + MODULO(xq-xgrid(0), lperiod)
CALL allsplines(spl, xq, splines)
DO j=1,dim
avermat(i,j) = DOT_PRODUCT(wth, splines(:,j))/twopi
END DO
END DO
!
! Gyro-averaged of F at grid points xgrid(0:nx)
averf = MATMUL(avermat, coefs)
!
DEALLOCATE(avermat)
END SUBROUTINE gyro