LCOV - code coverage report
Current view: top level - src/70_gw - m_gwls_utility.F90 (source / functions) Coverage Total Hit
Test: coverage.info Lines: 100.0 % 79 79
Test Date: 2026-09-20 18:56:22 Functions: 100.0 % 4 4

            Line data    Source code
       1              : !!****m* ABINIT/m_gwls_utility
       2              : !! NAME
       3              : !! m_gwls_utility
       4              : !!
       5              : !! FUNCTION
       6              : !!  .
       7              : !!
       8              : !! COPYRIGHT
       9              : !! Copyright (C) 2009-2026 ABINIT group (JLJ, BR, MC)
      10              : !! This file is distributed under the terms of the
      11              : !! GNU General Public License, see ~abinit/COPYING
      12              : !! or http://www.gnu.org/copyleft/gpl.txt .
      13              : !!
      14              : !! SOURCE
      15              : 
      16              : #if defined HAVE_CONFIG_H
      17              : #include "config.h"
      18              : #endif
      19              : 
      20              : #include "abi_common.h"
      21              : 
      22              : 
      23              : !---------------------------------------------------------------------
      24              : !  Utility modules, which are not directly related to the
      25              : !  problem to be solved.
      26              : !---------------------------------------------------------------------
      27              : 
      28              : module m_gwls_utility
      29              : !----------------------------------------------------------------------------------------------------
      30              : ! This module contains useful functions and subroutines, which are not necessarily numerical
      31              : ! in nature, for timing, opening files, etc...
      32              : !----------------------------------------------------------------------------------------------------
      33              : 
      34              : ! abinit modules
      35              : use defs_basis
      36              : use m_abicore
      37              : use m_xmpi
      38              : 
      39              : use m_abi_linalg
      40              : use m_io_tools, only : get_unit
      41              : 
      42              : implicit none
      43              : 
      44              : private
      45              : 
      46              : complex(dp), public, parameter :: cmplx_i = (0.0_dp,1.0_dp)
      47              : complex(dp), public, parameter :: cmplx_1 = (1.0_dp,0.0_dp)
      48              : complex(dp), public, parameter :: cmplx_0 = (0.0_dp,0.0_dp)
      49              : 
      50              : logical, public  :: master_debug
      51              : character(len=100), public :: files_status_new='new'
      52              : character(len=100), public :: files_status_old='unknown'
      53              : 
      54              : public :: driver_invert_positive_definite_hermitian_matrix
      55              : public :: ritz_analysis_general, orthogonalize
      56              : public :: complex_vector_product
      57              : !!***
      58              : contains
      59              : 
      60              : !!****f* m_gwls_utility/complex_vector_product
      61              : !! NAME
      62              : !!  complex_vector_product
      63              : !!
      64              : !! FUNCTION
      65              : !!  .
      66              : !!
      67              : !! INPUTS
      68              : !!
      69              : !! OUTPUT
      70              : !!
      71              : !!
      72              : !!
      73              : !! SOURCE
      74              : 
      75         9848 : complex(dp) function complex_vector_product(v1,v2,l)
      76              : !--------------------------------------------------------------------------
      77              : ! This function computes the vector product of two complex vectors.
      78              : !--------------------------------------------------------------------------
      79              : integer,     intent(in)  :: l
      80              : complex(dp),intent(in)  :: v1(l), v2(l)
      81              : ! *************************************************************************
      82              : 
      83      1288680 : complex_vector_product = sum(conjg(v1(:))*v2(:))
      84              : 
      85         9848 : end function complex_vector_product
      86              : !!***
      87              : 
      88              : !!****f* m_gwls_utility/orthogonalize
      89              : !! NAME
      90              : !!  orthogonalize
      91              : !!
      92              : !! FUNCTION
      93              : !!  .
      94              : !!
      95              : !! INPUTS
      96              : !!
      97              : !! OUTPUT
      98              : !!
      99              : !! SOURCE
     100              : 
     101         1904 : subroutine orthogonalize(mpi_communicator, Hsize,Qsize,Xsize,Q,X)
     102              : !--------------------------------------------------------------------------
     103              : ! This function wraps the relevant LAPACK routines to perform
     104              : !
     105              : !                X = (1 - Q.Q^H ) . X
     106              : !
     107              : ! This essentially projects out  the subspace in Q from X.
     108              : ! The array dimensions are:
     109              : !
     110              : !                                Q [ Hsize, Qsize]
     111              : !                                X [ Hsize, Xsize]
     112              : !                                Y [ Hsize, Xsize]
     113              : !
     114              : !  Hsize means "dimension of the Hilbert space", so typically the number
     115              : !  of plane waves...
     116              : !--------------------------------------------------------------------------
     117              : integer,     intent(in)  :: mpi_communicator
     118              : integer,     intent(in)  :: Hsize, Qsize, Xsize
     119              : complex(dp),intent(in)  :: Q(Hsize,Qsize)
     120              : complex(dp),intent(inout)  :: X(Hsize,Xsize)
     121         1904 : complex(dp),allocatable :: C(:,:)
     122              : 
     123              : integer :: ierr
     124              : 
     125              : ! *************************************************************************
     126              : 
     127              : 
     128         7616 : ABI_MALLOC(C,(Qsize,Xsize))
     129              : 
     130              : ! Compute Q^dagger . X
     131              : call ZGEMM(            'C',   & ! Hermitian conjugate the first array
     132              : 'N',   & ! Leave second array as is
     133              : Qsize,   & ! the number of rows of the  matrix op( A )
     134              : Xsize,   & ! the number of columns of the  matrix op( B )
     135              : Hsize,   & ! the number of columns of the  matrix op( A ) == rows of matrix op( B )
     136              : cmplx_1,   & ! alpha constant
     137              : Q,   & ! matrix A
     138              : Hsize,   & ! LDA
     139              : X,   & ! matrix B
     140              : Hsize,   & ! LDB
     141              : cmplx_0,   & ! beta constant
     142              : C,   & ! matrix C
     143         1904 : Qsize)     ! LDC
     144              : 
     145              : 
     146         1904 : call xmpi_sum(C,mpi_communicator,ierr) ! sum on all processors working on FFT!
     147              : 
     148              : ! Compute X - Q.(Q^dagger . X)
     149              : call ZGEMM(            'N',   & ! Leave first array as is
     150              : 'N',   & ! Leave second array as is
     151              : Hsize,   & ! the number of rows of the  matrix op( A )
     152              : Xsize,   & ! the number of columns of the  matrix op( B )
     153              : Qsize,   & ! the number of columns of the  matrix op( A ) == rows of matrix op( B )
     154              : -cmplx_1,   & ! alpha constant
     155              : Q,   & ! matrix A
     156              : Hsize,   & ! LDA
     157              : C,   & ! matrix B
     158              : Qsize,   & ! LDB
     159              : cmplx_1,   & ! beta constant
     160              : X,   & ! matrix C
     161         1904 : Hsize)     ! LDC
     162              : 
     163         1904 : ABI_FREE(C)
     164              : 
     165         1904 : end subroutine orthogonalize
     166              : !!***
     167              : 
     168              : !!****f* m_gwls_utility/driver_invert_positive_definite_hermitian_matrix
     169              : !! NAME
     170              : !!  driver_invert_positive_definite_hermitian_matrix
     171              : !!
     172              : !! FUNCTION
     173              : !!  .
     174              : !!
     175              : !! INPUTS
     176              : !!
     177              : !! OUTPUT
     178              : !!
     179              : !! SOURCE
     180              : 
     181          175 : subroutine driver_invert_positive_definite_hermitian_matrix(matrix,ldim)
     182              : !----------------------------------------------------------------------------------------------------
     183              : !        This is a utility-type subroutine, which encapsulates the many Lapack steps necessary
     184              : !        to invert a positive definite hermitian matrix, and returns the full inverse to avoid
     185              : !        errors!
     186              : !
     187              : !        The subroutine overwrites the input.
     188              : !----------------------------------------------------------------------------------------------------
     189              : integer     , intent(in)    :: ldim
     190              : complex(dp), intent(inout) :: matrix(ldim,ldim)
     191              : 
     192              : ! local variables
     193              : integer      :: i, j
     194              : 
     195              : 
     196              : integer      :: info
     197              : 
     198              : ! *************************************************************************
     199              : 
     200              : 
     201              : 
     202              : ! First, peform a decomposition
     203          175 : call abi_xpotrf( 'U', ldim, matrix, ldim, info )
     204              : 
     205              : ! Second, inverse the matrix in the new format
     206          175 : call zpotri( 'U', ldim,matrix, ldim, info )
     207              : 
     208              : 
     209              : ! Finally,  properly symmetrise the matrix so that it is hermitian!
     210              : ! The upper triangular part of the matrix is correct; the lower triangular must be built
     211         1571 : do j=1, ldim
     212         6449 : do i=j+1, ldim
     213         6274 : matrix(i,j)= conjg(matrix(j,i))
     214              : end do
     215              : end do
     216              : 
     217              : 
     218          175 : end subroutine driver_invert_positive_definite_hermitian_matrix
     219              : !!***
     220              : 
     221              : !!****f* m_gwls_utility/ritz_analysis_general
     222              : !! NAME
     223              : !!  ritz_analysis_general
     224              : !!
     225              : !! FUNCTION
     226              : !!  .
     227              : !!
     228              : !! INPUTS
     229              : !!
     230              : !! OUTPUT
     231              : !!
     232              : !! SOURCE
     233              : 
     234            2 : subroutine ritz_analysis_general(mpi_communicator,matrix_function,lmax,Hsize,Lbasis,eigenvalues)
     235              : !----------------------------------------------------------------------
     236              : !
     237              : ! This subroutine is mostly for testing purposes.
     238              : !
     239              : ! Given a matrix A_{NxN} which undergoes Lanczos analysis to yield
     240              : ! a trigonal matrix T_{k x k}, for k lanczos steps, it is useful to
     241              : ! test how well the eivenalues of T reproduce the eigenvalues of A.
     242              : !
     243              : ! Following Matrix computations by Golub and Van Loan, define
     244              : !
     245              : !                Q = [ |  |  ...  | ],        T = S^H.D.S,  D diagonal, S unitary
     246              : !                    [ q1 q2 ...  qk]
     247              : !                    [ |  |  ...  | ]
     248              : !
     249              : !                Y = Q.S
     250              : !
     251              : ! If tridiagonalisation was taken all the way to k = N, we would expect
     252              : ! Y to contain the eigenvectors of A. It is useful to ask if, for a finite
     253              : ! k, Y already contains good approximations to eigenvectors, by computing
     254              : ! the Ritz residual,
     255              : !
     256              : !        Ri = || A.yi - di yi ||.
     257              : !
     258              : !        INPUTS:
     259              : !                     matrix_function    : the function which yields the action
     260              : !                                        of the implicit matrix on a vector
     261              : !                        lmax            : the total number of Lanczos steps
     262              : !                        Hsize           : the dimension of the Hilbert space
     263              : !                        Lbasis          : the Y matrix
     264              : !                       eigenvalues      : the computed approximate eigenvalues
     265              : !                                        of the matrix
     266              : !----------------------------------------------------------------------
     267              : interface
     268              :   subroutine matrix_function(v_out,v_in,l)
     269              :   use defs_basis
     270              : 
     271              :   integer,     intent(in)  :: l
     272              :   complex(dp), intent(out) :: v_out(l)
     273              :   complex(dp), intent(in)  :: v_in(l)
     274              : 
     275              :   end subroutine matrix_function
     276              : end interface
     277              : 
     278              : 
     279              : integer,      intent(in)    :: Hsize, lmax , mpi_communicator
     280              : complex(dp), intent(in)    :: Lbasis(Hsize,lmax)
     281              : real(dp),     intent(in)    :: eigenvalues(lmax)
     282              : 
     283              : 
     284              : ! local variables
     285            2 : complex(dp),allocatable :: check_matrix(:,:)
     286            2 : complex(dp),allocatable :: yl(:), rl(:), Ayl(:)
     287              : 
     288              : real(dp)     :: lambda_l
     289              : real(dp)     :: check_norm
     290              : integer      :: l, i
     291              : 
     292              : real(dp)     :: norm_ritz, norm_ritz_squared
     293              : 
     294              : character(128) :: filename
     295              : logical        :: file_exists
     296              : integer        :: io_unit
     297              : integer        :: ierr
     298              : integer        :: mpi_rank
     299              : 
     300              : logical        :: head_node
     301              : 
     302              : ! *************************************************************************
     303              : 
     304            8 : ABI_MALLOC(check_matrix,(lmax,lmax))
     305            6 : ABI_MALLOC(yl,(Hsize))
     306            4 : ABI_MALLOC(rl,(Hsize))
     307            4 : ABI_MALLOC(Ayl,(Hsize))
     308              : 
     309            2 : mpi_rank  = xmpi_comm_rank(mpi_communicator)
     310              : 
     311            2 : head_node = mpi_rank == 0
     312              : 
     313            2 : if (head_node) then
     314            2 :   io_unit = get_unit()
     315              : 
     316            2 :   i = 0
     317            2 :   file_exists = .true.
     318            5 :   do while (file_exists)
     319            3 :   i = i+1
     320            3 :   write(filename,'(A,I0.4,A)') "General_Ritz_Analisis_",i,".log"
     321            5 :   inquire(file=filename,exist=file_exists)
     322              :   end do
     323              : 
     324              : 
     325            2 :   open(io_unit,file=filename,status=files_status_new)
     326              : 
     327            2 :   write(io_unit,10) ''
     328            2 :   write(io_unit,10) '#===================================================================================================='
     329            2 :   write(io_unit,10) '# Entering ritz_analisis'
     330            2 :   write(io_unit,10) '# '
     331            2 :   write(io_unit,10) '#  parameters'
     332            2 :   write(io_unit,16) '#          Dimension of Hilbert space    : ',Hsize
     333            2 :   write(io_unit,16) '#          total number of Lanczos steps : ',lmax
     334            2 :   write(io_unit,10) '# '
     335            2 :   write(io_unit,10) '#===================================================================================================='
     336            2 :   write(io_unit,10) ''
     337            2 :   flush(io_unit)
     338              : end if
     339              : 
     340              : ! NEVER use MATMUL! It stores temp arrays on stack, which kills executables compiled with intel!
     341              : ! check_matrix(:,:) = matmul(transpose(conjg(Lbasis)),Lbasis)
     342              : call ZGEMM(            'C',   & ! Hermitian conjugate the first array
     343              : 'N',   & ! Leave second array as is
     344              : lmax,   & ! the number of rows of the  matrix op( A )
     345              : lmax,   & ! the number of columns of the  matrix op( B )
     346              : Hsize,   & ! the number of columns of the  matrix op( A ) == rows of matrix op( B )
     347              : cmplx_1,   & ! alpha constant
     348              : Lbasis,   & ! matrix A
     349              : Hsize,   & ! LDA
     350              : Lbasis,   & ! matrix B
     351              : Hsize,   & ! LDB
     352              : cmplx_0,   & ! beta constant
     353              : check_matrix,   & ! matrix C
     354            2 : lmax)     ! LDC
     355              : 
     356              : 
     357            2 : call xmpi_sum(check_matrix,mpi_communicator,ierr) ! sum on all processors working on FFT!
     358              : 
     359           18 : do l = 1, lmax
     360           18 : check_matrix(l,l) =  check_matrix(l,l) - cmplx_1
     361              : end do
     362          146 : check_norm = sqrt(sum(abs(check_matrix(:,:))**2))
     363              : 
     364              : 
     365            2 : if (head_node) then
     366            2 :   write(io_unit,10) '#'
     367            2 :   write(io_unit,11) '#  Is the basis orthonormal?   || I - Y^H . Y || = ',check_norm
     368            2 :   write(io_unit,10) '#'
     369            2 :   flush(io_unit)
     370              : 
     371              : 
     372              :   ! Compute Ritz norms
     373            2 :   write(io_unit,10) ''
     374            2 :   write(io_unit,10) '#  Ritz analysis Lanczos Basis'
     375            2 :   write(io_unit,10) "#   l               lambda_l                       || R_l ||                                         "
     376            2 :   write(io_unit,10) '#===================================================================================================='
     377            2 :   flush(io_unit)
     378              : end if
     379              : 
     380           18 : do l = 1, lmax
     381              : 
     382           16 : lambda_l = eigenvalues(l)
     383              : 
     384         4144 : yl       = Lbasis(:,l)
     385           16 : call matrix_function(Ayl,yl,Hsize)
     386         4144 : rl       = Ayl - lambda_l*yl
     387              : 
     388         4128 : norm_ritz_squared = sum(abs(rl(:))**2)
     389           16 : call xmpi_sum(norm_ritz_squared ,mpi_communicator,ierr)
     390              : 
     391           16 : norm_ritz = sqrt(norm_ritz_squared )
     392              : 
     393              : 
     394           18 : if (head_node) write(io_unit,14) l, lambda_l, norm_ritz
     395              : 
     396              : end do
     397              : 
     398            2 : if (head_node) then
     399            2 :   flush(io_unit)
     400            2 :   close(io_unit)
     401              : end if
     402              : 
     403              : 
     404            2 : ABI_FREE(check_matrix)
     405            2 : ABI_FREE(yl)
     406            2 : ABI_FREE(rl)
     407            2 : ABI_FREE(Ayl)
     408              : 
     409              : 
     410              : 10 format(A)
     411              : 11 format(A,ES24.16)
     412              : 14 format(I5,2(5X,F24.12))
     413              : 16 format(A,I5)
     414              : 
     415              : 
     416            2 : end subroutine ritz_analysis_general
     417              : !!***
     418              : 
     419              : end module m_gwls_utility
     420              : 
     421              : !!***
        

Generated by: LCOV version 2.3-1