!>
!> @file gvector_mod.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
!>
MODULE gvector
!
! Implementation of 2D vectors with arbitrary
! vector bounds and ghost cell width.
!
! T.M. Tran, CRPP-EPFL
! September 2013
!
USE iso_fortran_env, ONLY : rkind => real64
IMPLICIT NONE
PRIVATE
PUBLIC :: gvector_2d, disp, norm2, &
& OPERATOR(+), OPERATOR(-), OPERATOR(*), &
& ASSIGNMENT(=)
TYPE gvector_2d
INTEGER, DIMENSION(2) :: s, e ! vector internal bounds
INTEGER, DIMENSION(2) :: g ! ghost cell widths
REAL(rkind), ALLOCATABLE :: val(:,:)
END TYPE gvector_2d
INTERFACE gvector_2d
MODULE PROCEDURE constructor
END INTERFACE gvector_2d
INTERFACE OPERATOR(+)
MODULE PROCEDURE add_scal
MODULE PROCEDURE add_vec
END INTERFACE OPERATOR(+)
INTERFACE OPERATOR(-)
MODULE PROCEDURE minus_vec
MODULE PROCEDURE substract_vec
END INTERFACE OPERATOR(-)
INTERFACE OPERATOR(*)
MODULE PROCEDURE scale_left
MODULE PROCEDURE scale_right
END INTERFACE OPERATOR(*)
INTERFACE ASSIGNMENT(=)
MODULE PROCEDURE from_scal
MODULE PROCEDURE from_vec
END INTERFACE ASSIGNMENT(=)
INTERFACE norm2
MODULE PROCEDURE norm2_gvector_2d
MODULE PROCEDURE norm2_root_g_2d
MODULE PROCEDURE norm2_all_g_2d
END INTERFACE norm2
CONTAINS
!=======================================================================
FUNCTION constructor(s, e, g) RESULT(res)
INTEGER, INTENT(in) :: s(2), e(2)
INTEGER, OPTIONAL, INTENT(in) :: g(2)
TYPE(gvector_2d) :: res
INTEGER :: lb(2), ub(2)
res%g= 0
IF(PRESENT(g)) res%g = g
res%s = s
res%e = e
lb = res%s - res%g
ub = res%e + res%g
ALLOCATE(res%val(lb(1):ub(1),lb(2):ub(2)))
!
! Initialize to 0 on all ghost cells
res%val(lb(1):s(1)-1,:) = 0._rkind
res%val(e(1)+1:ub(1),:) = 0._rkind
res%val(:,lb(2):s(2)-1) = 0._rkind
res%val(:,e(2)+1:ub(2)) = 0._rkind
END FUNCTION constructor
!=======================================================================
FUNCTION add_vec(lhs, rhs) RESULT(res)
TYPE(gvector_2d), INTENT(in) :: lhs, rhs
TYPE(gvector_2d) :: res
res = gvector_2d(lhs%s, lhs%e, lhs%g)
res%val(res%s(1):res%e(1),res%s(2):res%e(2)) = &
& lhs%val(res%s(1):res%e(1),res%s(2):res%e(2)) + &
& rhs%val(res%s(1):res%e(1),res%s(2):res%e(2))
END FUNCTION add_vec
!=======================================================================
FUNCTION add_scal(lhs, rhs) RESULT(res)
TYPE(gvector_2d), INTENT(in) :: lhs
REAL(rkind), INTENT(in) :: rhs
TYPE(gvector_2d) :: res
res = gvector_2d(lhs%s, lhs%e, lhs%g)
res%val(res%s(1):res%e(1),res%s(2):res%e(2)) = &
& lhs%val(res%s(1):res%e(1),res%s(2):res%e(2)) + rhs
END FUNCTION add_scal
!=======================================================================
FUNCTION minus_vec(this) RESULT(res)
TYPE(gvector_2d), INTENT(in) :: this
TYPE(gvector_2d) :: res
res = gvector_2d(this%s, this%e, this%g)
res%val(res%s(1):res%e(1),res%s(2):res%e(2)) = &
& -this%val(res%s(1):res%e(1),res%s(2):res%e(2))
END FUNCTION minus_vec
!=======================================================================
FUNCTION substract_vec(lhs, rhs) RESULT(res)
TYPE(gvector_2d), INTENT(in) :: lhs, rhs
TYPE(gvector_2d) :: res
res = gvector_2d(lhs%s, lhs%e, lhs%g)
res%val(res%s(1):res%e(1),res%s(2):res%e(2)) = &
& lhs%val(res%s(1):res%e(1),res%s(2):res%e(2)) - &
& rhs%val(res%s(1):res%e(1),res%s(2):res%e(2))
END FUNCTION substract_vec
!=======================================================================
FUNCTION scale_left(lhs, rhs) RESULT(res)
REAL(rkind), INTENT(in) :: lhs
TYPE(gvector_2d), INTENT(in) :: rhs
TYPE(gvector_2d) :: res
res = gvector_2d(rhs%s, rhs%e, rhs%g)
res%val(res%s(1):res%e(1),res%s(2):res%e(2)) = &
& lhs * rhs%val(res%s(1):res%e(1),res%s(2):res%e(2))
END FUNCTION scale_left
!=======================================================================
FUNCTION scale_right(lhs, rhs) RESULT(res)
TYPE(gvector_2d), INTENT(in) :: lhs
REAL(rkind), INTENT(in) :: rhs
TYPE(gvector_2d) :: res
res = gvector_2d(lhs%s, lhs%e, lhs%g)
res%val(res%s(1):res%e(1),res%s(2):res%e(2)) = &
& lhs%val(res%s(1):res%e(1),res%s(2):res%e(2)) * rhs
END FUNCTION scale_right
!=======================================================================
SUBROUTINE from_vec(lhs, rhs)
TYPE(gvector_2d), INTENT(inout) :: lhs
REAL(rkind), INTENT(in) :: rhs(:,:)
INTEGER :: n(2)
n = lhs%e - lhs%s + 1
IF(SIZE(rhs,1).NE.n(1) .OR. SIZE(rhs,2).NE.n(2)) THEN
PRINT*, 'from_vec: sizes of rhs and lhs not equal!'
STOP
END IF
lhs%val(lhs%s(1):lhs%e(1),lhs%s(2):lhs%e(2)) = rhs(:,:)
END SUBROUTINE from_vec
!=======================================================================
SUBROUTINE from_scal(lhs, rhs)
TYPE(gvector_2d), INTENT(inout) :: lhs
REAL(rkind), INTENT(in) :: rhs
lhs%val(lhs%s(1):lhs%e(1),lhs%s(2):lhs%e(2)) = rhs
END SUBROUTINE from_scal
!=======================================================================
SUBROUTINE disp(str,this)
CHARACTER(len=*), INTENT(in) :: str
TYPE(gvector_2d), INTENT(in) :: this
INTEGER :: i
WRITE(*,'(/a,3(" (",i0,",",i0,") "))') str//': s, e, g =',&
& this%s, this%e, this%g
DO i=LBOUND(this%val,1),UBOUND(this%val,1)
WRITE(*,'(10(1pe11.3))') (this%val(i,:))
END DO
END SUBROUTINE disp
!=======================================================================
FUNCTION norm2_gvector_2d(this) RESULT(res)
TYPE(gvector_2d), INTENT(in) :: this
REAL(rkind) :: res
res = NORM2( this%val(this%s(1):this%e(1), &
& this%s(2):this%e(2)) )
END FUNCTION norm2_gvector_2d
!=======================================================================
FUNCTION norm2_root_g_2d(x, comm, root) RESULT(res)
!
! Vector norm of 2d distributed array with ghost cells
!
USE mpi
TYPE(gvector_2d), INTENT(in) :: x
INTEGER, INTENT(in) :: comm
INTEGER, INTENT(in) :: root
REAL(rkind) :: res
INTEGER, PARAMETER :: ndim=2
INTEGER, DIMENSION(ndim) :: s, e
REAL(rkind) :: res_loc
INTEGER :: me, ierr
!
CALL mpi_comm_rank(comm, me, ierr)
s = x%s
e = x%e
res_loc = SUM(x%val(s(1):e(1),s(2):e(2))**2)
res = 0.0
CALL mpi_reduce(res_loc, res, 1, MPI_DOUBLE_PRECISION, MPI_SUM,&
& root, comm, ierr)
IF(me.EQ.root) res = SQRT(res)
END FUNCTION norm2_root_g_2d
!=======================================================================
FUNCTION norm2_all_g_2d(x, comm) RESULT(res)
!
! Vector norm of 2d distributed array with ghost cells
!
USE mpi
TYPE(gvector_2d), INTENT(in) :: x
INTEGER, INTENT(in) :: comm
REAL(rkind) :: res
INTEGER, PARAMETER :: ndim=2
INTEGER, DIMENSION(ndim) :: s, e
REAL(rkind) :: res_loc
INTEGER :: ierr
!
s = x%s
e = x%e
res_loc = SUM(x%val(s(1):e(1),s(2):e(2))**2)
CALL mpi_allreduce(res_loc, res, 1, MPI_DOUBLE_PRECISION, MPI_SUM, &
& comm, ierr)
res = SQRT(res)
END FUNCTION norm2_all_g_2d
!=======================================================================
END MODULE gvector