LCOV - code coverage report
Current view: top level - src/78_effpot - m_mathfuncs.F90 (source / functions) Coverage Total Hit
Test: coverage.info Lines: 37.4 % 115 43
Test Date: 2026-11-07 19:31:18 Functions: 37.5 % 16 6
Branches: 23.5 % 238 56

             Branch data     Line data    Source code
       1                 :             : 
       2                 :             : #if defined HAVE_CONFIG_H
       3                 :             : #include "config.h"
       4                 :             : #endif
       5                 :             : #include "abi_common.h"
       6                 :             : 
       7                 :             : module m_mathfuncs
       8                 :             : 
       9                 :             :   use defs_basis, only: dp, PI, std_out
      10                 :             :   use m_errors
      11                 :             :   use m_abicore
      12                 :             :   use m_random_xoroshiro128plus
      13                 :             :   implicit none
      14                 :             : 
      15                 :             : 
      16                 :             :   ! integer/real
      17                 :             :   ! change a diagonal (a array) to a matrix
      18                 :             :   ! or get the diagonal of a 2D matrix
      19                 :             :   ! similar to matlab diag function
      20                 :             :   interface diag
      21                 :             :      procedure diag_mat_int
      22                 :             :      procedure diag_mat_real
      23                 :             :      procedure diag_array_int
      24                 :             :      procedure diag_array_real
      25                 :             :   end interface diag
      26                 :             : 
      27                 :             : contains
      28                 :             : 
      29                 :             :   ! vector cross production
      30         [ -  + ]:      865728 :   function cross(a, b) result(c)
      31                 :             :     real(dp), intent(in) :: a(3), b(3)
      32                 :             :     real(dp)  :: c(3)
      33                 :      865728 :     c(1) = a(2)*b(3) - a(3)*b(2)
      34                 :      865728 :     c(2) = a(3)*b(1) - a(1)*b(3)
      35                 :      865728 :     c(3) = a(1)*b(2) - a(2)*b(1)
      36                 :      865728 :     return
      37                 :             :   end function cross
      38                 :             : 
      39                 :             : 
      40                 :             :   ! defines outer product of two vectors.
      41   [ #  #  #  #  :           0 :   function outer_product(a,b) ! result (c)
                   #  # ]
      42                 :             : 
      43                 :             :     real(dp), intent(in) :: a(:), b(:)
      44                 :             :     real(dp)  :: outer_product(size(b, dim=1), size(a, dim=1))
      45                 :             :     integer:: i, j
      46         [ #  # ]:           0 :       do i=1, size(a, dim=1)
      47         [ #  # ]:           0 :         do j=1, size(b, dim=1)
      48                 :           0 :           outer_product(j,i) = a(i)*b(j)
      49                 :             :       enddo
      50                 :             :     enddo
      51                 :           0 :     return
      52                 :             :   end function outer_product
      53                 :             : 
      54                 :             :   !----------------------------------------------------------------------
      55                 :             :   !> @brief compare two arrays a<b
      56                 :             :   !>
      57                 :             :   !> @param[in]  a: integer array
      58                 :             :   !> @param[in]  b: integer array
      59                 :             :   !> @param[in]  N: length of a and b
      60                 :             :   !> @return bool.
      61                 :             :   !----------------------------------------------------------------------
      62   [ -  +  -  + ]:    29097478 :   function array_lessthan(a, b, N) result (y)
      63                 :             :     integer, intent(in)  :: a(:), b(:), N
      64                 :             :     logical :: y
      65                 :             :     integer :: i
      66                 :    29097478 :     y=.False.
      67         [ +  + ]:    66325592 :     do i =1, N
      68         [ +  + ]:    66325592 :        if (a(i).lt.b(i)) then
      69                 :             :           y=.True.
      70                 :             :           exit
      71         [ +  + ]:    48697614 :        elseif (a(i).gt.b(i)) then
      72                 :             :           y=.False.
      73                 :             :           exit
      74                 :             :        end if
      75                 :             :     end do
      76                 :    29097478 :   end function array_lessthan
      77                 :             : 
      78                 :             : 
      79                 :             :   !----------------------------------------------------------------------
      80                 :             :   !> @brief compare two arrays a>b
      81                 :             :   !>
      82                 :             :   !> @param[in]  a: integer array
      83                 :             :   !> @param[in]  b: integer array
      84                 :             :   !> @param[in]  N: length of a and b
      85                 :             :   !> @return bool.
      86                 :             :   !----------------------------------------------------------------------
      87   [ -  +  -  + ]:     1278480 :   function array_morethan(a, b, N) result (y)
      88                 :             :     integer, intent(in)  :: a(:), b(:), N
      89                 :             :     logical :: y
      90                 :             :     integer :: i
      91                 :     1278480 :     y=.False.
      92         [ +  + ]:     1303790 :     do i =1, N
      93         [ +  + ]:     1303790 :        if (a(i).gt.b(i)) then
      94                 :             :           y=.True.
      95                 :             :           exit
      96         [ +  + ]:     1254295 :        elseif (a(i).lt.b(i)) then
      97                 :             :           y=.False.
      98                 :             :           exit
      99                 :             :        end if
     100                 :             :     end do
     101                 :     1278480 :   end function array_morethan
     102                 :             : 
     103                 :             :   !----------------------------------------------------------------------
     104                 :             :   !> @brief compare two arrays a <= b
     105                 :             :   !>
     106                 :             :   !> @param[in]  a: integer array
     107                 :             :   !> @param[in]  b: integer array
     108                 :             :   !> @param[in]  N: length of a and b
     109                 :             :   !> @return bool.
     110                 :             :   !----------------------------------------------------------------------
     111   [ -  +  -  + ]:    15325708 :   function array_le(a, b, N) result (y)
     112                 :             :     integer, intent(in)  :: a(:), b(:), N
     113                 :             :     logical :: y
     114                 :             :     integer :: i
     115                 :    15325708 :     y=.True.
     116         [ +  + ]:    28412720 :     do i =1, N
     117         [ +  + ]:    28412720 :        if (a(i).gt.b(i)) then
     118                 :             :           y=.False.
     119                 :             :           exit
     120         [ +  + ]:    20742931 :        elseif (a(i).lt.b(i)) then
     121                 :             :           y=.True.
     122                 :             :           exit
     123                 :             :        end if
     124                 :             :     end do
     125                 :    15325708 :   end function array_le
     126                 :             : 
     127                 :             : 
     128                 :             : 
     129                 :             : 
     130                 :             :   !----------------------------------------------------------------------
     131                 :             :   !> @brief find an integer from a array
     132                 :             :   !>
     133                 :             :   !> @param[in]  a: the array to find from
     134                 :             :   !> @param[in] x: the value to be find
     135                 :             :   !> @param[out] ix: the index found.  0 if not found.
     136                 :             :   !----------------------------------------------------------------------
     137         [ #  # ]:           0 :   function find_int(a, x) result(ix)
     138                 :             :     integer, intent(in):: a(:), x
     139                 :             :     integer :: ix, i
     140                 :           0 :     ix=0
     141         [ #  # ]:           0 :     do i=1, size(a)
     142         [ #  # ]:           0 :        if( a(i)==x ) then
     143                 :           0 :           ix=i
     144                 :             :        endif
     145                 :             :     end do
     146                 :           0 :   end function find_int
     147                 :             : 
     148                 :             :   !----------------------------------------------------------------------
     149                 :             :   !> @brief find an integer from a SORTED array using binary search
     150                 :             :   !>
     151                 :             :   !> @param[in]  a: the array to find from
     152                 :             :   !> @param[in] x: the value to be find
     153                 :             :   !> @param[out] ix: the index found.  0 if not found.
     154                 :             :   !----------------------------------------------------------------------
     155         [ #  # ]:           0 :   function binsearch_left_integer(a, x) result(ix)
     156                 :             :     integer, intent(in):: a(:), x
     157                 :             :     integer :: n,ix, ub, lb
     158                 :             :     integer , save :: i=1
     159                 :           0 :     n=size(a)
     160   [ #  #  #  # ]:           0 :     if (i<0 .or. i>n) i=(size(a)/2+1)
     161         [ #  # ]:           0 :     if (a(i)==x) then
     162                 :             :        ix=i
     163                 :             :     else
     164                 :             :        ub=n
     165                 :             :        lb=1
     166         [ #  # ]:           0 :        do while (lb<ub)
     167         [ #  # ]:           0 :           i=floor((lb+ub)/2.0)
     168         [ #  # ]:           0 :           if (a(i)< x) then
     169                 :           0 :              lb=i+1
     170                 :             :           else
     171                 :             :              ub=i
     172                 :             :           end if
     173                 :             :        end do
     174         [ #  # ]:           0 :        if(a(lb)==x) then
     175                 :           0 :           ix=lb
     176                 :           0 :           i=ix
     177                 :             :        else
     178                 :             :           ix=0
     179                 :             :        end if
     180                 :             :     endif
     181                 :           0 :   end function binsearch_left_integer
     182                 :             : 
     183                 :             :   !-------------------------------------------------------------------!
     184                 :             :   !Binaray search in a interger list.
     185                 :             :   !  Once it find one match, the index is returned
     186                 :             :   ! Input:
     187                 :             :   !  a: the list.
     188                 :             :   !  x: the element to search for
     189                 :             :   ! Output:
     190                 :             :   !  ix: the index of x. If x is not in a, ix =0. 
     191                 :             :   !-------------------------------------------------------------------!
     192   [ -  +  -  + ]:     3617120 :   function binsearch_left_integerlist(a, x) result(ix)
     193                 :             :     integer, intent(in):: a(:,:), x(:)
     194                 :             :     integer :: n,ix, ub, lb, nx
     195                 :             :     integer , save :: i=1
     196                 :     3617120 :     nx=size(x)
     197                 :     3617120 :     n=size(a, dim=2)
     198   [ +  -  -  + ]:     3617120 :     if (i<0 .or. i>n) i=(size(a, dim=2)/2+1)
     199   [ +  +  +  +  :    10187864 :     if (all(a(:,i)==x(:))) then
                   +  + ]
     200                 :             :        ix=i
     201                 :             :     else
     202                 :             :        ub=n
     203                 :             :        lb=1
     204         [ +  + ]:    32714449 :        do while (lb<ub)
     205         [ -  + ]:    29097478 :           i=floor((lb+ub)/2.0)
     206         [ +  + ]:    32714449 :           if (array_lessthan(a(:, i), x, nx)) then
     207                 :    14026128 :              lb=i+1
     208                 :             :           else
     209                 :             :              ub=i
     210                 :             :           end if
     211                 :             :        end do
     212   [ +  +  +  -  :    14467884 :        if(all(a(:, lb)==x)) then
                   +  - ]
     213                 :     3616971 :           ix=lb
     214                 :     3616971 :           i=ix
     215                 :             :        else
     216                 :             :           ix=0
     217                 :             :        end if
     218                 :             :     endif
     219                 :     3617120 :   end function binsearch_left_integerlist
     220                 :             : 
     221         [ #  # ]:           0 :   subroutine set_random_seed(seed)
     222                 :             : 
     223                 :             :       integer , intent(in) :: seed(:)
     224                 :             :       write(std_out,*) "Warning! Currently I'm not sure about how this function  &
     225                 :           0 :       &(set_random_seed,which calls RANDOM_SEED) works. Do test it!"
     226                 :           0 :       call RANDOM_SEED(put=seed(:))
     227                 :           0 :   end subroutine set_random_seed
     228                 :             : 
     229                 :             :   !----------------------------------------------------------------------
     230                 :             :   !> @brief get the diagonal of a matrix
     231                 :             :   !>
     232                 :             :   !> @param[in]  mat: matrix
     233                 :             :   !> @param[out] ret: the diagonal, a 1d array
     234                 :             :   !----------------------------------------------------------------------
     235   [ #  #  #  # ]:           0 :   pure function diag_mat_real(mat) result (ret)
     236                 :             :     real(dp), intent(in) :: mat(:, :)
     237                 :             :     real(dp):: ret(size(mat, dim=1))
     238                 :             :     integer :: n, i
     239                 :           0 :     n=size(mat, dim=1)
     240         [ #  # ]:           0 :     do i=1, n
     241                 :           0 :        ret(i)=mat(i,i)
     242                 :             :     end do
     243                 :           0 :   end function diag_mat_real
     244                 :             : 
     245                 :             :   !----------------------------------------------------------------------
     246                 :             :   !> @brief get the diagonal of a integer matrix
     247                 :             :   !>
     248                 :             :   !> @param[in]  mat: matrix
     249                 :             :   !> @param[out] ret: the diagonal, a 1d array
     250                 :             :   !----------------------------------------------------------------------
     251   [ #  #  #  # ]:           0 :   pure function diag_mat_int(mat) result (ret)
     252                 :             :     integer, intent(in) :: mat(:, :)
     253                 :             :     integer:: ret(size(mat, dim=1))
     254                 :             :     integer :: n, i
     255                 :           0 :     n=size(mat, dim=1)
     256         [ #  # ]:           0 :     do i=1, n
     257                 :           0 :        ret(i)=mat(i,i)
     258                 :             :     end do
     259                 :           0 :   end function diag_mat_int
     260                 :             : 
     261                 :             :   !----------------------------------------------------------------------
     262                 :             :   !> @brief build a matrix from the diagonal (int)
     263                 :             :   !>
     264                 :             :   !> @param[in]  a: the diagonal array
     265                 :             :   !> @param[out] the matrix
     266                 :             :   !----------------------------------------------------------------------
     267   [ #  #  #  # ]:           0 :   pure function diag_array_int(a) result (ret)
     268                 :             :     integer, intent(in) :: a(:)
     269                 :             :     integer:: ret(size(a), size(a))
     270                 :             :     integer :: i
     271   [ #  #  #  # ]:           0 :     ret(:,:)=0
     272         [ #  # ]:           0 :     do i=1, size(a)
     273                 :           0 :        ret(i, i)=a(i)
     274                 :             :     end do
     275                 :           0 :   end function diag_array_int
     276                 :             : 
     277                 :             :   !----------------------------------------------------------------------
     278                 :             :   !> @brief build a matrix from the diagonal (real)
     279                 :             :   !>
     280                 :             :   !> @param[in]  a: the diagonal array
     281                 :             :   !> @param[out] the matrix
     282                 :             :   !----------------------------------------------------------------------
     283   [ #  #  #  # ]:           0 :   pure function diag_array_real(a) result (ret)
     284                 :             :     real(dp), intent(in) :: a(:)
     285                 :             :     real(dp):: ret(size(a), size(a))
     286                 :             :     integer :: i
     287   [ #  #  #  # ]:           0 :     ret(:,:)=0.0_dp
     288         [ #  # ]:           0 :     do i=1, size(a)
     289                 :           0 :        ret(i, i)=a(i)
     290                 :             :     end do
     291                 :           0 :   end function diag_array_real
     292                 :             : 
     293                 :             : 
     294                 :             : 
     295                 :             :   ! Random number generator; Normal (Gaussian) dist.
     296                 :             :   ! This should NOT be used in practice.
     297                 :             :   ! There is no standart builtin random number in fortran compiler,
     298                 :             :   ! which could be a very bad one.
     299                 :             :   ! also the algorithm used here is not efficient.
     300                 :             :   ! Only for test purpose
     301         [ #  # ]:           0 :   subroutine rand_normal_builtin(a)
     302                 :             : 
     303                 :             :     real(dp), intent(out)::a(:,:)
     304                 :           0 :     real(dp), allocatable :: b(:,:)
     305   [ #  #  #  #  :           0 :     ABI_MALLOC(b, (size(a,dim=1), size(a, dim=2)))
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     306                 :           0 :     call random_number(a)
     307   [ #  #  #  # ]:           0 :     b(:,:) = sqrt(-2*dlog(1.0-a(:,:)))
     308                 :           0 :     call random_number(a)
     309   [ #  #  #  # ]:           0 :     a(:,:)=b(:,:)*cos(PI*a(:,:))
     310         [ #  # ]:           0 :     ABI_FREE(b)
     311                 :           0 :   end subroutine rand_normal_builtin
     312                 :             : 
     313                 :             :   !-------------------------------------------------------------------!
     314                 :             :   ! Shortcut for Hermitian matrix eigen value and eigen vectors.
     315                 :             :   ! Input:
     316                 :             :   !   evecs
     317                 :             :   ! Output:
     318                 :             :   !  evals: eigen values
     319                 :             :   !  evecs: eigen vectors
     320                 :             :   !-------------------------------------------------------------------!
     321   [ #  #  #  # ]:           0 :   subroutine eigensh(evals, evecs)
     322                 :             :     real(dp), intent(inout) :: evals(:)
     323                 :             :     complex(dp), intent(inout) :: evecs(:,:)
     324                 :           0 :     complex(dp), allocatable  :: work(:)
     325                 :             :     integer ::  info, lwork
     326                 :           0 :     real(dp) ::  Rwork(3*size(evecs,1)-2)
     327                 :             :     integer :: ndim
     328                 :             :     external ZHEEV
     329                 :           0 :     ndim = size(evecs, 1)
     330                 :           0 :     lwork = -1
     331         [ #  # ]:           0 :     ABI_MALLOC(work , (1))
     332   [ #  #  #  #  :           0 :     call ZHEEV('V', 'U', ndim, evecs, ndim, evals, work, lwork, rwork, info)
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  #  
                      # ]
     333                 :           0 :     lwork= INT(work(1))
     334                 :           0 :     ABI_SFREE(work)
     335                 :             : 
     336   [ #  #  #  #  :           0 :     ABI_MALLOC(work , (lwork))
          #  #  #  #  #  
             #  #  #  #  
                      # ]
     337   [ #  #  #  #  :           0 :     call ZHEEV('V', 'U', ndim, evecs, ndim, evals, work, lwork, rwork, info)
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  #  
                      # ]
     338         [ #  # ]:           0 :     ABI_SFREE(work)
     339         [ #  # ]:           0 :     IF( INFO.gt.0 ) THEN
     340                 :           0 :        ABI_ERROR('The zheev algorithm failed to compute eigenvalues.')
     341                 :           0 :        STOP
     342                 :             :     END IF
     343                 :           0 :   end subroutine eigensh
     344                 :             : 
     345                 :             :   !-----------------------------------------------------------------------
     346                 :             :   !> @brief rotate vector around axis by angle
     347                 :             :   !>  Using the quaternion rotation algorithm
     348                 :             :   !>   \vec{v}_new = \vec{v} + 2 \vec{r} \cross (\vec{r}\cross\vec{v}
     349                 :             :   !>                  + w \vec{v})
     350                 :             :   !> see https://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation
     351                 :             :   !> @param [in] angle : angle
     352                 :             :   !> @param [in] axis  : axis vector. The norm of axis does not matter.
     353                 :             :   !> @param [in] vec  : vector to roate
     354                 :             :   !> @param [out] vec2 : result vector
     355                 :             :   !-----------------------------------------------------------------------
     356         [ -  + ]:         432 :   function rotate_by_angle_around_axis(angle, axis, vec) result(vec2)
     357                 :             :     real(dp), intent(in) :: angle, axis(3), vec(3)
     358                 :             :     real(dp) :: vec2(3)
     359                 :             :     real(dp) :: half_angle, r(3), w, norm
     360                 :         432 :     half_angle=angle/2.0_dp
     361   [ +  +  +  +  :        1728 :     norm=norm2(axis)
                   -  + ]
     362         [ +  + ]:        1728 :     r(:)=axis(:)/norm * sin(half_angle)
     363                 :         432 :     w=cos(half_angle)
     364                 :             :     ! (w, r) is the quaternion
     365   [ +  +  +  + ]:        3456 :     vec2(:) = vec(:) + 2.0 * cross(r, (cross(r, vec) + w*vec))
     366                 :         432 :   end function rotate_by_angle_around_axis
     367                 :             : 
     368                 :             : end module m_mathfuncs
        

Generated by: LCOV version 2.3-1