Line data Source code
1 : !--------------------------------------------------------------------------------------------------!
2 : ! CP2K: A general program to perform molecular dynamics simulations !
3 : ! Copyright 2000-2024 CP2K developers group <https://cp2k.org> !
4 : ! !
5 : ! SPDX-License-Identifier: GPL-2.0-or-later !
6 : !--------------------------------------------------------------------------------------------------!
7 :
8 : ! **************************************************************************************************
9 : MODULE atom_admm_methods
10 : USE atom_operators, ONLY: atom_basis_projection_overlap,&
11 : atom_int_release,&
12 : atom_int_setup
13 : USE atom_output, ONLY: atom_print_basis
14 : USE atom_types, ONLY: &
15 : atom_basis_type, atom_integrals, atom_orbitals, atom_p_type, atom_type, create_atom_orbs, &
16 : init_atom_basis, lmat, release_atom_basis, release_atom_orbs
17 : USE atom_utils, ONLY: atom_consistent_method,&
18 : atom_denmat,&
19 : atom_trace,&
20 : eeri_contract
21 : USE atom_xc, ONLY: atom_dpot_lda,&
22 : atom_vxc_lda,&
23 : atom_vxc_lsd
24 : USE input_constants, ONLY: do_rhf_atom,&
25 : do_rks_atom,&
26 : do_rohf_atom,&
27 : do_uhf_atom,&
28 : do_uks_atom,&
29 : xc_funct_no_shortcut
30 : USE input_section_types, ONLY: section_vals_duplicate,&
31 : section_vals_get_subs_vals,&
32 : section_vals_get_subs_vals2,&
33 : section_vals_release,&
34 : section_vals_remove_values,&
35 : section_vals_type,&
36 : section_vals_val_set
37 : USE kinds, ONLY: dp
38 : USE mathlib, ONLY: invmat_symm,&
39 : jacobi
40 : #include "./base/base_uses.f90"
41 :
42 : IMPLICIT NONE
43 :
44 : PRIVATE
45 : PUBLIC :: atom_admm
46 :
47 : CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'atom_admm_methods'
48 :
49 : CONTAINS
50 :
51 : ! **************************************************************************************************
52 : !> \brief Analysis of ADMM approximation to exact exchange.
53 : !> \param atom_info information about the atomic kind. Two-dimensional array of size
54 : !> (electronic-configuration, electronic-structure-method)
55 : !> \param admm_section ADMM print section
56 : !> \param iw output file unit
57 : !> \par History
58 : !> * 07.2016 created [Juerg Hutter]
59 : ! **************************************************************************************************
60 1 : SUBROUTINE atom_admm(atom_info, admm_section, iw)
61 :
62 : TYPE(atom_p_type), DIMENSION(:, :), POINTER :: atom_info
63 : TYPE(section_vals_type), POINTER :: admm_section
64 : INTEGER, INTENT(IN) :: iw
65 :
66 : CHARACTER(LEN=2) :: btyp
67 : INTEGER :: i, ifun, j, l, m, maxl, mo, n, na, nb, &
68 : zval
69 : LOGICAL :: pp_calc, rhf
70 : REAL(KIND=dp) :: admm1_k_energy, admm2_k_energy, admmq_k_energy, dfexc_admm1, dfexc_admm2, &
71 : dfexc_admmq, dxc, dxk, el1, el2, elq, elref, fexc_optx_admm1, fexc_optx_admm2, &
72 : fexc_optx_admmq, fexc_optx_ref, fexc_pbex_admm1, fexc_pbex_admm2, fexc_pbex_admmq, &
73 : fexc_pbex_ref, ref_energy, xsi
74 1 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :) :: lamat
75 1 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :) :: admm1_k, admm2_k, admm_xcmat, admm_xcmata, &
76 1 : admm_xcmatb, admmq_k, ovlap, ref_k, ref_xcmat, ref_xcmata, ref_xcmatb, sinv, siref, tmat
77 : TYPE(atom_basis_type), POINTER :: admm_basis, ref_basis
78 : TYPE(atom_integrals), POINTER :: admm_int, ref_int
79 : TYPE(atom_orbitals), POINTER :: admm1_orbs, admm2_orbs, admmq_orbs, &
80 : ref_orbs
81 : TYPE(atom_type), POINTER :: atom
82 : TYPE(section_vals_type), POINTER :: basis_section, xc_fun, xc_fun_section, &
83 : xc_optx, xc_pbex, xc_section
84 :
85 1 : IF (iw > 0) THEN
86 : WRITE (iw, '(/,T2,A)') &
87 1 : '!-----------------------------------------------------------------------------!'
88 1 : WRITE (iw, '(T30,A)') "Analysis of ADMM approximations"
89 : WRITE (iw, '(T2,A)') &
90 1 : '!-----------------------------------------------------------------------------!'
91 : END IF
92 :
93 : ! setup an xc section
94 1 : NULLIFY (xc_section, xc_pbex, xc_optx)
95 1 : CALL section_vals_duplicate(atom_info(1, 1)%atom%xc_section, xc_section)
96 1 : xc_fun_section => section_vals_get_subs_vals(xc_section, "XC_FUNCTIONAL")
97 : ! Overwrite possible shortcut
98 : CALL section_vals_val_set(xc_fun_section, "_SECTION_PARAMETERS_", &
99 1 : i_val=xc_funct_no_shortcut)
100 1 : ifun = 0
101 1 : DO
102 2 : ifun = ifun + 1
103 2 : xc_fun => section_vals_get_subs_vals2(xc_fun_section, i_section=ifun)
104 2 : IF (.NOT. ASSOCIATED(xc_fun)) EXIT
105 1 : CALL section_vals_remove_values(xc_fun)
106 : END DO
107 : ! PBEX
108 1 : CALL section_vals_duplicate(xc_section, xc_pbex)
109 1 : xc_fun_section => section_vals_get_subs_vals(xc_pbex, "XC_FUNCTIONAL")
110 1 : CALL section_vals_val_set(xc_fun_section, "PBE%_SECTION_PARAMETERS_", l_val=.TRUE.)
111 1 : CALL section_vals_val_set(xc_fun_section, "PBE%SCALE_X", r_val=1.0_dp)
112 1 : CALL section_vals_val_set(xc_fun_section, "PBE%SCALE_C", r_val=0.0_dp)
113 : ! OPTX
114 1 : CALL section_vals_duplicate(xc_section, xc_optx)
115 1 : xc_fun_section => section_vals_get_subs_vals(xc_optx, "XC_FUNCTIONAL")
116 1 : CALL section_vals_val_set(xc_fun_section, "OPTX%_SECTION_PARAMETERS_", l_val=.TRUE.)
117 1 : CALL section_vals_val_set(xc_fun_section, "OPTX%SCALE_X", r_val=1.0_dp)
118 :
119 : ! ADMM basis set
120 1 : zval = atom_info(1, 1)%atom%z
121 1 : pp_calc = atom_info(1, 1)%atom%pp_calc
122 1 : btyp = "AE"
123 1 : IF (pp_calc) btyp = "PP"
124 19 : ALLOCATE (admm_basis)
125 1 : basis_section => section_vals_get_subs_vals(admm_section, "ADMM_BASIS")
126 1 : NULLIFY (admm_basis%grid)
127 1 : CALL init_atom_basis(admm_basis, basis_section, zval, btyp)
128 1 : IF (iw > 0) THEN
129 1 : CALL atom_print_basis(admm_basis, iw, " ADMM Basis")
130 : END IF
131 : ! reference basis set
132 1 : ref_basis => atom_info(1, 1)%atom%basis
133 : ! integrals
134 425 : ALLOCATE (ref_int, admm_int)
135 1 : CALL atom_int_setup(ref_int, ref_basis, eri_exchange=.TRUE.)
136 1 : CALL atom_int_setup(admm_int, admm_basis, eri_exchange=.TRUE.)
137 7 : DO l = 0, lmat
138 7 : IF (admm_int%n(l) /= admm_int%nne(l)) THEN
139 0 : IF (iw > 0) WRITE (iw, *) "ADMM Basis is linear dependent ", l, admm_int%n(l), admm_int%nne(l)
140 0 : CPABORT("ADMM basis is linear dependent")
141 : END IF
142 : END DO
143 : ! mixed overlap
144 7 : na = MAXVAL(admm_basis%nbas(:))
145 7 : nb = MAXVAL(ref_basis%nbas(:))
146 5 : ALLOCATE (ovlap(1:na, 1:nb, 0:lmat))
147 1 : CALL atom_basis_projection_overlap(ovlap, admm_basis, ref_basis)
148 : ! Inverse of ADMM overlap matrix
149 5 : ALLOCATE (sinv(1:na, 1:na, 0:lmat))
150 7 : DO l = 0, lmat
151 6 : n = admm_basis%nbas(l)
152 6 : IF (n < 1) CYCLE
153 20 : sinv(1:n, 1:n, l) = admm_int%ovlp(1:n, 1:n, l)
154 7 : CALL invmat_symm(sinv(1:n, 1:n, l))
155 : END DO
156 : ! ADMM transformation matrix
157 3 : ALLOCATE (tmat(1:na, 1:nb, 0:lmat))
158 7 : DO l = 0, lmat
159 6 : n = admm_basis%nbas(l)
160 6 : m = ref_basis%nbas(l)
161 6 : IF (n < 1 .OR. m < 1) CYCLE
162 132 : tmat(1:n, 1:m, l) = MATMUL(sinv(1:n, 1:n, l), ovlap(1:n, 1:m, l))
163 : END DO
164 : ! Inverse of REF overlap matrix
165 5 : ALLOCATE (siref(1:nb, 1:nb, 0:lmat))
166 7 : DO l = 0, lmat
167 6 : n = ref_basis%nbas(l)
168 6 : IF (n < 1) CYCLE
169 72 : siref(1:n, 1:n, l) = ref_int%ovlp(1:n, 1:n, l)
170 7 : CALL invmat_symm(siref(1:n, 1:n, l))
171 : END DO
172 :
173 2 : DO i = 1, SIZE(atom_info, 1)
174 3 : DO j = 1, SIZE(atom_info, 2)
175 1 : atom => atom_info(i, j)%atom
176 2 : IF (atom_consistent_method(atom%method_type, atom%state%multiplicity)) THEN
177 1 : ref_orbs => atom%orbitals
178 3 : ALLOCATE (ref_k(1:nb, 1:nb, 0:lmat))
179 1 : SELECT CASE (atom%method_type)
180 : CASE (do_rks_atom, do_rhf_atom)
181 : ! restricted
182 7 : rhf = .TRUE.
183 187 : ref_k = 0.0_dp
184 1 : CALL eeri_contract(ref_k, ref_int%eeri, ref_orbs%pmat, ref_basis%nbas)
185 1 : ref_energy = 0.5_dp*atom_trace(ref_k, ref_orbs%pmat)
186 : CASE (do_uks_atom, do_uhf_atom)
187 : ! unrestricted
188 0 : rhf = .FALSE.
189 0 : ref_k = 0.0_dp
190 0 : CALL eeri_contract(ref_k, ref_int%eeri, ref_orbs%pmata, ref_basis%nbas)
191 0 : ref_energy = atom_trace(ref_k, ref_orbs%pmata)
192 0 : ref_k = 0.0_dp
193 0 : CALL eeri_contract(ref_k, ref_int%eeri, ref_orbs%pmatb, ref_basis%nbas)
194 0 : ref_energy = ref_energy + atom_trace(ref_k, ref_orbs%pmatb)
195 : CASE (do_rohf_atom)
196 0 : CPABORT("ADMM not available")
197 : CASE DEFAULT
198 1 : CPABORT("ADMM not available")
199 : END SELECT
200 1 : DEALLOCATE (ref_k)
201 : ! reference number of electrons
202 1 : elref = atom_trace(ref_int%ovlp, ref_orbs%pmat)
203 : ! admm orbitals and density matrices
204 7 : mo = MAXVAL(atom%state%maxn_calc)
205 1 : NULLIFY (admm1_orbs, admm2_orbs, admmq_orbs)
206 1 : CALL create_atom_orbs(admm1_orbs, na, mo)
207 1 : CALL create_atom_orbs(admm2_orbs, na, mo)
208 1 : CALL create_atom_orbs(admmq_orbs, na, mo)
209 4 : ALLOCATE (lamat(1:mo, 1:mo))
210 5 : ALLOCATE (admm1_k(1:na, 1:na, 0:lmat))
211 3 : ALLOCATE (admm2_k(1:na, 1:na, 0:lmat))
212 3 : ALLOCATE (admmq_k(1:na, 1:na, 0:lmat))
213 1 : IF (rhf) THEN
214 7 : DO l = 0, lmat
215 6 : n = admm_basis%nbas(l)
216 6 : m = ref_basis%nbas(l)
217 6 : mo = atom%state%maxn_calc(l)
218 6 : IF (n < 1 .OR. m < 1 .OR. mo < 1) CYCLE
219 123 : admm2_orbs%wfn(1:n, 1:mo, l) = MATMUL(tmat(1:n, 1:m, l), ref_orbs%wfn(1:m, 1:mo, l))
220 2 : CALL lowdin_matrix(admm2_orbs%wfn(1:n, 1:mo, l), lamat(1:mo, 1:mo), admm_int%ovlp(1:n, 1:n, l))
221 61 : admm1_orbs%wfn(1:n, 1:mo, l) = MATMUL(admm2_orbs%wfn(1:n, 1:mo, l), lamat(1:mo, 1:mo))
222 : END DO
223 : CALL atom_denmat(admm1_orbs%pmat, admm1_orbs%wfn, admm_basis%nbas, atom%state%occupation, &
224 1 : atom%state%maxl_occ, atom%state%maxn_occ)
225 : CALL atom_denmat(admm2_orbs%pmat, admm2_orbs%wfn, admm_basis%nbas, atom%state%occupation, &
226 1 : atom%state%maxl_occ, atom%state%maxn_occ)
227 1 : el1 = atom_trace(admm_int%ovlp, admm1_orbs%pmat)
228 1 : el2 = atom_trace(admm_int%ovlp, admm2_orbs%pmat)
229 1 : xsi = elref/el2
230 157 : admmq_orbs%pmat = xsi*admm2_orbs%pmat
231 1 : elq = atom_trace(admm_int%ovlp, admmq_orbs%pmat)
232 109 : admmq_orbs%wfn = SQRT(xsi)*admm2_orbs%wfn
233 : !
234 79 : admm1_k = 0.0_dp
235 1 : CALL eeri_contract(admm1_k, admm_int%eeri, admm1_orbs%pmat, admm_basis%nbas)
236 1 : admm1_k_energy = 0.5_dp*atom_trace(admm1_k, admm1_orbs%pmat)
237 79 : admm2_k = 0.0_dp
238 1 : CALL eeri_contract(admm2_k, admm_int%eeri, admm2_orbs%pmat, admm_basis%nbas)
239 1 : admm2_k_energy = 0.5_dp*atom_trace(admm2_k, admm2_orbs%pmat)
240 79 : admmq_k = 0.0_dp
241 1 : CALL eeri_contract(admmq_k, admm_int%eeri, admmq_orbs%pmat, admm_basis%nbas)
242 1 : admmq_k_energy = 0.5_dp*atom_trace(admmq_k, admmq_orbs%pmat)
243 : ELSE
244 0 : DO l = 0, lmat
245 0 : n = admm_basis%nbas(l)
246 0 : m = ref_basis%nbas(l)
247 0 : mo = atom%state%maxn_calc(l)
248 0 : IF (n < 1 .OR. m < 1 .OR. mo < 1) CYCLE
249 0 : admm2_orbs%wfna(1:n, 1:mo, l) = MATMUL(tmat(1:n, 1:m, l), ref_orbs%wfna(1:m, 1:mo, l))
250 0 : CALL lowdin_matrix(admm2_orbs%wfna(1:n, 1:mo, l), lamat, admm_int%ovlp(1:n, 1:n, l))
251 0 : admm1_orbs%wfna(1:n, 1:mo, l) = MATMUL(admm2_orbs%wfna(1:n, 1:mo, l), lamat(1:mo, 1:mo))
252 0 : admm2_orbs%wfnb(1:n, 1:mo, l) = MATMUL(tmat(1:n, 1:m, l), ref_orbs%wfnb(1:m, 1:mo, l))
253 0 : CALL lowdin_matrix(admm2_orbs%wfnb(1:n, 1:mo, l), lamat, admm_int%ovlp(1:n, 1:n, l))
254 0 : admm1_orbs%wfnb(1:n, 1:mo, l) = MATMUL(admm2_orbs%wfnb(1:n, 1:mo, l), lamat(1:mo, 1:mo))
255 : END DO
256 : CALL atom_denmat(admm1_orbs%pmata, admm1_orbs%wfna, admm_basis%nbas, atom%state%occa, &
257 0 : atom%state%maxl_occ, atom%state%maxn_occ)
258 : CALL atom_denmat(admm1_orbs%pmatb, admm1_orbs%wfnb, admm_basis%nbas, atom%state%occb, &
259 0 : atom%state%maxl_occ, atom%state%maxn_occ)
260 0 : admm1_orbs%pmat = admm1_orbs%pmata + admm1_orbs%pmatb
261 : CALL atom_denmat(admm2_orbs%pmata, admm2_orbs%wfna, admm_basis%nbas, atom%state%occa, &
262 0 : atom%state%maxl_occ, atom%state%maxn_occ)
263 : CALL atom_denmat(admm2_orbs%pmatb, admm2_orbs%wfnb, admm_basis%nbas, atom%state%occb, &
264 0 : atom%state%maxl_occ, atom%state%maxn_occ)
265 0 : admm2_orbs%pmat = admm2_orbs%pmata + admm2_orbs%pmatb
266 0 : elref = atom_trace(ref_int%ovlp, ref_orbs%pmata)
267 0 : el2 = atom_trace(admm_int%ovlp, admm2_orbs%pmata)
268 0 : xsi = elref/el2
269 0 : admmq_orbs%pmata = xsi*admm2_orbs%pmata
270 0 : admmq_orbs%wfna = SQRT(xsi)*admm2_orbs%wfna
271 0 : elref = atom_trace(ref_int%ovlp, ref_orbs%pmatb)
272 0 : el2 = atom_trace(admm_int%ovlp, admm2_orbs%pmatb)
273 0 : xsi = elref/el2
274 0 : admmq_orbs%pmatb = xsi*admm2_orbs%pmatb
275 0 : admmq_orbs%wfnb = SQRT(xsi)*admm2_orbs%wfnb
276 0 : admmq_orbs%pmat = admmq_orbs%pmata + admmq_orbs%pmatb
277 0 : el1 = atom_trace(admm_int%ovlp, admm1_orbs%pmat)
278 0 : el2 = atom_trace(admm_int%ovlp, admm2_orbs%pmat)
279 : elq = atom_trace(admm_int%ovlp, admmq_orbs%pmat)
280 0 : elref = atom_trace(ref_int%ovlp, ref_orbs%pmat)
281 : !
282 0 : admm1_k = 0.0_dp
283 0 : CALL eeri_contract(admm1_k, admm_int%eeri, admm1_orbs%pmata, admm_basis%nbas)
284 0 : admm1_k_energy = atom_trace(admm1_k, admm1_orbs%pmata)
285 0 : admm1_k = 0.0_dp
286 0 : CALL eeri_contract(admm1_k, admm_int%eeri, admm1_orbs%pmatb, admm_basis%nbas)
287 0 : admm1_k_energy = admm1_k_energy + atom_trace(admm1_k, admm1_orbs%pmatb)
288 0 : admm2_k = 0.0_dp
289 0 : CALL eeri_contract(admm2_k, admm_int%eeri, admm2_orbs%pmata, admm_basis%nbas)
290 0 : admm2_k_energy = atom_trace(admm2_k, admm2_orbs%pmata)
291 0 : admm2_k = 0.0_dp
292 0 : CALL eeri_contract(admm2_k, admm_int%eeri, admm2_orbs%pmatb, admm_basis%nbas)
293 0 : admm2_k_energy = admm2_k_energy + atom_trace(admm2_k, admm2_orbs%pmatb)
294 0 : admmq_k = 0.0_dp
295 0 : CALL eeri_contract(admmq_k, admm_int%eeri, admmq_orbs%pmata, admm_basis%nbas)
296 0 : admmq_k_energy = atom_trace(admmq_k, admmq_orbs%pmata)
297 0 : admmq_k = 0.0_dp
298 0 : CALL eeri_contract(admmq_k, admm_int%eeri, admmq_orbs%pmatb, admm_basis%nbas)
299 0 : admmq_k_energy = admmq_k_energy + atom_trace(admmq_k, admmq_orbs%pmatb)
300 : END IF
301 1 : DEALLOCATE (lamat)
302 : !
303 : ! ADMM correction terms
304 1 : maxl = atom%state%maxl_occ
305 1 : IF (rhf) THEN
306 3 : ALLOCATE (ref_xcmat(1:nb, 1:nb, 0:lmat))
307 5 : ALLOCATE (admm_xcmat(1:na, 1:na, 0:lmat))
308 : ! PBEX
309 1 : CALL atom_vxc_lda(ref_basis, ref_orbs%pmat, maxl, xc_pbex, fexc_pbex_ref, ref_xcmat)
310 1 : CALL atom_vxc_lda(admm_basis, admm1_orbs%pmat, maxl, xc_pbex, fexc_pbex_admm1, admm_xcmat)
311 1 : CALL atom_vxc_lda(admm_basis, admm2_orbs%pmat, maxl, xc_pbex, fexc_pbex_admm2, admm_xcmat)
312 1 : CALL atom_vxc_lda(admm_basis, admmq_orbs%pmat, maxl, xc_pbex, fexc_pbex_admmq, admm_xcmat)
313 : ! OPTX
314 1 : CALL atom_vxc_lda(ref_basis, ref_orbs%pmat, maxl, xc_optx, fexc_optx_ref, ref_xcmat)
315 1 : CALL atom_vxc_lda(admm_basis, admm1_orbs%pmat, maxl, xc_optx, fexc_optx_admm1, admm_xcmat)
316 1 : CALL atom_vxc_lda(admm_basis, admm2_orbs%pmat, maxl, xc_optx, fexc_optx_admm2, admm_xcmat)
317 1 : CALL atom_vxc_lda(admm_basis, admmq_orbs%pmat, maxl, xc_optx, fexc_optx_admmq, admm_xcmat)
318 : ! LINX
319 : CALL atom_dpot_lda(ref_basis, ref_orbs%pmat, admm_basis, admm1_orbs%pmat, &
320 1 : maxl, "LINX", dfexc_admm1)
321 : CALL atom_dpot_lda(ref_basis, ref_orbs%pmat, admm_basis, admm2_orbs%pmat, &
322 1 : maxl, "LINX", dfexc_admm2)
323 : CALL atom_dpot_lda(ref_basis, ref_orbs%pmat, admm_basis, admmq_orbs%pmat, &
324 1 : maxl, "LINX", dfexc_admmq)
325 1 : DEALLOCATE (ref_xcmat, admm_xcmat)
326 : ELSE
327 0 : ALLOCATE (ref_xcmata(1:nb, 1:nb, 0:lmat))
328 0 : ALLOCATE (ref_xcmatb(1:nb, 1:nb, 0:lmat))
329 0 : ALLOCATE (admm_xcmata(1:na, 1:na, 0:lmat))
330 0 : ALLOCATE (admm_xcmatb(1:na, 1:na, 0:lmat))
331 : ! PBEX
332 : CALL atom_vxc_lsd(ref_basis, ref_orbs%pmata, ref_orbs%pmatb, maxl, xc_pbex, fexc_pbex_ref, &
333 0 : ref_xcmata, ref_xcmatb)
334 : CALL atom_vxc_lsd(admm_basis, admm1_orbs%pmata, admm1_orbs%pmatb, maxl, xc_pbex, &
335 0 : fexc_pbex_admm1, admm_xcmata, admm_xcmatb)
336 : CALL atom_vxc_lsd(admm_basis, admm2_orbs%pmata, admm2_orbs%pmatb, maxl, xc_pbex, &
337 0 : fexc_pbex_admm2, admm_xcmata, admm_xcmatb)
338 : CALL atom_vxc_lsd(admm_basis, admmq_orbs%pmata, admmq_orbs%pmatb, maxl, xc_pbex, &
339 0 : fexc_pbex_admmq, admm_xcmata, admm_xcmatb)
340 : CALL atom_vxc_lsd(ref_basis, ref_orbs%pmata, ref_orbs%pmatb, maxl, xc_optx, fexc_optx_ref, &
341 0 : ref_xcmata, ref_xcmatb)
342 : CALL atom_vxc_lsd(admm_basis, admm1_orbs%pmata, admm1_orbs%pmatb, maxl, xc_optx, &
343 0 : fexc_optx_admm1, admm_xcmata, admm_xcmatb)
344 : CALL atom_vxc_lsd(admm_basis, admm2_orbs%pmata, admm2_orbs%pmatb, maxl, xc_optx, &
345 0 : fexc_optx_admm2, admm_xcmata, admm_xcmatb)
346 : CALL atom_vxc_lsd(admm_basis, admmq_orbs%pmata, admmq_orbs%pmatb, maxl, xc_optx, &
347 0 : fexc_optx_admmq, admm_xcmata, admm_xcmatb)
348 0 : DEALLOCATE (ref_xcmata, ref_xcmatb, admm_xcmata, admm_xcmatb)
349 : END IF
350 : !
351 :
352 1 : IF (iw > 0) THEN
353 1 : WRITE (iw, "(/,A,I3,T48,A,I3)") " Electronic Structure Setting: ", i, &
354 2 : " Electronic Structure Method: ", j
355 1 : WRITE (iw, "(' Norm of ADMM Basis projection ',T61,F20.10)") el2/elref
356 1 : WRITE (iw, "(' Reference Exchange Energy [Hartree]',T61,F20.10)") ref_energy
357 : ! ADMM1
358 1 : dxk = ref_energy - admm1_k_energy
359 1 : WRITE (iw, "(A,F20.10,T60,A,F13.10)") " ADMM1 METHOD: Energy ", admm1_k_energy, &
360 2 : " Error: ", dxk
361 1 : dxc = fexc_pbex_ref - fexc_pbex_admm1
362 1 : WRITE (iw, "(T10,A,F12.6,F12.3,'%',T60,A,F13.10)") "PBEX Correction ", dxc, dxc/dxk*100._dp, &
363 2 : " Error: ", dxk - dxc
364 1 : dxc = fexc_optx_ref - fexc_optx_admm1
365 1 : WRITE (iw, "(T10,A,F12.6,F12.3,'%',T60,A,F13.10)") "OPTX Correction ", dxc, dxc/dxk*100._dp, &
366 2 : " Error: ", dxk - dxc
367 1 : dxc = dfexc_admm1
368 1 : WRITE (iw, "(T10,A,F12.6,F12.3,'%',T60,A,F13.10)") "LINX Correction ", dxc, dxc/dxk*100._dp, &
369 2 : " Error: ", dxk - dxc
370 : ! ADMM2
371 1 : dxk = ref_energy - admm2_k_energy
372 1 : WRITE (iw, "(A,F20.10,T60,A,F13.10)") " ADMM2 METHOD: Energy ", admm2_k_energy, &
373 2 : " Error: ", dxk
374 1 : dxc = fexc_pbex_ref - fexc_pbex_admm2
375 1 : WRITE (iw, "(T10,A,F12.6,F12.3,'%',T60,A,F13.10)") "PBEX Correction ", dxc, dxc/dxk*100._dp, &
376 2 : " Error: ", dxk - dxc
377 1 : dxc = fexc_optx_ref - fexc_optx_admm2
378 1 : WRITE (iw, "(T10,A,F12.6,F12.3,'%',T60,A,F13.10)") "OPTX Correction ", dxc, dxc/dxk*100._dp, &
379 2 : " Error: ", dxk - dxc
380 1 : dxc = dfexc_admm2
381 1 : WRITE (iw, "(T10,A,F12.6,F12.3,'%',T60,A,F13.10)") "LINX Correction ", dxc, dxc/dxk*100._dp, &
382 2 : " Error: ", dxk - dxc
383 : ! ADMMQ
384 1 : dxk = ref_energy - admmq_k_energy
385 1 : WRITE (iw, "(A,F20.10,T60,A,F13.10)") " ADMMQ METHOD: Energy ", admmq_k_energy, &
386 2 : " Error: ", dxk
387 1 : dxc = fexc_pbex_ref - fexc_pbex_admmq
388 1 : WRITE (iw, "(T10,A,F12.6,F12.3,'%',T60,A,F13.10)") "PBEX Correction ", dxc, dxc/dxk*100._dp, &
389 2 : " Error: ", dxk - dxc
390 1 : dxc = fexc_optx_ref - fexc_optx_admmq
391 1 : WRITE (iw, "(T10,A,F12.6,F12.3,'%',T60,A,F13.10)") "OPTX Correction ", dxc, dxc/dxk*100._dp, &
392 2 : " Error: ", dxk - dxc
393 1 : dxc = dfexc_admmq
394 1 : WRITE (iw, "(T10,A,F12.6,F12.3,'%',T60,A,F13.10)") "LINX Correction ", dxc, dxc/dxk*100._dp, &
395 2 : " Error: ", dxk - dxc
396 : ! ADMMS
397 : dxk = ref_energy - admmq_k_energy
398 1 : WRITE (iw, "(A,F20.10,T60,A,F13.10)") " ADMMS METHOD: Energy ", admmq_k_energy, &
399 2 : " Error: ", dxk
400 1 : dxc = fexc_pbex_ref - fexc_pbex_admmq*xsi**(2._dp/3._dp)
401 1 : WRITE (iw, "(T10,A,F12.6,F12.3,'%',T60,A,F13.10)") "PBEX Correction ", dxc, dxc/dxk*100._dp, &
402 2 : " Error: ", dxk - dxc
403 1 : dxc = fexc_optx_ref - fexc_optx_admmq*xsi**(2._dp/3._dp)
404 1 : WRITE (iw, "(T10,A,F12.6,F12.3,'%',T60,A,F13.10)") "OPTX Correction ", dxc, dxc/dxk*100._dp, &
405 2 : " Error: ", dxk - dxc
406 : END IF
407 : !
408 1 : DEALLOCATE (admm1_k, admm2_k, admmq_k)
409 : !
410 1 : CALL release_atom_orbs(admm1_orbs)
411 1 : CALL release_atom_orbs(admm2_orbs)
412 1 : CALL release_atom_orbs(admmq_orbs)
413 : END IF
414 : END DO
415 : END DO
416 :
417 : ! clean up
418 1 : CALL atom_int_release(ref_int)
419 1 : CALL atom_int_release(admm_int)
420 1 : CALL release_atom_basis(admm_basis)
421 1 : DEALLOCATE (ref_int, admm_int, admm_basis)
422 1 : DEALLOCATE (ovlap, sinv, tmat, siref)
423 :
424 1 : CALL section_vals_release(xc_pbex)
425 1 : CALL section_vals_release(xc_optx)
426 1 : CALL section_vals_release(xc_section)
427 :
428 1 : IF (iw > 0) THEN
429 : WRITE (iw, '(/,T2,A)') &
430 1 : '!------------------------------End of ADMM analysis---------------------------!'
431 : END IF
432 :
433 1 : END SUBROUTINE atom_admm
434 :
435 : ! **************************************************************************************************
436 : !> \brief ...
437 : !> \param wfn ...
438 : !> \param lamat ...
439 : !> \param ovlp ...
440 : ! **************************************************************************************************
441 2 : SUBROUTINE lowdin_matrix(wfn, lamat, ovlp)
442 : REAL(KIND=dp), DIMENSION(:, :), INTENT(IN) :: wfn
443 : REAL(KIND=dp), DIMENSION(:, :), INTENT(OUT) :: lamat
444 : REAL(KIND=dp), DIMENSION(:, :), INTENT(IN) :: ovlp
445 :
446 : INTEGER :: i, j, k, n
447 2 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: w
448 2 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :) :: vmat
449 :
450 2 : n = SIZE(wfn, 2)
451 2 : IF (n > 0) THEN
452 96 : lamat = MATMUL(TRANSPOSE(wfn), MATMUL(ovlp, wfn))
453 12 : ALLOCATE (w(n), vmat(n, n))
454 2 : CALL jacobi(lamat(1:n, 1:n), w(1:n), vmat(1:n, 1:n))
455 5 : w(1:n) = 1.0_dp/SQRT(w(1:n))
456 5 : DO i = 1, n
457 10 : DO j = 1, n
458 5 : lamat(i, j) = 0.0_dp
459 17 : DO k = 1, n
460 14 : lamat(i, j) = lamat(i, j) + vmat(i, k)*w(k)*vmat(j, k)
461 : END DO
462 : END DO
463 : END DO
464 2 : DEALLOCATE (vmat, w)
465 : END IF
466 :
467 2 : END SUBROUTINE lowdin_matrix
468 :
469 2 : END MODULE atom_admm_methods
|