LCOV - code coverage report
Current view: top level - src/70_gw - m_gwls_QR_factorization.F90 (source / functions) Coverage Total Hit
Test: coverage.info Lines: 62.4 % 218 136
Test Date: 2026-09-19 15:24:51 Functions: 100.0 % 4 4

            Line data    Source code
       1              : !!****m* ABINIT/m_gwls_QR_factorization
       2              : !! NAME
       3              : !! m_gwls_QR_factorization
       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              : module m_gwls_QR_factorization
      25              : !----------------------------------------------------------------------------------------------------
      26              : ! This module implements the QR factorization using various algorithms, for the specific
      27              : ! data distribution corresponding to FFT parallelism.
      28              : !
      29              : ! There are standard routines which do this (lapack, scalapack, etc), however it is complicated
      30              : ! to get scalapack to run properly in parallel. Implementing ourselves is the shortest path to
      31              : ! a working solution.
      32              : !----------------------------------------------------------------------------------------------------
      33              : !local modules
      34              : use m_gwls_utility
      35              : use m_gwls_TimingLog
      36              : use m_gwls_wf
      37              : use m_gwls_hamiltonian
      38              : 
      39              : !abinit modules
      40              : use defs_basis
      41              : use defs_wvltypes
      42              : use m_abicore
      43              : use m_xmpi
      44              : use m_errors
      45              : 
      46              : use defs_abitypes, only : MPI_type
      47              : use m_io_tools,  only : get_unit
      48              : use m_time,      only : timab
      49              : 
      50              : 
      51              : implicit none
      52              : save
      53              : private
      54              : !!***
      55              : 
      56              : logical, private ::  debug = .false.
      57              : !!***
      58              : 
      59              : public :: extract_QR, extract_SVD
      60              : !!***
      61              : 
      62              : contains
      63              : 
      64              : !!****f* m_hamiltonian/extract_QR
      65              : !! NAME
      66              : !!  extract_QR
      67              : !!
      68              : !! FUNCTION
      69              : !!  .
      70              : !!
      71              : !! INPUTS
      72              : !!
      73              : !! OUTPUT
      74              : !!
      75              : !! SOURCE
      76              : 
      77         2105 : subroutine extract_QR(mpi_communicator,Hsize,Xsize,Xmatrix,Rmatrix)
      78              : !--------------------------------------------------------------------------
      79              : ! This function computes the QR factorization:
      80              : !
      81              : !                X = Q . R
      82              : !
      83              : ! in order to extract the matrix of orthonormal vectors Q and
      84              : ! the R matrix.
      85              : !
      86              : ! On output, the matrix X is replaced by Q.
      87              : !
      88              : ! If the code is running with only one processor, this routine
      89              : ! simply invokes extract_QR_serial, which wraps standard Lapack routines.
      90              : ! If we are running in MPI parallel, the serial Lapack routines no
      91              : ! longer work (and understanding scalapack is too complicated right now).
      92              : ! Thus, in that case, this routine implements some old school Gram-Schmidt
      93              : ! algorithm.
      94              : !--------------------------------------------------------------------------
      95              : 
      96              : integer,        intent(in) :: Hsize, Xsize, mpi_communicator
      97              : complex(dp),intent(inout) :: Xmatrix(Hsize,Xsize)
      98              : 
      99              : complex(dp),  intent(out),optional :: Rmatrix(Xsize,Xsize)
     100              : 
     101              : ! local variables
     102              : 
     103              : real(dp) :: tsec(2)
     104              : integer :: GWLS_TIMAB, OPTION_TIMAB
     105              : 
     106              : ! *************************************************************************
     107              : 
     108              : 
     109              : 
     110         2105 : GWLS_TIMAB   = 1519
     111         2105 : OPTION_TIMAB = 1
     112         2105 : call timab(GWLS_TIMAB,OPTION_TIMAB,tsec)
     113              : 
     114              : 
     115              : !--------------------------------------------------------------------------------
     116              : ! Implement Gram-Schmidt.
     117              : !--------------------------------------------------------------------------------
     118         2105 : call extract_QR_Householder(mpi_communicator,Hsize,Xsize,Xmatrix,Rmatrix)
     119              : 
     120         2105 : OPTION_TIMAB = 2
     121         2105 : call timab(GWLS_TIMAB,OPTION_TIMAB,tsec)
     122              : 
     123         2105 : end subroutine extract_QR
     124              : !!***
     125              : 
     126              : 
     127              : !!****f* m_hamiltonian/extract_SVD
     128              : !! NAME
     129              : !!  extract_SVD
     130              : !!
     131              : !! FUNCTION
     132              : !!  .
     133              : !!
     134              : !! INPUTS
     135              : !!
     136              : !! OUTPUT
     137              : !!
     138              : !! SOURCE
     139              : 
     140           28 : subroutine extract_SVD(mpi_communicator, Hsize,lsolutions_max,svd_matrix,svd_values)
     141              : !--------------------------------------------------------------------------
     142              : ! This function computes the singular value decomposition
     143              : !
     144              : !                X = U . SIGMA . V^dagger
     145              : !
     146              : ! More specifically,  the matrix U of orthonormal vectors and SIGMA
     147              : ! the eigenvalues are returned.
     148              : !
     149              : ! different algorithms are used, depending on parallelisation scheme.
     150              : !--------------------------------------------------------------------------
     151              : 
     152              : integer,      intent(in)    :: mpi_communicator
     153              : integer,      intent(in)    :: Hsize, lsolutions_max
     154              : complex(dp), intent(inout) :: svd_matrix(Hsize,lsolutions_max)
     155              : real(dp),     intent(out)   :: svd_values(lsolutions_max)
     156              : 
     157              : 
     158           28 : complex(dp), allocatable   :: Rmatrix(:,:)
     159           28 : complex(dp), allocatable   :: svd_tmp(:,:)
     160              : 
     161              : real(dp) :: tsec(2)
     162              : integer :: GWLS_TIMAB, OPTION_TIMAB
     163              : 
     164              : ! *************************************************************************
     165              : 
     166              : 
     167              : 
     168           28 : GWLS_TIMAB   = 1520
     169           28 : OPTION_TIMAB = 1
     170           28 : call timab(GWLS_TIMAB,OPTION_TIMAB,tsec)
     171              : 
     172              : 
     173              : !if ( mpi_enreg%nproc_fft ==1 ) then
     174              : if ( .false. ) then
     175              : 
     176              :   call extract_SVD_lapack(Hsize,lsolutions_max,svd_matrix,svd_values)
     177              : 
     178              : else
     179              : 
     180          112 :   ABI_MALLOC(Rmatrix,(lsolutions_max,lsolutions_max))
     181              : 
     182              :   ! perform QR first
     183           28 :   call extract_QR(mpi_communicator, Hsize,lsolutions_max,svd_matrix,Rmatrix)
     184              : 
     185              :   ! perform SVD on the much smaller Rmatrix!
     186           28 :   call extract_SVD_lapack(lsolutions_max,lsolutions_max,Rmatrix,svd_values)
     187              : 
     188          112 :   ABI_MALLOC(svd_tmp,(Hsize,lsolutions_max))
     189              : 
     190              :   ! Rmatrix is overwritten with U matrix from SVD. Update the svd_matrix
     191              :   call ZGEMM(            'N',   & ! Leave first array as is
     192              :   'N',   & ! Leave second array as is
     193              :   Hsize,   & ! the number of rows of the  matrix op( A )
     194              :   lsolutions_max,   & ! the number of columns of the  matrix op( B )
     195              :   lsolutions_max,   & ! the number of columns of the  matrix op( A ) == rows of matrix op( B )
     196              :   cmplx_1,   & ! alpha constant
     197              :   svd_matrix,   & ! matrix A
     198              :   Hsize,   & ! LDA
     199              :   Rmatrix,   & ! matrix B
     200              :   lsolutions_max,   & ! LDB
     201              :   cmplx_0,   & ! beta constant
     202              :   svd_tmp,   & ! matrix C
     203           28 :   Hsize)     ! LDC
     204              : 
     205        66268 :   svd_matrix(:,:) = svd_tmp(:,:)
     206              : 
     207           28 :   ABI_FREE(svd_tmp)
     208           28 :   ABI_FREE(Rmatrix)
     209              : end if
     210           28 : OPTION_TIMAB = 2
     211           28 : call timab(GWLS_TIMAB,OPTION_TIMAB,tsec)
     212              : 
     213              : 
     214           28 : end subroutine extract_SVD
     215              : !!***
     216              : 
     217              : !!****f* m_hamiltonian/extract_SVD_lapack
     218              : !! NAME
     219              : !!  extract_SVD_lapack
     220              : !!
     221              : !! FUNCTION
     222              : !!  .
     223              : !!
     224              : !! INPUTS
     225              : !!
     226              : !! OUTPUT
     227              : !!
     228              : !! SOURCE
     229              : 
     230           28 : subroutine extract_SVD_lapack(Hsize,lsolutions_max,svd_matrix,svd_values)
     231              : !--------------------------------------------------------------------------
     232              : ! This function computes the singular value decomposition
     233              : ! using lapack routines. This is not appropriate in MPI parallel!
     234              : !
     235              : !
     236              : !--------------------------------------------------------------------------
     237              : 
     238              : 
     239              : integer,      intent(in)    :: Hsize, lsolutions_max
     240              : complex(dp), intent(inout) :: svd_matrix(Hsize,lsolutions_max)
     241              : real(dp),     intent(out)   :: svd_values(lsolutions_max)
     242              : 
     243              : 
     244              : 
     245              : integer                   :: info_zgesvd
     246              : integer                   :: lwork_svd
     247           28 : complex(dp), allocatable :: work_svd(:)
     248           28 : complex(dp), allocatable :: svd_U(:,:), svd_V(:,:)
     249           28 : real   (dp ), allocatable :: rwork_svd(:)
     250              : 
     251              : integer        :: debug_unit
     252              : character(50)  :: debug_filename
     253              : 
     254              : ! *************************************************************************
     255              : 
     256              : 
     257              : 
     258              : 
     259              : ! allocate arrays for the svd
     260           28 : ABI_MALLOC(svd_U                  ,(1,1))
     261           28 : ABI_MALLOC(svd_V                  ,(1,1))
     262              : 
     263              : 
     264              : ! DIMENSION QUERRY for singluar decomposition problem
     265              : 
     266           84 : ABI_MALLOC(rwork_svd    ,(5*min(Hsize,lsolutions_max)))
     267           28 : ABI_MALLOC(work_svd,(1))
     268           28 : lwork_svd = -1
     269              : 
     270              : call zgesvd('O',            & ! The first min(m,n) columns of U (the left singular vectors) are overwritten on the array A;
     271              : 'N',            & ! no column vectors of V are computed
     272              : Hsize,          & ! number of rows of the matrix
     273              : lsolutions_max, & ! number of columns of the matrix
     274              : svd_matrix,     & ! matrix to be decomposed
     275              : Hsize,          & ! LDA
     276              : svd_values,     & ! singular values
     277              : svd_U,          & ! dummy U; not referenced
     278              : 1,              & ! size of U
     279              : svd_V,          & ! dummy V; not referenced
     280              : 1,              & ! size of V
     281              : work_svd,       & ! work array
     282              : lwork_svd,      & ! size of work array
     283              : rwork_svd,      & ! work array
     284           28 : info_zgesvd )
     285              : 
     286           28 : if ( info_zgesvd /= 0) then
     287            0 :   debug_unit = get_unit()
     288            0 :   write(debug_filename,'(A,I4.4,A)') 'LAPACK_DEBUG_PROC=',mpi_enreg%me,'.log'
     289              : 
     290            0 :   open(debug_unit,file=trim(debug_filename),status='unknown')
     291              : 
     292            0 :   write(debug_unit,'(A)')      '*********************************************************************************************'
     293            0 :   write(debug_unit,'(A,I4,A)') '*      ERROR: info = ',info_zgesvd,' in ZGESVD(1), gwls_QR_factorization'
     294            0 :   write(debug_unit,'(A)')      '*********************************************************************************************'
     295              : 
     296            0 :   close(debug_unit)
     297              : 
     298              : end if
     299              : 
     300              : 
     301              : 
     302              : 
     303              : 
     304              : 
     305           28 : lwork_svd = nint(dble(work_svd(1)))
     306              : 
     307           28 : ABI_FREE(work_svd)
     308              : 
     309           84 : ABI_MALLOC(work_svd,(lwork_svd))
     310              : 
     311              : ! computation run
     312              : 
     313              : call zgesvd('O',            & ! The first min(m,n) columns of U (the left singular vectors) are overwritten on the array A;
     314              : 'N',            & ! no column vectors of V are computed
     315              : Hsize,          & ! number of rows of the matrix
     316              : lsolutions_max, & ! number of columns of the matrix
     317              : svd_matrix,     & ! matrix to be decomposed
     318              : Hsize,          & ! LDA
     319              : svd_values,     & ! singular values
     320              : svd_U,          & ! dummy U; not referenced
     321              : 1,              & ! size of U
     322              : svd_V,          & ! dummy V; not referenced
     323              : 1,              & ! size of V
     324              : work_svd,       & ! work array
     325              : lwork_svd,      & ! size of work array
     326              : rwork_svd,      & ! work array
     327           28 : info_zgesvd )
     328              : 
     329           28 : if ( info_zgesvd /= 0) then
     330            0 :   debug_unit = get_unit()
     331            0 :   write(debug_filename,'(A,I4.4,A)') 'LAPACK_DEBUG_PROC=',mpi_enreg%me,'.log'
     332              : 
     333            0 :   open(debug_unit,file=trim(debug_filename),status='unknown')
     334              : 
     335            0 :   write(debug_unit,'(A)')      '*********************************************************************************************'
     336            0 :   write(debug_unit,'(A,I4,A)') '*      ERROR: info = ',info_zgesvd,' in ZGESVD(2), gwls_QR_factorization'
     337            0 :   write(debug_unit,'(A)')      '*********************************************************************************************'
     338              : 
     339            0 :   close(debug_unit)
     340              : 
     341              : end if
     342              : 
     343              : 
     344              : 
     345              : 
     346           28 : ABI_FREE(work_svd)
     347           28 : ABI_FREE(rwork_svd)
     348           28 : ABI_FREE(svd_U)
     349           28 : ABI_FREE(svd_V)
     350              : 
     351           28 : end subroutine extract_SVD_lapack
     352              : !!***
     353              : 
     354              : 
     355              : 
     356              : 
     357              : 
     358              : !!****f* m_hamiltonian/extract_QR_Householder
     359              : !! NAME
     360              : !!  extract_QR_Householder
     361              : !!
     362              : !! FUNCTION
     363              : !!  .
     364              : !!
     365              : !! INPUTS
     366              : !!
     367              : !! OUTPUT
     368              : !!
     369              : !! SOURCE
     370              : 
     371         1932 : subroutine extract_QR_Householder(mpi_communicator,Hsize,Xsize,Xmatrix,Rmatrix)
     372              : !--------------------------------------------------------------------------
     373              : ! This function computes the QR factorization:
     374              : !
     375              : !                X = Q . R
     376              : !
     377              : ! in order to extract the matrix of orthonormal vectors Q and
     378              : ! the R matrix.
     379              : !
     380              : ! On output, the matrix X is replaced by Q.
     381              : !
     382              : ! This routine uses Householder operations to generate Q and R.
     383              : ! Special attention is given to the fact that the matrix may be
     384              : ! distributed across processors and MPI communication is necessary.
     385              : !
     386              : !--------------------------------------------------------------------------
     387              : 
     388              : integer,        intent(in) :: Hsize, Xsize, mpi_communicator
     389              : complex(dp),intent(inout) :: Xmatrix(Hsize,Xsize)
     390              : 
     391              : complex(dp),  intent(out),optional :: Rmatrix(Xsize,Xsize)
     392              : 
     393              : ! local variables
     394              : integer        :: numbrer_of_plane_waves
     395              : 
     396              : integer        :: io_unit
     397              : integer        :: ierr
     398              : character(50)  :: filename
     399              : logical        :: file_exists
     400              : 
     401              : integer,save :: counter = 0
     402              : 
     403              : integer :: i, j, l_local
     404              : integer :: l1, l2
     405              : 
     406         2105 : integer, allocatable      :: nproc_array(:)
     407              : 
     408         2105 : complex(dp), allocatable :: Qinternal(:,:)
     409         2105 : complex(dp), allocatable :: Rinternal(:,:)
     410         2105 : complex(dp), allocatable :: vj(:)
     411         2105 : complex(dp), allocatable :: A_matrix(:,:)
     412         2105 : complex(dp), allocatable :: V_matrix(:,:)
     413         2105 : complex(dp), allocatable :: list_beta(:)
     414              : complex(dp) :: cmplx_value
     415              : real   (dp ) :: real_value
     416              : 
     417              : complex(dp) :: norm_x
     418              : complex(dp) :: phase
     419         2105 : complex(dp), allocatable :: error(:,:)
     420         2105 : complex(dp), allocatable :: coeff(:)
     421              : 
     422              : 
     423              : integer :: mpi_rank
     424              : integer :: mpi_nproc
     425              : logical :: head_node
     426              : 
     427              : ! *************************************************************************
     428              : 
     429              : 
     430              : !--------------------------------------------------------------------------------
     431              : ! Implement Householder algorithm, in parallel
     432              : !--------------------------------------------------------------------------------
     433         2105 : mpi_nproc        = xmpi_comm_size(mpi_communicator)
     434              : 
     435              : ! extract the rank of this processor in the communicator
     436         2105 : mpi_rank         = xmpi_comm_rank(mpi_communicator)
     437              : 
     438              : ! only head node will write!
     439         2105 : head_node        = mpi_rank == 0
     440              : 
     441              : 
     442              : !--------------------------------------------------------------------------------
     443              : ! Open a log file for the output of extract_QR
     444              : !--------------------------------------------------------------------------------
     445         2105 : if (debug .and.  head_node ) then
     446              : 
     447            0 :   io_unit  = get_unit()
     448            0 :   write(filename,'(A,I0.4,A)') "extract_QR_",mpi_rank,".log"
     449            0 :   inquire(file=trim(filename),exist=file_exists)
     450              : 
     451            0 :   if (file_exists) then
     452            0 :     open(io_unit,file=trim(filename),position='append',status=files_status_old)
     453              :   else
     454            0 :     open(io_unit,file=trim(filename),status=files_status_new)
     455            0 :     write(io_unit,10) "#======================================================================================="
     456            0 :     write(io_unit,10) "#                                                                                       "
     457            0 :     write(io_unit,10) "#   This file contains information regarding the QR factorization, from extract_QR      "
     458            0 :     write(io_unit,25) "#   The algorithm is running in MPI parallel with ",mpi_nproc," processors"
     459            0 :     write(io_unit,10) "#                                                                                       "
     460            0 :     write(io_unit,10) "#======================================================================================="
     461              :   end if
     462              : 
     463            0 :   counter = counter + 1
     464              : 
     465            0 :   write(io_unit,10) "#                                                                                       "
     466            0 :   write(io_unit,11) "#   Call # ", counter
     467            0 :   write(io_unit,10) "#                                                                                       "
     468            0 :   write(io_unit,11) "#                        Hsize    = ",Hsize
     469            0 :   write(io_unit,11) "#                        Xsize    = ",Xsize
     470            0 :   write(io_unit,13) "#                Rmatrix present? = ",present(Rmatrix)
     471              : 
     472              : 
     473              : end if
     474              : 
     475              : !--------------------------------------------------------------------------------
     476              : ! Get the number of plane waves on every processor
     477              : !--------------------------------------------------------------------------------
     478         6315 : ABI_MALLOC(nproc_array,(mpi_nproc))
     479              : 
     480         5426 : nproc_array = 0
     481              : 
     482         2105 : numbrer_of_plane_waves = Hsize ! do this to avoid "intent" problems
     483         2105 : call xmpi_allgather(numbrer_of_plane_waves, nproc_array, mpi_communicator, ierr)
     484              : 
     485              : 
     486              : !--------------------------------------------------------------------------------
     487              : ! Get the offset for each processor
     488              : !
     489              : ! The global index is then given by
     490              : !                   I_{global} = nproc_array(1+rank)+i_{local}
     491              : !
     492              : ! similarly, the local index is given by
     493              : !                  i_{local} = I_{global} - nproc_array(1+rank)
     494              : ! which is only meaningful if 1 <= i_{local} <= Hsize
     495              : !--------------------------------------------------------------------------------
     496              : 
     497         5426 : do j = mpi_nproc, 1, -1
     498         3321 : nproc_array(j) = 0
     499         7026 : do i = 1, j-1
     500         4921 : nproc_array(j) = nproc_array(j)+nproc_array(i)
     501              : end do
     502              : end do
     503              : 
     504              : 
     505              : !--------------------------------------------------------------------------------
     506              : ! Act on the A matrix, following the book by Golub  (more or less ;) )
     507              : !
     508              : !--------------------------------------------------------------------------------
     509              : 
     510         8420 : ABI_MALLOC(A_matrix, (Hsize,Xsize))
     511         6315 : ABI_MALLOC(V_matrix, (Hsize,Xsize))
     512         6315 : ABI_MALLOC(list_beta, (Xsize))
     513         4210 : ABI_MALLOC(coeff   , (Xsize))
     514              : 
     515       486061 : A_matrix(:,:) = Xmatrix(:,:)
     516       486061 : V_matrix(:,:) = cmplx_0
     517         4700 : list_beta(:)  = cmplx_0
     518              : 
     519              : 
     520         6315 : ABI_MALLOC(vj, (Hsize))
     521              : 
     522         4700 : do j = 1, Xsize
     523              : 
     524              : ! Store xj in vj, for now
     525       483956 : vj(:) = A_matrix(:,j)
     526              : 
     527              : 
     528         2595 : if (j > 1) then
     529              :   !------------------------------------------
     530              :   ! set the array to zero all the way to j-1
     531              :   !------------------------------------------
     532          490 :   l_local = j-1-nproc_array(1+mpi_rank)
     533              : 
     534          490 :   if ( l_local > Hsize) then
     535            0 :     vj(:) = cmplx_0
     536          490 :   else if ( l_local <= Hsize  .and. l_local >= 1) then
     537         2260 :     vj(1:l_local) = cmplx_0
     538              :   end if
     539              : 
     540              : end if
     541              : 
     542              : ! compute the norm of x
     543       483956 : norm_x = sum(conjg(vj(:))*vj(:))
     544         2595 : call xmpi_sum(norm_x,mpi_communicator,ierr) ! sum on all processors in communicator
     545         2595 : norm_x = sqrt(norm_x)
     546              : 
     547              : 
     548         4700 : if (abs(norm_x) > tol14) then
     549              :   ! if |x| ~ 0, there is nothing to do! the column in A is full of zeros.
     550              : 
     551              :   ! find the j^th component of x
     552         2595 :   l_local = j-nproc_array(1+mpi_rank)
     553              : 
     554              :   ! update vj, on the right processor!
     555         2595 :   if ( l_local <= Hsize  .and. l_local >= 1) then
     556              : 
     557         1873 :     phase = vj(l_local)
     558              : 
     559         1873 :     if (abs(phase) < tol14) then
     560              :       phase = cmplx_1
     561              :     else
     562         1829 :       phase = phase/abs(phase)
     563              :     end if
     564              : 
     565         1873 :     vj(l_local) = vj(l_local) + phase*norm_x
     566              : 
     567              :   end if
     568              : 
     569              :   !compute beta
     570       483956 :   cmplx_value = sum(conjg(vj(:))*vj(:))
     571         2595 :   call xmpi_sum(cmplx_value,mpi_communicator,ierr) ! sum on all processors
     572              : 
     573         2595 :   list_beta(j) = 2.0_dp/cmplx_value
     574              : 
     575              :   ! store v for later use; this is less efficient than storing it in the null part of A,
     576              :   ! but it is less of a pain to implement. Feel free to clean this up.
     577       483956 :   V_matrix(:,j) = vj(:)
     578              : 
     579              : 
     580              :   ! Update the A matrix
     581              : 
     582              :   ! Compute v^dagger . A
     583              :   !call ZGEMM(            'C',   & ! Hermitian conjugate the first array
     584              :   !                       'N',   & ! Leave second array as is
     585              :   !                         1,   & ! the number of rows of the  matrix op( A )
     586              :   !                 Xsize-j+1,   & ! the number of columns of the  matrix op( B )
     587              :   !                     Hsize,   & ! the number of columns of the  matrix op( A ) == rows of matrix op( B )
     588              :   !                   cmplx_1,   & ! alpha constant
     589              :   !                        vj,   & ! matrix A
     590              :   !                     Hsize,   & ! LDA
     591              :   !       A_matrix(:,j:Xsize),   & ! matrix B
     592              :   !                     Hsize,   & ! LDB
     593              :   !                   cmplx_0,   & ! beta constant
     594              :   !          coeff(:,j:Xsize),   & ! matrix C
     595              :   !                         1)     ! LDC
     596         8655 :   do i = j, Xsize
     597       998876 :   coeff(i) = sum(conjg(vj)*A_matrix(:,i))
     598              :   end do
     599         2595 :   call xmpi_sum(coeff,mpi_communicator,ierr) ! sum on all processors in the communicator
     600              : 
     601              :   ! update A
     602         8655 :   do i = j, Xsize
     603       998876 :   A_matrix(:,i) = A_matrix(:,i) - list_beta(j)*coeff(i)*vj(:)
     604              :   end do
     605              : 
     606              : end if
     607              : 
     608              : end do
     609              : 
     610              : !--------------------------------------------------------------------------------
     611              : ! Extract the R matrix
     612              : !
     613              : !--------------------------------------------------------------------------------
     614              : 
     615         8420 : ABI_MALLOC(Rinternal,(Xsize,Xsize))
     616              : 
     617        14225 : Rinternal = cmplx_0
     618              : 
     619              : 
     620         4700 : do j = 1, Xsize
     621        10760 : do i = 1, j
     622         6060 : l_local = i-nproc_array(1+mpi_rank)
     623              : 
     624         8655 : if ( l_local <= Hsize  .and. l_local >= 1) then
     625         3853 :   Rinternal(i,j) = A_matrix(l_local,j)
     626              : end if
     627              : 
     628              : end do ! i
     629              : end do ! j
     630              : 
     631         2105 : call xmpi_sum(Rinternal,mpi_communicator,ierr) ! sum on all processors
     632              : 
     633              : 
     634              : 
     635              : !--------------------------------------------------------------------------------
     636              : ! Extract the Q matrix
     637              : !
     638              : !--------------------------------------------------------------------------------
     639              : 
     640         6315 : ABI_MALLOC( Qinternal, (Hsize,Xsize))
     641              : 
     642              : ! initialize Q to the identity in the top corner
     643       486061 : Qinternal = cmplx_0
     644              : 
     645         4700 : do j = 1, Xsize
     646         2595 : l_local = j-nproc_array(1+mpi_rank)
     647              : 
     648         4700 : if ( l_local <= Hsize  .and. l_local >= 1 ) then
     649         1873 :   Qinternal(l_local,j) = cmplx_1
     650              : end if
     651              : 
     652              : end do ! j
     653              : 
     654              : 
     655              : ! Build Q interatively
     656         4700 : do j = Xsize,1, -1
     657              : 
     658       483956 : vj(:) = V_matrix(:,j)
     659              : 
     660              : 
     661              : ! Update the A matrix
     662              : 
     663              : ! Compute v^dagger . A
     664              : !call ZGEMM(            'C',   & ! Hermitian conjugate the first array
     665              : !                       'N',   & ! Leave second array as is
     666              : !                         1,   & ! the number of rows of the  matrix op( A )
     667              : !                     Xsize,   & ! the number of columns of the  matrix op( B )
     668              : !                     Hsize,   & ! the number of columns of the  matrix op( A ) == rows of matrix op( B )
     669              : !                   cmplx_1,   & ! alpha constant
     670              : !                        vj,   & ! matrix A
     671              : !                     Hsize,   & ! LDA
     672              : !                 Qinternal,   & ! matrix B
     673              : !                     Hsize,   & ! LDB
     674              : !                   cmplx_0,   & ! beta constant
     675              : !                     coeff,   & ! matrix C
     676              : !                         1)     ! LDC
     677              : 
     678        12120 : do i = 1, Xsize
     679      1511201 : coeff(i) = sum(conjg(vj)*Qinternal(:,i))
     680              : end do
     681         2595 : call xmpi_sum(coeff,mpi_communicator,ierr) ! sum on all processors in communicator
     682              : 
     683              : 
     684              : ! update Q
     685        14225 : do i = 1, Xsize
     686      1511201 : Qinternal(:,i) = Qinternal(:,i) - list_beta(j)*coeff(i)*vj(:)
     687              : end do
     688              : 
     689              : end do ! j
     690              : 
     691              : 
     692              : 
     693              : ! clean up
     694         2105 : ABI_FREE(V_matrix)
     695         2105 : ABI_FREE(coeff)
     696         2105 : ABI_FREE(vj)
     697              : 
     698              : !--------------------------------------------------------------------------------
     699              : ! Do some debug, if requested
     700              : !
     701              : !--------------------------------------------------------------------------------
     702              : 
     703         2105 : if (debug ) then
     704              : 
     705            0 :   if ( head_node ) then
     706              : 
     707            0 :     write(io_unit,20) "#    nproc_array   = ",nproc_array
     708            0 :     flush(io_unit)
     709              : 
     710            0 :     write(io_unit,40) "#    list_beta     = ",real(list_beta)
     711            0 :     flush(io_unit)
     712              :   end if
     713              : 
     714              : 
     715            0 :   ABI_MALLOC(error,(Xsize,Xsize))
     716              : 
     717            0 :   error = cmplx_0
     718              : 
     719            0 :   do l2=1,Xsize
     720            0 :   error(l2,l2) = error(l2,l2) - cmplx_1
     721            0 :   do l1=1,Xsize
     722              : 
     723            0 :   cmplx_value = complex_vector_product(Qinternal(:,l1),Qinternal(:,l2),Hsize)
     724            0 :   call xmpi_sum(cmplx_value,mpi_communicator,ierr) ! sum on all processors working on FFT!
     725              : 
     726            0 :   error(l1,l2) = error(l1,l2)+cmplx_value
     727              : 
     728              :   end do
     729              :   end do
     730              : 
     731            0 :   if ( head_node ) then
     732            0 :     write(io_unit,12) "#               || Q^t.Q - I ||   = ",sqrt(sum(abs(error(:,:))**2))
     733            0 :     flush(io_unit)
     734              :   end if
     735              : 
     736              : 
     737            0 :   ABI_FREE(error)
     738              : 
     739            0 :   ABI_MALLOC(error,(Hsize,Xsize))
     740              : 
     741            0 :   error = Xmatrix
     742              : 
     743            0 :   do l2=1,Xsize
     744            0 :   do l1=1,Xsize
     745            0 :   error(:,l2) = error(:,l2) - Qinternal(:,l1)*Rinternal(l1,l2)
     746              :   end do
     747              :   end do
     748              : 
     749            0 :   real_value = zero
     750            0 :   do l2=1,Xsize
     751            0 :   do l1=1,Xsize
     752            0 :   cmplx_value = complex_vector_product(error(:,l1),error(:,l2),Hsize)
     753              : 
     754            0 :   real_value  = real_value + abs(cmplx_value)**2
     755              :   end do
     756              :   end do
     757              : 
     758            0 :   call xmpi_sum(real_value,mpi_communicator,ierr) ! sum on all processors
     759              : 
     760              : 
     761            0 :   real_value = sqrt(real_value)
     762              : 
     763            0 :   if ( head_node) then
     764            0 :     write(io_unit,12) "#               || Xin - Q.R ||   = ",real_value
     765              : 
     766            0 :     if ( real_value > 1.0D-10 ) write(io_unit,10) "#               ERROR!              "
     767              : 
     768            0 :     write(io_unit,10) '#'
     769            0 :     write(io_unit,10) '# R matrix'
     770            0 :     write(io_unit,10) '#'
     771            0 :     do l1=1, Xsize
     772            0 :     write(io_unit,30) Rinternal(l1,:)
     773              :     end do
     774            0 :     write(io_unit,10) ''
     775            0 :     write(io_unit,10) ''
     776              : 
     777              : 
     778            0 :     write(io_unit,10) '#'
     779            0 :     write(io_unit,10) '# top of A matrix'
     780            0 :     write(io_unit,10) '#'
     781            0 :     do l1=1, 2*Xsize
     782            0 :     write(io_unit,30) A_matrix(l1,:)
     783              :     end do
     784            0 :     write(io_unit,10) ''
     785            0 :     write(io_unit,10) ''
     786              : 
     787            0 :     close(io_unit)
     788              : 
     789              :   end if
     790              : 
     791            0 :   ABI_FREE(error)
     792              : 
     793              : end if
     794              : 
     795              : !--------------------------------------------------------------------------------
     796              : ! Final assignment
     797              : !
     798              : !--------------------------------------------------------------------------------
     799              : 
     800       486061 : Xmatrix = Qinternal
     801              : 
     802         2105 : if (present(Rmatrix)) then
     803        13636 :   Rmatrix = Rinternal
     804              : end if
     805              : 
     806         2105 : ABI_FREE(Qinternal)
     807         2105 : ABI_FREE(Rinternal)
     808         2105 : ABI_FREE(nproc_array)
     809         2105 : ABI_FREE(A_matrix)
     810         2105 : ABI_FREE(list_beta)
     811              : 
     812              : 
     813              : 10 format(A)
     814              : 11 format(A,I8)
     815              : 12 format(A,E24.16)
     816              : 13 format(A,2X,L10)
     817              : 20 format(A,1000I10)
     818              : 25 format(A,I5,A)
     819              : 30 format(1000(F22.16,2X,F22.16,5X))
     820              : 40 format(A,1000(F22.16,5X))
     821              : 
     822         6315 : end subroutine extract_QR_Householder
     823              : !!***
     824              : 
     825              : 
     826              : 
     827              : 
     828              : end module m_gwls_QR_factorization
     829              : !!***
        

Generated by: LCOV version 2.3-1