409 lines
9.2 KiB
Fortran
409 lines
9.2 KiB
Fortran
! -*- mode: F90; mode: font-lock -*-
|
|
! ------------------------------------------------------------------------------
|
|
! $Id$
|
|
! ------------------------------------------------------------------------------
|
|
! Module functions
|
|
! ------------------------------------------------------------------------------
|
|
! Code area 9: general
|
|
! ------------------------------------------------------------------------------
|
|
|
|
!!****h* Conquest/functions *
|
|
!! NAME
|
|
!! functions
|
|
!! PURPOSE
|
|
!! Collects mathematical and other useful functions in one module
|
|
!! AUTHOR
|
|
!! D.R.Bowler
|
|
!! CREATION DATE
|
|
!! 2016/02/09
|
|
!! MODIFICATION HISTORY
|
|
!! 2019/11/12 08:13 dave
|
|
!! Adding sort routines
|
|
!! SOURCE
|
|
!!
|
|
module functions
|
|
|
|
implicit none
|
|
|
|
!!***
|
|
|
|
contains
|
|
|
|
! -----------------------------------------------------------
|
|
! Function erfc
|
|
! -----------------------------------------------------------
|
|
|
|
!!****f* DiagModle/erfc *
|
|
!!
|
|
!! NAME
|
|
!! erfc
|
|
!! USAGE
|
|
!! erfc(x)
|
|
!! PURPOSE
|
|
!! Calculated the complementary error function to rounding-error
|
|
!! based on erfc() in ewald_module
|
|
!! accuracy
|
|
!! INPUTS
|
|
!! real(double) :: x, argument of complementary error function
|
|
!! AUTHOR
|
|
!! Iain Chapman/Lianeng Tong
|
|
!! CREATION DATE
|
|
!! 2001 sometime/2010/07/26
|
|
!! MODIFICATION HISTORY
|
|
!! 2016/02/09 08:14 dave
|
|
!! Moved to functions module from DiagModule
|
|
!! SOURCE
|
|
!!
|
|
real(double) function erfc_cq(x)
|
|
|
|
use datatypes
|
|
use numbers, only: RD_ERR, one, zero, half, two
|
|
use GenComms, only: cq_abort
|
|
|
|
implicit none
|
|
|
|
real(double), parameter :: erfc_delta = 1.0e-12_double, &
|
|
erfc_gln = 0.5723649429247447e0_double, &
|
|
erfc_fpmax = 1.e30_double
|
|
integer, parameter:: erfc_iterations = 10000
|
|
|
|
real(double), intent(in) :: x
|
|
|
|
! local variables
|
|
real(double) :: y, y2
|
|
real(double) :: ap, sum, del
|
|
real(double) :: an, b, c, d
|
|
integer :: i
|
|
|
|
if(x < zero) then
|
|
y = -x
|
|
else
|
|
y = x
|
|
end if
|
|
! This expects y^2
|
|
y2 = y*y
|
|
if(y<RD_ERR) then
|
|
erfc_cq = one
|
|
return
|
|
end if
|
|
if (y2 < 2.25_double) then
|
|
ap = half
|
|
sum = two
|
|
del = sum
|
|
do i = 1, erfc_iterations
|
|
ap = ap + 1.0_double
|
|
del = del * y2 / ap
|
|
sum = sum + del
|
|
if (abs(del) < abs(sum) * erfc_delta) exit
|
|
end do
|
|
erfc_cq = one - sum * exp(-y2 + half * log(y2) - erfc_gln)
|
|
else
|
|
b = y2 + half
|
|
c = erfc_fpmax
|
|
d = one / b
|
|
sum = d
|
|
do i = 1, erfc_iterations
|
|
an = - i * (i - half)
|
|
b = b + two
|
|
d = an * d + b
|
|
c = b + an / c
|
|
d = one / d
|
|
del = d * c
|
|
sum = sum * del
|
|
if (abs(del - one) < erfc_delta) exit
|
|
end do
|
|
erfc_cq = sum * exp(-y2 + half * log(y2) - erfc_gln)
|
|
end if
|
|
if (x < zero) erfc_cq = two - erfc_cq
|
|
return
|
|
end function erfc_cq
|
|
!!***
|
|
|
|
!!****f* functions/j0 *
|
|
!!
|
|
!! NAME
|
|
!! j0
|
|
!! USAGE
|
|
!!
|
|
!! PURPOSE
|
|
!! Calculates 0th-order Bessel function
|
|
!! INPUTS
|
|
!! x
|
|
!! OUTPUTS
|
|
!!
|
|
!! USES
|
|
!!
|
|
!! AUTHOR
|
|
!! N. Watanabe (Mizuho) with TM, DRB
|
|
!! CREATION DATE
|
|
!! 2014
|
|
!! MODIFICATION HISTORY
|
|
!! 2015/11/09 17:28 dave
|
|
!! - Moved into pseudo_tm_module
|
|
!! 2016/02/09 08:23 dave
|
|
!! Moved into functions module
|
|
!! SOURCE
|
|
!!
|
|
function j0( x )
|
|
|
|
use datatypes
|
|
use numbers, only: very_small, one_sixth, one
|
|
|
|
implicit none
|
|
|
|
real(double) :: x
|
|
real(double) :: j0
|
|
|
|
if( x<very_small ) then
|
|
j0 = one - one_sixth*x*x
|
|
else
|
|
j0 = sin(x)/x
|
|
endif
|
|
end function j0
|
|
!!***
|
|
|
|
!!****f* functions/j1 *
|
|
!!
|
|
!! NAME
|
|
!! j1
|
|
!! USAGE
|
|
!!
|
|
!! PURPOSE
|
|
!! 1st order bessel function with provision for very small numbers
|
|
!! INPUTS
|
|
!!
|
|
!!
|
|
!! USES
|
|
!!
|
|
!! AUTHOR
|
|
!! NW (Mizuho) with TM and DRB
|
|
!! CREATION DATE
|
|
!! Mid 2014
|
|
!! MODIFICATION HISTORY
|
|
!! 2016/02/09 08:24 dave
|
|
!! Moved to functions module
|
|
!! SOURCE
|
|
!!
|
|
function j1x( x )
|
|
|
|
use datatypes
|
|
use numbers
|
|
|
|
implicit none
|
|
|
|
real(double) :: x
|
|
real(double) :: j1x
|
|
|
|
if( x<very_small ) then
|
|
j1x = one_third - one/30.0_double*x*x
|
|
else
|
|
j1x = (sin(x)-x*cos(x))/(x*x*x)
|
|
endif
|
|
end function j1x
|
|
!!***
|
|
|
|
!!****f* functions/heapsort_integer_index *
|
|
!!
|
|
!! NAME
|
|
!! heapsort_integer_index
|
|
!! USAGE
|
|
!!
|
|
!! PURPOSE
|
|
!! Heap sort for an integer array returning sorted index (not in-place)
|
|
!! Note that this may appear subtly different to standard implementations
|
|
!! Arrays starting at 1 have different parent/child formulae to arrays
|
|
!! starting at 0. Contains the sift_down routine.
|
|
!! INPUTS
|
|
!!
|
|
!!
|
|
!! USES
|
|
!!
|
|
!! AUTHOR
|
|
!! David Bowler
|
|
!! CREATION DATE
|
|
!! 2019/11/12
|
|
!! MODIFICATION HISTORY
|
|
!! SOURCE
|
|
!!
|
|
subroutine heapsort_integer_index(n_arr,array,arr_index,reverse)
|
|
|
|
! Passed variables
|
|
integer :: n_arr
|
|
integer, OPTIONAL :: reverse
|
|
integer, dimension(n_arr) :: array
|
|
integer, dimension(n_arr) :: arr_index, tmp_index
|
|
|
|
! Local variables
|
|
integer :: i, temp
|
|
|
|
! Set up index
|
|
do i=1,n_arr
|
|
arr_index(i) = i
|
|
end do
|
|
if(n_arr==1) return
|
|
! Create heap
|
|
do i = n_arr/2, 1, -1
|
|
call sift_down_integer_index(i, n_arr)
|
|
end do
|
|
! Sort array
|
|
do i=n_arr, 2, -1
|
|
temp = arr_index(1)
|
|
arr_index(1) = arr_index(i)
|
|
arr_index(i) = temp
|
|
call sift_down_integer_index(1, i-1)
|
|
end do
|
|
if(present(reverse)) then
|
|
if(reverse==1) then
|
|
do i=1,n_arr
|
|
tmp_index(n_arr-i+1) = arr_index(i)
|
|
end do
|
|
arr_index = tmp_index
|
|
end if
|
|
end if
|
|
return
|
|
|
|
contains
|
|
|
|
! Note that we inherit access to array and arr_index while this is contained
|
|
! in the original routine
|
|
subroutine sift_down_integer_index(start,end)
|
|
|
|
! Passed variables
|
|
integer :: start, end
|
|
|
|
! Local variables
|
|
integer :: child, root, temp
|
|
|
|
root = start
|
|
! Left child is i*2
|
|
child = root*2
|
|
do while(child<=end)
|
|
! Right child is i*2 + 1
|
|
if(child+1<=end) then
|
|
if(array(arr_index(child))<array(arr_index(child+1))) child = child+1
|
|
end if
|
|
if(array(arr_index(root))<array(arr_index(child))) then
|
|
temp = arr_index(child)
|
|
arr_index(child) = arr_index(root)
|
|
arr_index(root) = temp
|
|
root = child
|
|
child = root*2
|
|
else
|
|
return
|
|
end if
|
|
end do
|
|
return
|
|
end subroutine sift_down_integer_index
|
|
|
|
end subroutine heapsort_integer_index
|
|
|
|
!!****f* functions/heapsort_real_index *
|
|
!!
|
|
!! NAME
|
|
!! heapsort_real_index
|
|
!! USAGE
|
|
!!
|
|
!! PURPOSE
|
|
!! Heap sort for an integer array returning sorted index (not in-place)
|
|
!! Note that this may appear subtly different to standard implementations
|
|
!! Arrays starting at 1 have different parent/child formulae to arrays
|
|
!! starting at 0. Contains the sift_down routine.
|
|
!!
|
|
!! Contains optional flag to signal descending rather than ascending order
|
|
!! INPUTS
|
|
!!
|
|
!!
|
|
!! USES
|
|
!!
|
|
!! AUTHOR
|
|
!! David Bowler
|
|
!! CREATION DATE
|
|
!! 2019/11/12
|
|
!! MODIFICATION HISTORY
|
|
!! 2020/01/24 08:05 dave
|
|
!! Corrected type of temp to integer
|
|
!! SOURCE
|
|
!!
|
|
subroutine heapsort_real_index(n_arr,array,arr_index,reverse)
|
|
|
|
use datatypes
|
|
|
|
implicit none
|
|
|
|
! Passed variables
|
|
integer :: n_arr
|
|
integer, OPTIONAL :: reverse
|
|
real(double), dimension(n_arr) :: array
|
|
integer, dimension(n_arr) :: arr_index, tmp_index
|
|
|
|
! Local variables
|
|
integer :: i, temp
|
|
|
|
! Set up index
|
|
do i=1,n_arr
|
|
arr_index(i) = i
|
|
end do
|
|
if(n_arr==1) return
|
|
! Create heap
|
|
do i = n_arr/2, 1, -1
|
|
call sift_down_real_index(i, n_arr)
|
|
end do
|
|
! Sort array
|
|
do i=n_arr, 2, -1
|
|
temp = arr_index(1)
|
|
arr_index(1) = arr_index(i)
|
|
arr_index(i) = temp
|
|
call sift_down_real_index(1, i-1)
|
|
end do
|
|
! Reverse order (descending) if required
|
|
if(present(reverse)) then
|
|
if(reverse==1) then
|
|
do i=1,n_arr
|
|
tmp_index(n_arr-i+1) = arr_index(i)
|
|
end do
|
|
arr_index = tmp_index
|
|
end if
|
|
end if
|
|
return
|
|
|
|
contains
|
|
|
|
! Note that we inherit access to array and arr_index while this is contained
|
|
! in the original routine
|
|
subroutine sift_down_real_index(start,end)
|
|
|
|
use datatypes
|
|
|
|
implicit none
|
|
|
|
! Passed variables
|
|
integer :: start, end
|
|
|
|
! Local variables
|
|
integer :: child, root, temp
|
|
|
|
root = start
|
|
! Left child is i*2
|
|
child = root*2
|
|
do while(child<=end)
|
|
! Right child is i*2 + 1
|
|
if(child+1<=end) then
|
|
if(array(arr_index(child))<array(arr_index(child+1))) child = child+1
|
|
end if
|
|
if(array(arr_index(root))<array(arr_index(child))) then
|
|
temp = arr_index(child)
|
|
arr_index(child) = arr_index(root)
|
|
arr_index(root) = temp
|
|
root = child
|
|
child = root*2
|
|
else
|
|
return
|
|
end if
|
|
end do
|
|
return
|
|
end subroutine sift_down_real_index
|
|
|
|
end subroutine heapsort_real_index
|
|
|
|
end module functions
|