!> !> @file driv1.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 ! ! Basis splines on a 2d grid. ! USE bsplines USE futils IMPLICIT NONE TYPE(spline1d) :: spx, spy INTEGER :: nx=10, ny=8, nidbas=2, ngauss=4, npts=1000 DOUBLE PRECISION :: a, b, coefx(5), coefy(5) DOUBLE PRECISION, ALLOCATABLE :: xgrid(:), ygrid(:), fun(:,:) DOUBLE PRECISION, ALLOCATABLE :: xp(:), funxp(:,:), yp(:), funyp(:,:) DOUBLE PRECISION :: dx, dy INTEGER :: i, j, left CHARACTER(len=256) :: title INTEGER :: fid NAMELIST /newrun/ nx, ny, nidbas, ngauss, a, b, coefx, coefy !=========================================================================== nidbas = 3 ngauss = 4 nx = 10 ! Number of intevals in x ny = 8 ! Number of intevals in y a = 0.0d0 ! Left boundary of interval b = 1.0d0 ! Right boundary of interval coefx(1:5) = (/1.0d0, 0.d0, 0.d0, 0.d0, 1.d0/) ! Mesh point distribution function coefy(1:5) = (/1.0d0, 0.d0, 0.d0, 0.d0, 1.d0/) ! Mesh point distribution function READ(*,newrun) WRITE(*,newrun) !=========================================================================== ! 1.0 Set up grids ! ALLOCATE( xgrid(0:nx) ) xgrid(0) = a xgrid(nx) = b CALL meshdist(coefx, xgrid, nx) ! !!$ dy = 2.d0*pi/REAL(ny) dy = 1.0d0 ALLOCATE( ygrid(0:ny) ) ygrid(0) = a ygrid(ny) = b CALL meshdist(coefy, ygrid, ny) !=========================================================================== ! 2.0 Set up splines on (x,y) ! CALL set_spline(nidbas, ngauss, xgrid, spx) CALL set_spline(nidbas, ngauss, ygrid, spy, period=.TRUE.) WRITE(*,'(/a,i6,a,i6/(10(f8.3)))') 'KNOTS of x-splines', LBOUND(spx%knots), & & ':',UBOUND(spx%knots), spx%knots WRITE(*,'(2(a,i5, 2x))') 'NX =', nx, 'DIM =', spx%dim WRITE(*,'(/a,i6,a,i6/(10(f8.3)))') 'KNOTS of y-splines', LBOUND(spy%knots), & & ':',UBOUND(spy%knots), spy%knots WRITE(*,'(2(a,i5, 2x))') 'NY =', ny, 'DIM =', spy%dim !=========================================================================== ! 3.0 Graph the splines on (x,y) ! ALLOCATE( fun(nidbas+1,1) ) ! Only 0-th derivative !!$ ALLOCATE( fun(nidbas+1,0:1) ) ! Only 0-th derivative ALLOCATE( xp(npts), funxp(npts,0:spx%dim-1) ) ALLOCATE( yp(npts-1), funyp(npts-1,0:spy%dim-1) ) ! ! Splines in X (non-peridic) ! WRITE(*,'(a)') 'Splines in x' dx = (xgrid(nx)-xgrid(0)) / REAL(NPTS-1) DO i=1,npts xp(i) = xgrid(0) + (i-1)*dx CALL locintv(spx, xp(i), left) CALL basfun(xp(i), spx, fun, left+1) funxp(i,left:left+nidbas) = fun(:,1) END DO ! ! Splines in Y (periodic) ! WRITE(*,'(a)') 'Splines in y' dy = (ygrid(ny)-ygrid(0)) / REAL(NPTS-1) DO i=1,npts-1 yp(i) = ygrid(0) + (i-1)*dy CALL locintv(spy, yp(i), left) CALL basfun(yp(i), spy, fun, left+1) funyp(i,left:left+nidbas) = fun(:,1) END DO ! ! Create hdf5 file ! CALL creatf('driv1.h5', fid, real_prec='d') ! WRITE(title,'(a,i3,5x,a,i6)') 'Splines of degree =', nidbas, 'NX =', nx CALL putarr(fid, 'X', xp) CALL putarr(fid, 'KNOTSX', spx%knots) CALL putarr(fid, 'splinesx', funxp, TRIM(title)) CALL putarr(fid, 'KNOTSY', spy%knots) ! WRITE(title,'(a,i3,5x,a,i6)') 'Periodic splines of degree =', nidbas, 'NY =', ny CALL putarr(fid, 'Y', yp) CALL putarr(fid, 'splinesy', funyp, TRIM(title)) CALL closef(fid) !=========================================================================== ! 9.0 Epilogue ! DEALLOCATE(fun) DEALLOCATE(xgrid, ygrid) DEALLOCATE(xp, funxp) CALL destroy_sp(spx) CALL destroy_sp(spy) END PROGRAM main !+++ SUBROUTINE meshdist(c, x, nx) ! ! Construct an 1d non-equidistant mesh given a ! mesh distribution function. ! IMPLICIT NONE DOUBLE PRECISION, INTENT(in) :: c(5) INTEGER, INTENT(iN) :: nx DOUBLE PRECISION, INTENT(inout) :: x(0:nx) INTEGER :: nintg DOUBLE PRECISION, DIMENSION(:), ALLOCATABLE :: xint, fint DOUBLE PRECISION :: a, b, dx, f0, f1, scal INTEGER :: i, k ! a=x(0) b=x(nx) nintg = 10*nx ALLOCATE(xint(0:nintg), fint(0:nintg)) ! ! Mesh distribution ! dx = (b-a)/REAL(nintg) xint(0) = a fint(0) = 0.0d0 f1 = fdist(xint(0)) DO i=1,nintg f0 = f1 xint(i) = xint(i-1) + dx f1 = fdist(xint(i)) fint(i) = fint(i-1) + 0.5*(f0+f1) END DO ! ! Normalization ! scal = REAL(nx) / fint(nintg) fint(0:nintg) = fint(0:nintg) * scal !!$ WRITE(*,'(a/(10f8.3))') 'FINT', fint ! ! Obtain mesh point by (inverse) interpolation ! k = 1 DO i=1,nintg-1 IF( fint(i) .GE. REAL(k) ) THEN x(k) = xint(i) + (xint(i+1)-xint(i))/(fint(i+1)-fint(i)) * & & (k-fint(i)) k = k+1 END IF END DO ! DEALLOCATE(xint, fint) CONTAINS DOUBLE PRECISION FUNCTION fdist(x) DOUBLE PRECISION, INTENT(in) :: x fdist = c(1) + c(2)*x + c(3)*EXP(-((x-c(4))/c(5))**2) END FUNCTION fdist END SUBROUTINE meshdist !+++