Branch data 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 : : !!***
|