Line data Source code
1 : !!****m* ABINIT/m_gwls_Projected_AT
2 : !! NAME
3 : !! m_gwls_Projected_AT
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_Projected_AT
24 : !----------------------------------------------------------------------------------------------------
25 : ! This module contains routines to compute the matrix elements of the so-called A operator,
26 : ! which accounts for the Static correlation energy term.
27 : !----------------------------------------------------------------------------------------------------
28 : ! local modules
29 : use m_gwls_utility
30 : use m_gwls_wf
31 : use m_gwls_TimingLog
32 : use m_gwls_hamiltonian
33 : use m_gwls_lineqsolver
34 : use m_gwls_GWlanczos
35 : use m_gwls_LanczosBasis
36 : use m_gwls_LanczosResolvents
37 :
38 : use m_gwls_GWanalyticPart, only : get_projection_band_indices
39 : ! abinit modules
40 : use defs_basis
41 : use m_abicore
42 : use m_xmpi
43 : use m_io_tools, only : get_unit
44 :
45 :
46 :
47 : implicit none
48 : save
49 : private
50 : !!***
51 :
52 : !!***
53 :
54 : ! Public methods
55 : public :: compute_AT_shift_Lanczos
56 : !!***
57 :
58 : contains
59 :
60 : !!****f* m_hamiltonian/compute_AT_shift_Lanczos
61 : !! NAME
62 : !! compute_AT_shift_Lanczos
63 : !!
64 : !! FUNCTION
65 : !! .
66 : !!
67 : !! INPUTS
68 : !!
69 : !! OUTPUT
70 : !!
71 : !! SOURCE
72 :
73 13 : subroutine compute_AT_shift_Lanczos(nfreq,list_external_omega,model_parameter,lmax, modified_Lbasis,kmax_analytic,list_AT_Lanczos)
74 : !----------------------------------------------------------------------------------------------------
75 : ! This function returns the diagonal matrix elements of the so-called A^T operator, which is pertinent to the
76 : ! computation of the analytic energy term.
77 : !
78 : ! The operator is given by
79 : !
80 : ! Am(W) = w0/2 Um^dagger . [ PW/(H-W-w0)+QW/(H-W+w0)] . Um
81 : !
82 : ! where W is the external frequency of the self energy, and w0 is the lorentzian parameter.
83 : ! The operator PW projects on states of energy lower than W, and QW on states or energy higher than W.
84 : !
85 : !
86 : ! For every l, We seek to compute AT_l = < l | A^T | l > = < l^* | A | l^* >
87 : !
88 : ! It will be assumed that the array modified_Lbasis already contains the basis vectors U_m | l^* >.
89 : !
90 : ! This function does not use SQMR, but rather shift Lanczos to extract the values of the matrix elements for
91 : ! all external frequencies.
92 : !----------------------------------------------------------------------------------------------------
93 : integer, intent(in) :: nfreq
94 : real(dp), intent(in) :: list_external_omega(nfreq)
95 : real(dp), intent(in) :: model_parameter
96 : integer, intent(in) :: lmax
97 : integer, intent(in) :: kmax_analytic
98 : complex(dp), intent(in) :: modified_Lbasis(npw_k,lmax)
99 : complex(dp), intent(out):: list_AT_Lanczos(nfreq,lmax)
100 :
101 :
102 13 : real(dp), allocatable :: psik_wrk(:,:)
103 13 : real(dp), allocatable :: psikb_wrk(:,:)
104 13 : real(dp), allocatable :: psikg_wrk(:,:)
105 :
106 13 : real(dp), allocatable :: psikg(:,:)
107 :
108 13 : complex(dp), allocatable :: seed_vector(:)
109 13 : complex(dp), allocatable :: list_left_vectors(:,:)
110 13 : complex(dp), allocatable :: matrix_elements_resolvent(:,:)
111 13 : complex(dp), allocatable :: list_z_P(:), list_z_Q(:)
112 13 : integer, allocatable :: frequency_indices_array(:,:)
113 :
114 :
115 : real(dp):: external_omega
116 : logical :: prec
117 : integer :: nvec
118 : integer :: band_index_below, band_index_above, bib0, bia0, bib, bia
119 :
120 : integer :: l, lloc, iw_ext, iw_ext_min, iw_ext_max
121 : integer :: ierr
122 :
123 : integer :: number_of_frequency_blocks, ifreq_block
124 :
125 : integer :: iblk, nbdblock_lanczos
126 : integer :: mb
127 :
128 : integer :: nz
129 :
130 : integer :: io_unit
131 : integer :: mpi_band_rank
132 :
133 : ! *************************************************************************
134 :
135 13 : mpi_band_rank = mpi_enreg%me_band
136 :
137 : !=================================================
138 : !
139 : ! Find the number of frequency blocks, where
140 : ! the projection operators are constant within a
141 : ! block.
142 : !=================================================
143 :
144 13 : if (mpi_enreg%me == 0 ) then
145 7 : io_unit = get_unit()
146 7 : open(io_unit,file='Frequency_blocks_AT.log',position='append')
147 :
148 7 : write(io_unit,10) "#================================================================================"
149 7 : write(io_unit,10) "# "
150 7 : write(io_unit,10) "# This log file documents how the algorithm in compute_AT_shift_Lanczos "
151 7 : write(io_unit,10) "# separates the external frequencies in blocks. It is quite easy to put "
152 7 : write(io_unit,10) "# bugs in this algorithm, so monitoring is critical. "
153 7 : write(io_unit,10) "# "
154 7 : write(io_unit,10) "#================================================================================"
155 :
156 :
157 7 : write(io_unit,10) " "
158 7 : write(io_unit,10) "#================================================================================"
159 7 : write(io_unit,10) "# "
160 7 : write(io_unit,10) "# input parameters: "
161 7 : write(io_unit,10) "# "
162 7 : write(io_unit,15) "# nfreq : ",nfreq
163 7 : write(io_unit,17) "# list_external_omega : ",list_external_omega
164 7 : write(io_unit,17) "# model_parameter : ",model_parameter
165 7 : write(io_unit,15) "# lmax : ",lmax
166 7 : write(io_unit,15) "# kmax_analytic : ",kmax_analytic
167 7 : write(io_unit,10) "# "
168 7 : write(io_unit,10) "#================================================================================"
169 7 : write(io_unit,10) "# "
170 7 : write(io_unit,10) "# Building the blocks "
171 7 : write(io_unit,10) "# "
172 7 : write(io_unit,10) "# bib : band index below "
173 7 : write(io_unit,10) "# bia : band index above "
174 7 : write(io_unit,10) "# nfb : number_of_frequency_blocks "
175 7 : write(io_unit,10) "# "
176 7 : write(io_unit,10) "# "
177 7 : write(io_unit,10) "# iw_ext external_omega (Ha) bib bia nfb "
178 7 : write(io_unit,10) "#================================================================================"
179 : end if
180 13 : external_omega = list_external_omega(1)
181 :
182 :
183 : ! bib == band_index_below
184 : ! bia == band_index_above
185 13 : call get_projection_band_indices(external_omega,bib0, bia0)
186 :
187 13 : number_of_frequency_blocks = 1
188 :
189 : ! loop on all external frequencies
190 26 : do iw_ext = 1 , nfreq
191 :
192 13 : external_omega = list_external_omega(iw_ext)
193 : ! Define the energy of the state to be corrected
194 :
195 : ! Find the indices for the projections PW and QW
196 13 : call get_projection_band_indices(external_omega,bib, bia)
197 :
198 :
199 13 : if (mpi_enreg%me == 0 ) write(io_unit,20) iw_ext, external_omega, bib, bia, number_of_frequency_blocks
200 :
201 39 : if (bib /= bib0 .or. bia /= bia0) then
202 :
203 0 : if (mpi_enreg%me == 0 ) write(io_unit,10) "************* new block! **********************"
204 0 : bib0 = bib
205 0 : bia0 = bia
206 :
207 0 : number_of_frequency_blocks = number_of_frequency_blocks + 1
208 :
209 : end if
210 : end do
211 :
212 : !=================================================
213 : !
214 : ! fill the frequency indices array
215 : !
216 : !=================================================
217 :
218 13 : if (mpi_enreg%me == 0 ) then
219 7 : write(io_unit,10) " "
220 7 : write(io_unit,10) "#================================================================================"
221 7 : write(io_unit,10) "# "
222 7 : write(io_unit,10) "# Filling the frequency indices array "
223 7 : write(io_unit,10) "# "
224 7 : write(io_unit,10) "# iw_ext iw_ext_min iw_ext_max ifreq_block "
225 7 : write(io_unit,10) "#================================================================================"
226 : end if
227 :
228 :
229 39 : ABI_MALLOC(frequency_indices_array, (2,number_of_frequency_blocks))
230 52 : frequency_indices_array = 0
231 :
232 13 : iw_ext_min = 1
233 13 : iw_ext_max = 1
234 :
235 : ! loop on all external frequencies
236 13 : external_omega = list_external_omega(1)
237 13 : call get_projection_band_indices(external_omega,bib0, bia0)
238 13 : ifreq_block = 1
239 :
240 26 : do iw_ext = 1 , nfreq
241 :
242 13 : if (mpi_enreg%me == 0 ) write(io_unit,30) iw_ext, iw_ext_min, iw_ext, ifreq_block
243 :
244 13 : external_omega = list_external_omega(iw_ext)
245 : ! Define the energy of the state to be corrected
246 :
247 : ! Find the indices for the projections PW and QW
248 13 : call get_projection_band_indices(external_omega,bib, bia)
249 :
250 26 : if (bib /= bib0 .or. bia /= bia0) then
251 :
252 0 : if (mpi_enreg%me == 0 ) write(io_unit,10) "************* new block! **********************"
253 0 : bib0 = bib
254 0 : bia0 = bia
255 :
256 : ! write previous block
257 0 : frequency_indices_array(1,ifreq_block) = iw_ext_min
258 0 : frequency_indices_array(2,ifreq_block) = iw_ext-1 ! we went one too far
259 :
260 0 : ifreq_block = ifreq_block + 1
261 0 : iw_ext_min = iw_ext
262 : end if
263 :
264 : end do
265 :
266 : ! write last block!
267 13 : frequency_indices_array(1,ifreq_block) = iw_ext_min
268 13 : frequency_indices_array(2,ifreq_block) = nfreq
269 :
270 13 : if (mpi_enreg%me == 0 ) then
271 7 : write(io_unit,10) " "
272 7 : write(io_unit,10) "#================================================================================"
273 7 : write(io_unit,10) "# "
274 7 : write(io_unit,10) "# "
275 7 : write(io_unit,10) "# Final frequency_indices_array : "
276 7 : write(io_unit,10) "# "
277 7 : write(io_unit,10) "# ifreq_block iw_ext_min iw_ext_max "
278 7 : write(io_unit,10) "#================================================================================"
279 :
280 14 : do ifreq_block = 1 , number_of_frequency_blocks
281 :
282 14 : write(io_unit,40) ifreq_block, frequency_indices_array(1,ifreq_block), frequency_indices_array(2,ifreq_block)
283 :
284 : end do
285 : end if
286 :
287 :
288 :
289 :
290 : !=================================================
291 : !
292 : ! Set up the LanczosResolvents algorithm
293 : !
294 : !=================================================
295 :
296 13 : prec = .false. ! let's not precondition for now
297 13 : call setup_LanczosResolvents(kmax_analytic, prec)
298 :
299 : !=================================================
300 : !
301 : ! iterate on frequency blocks!
302 : !
303 : !=================================================
304 13 : nvec = 1
305 :
306 39 : ABI_MALLOC(list_left_vectors, (npw_g,nvec))
307 39 : ABI_MALLOC(seed_vector, (npw_g))
308 :
309 39 : ABI_MALLOC(psik_wrk, (2,npw_k))
310 39 : ABI_MALLOC(psikb_wrk, (2,npw_kb))
311 :
312 39 : ABI_MALLOC(psikg_wrk, (2,npw_g))
313 26 : ABI_MALLOC(psikg, (2,npw_g))
314 :
315 221 : list_AT_Lanczos(:,:) = cmplx_0
316 :
317 : ! Number of blocks of lanczos vectors
318 13 : nbdblock_lanczos = lmax/blocksize
319 13 : if (modulo(lmax,blocksize) /= 0) nbdblock_lanczos = nbdblock_lanczos + 1
320 :
321 :
322 26 : do ifreq_block = 1, number_of_frequency_blocks
323 :
324 : !-------------------------------
325 : ! Build the frequency arrays
326 : !-------------------------------
327 13 : iw_ext_min = frequency_indices_array(1,ifreq_block)
328 13 : iw_ext_max = frequency_indices_array(2,ifreq_block)
329 :
330 :
331 13 : nz = iw_ext_max -iw_ext_min + 1
332 :
333 39 : ABI_MALLOC( list_z_P, (nz))
334 26 : ABI_MALLOC( list_z_Q, (nz))
335 26 : ABI_MALLOC(matrix_elements_resolvent, (nz,nvec))
336 :
337 :
338 13 : external_omega = list_external_omega(iw_ext_min)
339 13 : call get_projection_band_indices(external_omega,band_index_below, band_index_above)
340 :
341 :
342 26 : do iw_ext = iw_ext_min, iw_ext_max
343 :
344 13 : list_z_P(iw_ext-iw_ext_min+1) = list_external_omega(iw_ext)+ model_parameter
345 26 : list_z_Q(iw_ext-iw_ext_min+1) = list_external_omega(iw_ext)- model_parameter
346 :
347 : end do
348 :
349 : !-----------------------------------------
350 : ! Compute with shift Lanczos, using blocks
351 : !-----------------------------------------
352 85 : do iblk = 1, nbdblock_lanczos
353 : ! which l is on this row of FFT processors?
354 72 : l = (iblk-1)*blocksize + mpi_band_rank + 1
355 :
356 : ! Change the configuration of the data
357 176 : do mb =1, blocksize
358 104 : lloc = (iblk-1)*blocksize+mb
359 104 : if (lloc <= lmax) then
360 14496 : psik_wrk(1,:) = dble ( modified_Lbasis(:,lloc) )
361 14496 : psik_wrk(2,:) = dimag( modified_Lbasis(:,lloc) )
362 : else
363 0 : psik_wrk(:,:) = zero
364 : end if
365 :
366 43352 : psikb_wrk(:,(mb-1)*npw_k+1:mb*npw_k) = psik_wrk(:,:)
367 :
368 : end do ! mb
369 :
370 : ! change configuration of the data, from LA to FFT
371 72 : call wf_block_distribute(psikb_wrk, psikg_wrk, 1) ! LA -> FFT
372 :
373 :
374 85 : if (band_index_below == 0 .and. l <= lmax) then
375 : ! There are no DFT states with energy below W!
376 : ! PW is thus zero, and QW = I.
377 :
378 14464 : seed_vector(:) = cmplx_1*psikg_wrk(1,:) + cmplx_i*psikg_wrk(2,:)
379 14464 : list_left_vectors(:,1) = seed_vector(:)
380 :
381 : call compute_resolvent_column_shift_lanczos(nz, list_z_Q, nvec, list_left_vectors, seed_vector, &
382 72 : & matrix_elements_resolvent)
383 :
384 144 : list_AT_Lanczos(iw_ext_min:iw_ext_max, l) = 0.5_dp*model_parameter*matrix_elements_resolvent(:,1)
385 :
386 :
387 0 : else if ( l <= lmax ) then
388 :
389 : !----------------------------------------------------------------------------------
390 : !
391 : ! CAREFUL HERE! PW + QW != I. If the external frequency is exactly equal to a
392 : ! DFT eigenvalue, then the projections PW and QW both project OUT
393 : ! of the subspace corresponding to this energy!
394 : !
395 : !----------------------------------------------------------------------------------
396 :
397 : !-------------------
398 : ! Treat first PW
399 : !-------------------
400 0 : psikg(:,:) = psikg_wrk(:,:)
401 0 : call pc_k_valence_kernel(psikg,band_index_below)
402 :
403 0 : seed_vector = cmplx_1*psikg(1,:)+cmplx_i*psikg(2,:)
404 :
405 0 : list_left_vectors(:,1) = seed_vector(:)
406 :
407 : call compute_resolvent_column_shift_lanczos(nz, list_z_P, nvec, list_left_vectors, seed_vector, &
408 0 : & matrix_elements_resolvent)
409 :
410 0 : list_AT_Lanczos(iw_ext_min:iw_ext_max, l) = 0.5_dp*model_parameter*matrix_elements_resolvent(:,1)
411 :
412 :
413 : !-------------------
414 : ! Treat second QW
415 : !-------------------
416 :
417 0 : psikg(:,:) = psikg_wrk(:,:)
418 :
419 0 : call pc_k_valence_kernel(psikg,band_index_above)
420 :
421 0 : psikg(:,:) = psikg_wrk(:,:)-psikg(:,:)
422 :
423 0 : seed_vector = cmplx_1*psikg(1,:)+cmplx_i*psikg(2,:)
424 :
425 0 : list_left_vectors(:,1) = seed_vector(:)
426 :
427 : call compute_resolvent_column_shift_lanczos(nz, list_z_Q, nvec, list_left_vectors, seed_vector, &
428 0 : & matrix_elements_resolvent)
429 :
430 : list_AT_Lanczos(iw_ext_min:iw_ext_max, l) = list_AT_Lanczos(iw_ext_min:iw_ext_max, l) + &
431 0 : 0.5_dp*model_parameter*matrix_elements_resolvent(:,1)
432 :
433 : end if
434 :
435 : end do
436 :
437 13 : ABI_FREE( list_z_P)
438 13 : ABI_FREE( list_z_Q)
439 39 : ABI_FREE(matrix_elements_resolvent)
440 :
441 : end do
442 :
443 :
444 : ! sum all results
445 13 : call xmpi_sum(list_AT_Lanczos, mpi_enreg%comm_band,ierr) ! sum on all processors working on bands
446 :
447 :
448 13 : if (mpi_enreg%me == 0 ) then
449 7 : close(io_unit)
450 : end if
451 :
452 13 : ABI_FREE(list_left_vectors)
453 13 : ABI_FREE(seed_vector)
454 13 : ABI_FREE(frequency_indices_array)
455 :
456 :
457 13 : ABI_FREE(psik_wrk)
458 13 : ABI_FREE(psikb_wrk)
459 :
460 13 : ABI_FREE(psikg_wrk)
461 13 : ABI_FREE(psikg)
462 :
463 :
464 :
465 :
466 13 : call cleanup_LanczosResolvents
467 :
468 : 10 format(A)
469 : 15 format(A,I5)
470 : 17 format(A,1000F8.4)
471 : 20 format(I5,7X,ES24.16,3I5)
472 : 30 format(4(I5,10X))
473 : 40 format(3(I5,10x))
474 :
475 26 : end subroutine compute_AT_shift_Lanczos
476 : !!***
477 :
478 :
479 : end module m_gwls_Projected_AT
480 : !!***
|