Line data Source code
1 : !!****m* ABINIT/m_gwls_DielectricArray
2 : !! NAME
3 : !! m_gwls_DielectricArray
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 : module m_gwls_DielectricArray
24 : !----------------------------------------------------------------------------------------------------
25 : ! This module generates and stores the arrays
26 : !
27 : ! { eps^{-1}(iw)-eps_model^{-1}(iw) } in Lanczos basis
28 : ! { eps_model^{-1}(iw) - 1 } in model Lanczos basis
29 : !
30 : ! It makes sense to build these only once, as they do not depend on the external frequency.
31 : !
32 : !----------------------------------------------------------------------------------------------------
33 :
34 : ! local modules
35 : use m_gwls_utility
36 : use m_gwls_wf
37 : use m_gwls_valenceWavefunctions
38 : use m_gwls_hamiltonian
39 : use m_gwls_lineqsolver
40 : use m_gwls_polarisability
41 : use m_gwls_model_polarisability
42 : use m_gwls_GenerateEpsilon
43 : use m_gwls_TimingLog
44 : use m_gwls_QR_factorization
45 : use m_gwls_LanczosBasis
46 :
47 : ! abinit modules
48 : use defs_basis
49 : use m_abicore
50 : use m_xmpi
51 : use m_cgtools
52 :
53 : use m_time, only : timab
54 : use m_io_tools, only: get_unit
55 : use m_gaussian_quadrature, only: get_frequencies_and_weights_legendre
56 :
57 :
58 : implicit none
59 : save
60 :
61 : private
62 : !!***
63 :
64 : ! Frequencies and weights for Legendre integration
65 : real(dp), public, allocatable :: list_omega(:)
66 : real(dp), public, allocatable :: list_weights(:)
67 :
68 : ! Arrays to store the combinations of dielectric operators
69 : complex(dp), public, allocatable :: model_dielectric_Lanczos_basis(:,:,:)
70 : complex(dp), public, allocatable :: projected_dielectric_Lanczos_basis(:,:,:)
71 : complex(dp), public, allocatable :: eps_m1_minus_eps_model_m1(:,:,:)
72 :
73 : complex(dp), public, allocatable :: eps_model_m1_minus_one(:,:,:)
74 : complex(dp),public, allocatable :: eps_model_m1_minus_one_DISTR(:,:,:)
75 :
76 :
77 : ! dimensions of blocks in the model dielectric matrix
78 : integer,public :: nbdblock_epsilon
79 : integer,public :: blocksize_epsilon
80 : logical,public, allocatable :: model_lanczos_vector_belongs_to_this_node(:)
81 : integer,public, allocatable :: model_lanczos_vector_index(:)
82 :
83 :
84 : ! Arrays necessary to project the Sternheimer equation within
85 : ! the computation of the dielectric matrix.
86 : complex(dp), public, allocatable :: projected_epsilon_M_matrix(:,:,:)
87 : complex(dp), public, allocatable :: projected_epsilon_B_matrix(:,:,:)
88 : complex(dp), public, allocatable :: projected_epsilon_G_matrix(:,:,:)
89 :
90 : integer,public, allocatable :: list_lsolutions_EpsilonProjected(:)
91 : !!***
92 :
93 : public :: generate_frequencies_and_weights
94 : public :: cleanup_projected_Sternheimer_epsilon
95 : public :: compute_eps_m1_minus_eps_model_m1
96 : public :: compute_eps_m1_minus_one
97 : public :: compute_eps_model_m1_minus_one
98 : public :: ProjectedSternheimerEpsilon
99 : !!***
100 :
101 : contains
102 :
103 : !!****f* m_hamiltonian/generate_frequencies_and_weights
104 : !! NAME
105 : !! generate_frequencies_and_weights
106 : !!
107 : !! FUNCTION
108 : !! .
109 : !!
110 : !! INPUTS
111 : !!
112 : !! OUTPUT
113 : !!
114 : !! SOURCE
115 :
116 7 : subroutine generate_frequencies_and_weights(npt_gauss)
117 : !--------------------------------------------------------------------------------
118 : !
119 : ! This subroutine computes the frequencies and weights necessary for Gauss-Legendre
120 : ! quadrature, and stores the results in module arrays.
121 : !
122 : !--------------------------------------------------------------------------------
123 : integer, intent(in) :: npt_gauss
124 :
125 :
126 7 : real(dp), allocatable :: list_omega_tmp(:)
127 7 : real(dp), allocatable :: list_weights_tmp(:)
128 :
129 : integer :: i
130 :
131 : ! *************************************************************************
132 :
133 21 : ABI_MALLOC(list_omega_tmp, (npt_gauss))
134 14 : ABI_MALLOC(list_weights_tmp, (npt_gauss))
135 :
136 7 : call get_frequencies_and_weights_legendre(npt_gauss,list_omega_tmp,list_weights_tmp)
137 :
138 :
139 21 : ABI_MALLOC(list_omega, (npt_gauss+1))
140 14 : ABI_MALLOC(list_weights, (npt_gauss+1))
141 :
142 : ! make sure the first frequency in zero!
143 7 : list_omega(1) = zero
144 7 : list_weights(1) = zero
145 :
146 77 : do i = 1,npt_gauss
147 :
148 : ! inverse the order of the frequency points, as they come out
149 : ! in reverse order from the generating subroutine
150 70 : list_omega (i+1) = list_omega_tmp (npt_gauss+1-i)
151 77 : list_weights(i+1) = list_weights_tmp(npt_gauss+1-i)
152 :
153 : end do
154 :
155 :
156 7 : ABI_FREE(list_omega_tmp)
157 7 : ABI_FREE(list_weights_tmp)
158 :
159 :
160 7 : end subroutine generate_frequencies_and_weights
161 : !!***
162 :
163 : !!****f* m_hamiltonian/compute_eps_m1_minus_eps_model_m1
164 : !! NAME
165 : !! compute_eps_m1_minus_eps_model_m1
166 : !!
167 : !! FUNCTION
168 : !! .
169 : !!
170 : !! INPUTS
171 : !!
172 : !! OUTPUT
173 : !!
174 : !! SOURCE
175 :
176 6 : subroutine compute_eps_m1_minus_eps_model_m1(lmax, npt_gauss)
177 : !----------------------------------------------------------------------------------------------------
178 : !
179 : ! This subroutine computes the array
180 : !
181 : ! eps^{-1}(iw) - eps_model^{-1}(iw),
182 : !
183 : ! for all relevant frequencies in the Lanczos basis.
184 : !----------------------------------------------------------------------------------------------------
185 : integer , intent(in) :: lmax, npt_gauss
186 :
187 : character(256) :: timing_string
188 : real(dp) :: time1, time2
189 : real(dp) :: time
190 :
191 : integer :: iw, l
192 6 : complex(dp),allocatable :: dummy_matrix(:,:)
193 6 : complex(dp),allocatable :: iden(:,:)
194 : ! *************************************************************************
195 :
196 6 : timing_string = "#"
197 6 : call write_text_block_in_Timing_log(timing_string)
198 6 : timing_string = "# Computing eps^{-1}(iw) - eps_model^{-1}(iw) "
199 6 : call write_text_block_in_Timing_log(timing_string)
200 6 : timing_string = "#"
201 6 : call write_text_block_in_Timing_log(timing_string)
202 :
203 :
204 6 : call cpu_time(time1)
205 : ! Allocate the module array
206 30 : ABI_MALLOC(eps_m1_minus_eps_model_m1, (lmax,lmax,npt_gauss+1))
207 24 : ABI_MALLOC(dummy_matrix, (lmax,lmax))
208 18 : ABI_MALLOC(iden, (lmax,lmax))
209 :
210 :
211 438 : iden = cmplx_0
212 :
213 54 : do l = 1, lmax
214 54 : iden(l,l) = cmplx_1
215 : end do
216 :
217 72 : do iw = 1, npt_gauss + 1
218 :
219 :
220 4818 : dummy_matrix(:,:) = projected_dielectric_Lanczos_basis(:,:,iw)
221 :
222 66 : call driver_invert_positive_definite_hermitian_matrix(dummy_matrix,lmax)
223 :
224 :
225 4818 : eps_m1_minus_eps_model_m1(:,:,iw) = dummy_matrix(:,:)
226 :
227 4818 : dummy_matrix(:,:) = model_dielectric_Lanczos_basis(:,:,iw)
228 :
229 :
230 :
231 66 : call driver_invert_positive_definite_hermitian_matrix(dummy_matrix,lmax)
232 :
233 4824 : eps_m1_minus_eps_model_m1(:,:,iw) = eps_m1_minus_eps_model_m1(:,:,iw) - dummy_matrix(:,:)
234 :
235 :
236 : end do
237 :
238 :
239 :
240 :
241 : ! Deallocate the arrays which are no longer needed
242 6 : ABI_FREE(model_dielectric_Lanczos_basis)
243 6 : ABI_FREE(projected_dielectric_Lanczos_basis)
244 :
245 :
246 :
247 6 : ABI_FREE(dummy_matrix)
248 6 : ABI_FREE(iden)
249 :
250 :
251 :
252 6 : call cpu_time(time2)
253 6 : time = time2-time1
254 :
255 6 : timing_string = "# Total time : "
256 6 : call write_timing_log(timing_string,time)
257 :
258 :
259 :
260 :
261 6 : end subroutine compute_eps_m1_minus_eps_model_m1
262 : !!***
263 :
264 : !!****f* m_hamiltonian/compute_eps_m1_minus_one
265 : !! NAME
266 : !! compute_eps_m1_minus_one
267 : !!
268 : !! FUNCTION
269 : !! .
270 : !!
271 : !! INPUTS
272 : !!
273 : !! OUTPUT
274 : !!
275 : !! SOURCE
276 :
277 1 : subroutine compute_eps_m1_minus_one(lmax, npt_gauss)
278 : !----------------------------------------------------------------------------------------------------
279 : !
280 : ! This subroutine computes the array
281 : !
282 : ! eps^{-1}(iw) - I
283 : !
284 : ! for all relevant frequencies in the Lanczos basis.
285 : !----------------------------------------------------------------------------------------------------
286 : integer , intent(in) :: lmax, npt_gauss
287 :
288 : character(256) :: timing_string
289 : real(dp) :: time1, time2
290 : real(dp) :: time
291 :
292 : integer :: iw, l
293 1 : complex(dp),allocatable :: dummy_matrix(:,:)
294 1 : complex(dp),allocatable :: iden(:,:)
295 : ! *************************************************************************
296 :
297 1 : timing_string = "#"
298 1 : call write_text_block_in_Timing_log(timing_string)
299 1 : timing_string = "# Computing eps^{-1}(iw) - I "
300 1 : call write_text_block_in_Timing_log(timing_string)
301 1 : timing_string = "#"
302 1 : call write_text_block_in_Timing_log(timing_string)
303 :
304 1 : call cpu_time(time1)
305 : ! Allocate the module array
306 :
307 : ! The array eps_m1_minus_eps_model_m1 will be used to store
308 : ! eps^{-1}-1; we can think of eps_model = I in this case.
309 5 : ABI_MALLOC(eps_m1_minus_eps_model_m1, (lmax,lmax,npt_gauss+1))
310 :
311 4 : ABI_MALLOC(dummy_matrix, (lmax,lmax))
312 3 : ABI_MALLOC(iden, (lmax,lmax))
313 :
314 73 : iden = cmplx_0
315 :
316 9 : do l = 1, lmax
317 9 : iden(l,l) = cmplx_1
318 : end do
319 :
320 :
321 12 : do iw = 1, npt_gauss + 1
322 :
323 803 : dummy_matrix(:,:) = projected_dielectric_Lanczos_basis(:,:,iw)
324 :
325 11 : call driver_invert_positive_definite_hermitian_matrix(dummy_matrix,lmax)
326 :
327 804 : eps_m1_minus_eps_model_m1(:,:,iw) = dummy_matrix(:,:)-iden(:,:)
328 :
329 : end do
330 :
331 :
332 : ! Deallocate the arrays which are no longer needed
333 1 : ABI_FREE(projected_dielectric_Lanczos_basis)
334 :
335 1 : ABI_FREE(dummy_matrix)
336 1 : ABI_FREE(iden)
337 :
338 1 : call cpu_time(time2)
339 1 : time = time2-time1
340 :
341 1 : timing_string = "# Total time : "
342 1 : call write_timing_log(timing_string,time)
343 :
344 1 : end subroutine compute_eps_m1_minus_one
345 : !!***
346 :
347 : !!****f* m_hamiltonian/compute_eps_model_m1_minus_one
348 : !! NAME
349 : !! compute_eps_model_m1_minus_one
350 : !!
351 : !! FUNCTION
352 : !! .
353 : !!
354 : !! INPUTS
355 : !!
356 : !! OUTPUT
357 : !!
358 : !! SOURCE
359 :
360 6 : subroutine compute_eps_model_m1_minus_one(lmax_model, npt_gauss, second_model_parameter, epsilon_model_eigenvalues_0)
361 : !----------------------------------------------------------------------------------------------------
362 : !
363 : ! This subroutine computes the array
364 : !
365 : ! eps_model^{-1}(iw) - 1
366 : !
367 : ! for all relevant frequencies in the model Lanczos basis.
368 : !
369 : ! This array can potentially get very large, as the complementary basis gets big to achieve
370 : ! convergence. Correspondingly, it makes sense to DISTRIBUTE this array on all processors.
371 : !
372 : ! The algorithm will go as follows:
373 : !
374 : ! eps_m = 1 - V . P . V, V = sqrt{vc}
375 : !
376 : ! I ) compute VPV, storing blocks on different processors:
377 : !
378 : ! VPV = [ ------- -------- ] = VPV[lc, nB, nW]
379 : ! | [| block | block | ]
380 : ! lc [| 1 | 2 | ... ]
381 : ! | [| | | ]
382 : ! | [| | | ]
383 : ! | [ ------- --------- ]
384 : ! bsize
385 : !
386 : ! This construction *does* involve a fair bit of communications, but it takes
387 : ! a lot less RAM!
388 : !
389 : ! II) once VPV is constructed, do, one frequency at a time:
390 : ! - import all blocks to the HEAD processor
391 : ! - compute eps_m = 1- VPV
392 : ! - invert eps_m^{-1}
393 : ! - subtract identity eps_m^{-1} - 1
394 : ! - redistribute, block by block
395 : !
396 : ! Doing this frequency by frequency will reduce the RAM weight on the head node.
397 : !
398 : !
399 : !----------------------------------------------------------------------------------------------------
400 : integer, intent(in) :: lmax_model, npt_gauss
401 : real(dp), intent(in) :: second_model_parameter
402 : real(dp), intent(in) :: epsilon_model_eigenvalues_0(lmax_model)
403 :
404 : integer :: l, l1, l2
405 : integer :: iw
406 : integer :: v
407 : integer :: ierr
408 :
409 6 : real(dp), allocatable :: psikg_valence(:,:)
410 6 : real(dp), allocatable :: psir_valence(:,:,:,:)
411 :
412 :
413 6 : real(dp), allocatable :: psik_wrk(:,:)
414 6 : real(dp), allocatable :: psikb_wrk(:,:)
415 6 : real(dp), allocatable :: psikg_wrk(:,:)
416 6 : real(dp), allocatable :: psikg_tmp(:,:)
417 :
418 6 : complex(dp),allocatable :: local_Lbasis_conjugated(:,:)
419 :
420 :
421 6 : complex(dp),allocatable :: VPV(:,:,:)
422 6 : real(dp), allocatable :: re_buffer(:,:), im_buffer(:,:)
423 :
424 6 : complex(dp),allocatable :: vpv_row(:)
425 :
426 :
427 6 : complex(dp),allocatable :: epsilon_head(:,:)
428 :
429 6 : real(dp), allocatable :: re_BUFFER_head(:,:)
430 6 : real(dp), allocatable :: im_BUFFER_head(:,:)
431 :
432 :
433 :
434 6 : complex(dp),allocatable :: YL(:)
435 :
436 : character(256) :: timing_string
437 : real(dp) :: time1, time2, time
438 : real(dp) :: fft_time1, fft_time2, fft_time
439 : real(dp) :: prod_time1, prod_time2, prod_time
440 :
441 : complex(dp) :: z
442 :
443 :
444 : integer :: iblk_lanczos, nbdblock_lanczos
445 : integer :: mb
446 : integer :: lb
447 : integer :: ik
448 :
449 : integer :: mpi_communicator
450 : integer :: mpi_nproc
451 : integer :: mpi_rank
452 : integer :: mpi_head_rank
453 :
454 :
455 6 : integer,allocatable :: sendcounts(:), displs(:)
456 :
457 : integer :: sendcount, recvcount
458 :
459 :
460 : logical :: head
461 :
462 :
463 : ! timing
464 : real(dp) :: tsec(2)
465 : integer :: GWLS_TIMAB, OPTION_TIMAB
466 :
467 : ! *************************************************************************
468 :
469 :
470 6 : GWLS_TIMAB = 1541
471 6 : OPTION_TIMAB = 1
472 6 : call timab(GWLS_TIMAB,OPTION_TIMAB,tsec)
473 :
474 :
475 :
476 6 : timing_string = "#"
477 6 : call write_text_block_in_Timing_log(timing_string)
478 6 : timing_string = "# computing eps_model_m1_minus_one"
479 6 : call write_text_block_in_Timing_log(timing_string)
480 6 : timing_string = "#"
481 6 : call write_text_block_in_Timing_log(timing_string)
482 :
483 :
484 : ! Number of blocks of lanczos vectors (blocksize = npband)
485 6 : nbdblock_lanczos = lmax_model/blocksize
486 6 : if (modulo(lmax_model,blocksize) /= 0) nbdblock_lanczos = nbdblock_lanczos + 1
487 :
488 :
489 : ! communicator
490 6 : mpi_communicator = mpi_enreg%comm_bandfft
491 :
492 : ! total number of processors in the communicator
493 6 : mpi_nproc = xmpi_comm_size(mpi_communicator )
494 :
495 : ! what is the rank of this processor?
496 6 : mpi_rank = xmpi_comm_rank(mpi_communicator )
497 :
498 : ! rank of the "head" processor
499 6 : mpi_head_rank = 0
500 :
501 :
502 : ! number of blocks in the model dielectric matrix, which is equal to the number of processors
503 6 : nbdblock_epsilon = mpi_nproc
504 :
505 :
506 : ! number of vectors in every block
507 6 : blocksize_epsilon = lmax_model/mpi_nproc
508 6 : if (modulo(lmax_model,mpi_nproc) /= 0) blocksize_epsilon = blocksize_epsilon + 1
509 :
510 : ! attribute blocks to every nodes, and tabulate ownership in logical array
511 : ! This is not *the most efficient* implementation possible, but it is convenient
512 18 : ABI_MALLOC( model_lanczos_vector_belongs_to_this_node, (lmax_model))
513 12 : ABI_MALLOC( model_lanczos_vector_index, (lmax_model))
514 :
515 :
516 54 : model_lanczos_vector_index = 0
517 54 : model_lanczos_vector_belongs_to_this_node = .false.
518 :
519 54 : do l =1, lmax_model
520 54 : if (mpi_rank == (l-1)/blocksize_epsilon) then
521 24 : model_lanczos_vector_belongs_to_this_node(l) = .true.
522 24 : model_lanczos_vector_index(l) = l-mpi_rank*blocksize_epsilon
523 : end if
524 : end do
525 :
526 : !write(100+mpi_rank,*) "model_lanczos_vector_belongs_to_this_node = ",model_lanczos_vector_belongs_to_this_node(:)
527 : !write(100+mpi_rank,*) "model_lanczos_vector_index = ",model_lanczos_vector_index(:)
528 : !flush(100+mpi_rank)
529 :
530 : ! Prepare the array that will contain the matrix elements of the model operator
531 30 : ABI_MALLOC(VPV, (lmax_model,blocksize_epsilon,npt_gauss+1))
532 :
533 2448 : VPV(:,:,:) = cmplx_0
534 :
535 18 : ABI_MALLOC(vpv_row, (lmax_model))
536 :
537 :
538 : ! various working arrays
539 6 : GWLS_TIMAB = 1542
540 : OPTION_TIMAB = 1
541 6 : call timab(GWLS_TIMAB,OPTION_TIMAB,tsec)
542 :
543 18 : ABI_MALLOC(psikg_valence,(2,npw_g))
544 30 : ABI_MALLOC(psir_valence ,(2,n4,n5,n6))
545 :
546 :
547 18 : ABI_MALLOC(psik_wrk, (2,npw_k))
548 18 : ABI_MALLOC(psikb_wrk, (2,npw_kb))
549 12 : ABI_MALLOC(psikg_wrk, (2,npw_g))
550 12 : ABI_MALLOC(psikg_tmp, (2,npw_g))
551 :
552 24 : ABI_MALLOC(local_Lbasis_conjugated,(npw_k,lmax_model))
553 18 : ABI_MALLOC(YL,(npw_k))
554 :
555 6 : OPTION_TIMAB = 2
556 6 : call timab(GWLS_TIMAB,OPTION_TIMAB,tsec)
557 :
558 :
559 :
560 6 : fft_time = zero
561 6 : prod_time = zero
562 :
563 :
564 6 : call cpu_time(time1)
565 : ! loop on all valence bands
566 :
567 30 : do v = 1, nbandv
568 :
569 :
570 : ! copy pre-calculated valence state in this covenient local array
571 12360 : psikg_valence(:,:) = kernel_wavefunctions_FFT(:,:,v)
572 :
573 : ! compute fourier transform of valence state, and conjugate
574 24 : call g_to_r(psir_valence,psikg_valence)
575 164616 : psir_valence(2,:,:,:) = -psir_valence(2,:,:,:)
576 :
577 : !--------------------------------------------------------------------------
578 : !
579 : ! Step 1: build the modified basis Pc . [ (V^{1/2} l) . psi_v^*].
580 : !
581 : !--------------------------------------------------------------------------
582 24 : GWLS_TIMAB = 1543
583 24 : OPTION_TIMAB = 1
584 24 : call timab(GWLS_TIMAB,OPTION_TIMAB,tsec)
585 :
586 : ! loop on all blocks of lanczos vectors
587 152 : do iblk_lanczos = 1, nbdblock_lanczos
588 : ! loop on all states within this block
589 320 : do mb = 1, blocksize
590 :
591 : ! Determine the index of the Lanczos vector
592 192 : l = (iblk_lanczos-1)*blocksize + mb
593 :
594 192 : if ( l <= lmax_model) then
595 24864 : psik_wrk(1,:) = dble (Lbasis_model_lanczos(:,l))
596 24864 : psik_wrk(2,:) = dimag(Lbasis_model_lanczos(:,l))
597 : else
598 0 : psik_wrk(:,:) = zero
599 : end if
600 :
601 : ! apply Coulomb potential
602 192 : call sqrt_vc_k(psik_wrk)
603 :
604 : ! Store in array of blocks of wavefunctions
605 74336 : psikb_wrk(:,(mb-1)*npw_k+1:mb*npw_k) = psik_wrk(:,:)
606 :
607 : end do ! mb
608 :
609 128 : call cpu_time(fft_time1)
610 :
611 : ! Transform to FFT representation
612 128 : call wf_block_distribute(psikb_wrk, psikg_wrk,1) ! LA -> FFT
613 :
614 :
615 : ! generate the vector Pc [ (sqrt_V_c.l) psi_v^*]
616 :
617 : ! Compute the real space product, and return to k space, in FFT configuration
618 128 : call gr_to_g(psikg_tmp,psir_valence, psikg_wrk)
619 :
620 :
621 128 : call cpu_time(fft_time2)
622 128 : fft_time = fft_time + fft_time2-fft_time1
623 :
624 : ! project
625 128 : call pc_k_valence_kernel(psikg_tmp)
626 :
627 : ! Return to LA configuration
628 :
629 : ! Transform to FFT representation
630 128 : call wf_block_distribute(psikb_wrk, psikg_tmp, 2) ! FFT -> LA
631 :
632 344 : do mb = 1, blocksize
633 :
634 : ! Determine the index of the Lanczos vector
635 192 : l = (iblk_lanczos-1)*blocksize + mb
636 :
637 :
638 320 : if ( l <= lmax_model) then
639 74208 : psik_wrk(:,:) = psikb_wrk(:,(mb-1)*npw_k+1:mb*npw_k)
640 24864 : local_Lbasis_conjugated(:,l) = cmplx_1*psik_wrk(1,:)+cmplx_i*psik_wrk(2,:)
641 : end if
642 :
643 :
644 : end do ! mb
645 :
646 : end do !iblk_lanczos
647 24 : OPTION_TIMAB = 2
648 24 : call timab(GWLS_TIMAB,OPTION_TIMAB,tsec)
649 :
650 :
651 : !--------------------------------------------------------------------------
652 : ! Step 2: Now that we have the modified basis, compute the matrix
653 : ! elements of the model dielectric operator
654 : !
655 : !
656 : !--------------------------------------------------------------------------
657 24 : GWLS_TIMAB = 1544
658 24 : OPTION_TIMAB = 1
659 24 : call timab(GWLS_TIMAB,OPTION_TIMAB,tsec)
660 :
661 264 : do iw = 2, npt_gauss+1
662 :
663 240 : call setup_Pk_model(list_omega(iw),second_model_parameter)
664 :
665 240 : call cpu_time(prod_time1)
666 2160 : do l1 = 1, lmax_model
667 :
668 : ! Apply core function Y to left-vector; conjugate
669 248640 : do ik = 1, npw_k
670 248640 : YL(ik) = model_Y_LA(ik)*conjg(local_Lbasis_conjugated(ik,l1))
671 : end do
672 :
673 : ! Only compute lower diagonal part of matrix; epsilon is hermitian conjugate!
674 17280 : vpv_row = cmplx_0
675 10560 : do l2 = 1, l1
676 1120800 : do ik = 1, npw_k
677 1118880 : vpv_row(l2) = vpv_row(l2) + YL(ik)*local_Lbasis_conjugated(ik,l2)
678 : end do
679 : end do
680 :
681 : ! the code below is twice as long!
682 : !call ZGEMV ( TRANS, M, N, ALPHA, A, LDA, X, INCX, BETA, Y, INCY )
683 : !call ZGEMV ( 'T', npw_k, lmax_model, cmplx_1, local_Lbasis_conjugated, npw_k, YL, 1, cmplx_0, vpv_row, 1)
684 :
685 : !do l2 = 1, l1
686 : ! eps_model_m1_minus_one(l1,l2,iw) = eps_model_m1_minus_one(l1,l2,iw) &
687 : ! -complex_vector_product(YL, local_Lbasis_conjugated(:,l2),npw_k)
688 : !end do
689 :
690 : ! Sum on all processors, making sure all processors have the total vpv_row
691 1920 : call xmpi_sum(vpv_row, mpi_communicator, ierr) ! sum on all processors for LA configuration
692 :
693 : ! Each processor takes its slice!
694 10800 : do l2 =1, l1
695 10560 : if ( model_lanczos_vector_belongs_to_this_node(l2) ) then
696 4320 : lb = model_lanczos_vector_index(l2)
697 4320 : VPV(l1,lb,iw) = VPV(l1,lb,iw) + vpv_row(l2)
698 : end if
699 : end do
700 :
701 : end do
702 240 : call cpu_time(prod_time2)
703 :
704 264 : prod_time = prod_time + prod_time2-prod_time1
705 :
706 : end do ! iw
707 24 : OPTION_TIMAB = 2
708 30 : call timab(GWLS_TIMAB,OPTION_TIMAB,tsec)
709 :
710 : end do ! v
711 :
712 6 : call cpu_time(time2)
713 :
714 6 : time = time2-time1
715 6 : timing_string = "# computing VPV : "
716 6 : call write_timing_log(timing_string,time)
717 :
718 6 : timing_string = "# --- of which is FFT transforms : "
719 6 : call write_timing_log(timing_string,fft_time)
720 :
721 6 : timing_string = "# --- of which is products : "
722 6 : call write_timing_log(timing_string,prod_time)
723 :
724 :
725 :
726 :
727 :
728 6 : GWLS_TIMAB = 1542
729 6 : OPTION_TIMAB = 1
730 6 : call timab(GWLS_TIMAB,OPTION_TIMAB,tsec)
731 6 : ABI_FREE(local_Lbasis_conjugated)
732 6 : ABI_FREE(YL)
733 6 : ABI_FREE(psikg_valence)
734 6 : ABI_FREE(psir_valence)
735 6 : ABI_FREE(psik_wrk)
736 6 : ABI_FREE(psikb_wrk)
737 6 : ABI_FREE(psikg_wrk)
738 6 : ABI_FREE(psikg_tmp)
739 6 : ABI_FREE(vpv_row)
740 :
741 6 : OPTION_TIMAB = 2
742 6 : call timab(GWLS_TIMAB,OPTION_TIMAB,tsec)
743 :
744 :
745 :
746 6 : call cpu_time(time1)
747 6 : GWLS_TIMAB = 1547
748 6 : OPTION_TIMAB = 1
749 6 : call timab(GWLS_TIMAB,OPTION_TIMAB,tsec)
750 :
751 :
752 : !--------------------------------------------------------------------------------
753 : !
754 : !
755 : ! Gather dielectric matrix on head node, invert, and re-distribute. This
756 : ! Saves a lot of RAM, without needing the full machinery of ScaLAPACK.
757 : !
758 : !--------------------------------------------------------------------------------
759 :
760 :
761 30 : ABI_MALLOC(eps_model_m1_minus_one_DISTR, (lmax_model,blocksize_epsilon,npt_gauss+1))
762 24 : ABI_MALLOC(re_buffer, (lmax_model,blocksize_epsilon))
763 18 : ABI_MALLOC(im_buffer, (lmax_model,blocksize_epsilon))
764 :
765 2448 : eps_model_m1_minus_one_DISTR(:,:,:) = cmplx_0
766 :
767 : ! Define the head node, which will invert the dielectric matrices
768 6 : head = mpi_rank == mpi_head_rank
769 :
770 : ! Amount of data received and sent
771 6 : sendcount = lmax_model*blocksize_epsilon
772 6 : recvcount = lmax_model*blocksize_epsilon
773 :
774 18 : ABI_MALLOC(sendcounts,(mpi_nproc))
775 12 : ABI_MALLOC(displs ,(mpi_nproc))
776 24 : sendcounts(:) = sendcount
777 :
778 24 : do l =1, mpi_nproc
779 24 : displs(l) = (l-1)*sendcount
780 : end do
781 :
782 6 : if (head) then
783 : ! build and invert the dielectric array
784 : ! careful! lmax_model not necessarily equal to blocksize_epsilon*nbdblock_epsilon
785 12 : ABI_MALLOC(re_BUFFER_head, (lmax_model, blocksize_epsilon*nbdblock_epsilon))
786 9 : ABI_MALLOC(im_BUFFER_head, (lmax_model, blocksize_epsilon*nbdblock_epsilon))
787 12 : ABI_MALLOC(epsilon_head, (lmax_model, lmax_model))
788 : else
789 : !This looks superfluous and it is on large number of systems, but sending these
790 : !unallocated in xmpi_scatterv caused 'cannot allocate memory' cryptic errors on
791 : !several parallel test farm computers (cronos_gcc46_paral, petrus_nag, inca_gcc44_sdebug)
792 3 : ABI_MALLOC(re_BUFFER_head, (1,1))
793 3 : ABI_MALLOC(im_BUFFER_head, (1,1))
794 3 : ABI_MALLOC(epsilon_head, (1,1))
795 : end if
796 :
797 : ! Do one frequency at a time, to avoid overflowing the RAM
798 72 : do iw = 1, npt_gauss+1
799 : ! Gather, except for static case
800 66 : if ( iw /=1 ) then
801 : ! Gather VPV on head node, for this frequency
802 2220 : call xmpi_gather(dble(VPV(:,:,iw)), sendcount , re_BUFFER_head, recvcount, mpi_head_rank, mpi_communicator,ierr)
803 2220 : call xmpi_gather(dimag(VPV(:,:,iw)), sendcount , im_BUFFER_head, recvcount, mpi_head_rank, mpi_communicator,ierr)
804 : end if
805 :
806 66 : if ( head ) then
807 :
808 : ! fill the dielectric matrix
809 :
810 2409 : epsilon_head(:,:) = cmplx_0
811 33 : if (iw ==1) then
812 : ! STATIC CASE, diagonal matrix
813 27 : do l= 1, lmax_model
814 27 : epsilon_head(l,l) = cmplx_1/epsilon_model_eigenvalues_0(l)-cmplx_1
815 : end do
816 :
817 : else
818 : ! DYNAMIC CASE, compute
819 270 : do l1 =1, lmax_model
820 1320 : do l2 =1, l1
821 1080 : z = -cmplx_1*re_BUFFER_head(l1,l2)-cmplx_i*im_BUFFER_head(l1,l2)
822 1080 : epsilon_head(l1,l2) = z
823 1320 : epsilon_head(l2,l1) = conjg(z)
824 : end do
825 270 : epsilon_head(l1,l1) = epsilon_head(l1,l1) + cmplx_1
826 : end do
827 :
828 : ! invert the matrix
829 30 : call driver_invert_positive_definite_hermitian_matrix(epsilon_head,lmax_model)
830 :
831 : ! subtract identity
832 270 : do l =1, lmax_model
833 270 : epsilon_head(l,l) = epsilon_head(l,l) - cmplx_1
834 : end do
835 : end if
836 :
837 : ! copy in head buffer
838 2409 : re_BUFFER_head(:,:) = zero
839 2409 : im_BUFFER_head(:,:) = zero
840 297 : do l1 =1, lmax_model
841 2409 : do l2 =1, lmax_model
842 2112 : z = epsilon_head(l1,l2)
843 2112 : re_BUFFER_head(l1,l2) = dble(z)
844 2376 : im_BUFFER_head(l1,l2) = dimag(z)
845 : end do
846 : end do
847 :
848 : end if
849 :
850 : ! Scatter back the data on the head to all processors
851 66 : call xmpi_scatterv(re_BUFFER_head, sendcounts, displs, re_buffer, recvcount, mpi_head_rank, mpi_communicator, ierr)
852 66 : call xmpi_scatterv(im_BUFFER_head, sendcounts, displs, im_buffer, recvcount, mpi_head_rank, mpi_communicator, ierr)
853 :
854 2448 : eps_model_m1_minus_one_DISTR(:,:,iw) = cmplx_1*re_buffer(:,:) + cmplx_i*im_buffer(:,:)
855 :
856 : end do
857 :
858 6 : ABI_FREE(re_BUFFER_head)
859 6 : ABI_FREE(im_BUFFER_head)
860 6 : ABI_FREE(epsilon_head)
861 :
862 :
863 :
864 : !================================================================================
865 : !
866 : ! For debugging purposes, store distributed dielectric matrix back in the
867 : ! complete local copies, to insure the rest of the code works.
868 : !
869 : !================================================================================
870 :
871 : if (.false.) then
872 : ! Prepare the array that will contain the matrix elements of the model operator
873 : ! THIS IS ONLY FOR THE REST OF THE CODE TO WORK; WE WILL REMOVE THIS
874 : ! TO SAVE RAM LATER
875 : ABI_MALLOC(eps_model_m1_minus_one, (lmax_model,lmax_model,npt_gauss+1))
876 :
877 : ! initialize the array with zeros
878 : eps_model_m1_minus_one = cmplx_0
879 :
880 : ! Amount of data received and sent
881 : sendcount = lmax_model*blocksize_epsilon
882 : recvcount = lmax_model*blocksize_epsilon*nbdblock_epsilon
883 :
884 :
885 : ABI_MALLOC(re_BUFFER_head, (lmax_model,blocksize_epsilon*nbdblock_epsilon))
886 : ABI_MALLOC(im_BUFFER_head, (lmax_model,blocksize_epsilon*nbdblock_epsilon))
887 :
888 : do iw = 1, npt_gauss+1
889 :
890 : re_buffer(:,:) = dble( eps_model_m1_minus_one_DISTR(:,:,iw))
891 : im_buffer(:,:) = dimag(eps_model_m1_minus_one_DISTR(:,:,iw))
892 :
893 : call xmpi_allgather(re_buffer,sendcount,re_BUFFER_head,mpi_communicator,ierr)
894 : call xmpi_allgather(im_buffer,sendcount,im_BUFFER_head,mpi_communicator,ierr)
895 :
896 : do l = 1, lmax_model
897 : eps_model_m1_minus_one(:,l,iw) = cmplx_1*re_BUFFER_head(:,l)+ cmplx_i*im_BUFFER_head(:,l)
898 : end do
899 : end do
900 :
901 : ABI_FREE(re_BUFFER_head)
902 : ABI_FREE(im_BUFFER_head)
903 : end if
904 :
905 6 : call cpu_time(time2)
906 6 : OPTION_TIMAB = 2
907 6 : call timab(GWLS_TIMAB,OPTION_TIMAB,tsec)
908 :
909 : !================================================================================
910 : !
911 : !================================================================================
912 :
913 :
914 6 : time = time2-time1
915 6 : timing_string = "# inverting / distributing : "
916 :
917 6 : call write_timing_log(timing_string,time)
918 :
919 :
920 :
921 6 : ABI_FREE(re_buffer )
922 6 : ABI_FREE(im_buffer )
923 6 : ABI_FREE(sendcounts)
924 6 : ABI_FREE(displs )
925 6 : ABI_FREE(VPV )
926 :
927 :
928 :
929 6 : GWLS_TIMAB = 1541
930 : OPTION_TIMAB = 2
931 6 : call timab(GWLS_TIMAB,OPTION_TIMAB,tsec)
932 :
933 :
934 6 : end subroutine compute_eps_model_m1_minus_one
935 : !!***
936 :
937 : !!****f* m_hamiltonian/cleanup_projected_Sternheimer_epsilon
938 : !! NAME
939 : !! cleanup_projected_Sternheimer_epsilon
940 : !!
941 : !! FUNCTION
942 : !! .
943 : !!
944 : !! INPUTS
945 : !!
946 : !! OUTPUT
947 : !!
948 : !! SOURCE
949 :
950 7 : subroutine cleanup_projected_Sternheimer_epsilon
951 :
952 : ! *************************************************************************
953 :
954 7 : ABI_SFREE(projected_epsilon_M_matrix)
955 7 : ABI_SFREE(projected_epsilon_B_matrix)
956 7 : ABI_SFREE(projected_epsilon_G_matrix)
957 7 : ABI_SFREE(eps_m1_minus_eps_model_m1)
958 7 : ABI_SFREE(list_omega)
959 7 : ABI_SFREE(list_weights)
960 7 : ABI_SFREE(eps_model_m1_minus_one_DISTR)
961 7 : ABI_SFREE(model_lanczos_vector_belongs_to_this_node)
962 7 : ABI_SFREE(model_lanczos_vector_index)
963 :
964 7 : end subroutine cleanup_projected_Sternheimer_epsilon
965 : !!***
966 :
967 :
968 : !!****f* m_hamiltonian/ProjectedSternheimerEpsilon
969 : !! NAME
970 : !! ProjectedSternheimerEpsilon
971 : !!
972 : !! FUNCTION
973 : !! .
974 : !!
975 : !! INPUTS
976 : !!
977 : !! OUTPUT
978 : !!
979 : !! SOURCE
980 :
981 7 : subroutine ProjectedSternheimerEpsilon(lmax, npt_gauss, second_model_parameter, &
982 7 : list_projection_frequencies,nfrequencies,&
983 7 : epsilon_eigenvalues_0,debug,use_model)
984 : !----------------------------------------------------------------------------------------------------
985 : ! This subroutine combines in a single subprogram the jobs of previous routines
986 : !
987 : ! - setup_projected_Sternheimer_epsilon
988 : ! - compute_projected_Sternheimer_epsilon
989 : !
990 : ! The purpose of this combination is to avoid independent loops on nbandv, requiring the
991 : ! arrays
992 : ! projected_epsilon_M_matrix
993 : ! projected_epsilon_B_matrix
994 : ! projected_epsilon_G_matrix
995 : !
996 : ! from scaling like N^3, which grows very large with problem size.
997 : !
998 : ! Thus, this routine:
999 : !
1000 : ! - Computes the frequency-dependent dielectric matrix in the Lanczos basis, using
1001 : ! the projected Sternheimer equations.
1002 : !
1003 : ! - Computes the frequency-dependent MODEL dielectric matrix in the complementary Lanczos basis.
1004 : !
1005 : !
1006 : ! This routine will be verbose and write log files; indeed, large jobs crash in here, it will
1007 : ! be important to know where/why!
1008 : !
1009 : ! The subroutine also computes the matrix elements on epsilon_model(iw) in the Lanczos basis;
1010 : ! this is done here to avoid preforming direct products with the valence states again later.
1011 : !----------------------------------------------------------------------------------------------------
1012 : real(dp), parameter :: svd_tolerance = 1.0e-16_dp
1013 :
1014 : integer, intent(in) :: lmax, npt_gauss
1015 : integer, intent(in) :: nfrequencies
1016 : real(dp), intent(in) :: list_projection_frequencies(nfrequencies)
1017 : logical, intent(in) :: debug
1018 : real(dp), intent(in) :: epsilon_eigenvalues_0(lmax)
1019 :
1020 : logical,optional,intent(in) :: use_model
1021 :
1022 : real(dp), intent(in) :: second_model_parameter
1023 :
1024 :
1025 : integer :: l, l1, l2
1026 : integer :: i, iw, v
1027 : integer :: recy_i
1028 : integer :: lsolutions_max, lsolutions, ls
1029 : integer :: projection
1030 :
1031 7 : complex(dp), allocatable :: sternheimer_A0(:,:)
1032 7 : complex(dp), allocatable :: sternheimer_A(:,:)
1033 7 : complex(dp), allocatable :: sternheimer_B(:,:)
1034 7 : complex(dp), allocatable :: sternheimer_X(:,:)
1035 7 : complex(dp), allocatable :: sternheimer_G(:,:)
1036 :
1037 :
1038 7 : complex(dp), allocatable :: dummy_tmp_1(:,:)
1039 7 : complex(dp), allocatable :: dummy_tmp_2(:,:)
1040 :
1041 7 : integer, allocatable :: ipiv(:)
1042 :
1043 :
1044 :
1045 7 : complex(dp),allocatable :: local_Lbasis(:,:)
1046 7 : complex(dp),allocatable :: local_Lbasis_conjugated(:,:)
1047 7 : complex(dp),allocatable :: YL(:)
1048 :
1049 7 : real(dp), allocatable :: psikg_in(:,:), psikg_out(:,:)
1050 :
1051 7 : real(dp), allocatable :: psik_wrk(:,:), psikg_wrk(:,:), psikb_wrk(:,:)
1052 7 : real(dp), allocatable :: psi_gamma_l1(:,:), psi_gamma_l2(:,:)
1053 :
1054 7 : real(dp), allocatable :: psikg_valence(:,:)
1055 7 : real(dp), allocatable :: psir_valence(:,:,:,:)
1056 :
1057 7 : real(dp), allocatable :: psi_rhs(:,:,:)
1058 :
1059 7 : real(dp), allocatable :: psikg_VL(:,:)
1060 :
1061 :
1062 7 : complex(dp), allocatable :: check_matrix(:,:), check_matrix2(:,:)
1063 7 : complex(dp), allocatable :: c_sternheimer_solutions(:,:)
1064 7 : complex(dp), allocatable :: QR_orthonormal_basis(:,:)
1065 :
1066 7 : complex(dp), allocatable :: svd_matrix(:,:)
1067 7 : real (dp ), allocatable :: svd_values(:)
1068 :
1069 :
1070 : integer :: iblk_lanczos, nbdblock_lanczos
1071 : integer :: iblk_solutions, nbdblock_solutions
1072 : integer :: mb
1073 :
1074 : character(128) :: filename
1075 : logical :: file_exists
1076 : integer :: io_unit
1077 :
1078 : character(128) :: filename_log
1079 : integer :: io_unit_log
1080 :
1081 :
1082 : real(dp) :: omega
1083 :
1084 : character(256) :: timing_string
1085 : real(dp) :: time1, time2
1086 : real(dp) :: time_exact
1087 :
1088 :
1089 : integer :: info
1090 : integer :: ierr
1091 :
1092 : real(dp) :: z(2)
1093 :
1094 :
1095 : logical :: omega_is_imaginary
1096 : real(dp) :: omega0
1097 :
1098 : logical :: model
1099 : logical :: write_debug
1100 :
1101 :
1102 : integer :: mpi_communicator, mpi_rank, mpi_group
1103 :
1104 : ! *************************************************************************
1105 :
1106 :
1107 : !================================================================================
1108 : ! Prepare MPI information
1109 : !================================================================================
1110 :
1111 : ! for LA configuration ,The processors communicate over band+FFT
1112 7 : mpi_communicator = mpi_enreg%comm_bandfft
1113 :
1114 : ! what is the rank of this processor, within its group?
1115 7 : mpi_rank = mpi_enreg%me_fft
1116 :
1117 : ! Which group does this processor belong to, given the communicator?
1118 7 : mpi_group = mpi_enreg%me_band
1119 :
1120 :
1121 :
1122 :
1123 : !================================================================================
1124 : ! Setup a log file, to keep track of the algorithm
1125 : !================================================================================
1126 :
1127 :
1128 7 : write(filename_log,'(A,I4.4,A)') 'ProjectedSternheimerEpsilon_PROC=',mpi_enreg%me,'.log'
1129 :
1130 7 : io_unit_log = get_unit()
1131 7 : open(io_unit_log,file=filename_log,status=files_status_new)
1132 7 : write(io_unit_log,10) ''
1133 7 : write(io_unit_log,10) '#===================================================================================================='
1134 7 : write(io_unit_log,10) "# ProjectedSternheimerEpsilon: log file "
1135 7 : write(io_unit_log,10) "# ------------------------------------------------------------------- "
1136 7 : write(io_unit_log,10) "# "
1137 7 : write(io_unit_log,10) "# This file tracks the algorithm in the routine ProjectedSternheimerEpsilon. The goal is to "
1138 7 : write(io_unit_log,10) "# establish where the algorithm crashes if it does, and/or to track are far along the code is. "
1139 7 : write(io_unit_log,10) '#'
1140 7 : write(io_unit_log,10) '# MPI data for this process:'
1141 7 : write(io_unit_log,10) '#'
1142 7 : write(io_unit_log,22) '# mpi_rank :',mpi_rank,' (rank of this processor in its band group)'
1143 7 : write(io_unit_log,22) '# mpi_group:',mpi_group,' (band group to which this processor belongs)'
1144 7 : write(io_unit_log,10) '#===================================================================================================='
1145 7 : flush(io_unit_log)
1146 :
1147 :
1148 : !================================================================================
1149 : ! Setup timing; prepare arrays
1150 : !================================================================================
1151 :
1152 7 : write(io_unit_log,10) " - Preparing and allocating arrays ...."
1153 7 : flush(io_unit_log)
1154 :
1155 :
1156 :
1157 7 : timing_string = "#"
1158 7 : call write_text_block_in_Timing_log(timing_string)
1159 7 : timing_string = "# ProjectedSternheimerEpsilon "
1160 7 : call write_text_block_in_Timing_log(timing_string)
1161 7 : timing_string = "#"
1162 7 : call write_text_block_in_Timing_log(timing_string)
1163 :
1164 : ! Allocate the module array
1165 35 : ABI_MALLOC(projected_dielectric_Lanczos_basis, (lmax,lmax,npt_gauss+1))
1166 :
1167 5628 : projected_dielectric_Lanczos_basis(:,:,:) = cmplx_0
1168 :
1169 : ! initialize zero frequency with exact solution
1170 63 : do l = 1, lmax
1171 63 : projected_dielectric_Lanczos_basis(l,l,1) = cmplx_1*epsilon_eigenvalues_0(l)
1172 : end do
1173 :
1174 :
1175 : ! initialize other frequencies with the identity
1176 77 : do iw = 2, npt_gauss + 1
1177 637 : do l = 1, lmax
1178 630 : projected_dielectric_Lanczos_basis(l,l,iw) = cmplx_1
1179 : end do
1180 : end do
1181 :
1182 7 : time_exact = zero
1183 :
1184 :
1185 : !================================================================================
1186 : ! Parallelisation of the code is subtle; Hamiltonian must act over
1187 : ! FFT rows, we must be careful with memory, etc...
1188 : !
1189 : ! We will parallelise in block of Lanczos vectors, not over bands.
1190 : !================================================================================
1191 :
1192 : ! Number of blocks of lanczos vectors
1193 7 : nbdblock_lanczos = lmax/blocksize
1194 7 : if (modulo(lmax,blocksize) /= 0) nbdblock_lanczos = nbdblock_lanczos + 1
1195 :
1196 :
1197 7 : if (present(use_model)) then
1198 7 : model = use_model
1199 : else
1200 : model = .true.
1201 : end if
1202 :
1203 7 : if (model) then
1204 : ! Prepare the array that will contain the matrix elements of the model operator
1205 24 : ABI_MALLOC(model_dielectric_Lanczos_basis, (lmax,lmax,npt_gauss+1))
1206 :
1207 : ! initialize with zero. NOT with the identity, in order to avoid extra communications
1208 : ! (see below)
1209 4824 : model_dielectric_Lanczos_basis(:,:,:) = cmplx_0
1210 :
1211 : end if
1212 :
1213 : ! various working arrays
1214 :
1215 21 : ABI_MALLOC(psikg_valence ,(2,npw_g))
1216 35 : ABI_MALLOC(psir_valence ,(2,n4,n5,n6))
1217 :
1218 :
1219 14 : ABI_MALLOC(psikg_VL ,(2,npw_g))
1220 :
1221 :
1222 21 : ABI_MALLOC(psik_wrk ,(2,npw_k))
1223 21 : ABI_MALLOC(psikb_wrk ,(2,npw_kb))
1224 14 : ABI_MALLOC(psikg_wrk ,(2,npw_g))
1225 :
1226 :
1227 14 : ABI_MALLOC(psi_gamma_l1 ,(2,npw_k))
1228 14 : ABI_MALLOC(psi_gamma_l2 ,(2,npw_k))
1229 :
1230 28 : ABI_MALLOC(psi_rhs ,(2,npw_k,lmax))
1231 :
1232 :
1233 14 : ABI_MALLOC(psikg_in ,(2,npw_g))
1234 14 : ABI_MALLOC(psikg_out ,(2,npw_g))
1235 :
1236 :
1237 : ! maximal possible dimension of the solution space
1238 : ! +1 because the solutions at $\omega=\infty$ are free.
1239 : ! +1 if recycling is activated, because the solutions at $\omega=0$ are then available.
1240 7 : i=1
1241 7 : if(dtset%gwls_recycle == 1 .or. dtset%gwls_recycle == 2) then
1242 7 : i=2
1243 : end if
1244 7 : lsolutions_max = lmax*(nfrequencies+i)
1245 :
1246 :
1247 28 : ABI_MALLOC(local_Lbasis, (npw_k,lmax))
1248 21 : ABI_MALLOC(local_Lbasis_conjugated,(npw_k,lmax))
1249 21 : ABI_MALLOC(YL,(npw_k))
1250 :
1251 28 : ABI_MALLOC(c_sternheimer_solutions,(npw_k,lsolutions_max))
1252 21 : ABI_MALLOC(QR_orthonormal_basis ,(npw_k,lsolutions_max))
1253 :
1254 :
1255 7 : omega_is_imaginary = .true.
1256 :
1257 :
1258 21 : ABI_MALLOC(svd_matrix,(npw_k,lsolutions_max))
1259 21 : ABI_MALLOC(svd_values,(lsolutions_max))
1260 :
1261 :
1262 : ! Prepare files for writing
1263 7 : write_debug = debug .and. mpi_enreg%me == 0
1264 :
1265 : if ( write_debug ) then
1266 :
1267 0 : write(filename,'(A)') "ProjectedSternheimerEpsilon.log"
1268 0 : inquire(file=filename,exist=file_exists)
1269 :
1270 0 : i = 0
1271 0 : do while (file_exists)
1272 0 : i = i+1
1273 0 : write (filename,'(A,I0.4,A)') "ProjectedSternheimerEpsilon_",i,".log"
1274 0 : inquire(file=filename,exist=file_exists)
1275 : end do
1276 :
1277 :
1278 0 : io_unit = get_unit()
1279 0 : open(io_unit,file=filename,status=files_status_new)
1280 0 : write(io_unit,10) ''
1281 0 : write(io_unit,10) '#===================================================================================================='
1282 0 : write(io_unit,10) "# Building the dielectic matrix using projected Sternheimer equation "
1283 0 : write(io_unit,10) "# ------------------------------------------------------------------- "
1284 0 : write(io_unit,10) "# "
1285 0 : write(io_unit,10) '# This file contains some tests to check if the various elements entering the projected '
1286 0 : write(io_unit,10) '# dielectric matrix have the right properties. At this point, this is mostly for debugging.'
1287 0 : write(io_unit,10) '# The wavefunctions and other related arrays are stored in reciprocal space.'
1288 0 : write(io_unit,10) '#'
1289 0 : write(io_unit,10) '#===================================================================================================='
1290 0 : write(io_unit,10) ''
1291 0 : flush(io_unit)
1292 : end if
1293 :
1294 7 : if (debug) then
1295 0 : ABI_MALLOC(check_matrix ,(lsolutions_max,lsolutions_max))
1296 0 : ABI_MALLOC(check_matrix2,(lsolutions_max,lsolutions_max))
1297 : end if
1298 :
1299 : !================================================================================
1300 : ! Loop on all valence bands
1301 : !================================================================================
1302 :
1303 :
1304 :
1305 :
1306 35 : do v = 1, nbandv
1307 28 : write(io_unit_log,10) '#===================================================================================================='
1308 28 : write(io_unit_log,20) '# valence band index:', v
1309 28 : write(io_unit_log,10) '#===================================================================================================='
1310 28 : flush(io_unit_log)
1311 :
1312 :
1313 :
1314 :
1315 28 : if ( write_debug ) then
1316 0 : write(io_unit,10) '#===================================================================================================='
1317 0 : write(io_unit,20) '# valence band index:', v
1318 0 : write(io_unit,10) '#===================================================================================================='
1319 0 : flush(io_unit)
1320 : end if
1321 :
1322 28 : write(io_unit_log,10) ' - Fourier transform valence state ...'
1323 28 : flush(io_unit_log)
1324 :
1325 :
1326 : ! copy pre-calculated valence state in this covenient local array
1327 15448 : psikg_valence(:,:) = kernel_wavefunctions_FFT(:,:,v)
1328 :
1329 : ! compute fourier transform of valence state, and conjugate
1330 28 : call g_to_r(psir_valence,psikg_valence)
1331 192052 : psir_valence(2,:,:,:) = -psir_valence(2,:,:,:)
1332 :
1333 : ! loop on all blocks of lanczos vectors
1334 28 : write(io_unit_log,10) ' - Loop on all lanczos blocks to generate modified basis and Sternheimer RHS:'
1335 28 : flush(io_unit_log)
1336 188 : do iblk_lanczos = 1, nbdblock_lanczos
1337 : !--------------------------------------------------------------------------
1338 : ! Below, we build the modified basis, [ (V^{1/2} l)^* . psi_v],
1339 : ! as well as conjugated, projected form, Pc . [ (V^{1/2} l) . psi_v^*].
1340 : !
1341 : ! It is very irritating to have to do it this way, but I don't
1342 : ! see an alternative; see discussion below.
1343 : !
1344 : !--------------------------------------------------------------------------
1345 :
1346 160 : write(io_unit_log,23) ' iblk_lanczos = ',iblk_lanczos," / ",nbdblock_lanczos
1347 :
1348 :
1349 160 : write(io_unit_log,10) ' -- Prepare modified basis computation...'
1350 160 : flush(io_unit_log)
1351 :
1352 :
1353 :
1354 : ! loop on all states within this block
1355 384 : do mb = 1, blocksize
1356 :
1357 : ! Determine the index of the Lanczos vector
1358 224 : l = (iblk_lanczos-1)*blocksize + mb
1359 :
1360 : ! take a single lanczos vector
1361 :
1362 224 : if ( l <= lmax) then
1363 33120 : psik_wrk(1,:) = dble (Lbasis_lanczos(:,l))
1364 33120 : psik_wrk(2,:) = dimag(Lbasis_lanczos(:,l))
1365 : else
1366 0 : psik_wrk(:,:) = zero
1367 : end if
1368 :
1369 :
1370 : ! Apply coulomb potential
1371 224 : call sqrt_vc_k(psik_wrk)
1372 :
1373 : ! Store in array of blocks of wavefunctions
1374 99072 : psikb_wrk(:,(mb-1)*npw_k+1:mb*npw_k) = psik_wrk(:,:)
1375 :
1376 : end do ! mb
1377 :
1378 : ! Transform to FFT representation
1379 160 : call wf_block_distribute(psikb_wrk, psikg_VL,1) ! LA -> FFT
1380 :
1381 : ! psikg_VL now contains | V^1/2 . l >, in FFT configuration
1382 :
1383 :
1384 : !----------------------------------------------------------
1385 : ! i) Compute the modified basis
1386 : !----------------------------------------------------------
1387 160 : write(io_unit_log,10) ' -- compute modified basis ...'
1388 160 : flush(io_unit_log)
1389 :
1390 :
1391 :
1392 : ! Fourier transform to real space, and conjugate (psir1 is a global work array)
1393 160 : call g_to_r(psir1,psikg_VL)
1394 1097440 : psir1(2,:,:,:) = -psir1(2,:,:,:) ! IS THIS STACK-DANGEROUS?
1395 :
1396 : ! Compute the real space product, and return to k space, in FFT configuration
1397 160 : call gr_to_g(psikg_wrk,psir1,psikg_valence)
1398 :
1399 : ! psikg_wrk contains | (V^1/2 . l)^* phi_v >, in FFT configuration
1400 :
1401 : ! return to LA representation
1402 160 : call wf_block_distribute(psikb_wrk, psikg_wrk,2) ! FFT -> LA
1403 :
1404 : ! store data, in LA representation
1405 384 : do mb = 1, blocksize
1406 224 : l = (iblk_lanczos-1)*blocksize + mb
1407 :
1408 384 : if ( l <= lmax) then
1409 : ! local_Lbasis
1410 98912 : psik_wrk(:,:) = psikb_wrk(:,(mb-1)*npw_k+1:mb*npw_k)
1411 33120 : local_Lbasis(:,l) = cmplx_1*psik_wrk(1,:)+cmplx_i*psik_wrk(2,:)
1412 : end if
1413 :
1414 : end do !mb
1415 :
1416 : !--------------------------------------------------------------------------
1417 : ! ii) Build the Sternheimer coefficients, at various frequencies,
1418 : ! to define the Sternheimer basis.
1419 : !--------------------------------------------------------------------------
1420 160 : write(io_unit_log,20) ' -- Compute Sternheimer RHS...'
1421 160 : flush(io_unit_log)
1422 :
1423 :
1424 : ! psikg_wrk still contains | (V^1/2 . l)^* phi_v >, in FFT configuration
1425 :
1426 : ! Create right-hand-side of Sternheimer equation, in FFT configuration
1427 160 : call pc_k_valence_kernel(psikg_wrk)
1428 160 : call Hpsik(psikg_in,psikg_wrk,eig(v))
1429 160 : call pc_k_valence_kernel(psikg_in)
1430 98848 : psikg_in(:,:) = -psikg_in(:,:) ! IS THIS STACK-DANGEROUS?
1431 :
1432 : ! return RHS to LA representation, for explicit storage
1433 160 : call wf_block_distribute(psikb_wrk, psikg_in,2) ! FFT -> LA
1434 :
1435 : ! store data, in LA representation
1436 384 : do mb = 1, blocksize
1437 224 : l = (iblk_lanczos-1)*blocksize + mb
1438 :
1439 384 : if ( l <= lmax) then
1440 : ! psi_rhs
1441 98912 : psi_rhs(:,:,l) = psikb_wrk(:,(mb-1)*npw_k+1:mb*npw_k)
1442 : end if
1443 :
1444 : end do !mb
1445 :
1446 : !----------------------------------------------------------
1447 : ! iii) extract solutions for all projection frequencies
1448 : !----------------------------------------------------------
1449 160 : write(io_unit_log,20) ' -- Extract solutions for all projection frequencies...'
1450 160 : flush(io_unit_log)
1451 :
1452 :
1453 :
1454 160 : do iw = 1, nfrequencies
1455 :
1456 0 : omega0 = list_projection_frequencies(iw)
1457 : ! Solve Sternheimer equation
1458 :
1459 0 : projection = 0
1460 0 : if(omega0 < 1d-12) projection=1
1461 :
1462 : ! solve A x = b, over the whole lanczos block
1463 0 : call sqmr(psikg_in, psikg_out, eig(v), projection, omega0, omega_is_imaginary)
1464 :
1465 : ! return LA representation, for explicit storage
1466 0 : call wf_block_distribute(psikb_wrk, psikg_out, 2) ! FFT -> LA
1467 :
1468 160 : do mb = 1, blocksize
1469 0 : l = (iblk_lanczos-1)*blocksize + mb
1470 :
1471 0 : if ( l <= lmax) then
1472 0 : ls = (l-1)*nfrequencies+iw
1473 :
1474 0 : psik_wrk(:,:) = psikb_wrk(:,(mb-1)*npw_k+1:mb*npw_k)
1475 :
1476 0 : c_sternheimer_solutions(:,ls)= cmplx_1*psik_wrk(1,:)+cmplx_i*psik_wrk(2,:)
1477 : end if
1478 :
1479 : end do ! mb
1480 :
1481 : end do ! iw
1482 :
1483 : !----------------------------------------------------------
1484 : ! iv) Compute the conjugated, projected modified basis
1485 : !----------------------------------------------------------
1486 :
1487 160 : write(io_unit_log,20) ' -- compute the conjugated, projected modified basis...'
1488 160 : flush(io_unit_log)
1489 :
1490 :
1491 :
1492 :
1493 : ! Compute the real space product, | (V^1/2. l) phi_v^* > and return to k space, in FFT configuration
1494 160 : call gr_to_g(psikg_wrk, psir_valence, psikg_VL)
1495 :
1496 : ! project on conduction states
1497 160 : call pc_k_valence_kernel(psikg_wrk)
1498 :
1499 : ! return to LA representation
1500 160 : call wf_block_distribute(psikb_wrk, psikg_wrk,2) ! FFT -> LA
1501 :
1502 : ! store back, in LA configuration
1503 412 : do mb = 1, blocksize
1504 224 : l = (iblk_lanczos-1)*blocksize + mb
1505 :
1506 384 : if ( l <= lmax) then
1507 98912 : psik_wrk(:,:) = psikb_wrk(:,(mb-1)*npw_k+1:mb*npw_k)
1508 33120 : local_Lbasis_conjugated(:,l) = cmplx_1*psik_wrk(1,:)+cmplx_i*psik_wrk(2,:)
1509 : end if
1510 :
1511 : end do !mb
1512 :
1513 : end do ! iblk_lanczos
1514 :
1515 :
1516 :
1517 28 : write(io_unit_log,10) ' - Read in solutions at w=0 and/or w = infinity, if appropriate...'
1518 28 : flush(io_unit_log)
1519 :
1520 : ! Begin with the storage of the solutions at $\omega = 0.$, which are free.
1521 28 : if(dtset%gwls_recycle == 1) then
1522 : c_sternheimer_solutions(:,lsolutions_max-2*lmax+1:lsolutions_max-lmax) = cmplx_1*Sternheimer_solutions_zero(1,:,:,v) + &
1523 8368 : & cmplx_i*Sternheimer_solutions_zero(2,:,:,v)
1524 : end if
1525 28 : if(dtset%gwls_recycle == 2) then
1526 108 : do i=1,lmax
1527 96 : recy_i = (i-1)*nbandv + v
1528 : !BUG : On petrus, NAG 5.3.1 + OpenMPI 1.6.2 cause read(...,rec=i) to read the data written by write(...,rec=i+1).
1529 96 : read(recy_unit,rec=recy_i) psik_wrk
1530 24780 : c_sternheimer_solutions(:,lsolutions_max-2*lmax+i) = cmplx_1*psik_wrk(1,:) + cmplx_i*psik_wrk(2,:)
1531 : end do
1532 : end if
1533 :
1534 : ! and then continue with the storage of the vectors on which the Sternheimer solutions will be projected.
1535 33148 : c_sternheimer_solutions(:,lsolutions_max-lmax+1:lsolutions_max) = cmplx_1*psi_rhs(1,:,:) + cmplx_i*psi_rhs(2,:,:)
1536 : ! Previously was = local_Lbasis; but analysis in the Lanczos article reveals psi_rhs should be better.
1537 : ! Furthermore, tests show that, with psi_rhs, silane@1Ha has Sigma_c 0.01mHa away from the result with
1538 : ! gwls_list_proj_freq 0.0 1.0, in contrast with local_Lbasis, which has Sigma_c 0.3mHa away from the same result.
1539 :
1540 28 : if ( model ) then
1541 :
1542 24 : write(io_unit_log,10) ' - USE MODEL: model = .true., hence compute model model dielectric matrix...'
1543 24 : flush(io_unit_log)
1544 :
1545 :
1546 :
1547 : !--------------------------------------------------------------------------
1548 : ! Now that we have the modified basis, compute the matrix
1549 : ! elements of the model dielectric operator
1550 : !
1551 : ! CAREFUL!
1552 : !
1553 : ! The model is given by
1554 : !
1555 : ! P_model(iw) = sum_{v} phi_v(r) P_c.Y(iw).P_c phi_v^*(r')
1556 : !
1557 : ! such that
1558 : !
1559 : ! <l1 | eps_model(iw) | l2 > = delta_{l1,l2}
1560 : ! - sum_{v} < (V^{1/2}.l1).phi_v^*| Pc . Y . Pc | (V^{1/2}.l2).phi_v^* >
1561 : !
1562 : ! But local_Lbasis defined above corresponds to
1563 : ! Pc | (V^{1/2} .l )^* phi_v >.
1564 : !
1565 : ! This is why we must define local_Lbasis_conjugated, of the form
1566 : ! Pc | (V^{1/2} .l ) phi_v^* >.
1567 : !
1568 : !--------------------------------------------------------------------------
1569 :
1570 288 : do iw = 1, npt_gauss+1
1571 :
1572 264 : call setup_Pk_model(list_omega(iw),second_model_parameter)
1573 :
1574 : ! Only build the lower triangular part; the upper triangular part is obtained from the Hermitian conjugate
1575 2400 : do l1 = 1, lmax
1576 :
1577 273504 : YL(:) = model_Y_LA(:)*local_Lbasis_conjugated(:,l1)
1578 11880 : do l2 = 1, l1
1579 : model_dielectric_Lanczos_basis(l1,l2,iw) = model_dielectric_Lanczos_basis(l1,l2,iw) &
1580 11616 : -complex_vector_product(YL, local_Lbasis_conjugated(:,l2),npw_k)
1581 :
1582 : end do
1583 : end do
1584 :
1585 : end do ! iw
1586 :
1587 :
1588 : end if
1589 :
1590 :
1591 : !--------------------------------------------------------------------------
1592 : ! Check explicitly that solutions satisfy the Sternheimer equations
1593 : !--------------------------------------------------------------------------
1594 :
1595 28 : if ( debug ) then
1596 :
1597 0 : if (write_debug) then
1598 0 : write(io_unit,10) "#--------------------------------------------------------------------------------"
1599 0 : write(io_unit,10) "# Check explicitly that solutions satisfy the Sternheimer equation. "
1600 0 : write(io_unit,10) "# "
1601 0 : write(io_unit,10) "# Define: "
1602 0 : write(io_unit,10) "# E_l = || (omega^2+[H-Ev]^2) |phi_l> + Pc.[H-Ev].Pc |(V^1/2.q_l)^*.phi_v > || "
1603 0 : write(io_unit,10) "#--------------------------------------------------------------------------------"
1604 0 : write(io_unit,10) '# l Im[omega] (Ha) E_l'
1605 0 : write(io_unit,10) "#--------------------------------------------------------------------------------"
1606 0 : flush(io_unit)
1607 : end if
1608 :
1609 :
1610 0 : do iblk_lanczos = 1, nbdblock_lanczos
1611 :
1612 : ! loop on all states within this block
1613 0 : do mb = 1, blocksize
1614 :
1615 0 : l = (iblk_lanczos-1)*blocksize + mb
1616 :
1617 :
1618 0 : if ( l <= lmax) then
1619 : ! psik_wrk = | (V^{1/2} .l )^* phi_v >
1620 0 : psik_wrk(1,:) = dble (local_Lbasis(:,l))
1621 0 : psik_wrk(2,:) = dimag(local_Lbasis(:,l))
1622 : else
1623 0 : psik_wrk(:,:) = zero
1624 : end if
1625 :
1626 : ! Store in array of blocks of wavefunctions
1627 0 : psikb_wrk(:,(mb-1)*npw_k+1:mb*npw_k) = psik_wrk(:,:)
1628 : end do ! mb
1629 :
1630 : ! Transform to FFT representation
1631 0 : call wf_block_distribute(psikb_wrk, psikg_wrk, 1) ! LA -> FFT
1632 :
1633 : ! Create right-hand-side of Sternheimer equation
1634 0 : call pc_k_valence_kernel(psikg_wrk)
1635 0 : call Hpsik(psikg_in,psikg_wrk,eig(v))
1636 0 : call pc_k_valence_kernel(psikg_in)
1637 0 : psikg_in(:,:) = -psikg_in(:,:) ! IS THIS STACK-DANGEROUS?
1638 :
1639 0 : do iw = 1, nfrequencies
1640 : ! loop on all states within this block
1641 0 : do mb = 1, blocksize
1642 :
1643 0 : l = (iblk_lanczos-1)*blocksize + mb
1644 :
1645 0 : ls = (l-1)*nfrequencies+iw
1646 :
1647 0 : if ( l <= lmax) then
1648 0 : psik_wrk(1,:) = dble (c_sternheimer_solutions(:,ls))
1649 0 : psik_wrk(2,:) = dimag(c_sternheimer_solutions(:,ls))
1650 : else
1651 0 : psik_wrk(:,:) = zero
1652 : end if
1653 :
1654 : ! Store in array of blocks of wavefunctions
1655 0 : psikb_wrk(:,(mb-1)*npw_k+1:mb*npw_k) = psik_wrk(:,:)
1656 : end do
1657 :
1658 : ! Transform to FFT representation
1659 0 : call wf_block_distribute(psikb_wrk, psikg_wrk, 1) ! LA -> FFT
1660 :
1661 :
1662 0 : omega0 = list_projection_frequencies(iw)
1663 :
1664 0 : psikg_out(:,:) = omega0**2*psikg_wrk(:,:)
1665 :
1666 0 : call Hpsik(psikg_wrk,cte=eig(v))
1667 0 : call Hpsik(psikg_wrk,cte=eig(v))
1668 :
1669 :
1670 0 : psikg_out(:,:) = psikg_out(:,:) + psikg_wrk(:,:)-psikg_in(:,:)
1671 : ! psikg_out now contains [ w0^2 + [H-epsilon_v]^2 ] | x > - |RHS>, in FFT configuration.
1672 :
1673 : ! bring it back to LA configuration
1674 :
1675 : ! Transform to FFT representation
1676 0 : call wf_block_distribute(psikb_wrk, psikg_out, 2) ! FFT -> LA
1677 :
1678 0 : do mb = 1, blocksize
1679 0 : l = (iblk_lanczos-1)*blocksize + mb
1680 :
1681 0 : if ( l <= lmax) then
1682 0 : psik_wrk(:,:) = psikb_wrk(:,(mb-1)*npw_k+1:mb*npw_k)
1683 :
1684 0 : z(:) = cg_zdotc(npw_k ,psik_wrk, psik_wrk)
1685 :
1686 0 : call xmpi_sum(z, mpi_communicator,ierr) ! sum on all processors working on FFT!
1687 0 : if (write_debug) write(io_unit,21) l, omega0, sqrt(z(1))
1688 : end if
1689 : end do ! mb
1690 :
1691 : end do ! iw
1692 : end do ! iblk_lanczos
1693 :
1694 : end if
1695 :
1696 : !--------------------------------------------------------------------------
1697 : ! Step 5: Perform a singular value decomposition to extract a
1698 : ! linearly independent basis for the solution space.
1699 : !
1700 : !--------------------------------------------------------------------------
1701 28 : write(io_unit_log,10) ' - Perform SVD to extract linearly independent basis to Sternheimer equation...'
1702 28 : flush(io_unit_log)
1703 :
1704 :
1705 :
1706 :
1707 66268 : svd_matrix(:,:) = c_sternheimer_solutions(:,:)
1708 :
1709 28 : call extract_SVD(mpi_communicator, npw_k,lsolutions_max,svd_matrix,svd_values)
1710 :
1711 28 : if ( write_debug ) then
1712 0 : write(io_unit,10) "#--------------------------------------------------------------------------------"
1713 0 : write(io_unit,10) "# Check the singular value decomposition of the arrays"
1714 0 : write(io_unit,10) '# l svd'
1715 0 : write(io_unit,10) "#--------------------------------------------------------------------------------"
1716 0 : flush(io_unit)
1717 : end if
1718 :
1719 28 : lsolutions = 0
1720 66268 : QR_orthonormal_basis(:,:) = cmplx_0
1721 476 : do l=1, lsolutions_max
1722 476 : if (svd_values(l) > svd_tolerance ) then
1723 448 : lsolutions = lsolutions + 1
1724 :
1725 448 : if ( write_debug ) then
1726 0 : write(io_unit,14) l,svd_values(l)
1727 0 : flush(io_unit)
1728 : end if
1729 66240 : QR_orthonormal_basis(:,l) = svd_matrix(:,l)
1730 :
1731 : else
1732 0 : if ( write_debug ) then
1733 0 : write(io_unit,15) l,svd_values(l),' SVD value too small! Vector to be discarded!'
1734 0 : flush(io_unit)
1735 : end if
1736 : end if
1737 : end do
1738 :
1739 : !--------------------------------------------------------------------------
1740 : ! Step 6: project all relevant arrays onto the newly defined orthonormal
1741 : ! basis.
1742 : !--------------------------------------------------------------------------
1743 28 : write(io_unit_log,10) ' - Compute the B matrix...'
1744 28 : flush(io_unit_log)
1745 :
1746 28 : if (debug) then
1747 0 : check_matrix(:,:) = cmplx_0
1748 0 : do l = 1, lsolutions
1749 0 : check_matrix(l,l) = -cmplx_1
1750 : end do
1751 : end if
1752 :
1753 84 : ABI_MALLOC(ipiv ,(lsolutions))
1754 112 : ABI_MALLOC(sternheimer_A0 ,(lsolutions,lsolutions))
1755 112 : ABI_MALLOC(sternheimer_B ,(lsolutions,lmax))
1756 112 : ABI_MALLOC(sternheimer_G ,(lmax,lsolutions))
1757 :
1758 : ! Compute the X matrix and the check_matrix
1759 476 : do l1 = 1, lsolutions
1760 :
1761 66240 : psi_gamma_l1(1,:) = real (QR_orthonormal_basis(:,l1))
1762 66240 : psi_gamma_l1(2,:) = dimag(QR_orthonormal_basis(:,l1))
1763 :
1764 7644 : do l2 = 1, lsolutions
1765 :
1766 7168 : if (l2 <= lmax) then
1767 3584 : z(:) = cg_zdotc(npw_k, psi_gamma_l1, psi_rhs(:,:,l2))
1768 3584 : call xmpi_sum(z, mpi_communicator,ierr) ! sum on all processors for LA configuration
1769 :
1770 3584 : sternheimer_B(l1,l2) = cmplx_1*z(1)+cmplx_i*z(2)
1771 : end if
1772 :
1773 7616 : if (debug) then
1774 0 : psi_gamma_l2(1,:) = dble (QR_orthonormal_basis(:,l2))
1775 0 : psi_gamma_l2(2,:) = dimag(QR_orthonormal_basis(:,l2))
1776 :
1777 0 : z(:) = cg_zdotc(npw_k, psi_gamma_l1, psi_gamma_l2)
1778 0 : call xmpi_sum(z, mpi_communicator,ierr) ! sum on all processors
1779 :
1780 0 : check_matrix(l1,l2) = check_matrix(l1,l2) + cmplx_1*z(1)+cmplx_i*z(2)
1781 : end if
1782 :
1783 : end do ! l2
1784 : end do ! l1
1785 :
1786 :
1787 : ! Number of blocks of solution vectors
1788 28 : nbdblock_solutions = lsolutions/blocksize
1789 :
1790 28 : if (modulo(lsolutions,blocksize) /= 0) nbdblock_solutions = nbdblock_solutions + 1
1791 :
1792 :
1793 28 : write(io_unit_log,10) ' - Compute the A0 matrix...'
1794 28 : flush(io_unit_log)
1795 :
1796 : ! Compute the A matrix
1797 348 : do iblk_solutions =1, nbdblock_solutions
1798 :
1799 768 : do mb = 1, blocksize
1800 448 : l2 = (iblk_solutions-1)*blocksize + mb
1801 :
1802 448 : if ( l2 <= lsolutions) then
1803 66240 : psik_wrk(1,:) = dble (QR_orthonormal_basis(:,l2))
1804 66240 : psik_wrk(2,:) = dimag(QR_orthonormal_basis(:,l2))
1805 : else
1806 0 : psik_wrk(:,:) = zero
1807 : end if
1808 :
1809 : ! Store in array of blocks of wavefunctions
1810 198144 : psikb_wrk(:,(mb-1)*npw_k+1:mb*npw_k) = psik_wrk(:,:)
1811 : end do
1812 :
1813 : ! Transform to FFT representation
1814 320 : call wf_block_distribute(psikb_wrk, psikg_wrk,1) ! LA -> FFT
1815 :
1816 : ! act twice with the Hamiltonian operator
1817 320 : call Hpsik(psikg_out,psikg_wrk,eig(v))
1818 320 : call Hpsik(psikg_out,cte=eig(v))
1819 :
1820 : ! return to LA representation
1821 320 : call wf_block_distribute(psikb_wrk, psikg_out,2) ! FFT -> LA
1822 :
1823 796 : do mb = 1, blocksize
1824 448 : l2 = (iblk_solutions-1)*blocksize + mb
1825 :
1826 448 : if ( l2 <= lsolutions) then
1827 197824 : psik_wrk(:,:) = psikb_wrk(:,(mb-1)*npw_k+1:mb*npw_k)
1828 : else
1829 0 : psik_wrk(:,:) = zero
1830 : end if
1831 :
1832 7936 : do l1 = 1, lsolutions
1833 :
1834 1059840 : psi_gamma_l1(1,:) = real (QR_orthonormal_basis(:,l1))
1835 1059840 : psi_gamma_l1(2,:) = dimag(QR_orthonormal_basis(:,l1))
1836 :
1837 7168 : z(:) = cg_zdotc(npw_k, psi_gamma_l1, psik_wrk)
1838 7168 : call xmpi_sum(z,mpi_communicator,ierr) ! sum on all processors working on FFT!
1839 :
1840 :
1841 7616 : if ( l2 <= lsolutions ) then
1842 7168 : sternheimer_A0(l1,l2) = cmplx_1*z(1)+cmplx_i*z(2)
1843 : end if
1844 :
1845 :
1846 : end do ! l1
1847 : end do ! mb
1848 : end do ! iblk_solutions
1849 :
1850 :
1851 28 : if (debug) then
1852 : ! HERE we use a dummy variable to avoid operations which might blow the stack!
1853 : ! Stack overflows lead to hard-to-find bugs; let's avoid putting them in here.
1854 0 : ABI_MALLOC(dummy_tmp_1,(lsolutions,lsolutions))
1855 0 : ABI_MALLOC(dummy_tmp_2,(lsolutions,lsolutions))
1856 :
1857 :
1858 0 : dummy_tmp_1(:,:)= transpose(sternheimer_A0(:,:))
1859 0 : dummy_tmp_2(:,:)= conjg(dummy_tmp_1(:,:))
1860 :
1861 0 : check_matrix2(:,:) = sternheimer_A0(:,:)-dummy_tmp_2(:,:)
1862 :
1863 0 : ABI_FREE(dummy_tmp_1)
1864 0 : ABI_FREE(dummy_tmp_2)
1865 : end if
1866 :
1867 28 : write(io_unit_log,10) ' - Compute the GAMMA matrix...'
1868 28 : flush(io_unit_log)
1869 :
1870 :
1871 : ! Compute the GAMMA matrices
1872 252 : do l1 = 1, lmax
1873 :
1874 : ! psik_wrk = | (V^{1/2} . l )^* phi_v >
1875 33120 : psik_wrk(1,:) = dble (local_Lbasis(:,l1) )
1876 33120 : psik_wrk(2,:) = dimag(local_Lbasis(:,l1))
1877 :
1878 :
1879 3836 : do l2 = 1, lsolutions
1880 :
1881 529920 : psi_gamma_l2(1,:) = real (QR_orthonormal_basis(:,l2))
1882 529920 : psi_gamma_l2(2,:) = dimag(QR_orthonormal_basis(:,l2))
1883 :
1884 :
1885 : ! Note that G_{lJ} = < l | Vc^{1/2}.(gamma_J^*.phi_v)>
1886 : ! = < gamma_J | (Vc^{1/2}.l^*).phi_v >
1887 :
1888 3584 : z(:) = cg_zdotc(npw_k,psi_gamma_l2, psik_wrk)
1889 3584 : call xmpi_sum(z,mpi_communicator,ierr) ! sum on all processors working on FFT!
1890 3808 : sternheimer_G(l1,l2) = cmplx_1*z(1)+cmplx_i*z(2)
1891 :
1892 : end do ! l1
1893 : end do ! l2
1894 :
1895 :
1896 :
1897 28 : if ( write_debug ) then
1898 0 : write(io_unit,19) '<gamma| gamma>', sqrt(sum(abs(check_matrix(:,:))**2))
1899 0 : write(io_unit,19) ' M hermitian ',sqrt(sum(abs(check_matrix2(:,:))**2))
1900 0 : write(io_unit,10) " "
1901 0 : write(io_unit,10) "# GAMMA Matrix:"
1902 0 : write(io_unit,10) " "
1903 :
1904 0 : do l1 = 1, lmax
1905 0 : write(io_unit,30) sternheimer_G(l1,:)
1906 : end do
1907 0 : flush(io_unit)
1908 : end if
1909 :
1910 : !--------------------------------------------------------------------------
1911 : ! Step 7: Compute the solutions
1912 : !--------------------------------------------------------------------------
1913 :
1914 28 : write(io_unit_log,10) ' - Compute the Projected Sternheimer solutions and build approximate dielectric operator...'
1915 28 : flush(io_unit_log)
1916 :
1917 :
1918 :
1919 84 : ABI_MALLOC(sternheimer_A ,(lsolutions,lsolutions))
1920 84 : ABI_MALLOC(sternheimer_X ,(lsolutions,lmax))
1921 308 : do iw = 2, npt_gauss + 1
1922 :
1923 280 : write(io_unit_log,23) ' -- iw = ',iw,' / ',npt_gauss+1
1924 280 : flush(io_unit_log)
1925 :
1926 :
1927 280 : omega = list_omega(iw)
1928 :
1929 76440 : sternheimer_A(:,:) = sternheimer_A0(:,:)
1930 :
1931 4760 : do l = 1, lsolutions
1932 4760 : sternheimer_A(l,l) = sternheimer_A(l,l) + omega**2
1933 : end do
1934 :
1935 38360 : sternheimer_X(:,:) = sternheimer_B(:,:)
1936 :
1937 : !--------------------------------------------------------------------------
1938 : ! Step 2: solve A*X = B, a projected form of the Sternheimer equation
1939 : !--------------------------------------------------------------------------
1940 280 : write(io_unit_log,10) ' -- Solve A*X = B'
1941 280 : flush(io_unit_log)
1942 :
1943 :
1944 :
1945 280 : call cpu_time(time1)
1946 : call zgesv(lsolutions, & ! number of rows of A matrix
1947 : lmax, & ! number of columns of B matrix
1948 : sternheimer_A, & ! The A matrix on input, the LU factorization on output
1949 : lsolutions, & ! leading dimension of A
1950 : ipiv, & ! array of pivots
1951 : sternheimer_X, & ! B matrix on input, solution X on output
1952 : lsolutions, & ! leading dimension of B
1953 280 : info )
1954 280 : call cpu_time(time2)
1955 :
1956 280 : time_exact = time_exact + time2-time1
1957 :
1958 : !--------------------------------------------------------------------------
1959 : ! Step 3: Add contribution to projected epsilon
1960 : !--------------------------------------------------------------------------
1961 : ! perform E = E -4 sum_l Gamma_v*X^*_v
1962 :
1963 280 : write(io_unit_log,10) ' -- add contribution to dielectric matrix at this frequency'
1964 280 : flush(io_unit_log)
1965 :
1966 :
1967 :
1968 1120 : ABI_MALLOC(dummy_tmp_1,(lsolutions,lmax))
1969 38360 : dummy_tmp_1(:,:) = conjg(sternheimer_X) ! DO THIS to avoid potential stack problems
1970 :
1971 280 : call cpu_time(time1)
1972 : call zgemm( 'N', & ! A matrix is in normal order
1973 : 'N', & ! B matrix is in normal order
1974 : lmax, & ! number of rows of A
1975 : lmax, & ! number of columns of B
1976 : lsolutions, & ! number of columns of A
1977 : -4.0_dp*cmplx_1, & ! premultiply A*B by this scalar
1978 : sternheimer_G, & ! GAMMA matrix
1979 : lmax, & ! leading dimension of A
1980 : dummy_tmp_1, & ! B matrix
1981 : lsolutions, & ! leading dimension of B
1982 : cmplx_1, & ! beta is one
1983 : projected_dielectric_Lanczos_basis(:,:,iw), & ! C matrix
1984 280 : lmax) ! leading dimension of C
1985 :
1986 280 : ABI_FREE(dummy_tmp_1)
1987 :
1988 280 : call cpu_time(time2)
1989 308 : time_exact = time_exact + time2-time1
1990 :
1991 : end do ! iw
1992 :
1993 28 : write(io_unit_log,10) ' - Deallocate tmp arrays...'
1994 28 : flush(io_unit_log)
1995 :
1996 :
1997 :
1998 :
1999 28 : ABI_FREE(ipiv )
2000 28 : ABI_FREE(sternheimer_A )
2001 28 : ABI_FREE(sternheimer_A0 )
2002 28 : ABI_FREE(sternheimer_B )
2003 28 : ABI_FREE(sternheimer_X )
2004 35 : ABI_FREE(sternheimer_G )
2005 :
2006 : end do ! v
2007 :
2008 : !--------------------------------------------------------------------------
2009 : ! Finalize, post v loop
2010 : !--------------------------------------------------------------------------
2011 7 : write(io_unit_log,10) " - Finalize, after band iterations...."
2012 7 : flush(io_unit_log)
2013 :
2014 :
2015 :
2016 :
2017 :
2018 7 : timing_string = "# Exact Sector : "
2019 7 : call write_timing_log(timing_string,time_exact)
2020 :
2021 :
2022 28 : ABI_MALLOC(dummy_tmp_1,(lmax,lmax))
2023 21 : ABI_MALLOC(dummy_tmp_2,(lmax,lmax))
2024 :
2025 77 : do iw = 2, npt_gauss+1
2026 : ! finally, make sure matrix is hermitian
2027 :
2028 : ! play this little game to avoid STACK problems
2029 5110 : dummy_tmp_1(:,:) = 0.5_dp*transpose(projected_dielectric_Lanczos_basis(:,:,iw))
2030 5110 : dummy_tmp_2(:,:) = conjg(dummy_tmp_1(:,:))
2031 5110 : dummy_tmp_1(:,:) = dummy_tmp_2(:,:) +0.5_dp*projected_dielectric_Lanczos_basis(:,:,iw)
2032 :
2033 5117 : projected_dielectric_Lanczos_basis(:,:,iw) = dummy_tmp_1(:,:)
2034 : end do
2035 :
2036 7 : ABI_FREE(dummy_tmp_1)
2037 7 : ABI_FREE(dummy_tmp_2)
2038 :
2039 :
2040 :
2041 7 : if ( write_debug ) then
2042 : !write some results to a file
2043 :
2044 0 : write(io_unit,10) '#===================================================================================================='
2045 0 : write(io_unit,10) "# Projected dielectric matrices "
2046 0 : write(io_unit,10) "# ------------------------------------------------------- "
2047 0 : write(io_unit,10) "# This file contains the various projected dielectric matrices as a function of frequency. "
2048 0 : write(io_unit,10) '#===================================================================================================='
2049 0 : write(io_unit,10) ''
2050 0 : flush(io_unit)
2051 :
2052 0 : do iw = 1, npt_gauss+1
2053 0 : write(io_unit,10) "#"
2054 0 : write(io_unit,12) "# omega = ",list_omega(iw), " i Ha"
2055 0 : write(io_unit,10) "#"
2056 :
2057 0 : do l =1, lmax
2058 0 : write(io_unit,30) projected_dielectric_Lanczos_basis(l,:,iw)
2059 : end do
2060 : end do
2061 :
2062 : end if
2063 :
2064 :
2065 7 : if ( model ) then
2066 :
2067 :
2068 : ! Add all components on the processors
2069 6 : call xmpi_sum(model_dielectric_Lanczos_basis,mpi_communicator,ierr) ! sum on all processors
2070 :
2071 : ! add the identity
2072 72 : do iw = 1, npt_gauss+1
2073 600 : do l= 1, lmax
2074 594 : model_dielectric_Lanczos_basis(l,l,iw) = model_dielectric_Lanczos_basis(l,l,iw) + cmplx_1
2075 : end do
2076 : end do
2077 :
2078 : ! hermitian the operator
2079 72 : do iw = 1, npt_gauss+1
2080 :
2081 600 : do l1 = 1, lmax
2082 2970 : do l2 = 1, l1
2083 : ! operator is hermitian
2084 2904 : model_dielectric_Lanczos_basis(l2,l1,iw) = conjg(model_dielectric_Lanczos_basis(l1,l2,iw))
2085 : end do
2086 : end do
2087 :
2088 : end do ! iw
2089 :
2090 : end if
2091 :
2092 :
2093 :
2094 7 : if ( write_debug ) then
2095 0 : close(io_unit)
2096 : end if
2097 :
2098 7 : write(io_unit_log,10) " - Deallocate and exit...."
2099 7 : flush(io_unit_log)
2100 :
2101 :
2102 :
2103 7 : if (debug) then
2104 0 : ABI_FREE(check_matrix)
2105 0 : ABI_FREE(check_matrix2)
2106 : end if
2107 :
2108 :
2109 7 : ABI_FREE(psikg_valence)
2110 7 : ABI_FREE(psir_valence)
2111 7 : ABI_FREE(psikg_VL)
2112 :
2113 :
2114 7 : ABI_FREE(YL)
2115 :
2116 7 : ABI_FREE(local_Lbasis_conjugated)
2117 7 : ABI_FREE(local_Lbasis)
2118 :
2119 :
2120 7 : ABI_FREE(svd_matrix)
2121 7 : ABI_FREE(svd_values)
2122 7 : ABI_FREE(psi_gamma_l1)
2123 7 : ABI_FREE(psi_gamma_l2)
2124 :
2125 7 : ABI_FREE(psikg_in)
2126 7 : ABI_FREE(psikg_out)
2127 :
2128 7 : ABI_FREE(psi_rhs)
2129 :
2130 7 : ABI_FREE(c_sternheimer_solutions)
2131 7 : ABI_FREE(QR_orthonormal_basis)
2132 :
2133 7 : ABI_FREE(psik_wrk)
2134 7 : ABI_FREE(psikb_wrk)
2135 7 : ABI_FREE(psikg_wrk)
2136 :
2137 :
2138 7 : close(io_unit_log)
2139 :
2140 :
2141 : 10 format(A)
2142 : 12 format(A,F12.8,A)
2143 : 14 format(I5,10X,ES24.12)
2144 : 15 format(I5,10X,ES24.12,10X,A)
2145 :
2146 : 19 format(20X,A,15X,E24.16)
2147 :
2148 : 20 format(A,I5)
2149 : 21 format(I5,10X,F8.4,15X,ES24.12)
2150 : 22 format(A,I5,A)
2151 : 23 format(A,I5,A,I5)
2152 : 30 format(2X,1000(ES12.4,2X,ES12.4,5X))
2153 :
2154 7 : end subroutine ProjectedSternheimerEpsilon
2155 : !!***
2156 :
2157 :
2158 : end module m_gwls_DielectricArray
2159 : !!***
|