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