!>
!> @file moments.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
!>
!
! Compute moments of f(x), using its Spline representation
!
MODULE globals
USE bsplines
USE matrix
IMPLICIT NONE
DOUBLE PRECISION, PARAMETER :: pi = 3.14159265359d0
DOUBLE PRECISION, ALLOCATABLE :: xgrid(:), rhs(:), sol(:)
DOUBLE PRECISION, ALLOCATABLE :: finteg(:,:), moms(:)
TYPE(spline1d), SAVE :: splx
TYPE(gbmat), SAVE :: mat
CONTAINS
!+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE dismat(spl, mat)
!
! Assembly FE matrix mat using spline spl
!
TYPE(spline1d), INTENT(in) :: spl
TYPE(gbmat), INTENT(inout) :: mat
INTEGER :: nrank, nx, nidbas, ngauss
INTEGER :: i, igauss, iterm, iw, jt, irow, jcol
DOUBLE PRECISION, ALLOCATABLE :: fun(:,:)
DOUBLE PRECISION, ALLOCATABLE :: xgauss(:), wgauss(:)
DOUBLE PRECISION :: contrib
!
INTEGER :: kterms ! Number of terms in weak form
INTEGER, ALLOCATABLE :: idert(:), iderw(:) ! Derivative order
DOUBLE PRECISION, ALLOCATABLE :: coefs(:)
!===========================================================================
! 1.0 Prologue
!
! Properties of spline space
!
CALL get_dim(spl, nrank, nx, nidbas)
ALLOCATE(fun(0:nidbas,0:1)) ! Spline and its 1st derivative
!
! Weak form
!
kterms = mat%nterms
ALLOCATE(idert(kterms), iderw(kterms), coefs(kterms))
!
! Gauss quadature
!
CALL get_gauss(spl, ngauss)
ALLOCATE(xgauss(ngauss), wgauss(ngauss))
!===========================================================================
! 2.0 Assembly loop
!
DO i=1,nx
CALL get_gauss(spl, ngauss, i, xgauss, wgauss)
DO igauss=1,ngauss
CALL basfun(xgauss(igauss), spl, fun, i)
CALL coefeq(xgauss(igauss), idert, iderw, coefs)
DO iterm=1,kterms
DO jt=0,nidbas
DO iw=0,nidbas
contrib = fun(jt,idert(iterm)) * coefs(iterm) * &
& fun(iw,iderw(iterm)) * wgauss(igauss)
irow=i+iw; jcol=i+jt
CALL updtmat(mat, irow, jcol, contrib)
END DO
END DO
END DO
END DO
END DO
!===========================================================================
! 9.0 Epilogue
!
DEALLOCATE(fun)
DEALLOCATE(xgauss, wgauss)
DEALLOCATE(iderw, idert, coefs)
!
CONTAINS
SUBROUTINE coefeq(x, idt, idw, c)
DOUBLE PRECISION, INTENT(in) :: x
INTEGER, INTENT(out) :: idt(:), idw(:)
DOUBLE PRECISION, INTENT(out) :: c(SIZE(idt))
!
! Mass matrix
!
c(1) = 1.d0
idt(1) = 0
idw(1) = 0
END SUBROUTINE coefeq
END SUBROUTINE dismat
!+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE disrhs(spl, rhs)
!
! Assenbly the RHS using spline spl
!
TYPE(spline1d), INTENT(in) :: spl
DOUBLE PRECISION, INTENT(out) :: rhs(:)
INTEGER :: nrank, nx, nidbas, ngauss
INTEGER :: i, igauss
DOUBLE PRECISION, ALLOCATABLE :: fun(:,:)
DOUBLE PRECISION, ALLOCATABLE :: xgauss(:), wgauss(:)
DOUBLE PRECISION:: contrib
!===========================================================================
! 1.0 Prologue
!
! Properties of spline space
!
CALL get_dim(spl, nrank, nx, nidbas)
!
ALLOCATE(fun(nidbas+1,1)) ! needs only basis functions (no derivatives)
!
! Gauss quadature
!
CALL get_gauss(spl, ngauss)
ALLOCATE(xgauss(ngauss), wgauss(ngauss))
!===========================================================================
! 2.0 Assembly loop
!
rhs(1:nrank) = 0.0d0
!
DO i=1,nx
CALL get_gauss(spl, ngauss, i, xgauss, wgauss)
DO igauss=1,ngauss
CALL basfun(xgauss(igauss), spl, fun, i)
contrib = wgauss(igauss)*rhseq(xgauss(igauss))
rhs(i:i+nidbas) = rhs(i:i+nidbas) + contrib*fun(:,1)
END DO
END DO
!===========================================================================
! 9.0 Epilogue
!
DEALLOCATE(fun)
DEALLOCATE(xgauss, wgauss)
!
CONTAINS
DOUBLE PRECISION FUNCTION rhseq(v)
DOUBLE PRECISION, INTENT(in) :: v
rhseq = SQRT(1.0d0/(2.0d0*pi)) * EXP(-0.5d0*v**2)
END FUNCTION rhseq
END SUBROUTINE disrhs
END MODULE globals
!
!================================================================================
PROGRAM main
USE bsplines
USE globals
IMPLICIT NONE
INTEGER :: nidbas, nx, nmoms, ngauss, rank, kl, ku
INTEGER :: i
DOUBLE PRECISION :: a, b, dx
!
! Input
!
WRITE(*,'(a)') 'Enter, nidbas, a, b, nx, nmoms'
READ(*,*) nidbas, a, b, nx, nmoms
!
! Equidistant mesh
!
ALLOCATE(xgrid(0:nx))
dx = (b-a)/REAL(nx)
DO i=0, nx
xgrid(i) = a + i*dx
END DO
WRITE(*,'(a/(8(1pe12.4)))') 'XGRID', xgrid
!
! Set up spline
!
ngauss = nidbas+1
CALL set_spline(nidbas, ngauss, xgrid, splx)
!
! Mass matrix
!
CALL get_dim(splx, rank) ! Rank of the FE Mass matrix
kl = nidbas
ku = kl
CALL init(kl, ku, rank, 1, mat)
WRITE(*,'(a,3i6)') 'kl, ku, rank', kl, ku, rank
CALL dismat(splx, mat)
!
! RHS
!
ALLOCATE(rhs(rank), sol(rank))
CALL disrhs(splx, rhs)
!
! Solve for Spline coefs
!
CALL factor(mat)
CALL bsolve(mat, rhs, sol)
WRITE(*,'(a/(8(1pe12.4)))') 'SOL', sol
WRITE(*,'(a,1pe20.12)') ' Integral of sol using FINTG', fintg(splx, sol)
!
! Moments
!
ALLOCATE(finteg(rank,0:nmoms), moms(0:nmoms))
CALL calc_integ(splx, finteg)
DO i=0,nmoms
moms(i) = DOT_PRODUCT(sol(:), finteg(:,i))
END DO
WRITE(*,'(a,i3)') 'Moments of orders from 0 to', nmoms
WRITE(*,'(8(1pe20.12))') moms
!
DEALLOCATE(finteg, moms)
DEALLOCATE(rhs, sol)
DEALLOCATE(xgrid)
CALL destroy(mat)
CALL destroy_sp(splx)
END PROGRAM main