Line data Source code
1 : !--------------------------------------------------------------------------------------------------!
2 : ! CP2K: A general program to perform molecular dynamics simulations !
3 : ! Copyright 2000-2026 CP2K developers group <https://cp2k.org> !
4 : ! !
5 : ! SPDX-License-Identifier: GPL-2.0-or-later !
6 : !--------------------------------------------------------------------------------------------------!
7 :
8 : ! **************************************************************************************************
9 : !> \brief A collection of functions used by CNEO-DFT
10 : !> (see J. Chem. Theory Comput. 2025, 21, 16, 7865–7877)
11 : !> \par History
12 : !> 08.2025 created [zc62]
13 : !> \author Zehua Chen
14 : ! **************************************************************************************************
15 : MODULE qs_cneo_methods
16 : USE ai_verfc, ONLY: verfc
17 : USE ao_util, ONLY: trace_r_AxB
18 : USE atom_operators, ONLY: atom_int_release,&
19 : atom_int_setup
20 : USE atom_types, ONLY: CGTO_BASIS,&
21 : atom_basis_type,&
22 : atom_integrals,&
23 : lmat,&
24 : release_atom_basis
25 : USE atomic_kind_types, ONLY: atomic_kind_type,&
26 : get_atomic_kind,&
27 : get_atomic_kind_set
28 : USE basis_set_types, ONLY: get_gto_basis_set,&
29 : gto_basis_set_type
30 : USE bibliography, ONLY: Chen2025,&
31 : cite_reference
32 : USE core_ae, ONLY: verfc_force
33 : USE cp_control_types, ONLY: gapw_control_type
34 : USE cp_log_handling, ONLY: cp_to_string
35 : USE distribution_1d_types, ONLY: distribution_1d_type
36 : USE kinds, ONLY: dp
37 : USE mathconstants, ONLY: dfac,&
38 : fourpi,&
39 : pi
40 : USE mathlib, ONLY: get_pseudo_inverse_svd
41 : USE memory_utilities, ONLY: reallocate
42 : USE message_passing, ONLY: mp_para_env_type
43 : USE orbital_pointers, ONLY: indso,&
44 : indso_inv,&
45 : init_orbital_pointers,&
46 : ncoset,&
47 : nso,&
48 : nsoset
49 : USE particle_types, ONLY: particle_type
50 : USE physcon, ONLY: massunit
51 : USE qs_cneo_types, ONLY: allocate_rhoz_cneo_set,&
52 : cneo_potential_type,&
53 : get_cneo_potential,&
54 : rhoz_cneo_type,&
55 : set_cneo_potential
56 : USE qs_cneo_utils, ONLY: atom_solve_cneo,&
57 : cneo_gather,&
58 : create_harmonics_atom_cneo,&
59 : create_my_CG_cneo,&
60 : get_maxl_CG_cneo
61 : USE qs_environment_types, ONLY: get_qs_env,&
62 : qs_environment_type
63 : USE qs_force_types, ONLY: qs_force_type
64 : USE qs_grid_atom, ONLY: allocate_grid_atom,&
65 : grid_atom_type
66 : USE qs_harmonics_atom, ONLY: allocate_harmonics_atom,&
67 : get_none0_cg_list,&
68 : harmonics_atom_type
69 : USE qs_kind_types, ONLY: get_qs_kind,&
70 : get_qs_kind_set,&
71 : qs_kind_type
72 : USE qs_neighbor_list_types, ONLY: get_iterator_info,&
73 : neighbor_list_iterator_create,&
74 : neighbor_list_iterator_p_type,&
75 : neighbor_list_iterator_release,&
76 : neighbor_list_set_p_type,&
77 : nl_set_sub_iterator,&
78 : nl_sub_iterate
79 : USE util, ONLY: get_limit
80 : USE virial_methods, ONLY: virial_pair_force
81 : USE virial_types, ONLY: virial_type
82 : USE whittaker, ONLY: whittaker_c0a,&
83 : whittaker_ci
84 :
85 : !$ USE OMP_LIB, ONLY: omp_get_max_threads, omp_get_thread_num
86 :
87 : #include "./base/base_uses.f90"
88 :
89 : IMPLICIT NONE
90 :
91 : PRIVATE
92 :
93 : CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qs_cneo_methods'
94 :
95 : PUBLIC :: allocate_rhoz_cneo_internals, calculate_rhoz_cneo, cneo_core_matrices, &
96 : init_cneo_potential_internals, Vh_1c_nuc_integrals
97 :
98 : CONTAINS
99 :
100 : ! **************************************************************************************************
101 : !> \brief ...
102 : !> \param potential ...
103 : !> \param nuc_basis ...
104 : !> \param nuc_soft_basis ...
105 : !> \param gapw_control ...
106 : !> \param grid_atom ...
107 : ! **************************************************************************************************
108 8 : SUBROUTINE init_cneo_potential_internals(potential, nuc_basis, nuc_soft_basis, gapw_control, grid_atom)
109 :
110 : TYPE(cneo_potential_type), POINTER :: potential
111 : TYPE(gto_basis_set_type), POINTER :: nuc_basis, nuc_soft_basis
112 : TYPE(gapw_control_type), POINTER :: gapw_control
113 : TYPE(grid_atom_type), POINTER :: grid_atom
114 :
115 : CHARACTER(len=*), PARAMETER :: routineN = 'init_cneo_potential_internals'
116 :
117 : INTEGER :: handle, i, icg, ico, ii, ipgf, ipgf1, ipgf2, ir, is1, is2, iset, iset1, iset2, &
118 : iso, iso1, iso2, iso_pgf, iso_set, j, k, k1, k2, l, l_iso, l_sub, l_sum, ll, llmax, &
119 : lmax12, lmax_expansion, lmax_sphere, lmin12, m, m1, m2, max_iso_not0, max_iso_not0_local, &
120 : max_s, max_s_harm, maxl, maxso, n1, n2, nl, nne, npgf2, npgf_sum, npsgf, nr, ns, nset, &
121 : nsgf, nsotot, nsox
122 8 : INTEGER, ALLOCATABLE, DIMENSION(:) :: cg_n_list
123 8 : INTEGER, ALLOCATABLE, DIMENSION(:, :, :) :: cg_list
124 : INTEGER, DIMENSION(0:lmat, 100) :: set_index, shell_index
125 8 : INTEGER, DIMENSION(:), POINTER :: lmax, lmin, n2oindex, npgf, npgf_s, &
126 8 : nshell, o2nindex
127 8 : INTEGER, DIMENSION(:, :), POINTER :: first_sgf, ls
128 8 : LOGICAL, ALLOCATABLE, DIMENSION(:, :) :: done_vgg
129 : REAL(KIND=dp) :: c1, c2, gcc_tmp, mass, massinv, &
130 : root_zet12, scal, scal1, zet12
131 8 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: erf_zet12, g1, g2, gg0, int1, int2
132 8 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :) :: work
133 8 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :) :: dist
134 8 : REAL(KIND=dp), DIMENSION(:, :), POINTER :: kin, my_gcc_h, my_gcc_s, oorad2l, ovlp, &
135 8 : rad2l, utrans, zet
136 8 : REAL(KIND=dp), DIMENSION(:, :, :), POINTER :: distance, gcc_h, gcc_s, gg, my_CG
137 8 : REAL(KIND=dp), DIMENSION(:, :, :, :), POINTER :: vgg
138 : TYPE(atom_basis_type), POINTER :: basis
139 : TYPE(atom_integrals), POINTER :: integrals
140 : TYPE(grid_atom_type), POINTER :: grid
141 : TYPE(harmonics_atom_type), POINTER :: harmonics
142 :
143 0 : CPASSERT(ASSOCIATED(potential))
144 8 : CPASSERT(ASSOCIATED(nuc_basis))
145 8 : CPASSERT(ASSOCIATED(nuc_soft_basis))
146 :
147 8 : CALL cite_reference(Chen2025)
148 :
149 8 : CALL timeset(routineN, handle)
150 :
151 : CALL get_cneo_potential(potential, my_gcc_h=my_gcc_h, my_gcc_s=my_gcc_s, &
152 : ovlp=ovlp, kin=kin, utrans=utrans, distance=distance, &
153 : harmonics=harmonics, gg=gg, vgg=vgg, n2oindex=n2oindex, &
154 8 : o2nindex=o2nindex, rad2l=rad2l, oorad2l=oorad2l)
155 8 : CPASSERT(.NOT. ASSOCIATED(my_gcc_h))
156 8 : CPASSERT(.NOT. ASSOCIATED(my_gcc_s))
157 8 : CPASSERT(.NOT. ASSOCIATED(ovlp))
158 8 : CPASSERT(.NOT. ASSOCIATED(kin))
159 8 : CPASSERT(.NOT. ASSOCIATED(utrans))
160 8 : CPASSERT(.NOT. ASSOCIATED(distance))
161 8 : CPASSERT(.NOT. ASSOCIATED(harmonics))
162 8 : CPASSERT(.NOT. ASSOCIATED(gg))
163 8 : CPASSERT(.NOT. ASSOCIATED(vgg))
164 8 : CPASSERT(.NOT. ASSOCIATED(n2oindex))
165 8 : CPASSERT(.NOT. ASSOCIATED(o2nindex))
166 8 : CPASSERT(.NOT. ASSOCIATED(rad2l))
167 8 : CPASSERT(.NOT. ASSOCIATED(oorad2l))
168 :
169 : ! ovlp, kin and utrans parts are mostly copied from atom_kind_orbitals::calculate_atomic_orbitals
170 : ! and atom_set_basis::set_kind_basis_atomic
171 8 : NULLIFY (basis, integrals, grid)
172 1848 : ALLOCATE (basis, integrals)
173 8 : CALL allocate_grid_atom(grid)
174 8 : basis%grid => grid
175 8 : NULLIFY (basis%am, basis%cm, basis%as, basis%ns, basis%bf, basis%dbf, basis%ddbf)
176 : ! fill in the basis data structures
177 8 : basis%basis_type = CGTO_BASIS
178 8 : basis%eps_eig = 1.e-12_dp
179 :
180 8 : NULLIFY (nshell, npgf, lmin, lmax, ls, zet, gcc_h, first_sgf)
181 : CALL get_gto_basis_set(nuc_basis, nset=nset, nshell=nshell, npgf=npgf, lmin=lmin, &
182 : lmax=lmax, l=ls, nsgf=nsgf, zet=zet, gcc=gcc_h, first_sgf=first_sgf, &
183 8 : maxl=maxl, maxso=maxso, npgf_sum=npgf_sum)
184 8 : NULLIFY (npgf_s, gcc_s)
185 8 : CALL get_gto_basis_set(nuc_soft_basis, npgf=npgf_s, gcc=gcc_s)
186 : ! There is such a limitation because we rely on atomic code to build S, T and U.
187 : ! Usually l=5 is more than enough, suppoting PB6H basis.
188 8 : IF (maxl > lmat) THEN
189 : CALL cp_abort(__LOCATION__, "Nuclear basis with angular momentum higher than "// &
190 0 : "atom_types::lmat is not supported yet.")
191 : END IF
192 :
193 8 : set_index = 0
194 8 : shell_index = 0
195 56 : basis%nprim = 0
196 56 : basis%nbas = 0
197 80 : DO i = 1, nset
198 144 : DO j = lmin(i), MIN(lmax(i), lmat)
199 144 : basis%nprim(j) = basis%nprim(j) + npgf(i)
200 : END DO
201 152 : DO j = 1, nshell(i)
202 72 : l = ls(j, i)
203 144 : IF (l <= lmat) THEN
204 72 : basis%nbas(l) = basis%nbas(l) + 1
205 72 : k = basis%nbas(l)
206 72 : CPASSERT(k <= 100)
207 72 : set_index(l, k) = i
208 72 : shell_index(l, k) = j
209 : END IF
210 : END DO
211 : END DO
212 :
213 56 : nl = MAXVAL(basis%nprim)
214 56 : ns = MAXVAL(basis%nbas)
215 24 : ALLOCATE (basis%am(nl, 0:lmat))
216 248 : basis%am = 0._dp
217 40 : ALLOCATE (basis%cm(nl, ns, 0:lmat))
218 1016 : basis%cm = 0._dp
219 56 : DO l = 0, lmat
220 : nl = 0
221 : ns = 0
222 488 : DO i = 1, nset
223 480 : IF (l >= lmin(i) .AND. l <= lmax(i)) THEN
224 144 : DO ipgf = 1, npgf(i)
225 144 : basis%am(nl + ipgf, l) = zet(ipgf, i)
226 : END DO
227 144 : DO ii = 1, nshell(i)
228 144 : IF (ls(ii, i) == l) THEN
229 72 : ns = ns + 1
230 144 : DO ipgf = 1, npgf(i)
231 144 : basis%cm(nl + ipgf, ns, l) = gcc_h(ipgf, ii, i) ! NOTE: not normalized
232 : END DO
233 : END IF
234 : END DO
235 72 : nl = nl + npgf(i)
236 : END IF
237 : END DO
238 : END DO
239 :
240 : ! overlap, kinetic and transformation matrices
241 8 : CALL atom_int_setup(integrals, basis)
242 :
243 : ! make the integrals full matrix form
244 64 : ALLOCATE (ovlp(nsgf, nsgf), kin(nsgf, nsgf), utrans(nsgf, nsgf))
245 4424 : ovlp = 0.0_dp
246 4424 : kin = 0.0_dp
247 4424 : utrans = 0.0_dp
248 8 : CALL get_cneo_potential(potential, mass=mass)
249 8 : mass = mass*massunit
250 8 : massinv = 1._dp/mass
251 8 : nne = 0 ! number of linear-independent spherical basis functions
252 56 : DO l = 0, lmat
253 48 : ll = 2*l
254 120 : DO k2 = 1, integrals%nne(l)
255 304 : DO m = 0, ll
256 184 : nne = nne + 1
257 760 : DO k1 = 1, basis%nbas(l)
258 504 : scal1 = SQRT(integrals%ovlp(k1, k1, l))
259 504 : i = first_sgf(shell_index(l, k1), set_index(l, k1))
260 688 : utrans(i + m, nne) = integrals%utrans(k1, k2, l)*scal1
261 : END DO
262 : END DO
263 : END DO
264 128 : DO k1 = 1, basis%nbas(l)
265 72 : scal1 = 1._dp/SQRT(integrals%ovlp(k1, k1, l))
266 72 : i = first_sgf(shell_index(l, k1), set_index(l, k1))
267 352 : DO k2 = 1, basis%nbas(l)
268 232 : scal = scal1/SQRT(integrals%ovlp(k2, k2, l))
269 232 : j = first_sgf(shell_index(l, k2), set_index(l, k2))
270 808 : DO m = 0, ll
271 : ! normalize the integrals
272 504 : ovlp(i + m, j + m) = integrals%ovlp(k1, k2, l)*scal
273 736 : kin(i + m, j + m) = integrals%kin(k1, k2, l)*scal*massinv
274 : END DO
275 : END DO
276 : END DO
277 : END DO
278 :
279 8 : nsotot = maxso*nset
280 48 : ALLOCATE (my_gcc_h(nsotot, nsgf), my_gcc_s(nsotot, nsgf))
281 15096 : my_gcc_h = 0.0_dp
282 15096 : my_gcc_s = 0.0_dp
283 : ! create gcc that really 3D-normalize the basis functions
284 32 : DO l = 0, MIN(maxl, lmat)
285 24 : ns = 0
286 24 : m = 0
287 24 : ll = 2*l
288 24 : k = nsoset(l - 1) + 1
289 248 : DO i = 1, nset
290 216 : IF (l >= lmin(i) .AND. l <= lmax(i)) THEN
291 72 : nsox = nsoset(lmax(i))
292 144 : DO ii = 1, nshell(i)
293 144 : IF (ls(ii, i) == l) THEN
294 72 : ns = ns + 1
295 72 : k1 = first_sgf(shell_index(l, ns), set_index(l, ns))
296 72 : scal = 1._dp/SQRT(integrals%ovlp(ns, ns, l))
297 144 : DO ipgf = 1, npgf(i)
298 72 : gcc_tmp = gcc_h(ipgf, ii, i)*scal
299 72 : k2 = (ipgf - 1)*nsox + m
300 328 : DO j = 0, ll
301 256 : my_gcc_h(k + k2 + j, k1 + j) = gcc_tmp
302 : END DO
303 : END DO
304 86 : DO ipgf = 1, npgf_s(i)
305 14 : gcc_tmp = gcc_s(ipgf, ii, i)*scal
306 14 : k2 = (ipgf - 1)*nsox + m
307 112 : DO j = 0, ll
308 40 : my_gcc_s(k + k2 + j, k1 + j) = gcc_tmp
309 : END DO
310 : END DO
311 : END IF
312 : END DO
313 : END IF
314 240 : m = m + maxso
315 : END DO
316 : END DO
317 :
318 8 : CALL atom_int_release(integrals)
319 : CALL set_cneo_potential(potential, nsgf=nsgf, nne=nne, nsotot=nsotot, &
320 : my_gcc_h=my_gcc_h, my_gcc_s=my_gcc_s, &
321 8 : ovlp=ovlp, kin=kin, utrans=utrans)
322 8 : CALL release_atom_basis(basis)
323 8 : DEALLOCATE (basis, integrals)
324 :
325 : ! initialize my_CG
326 8 : lmax_sphere = gapw_control%lmax_sphere
327 : ! make sure llmax is at least 1 such that distance matrices can be generated
328 8 : llmax = MAX(1, MIN(lmax_sphere, 2*maxl))
329 8 : max_s_harm = nsoset(llmax)
330 8 : max_s = nsoset(maxl)
331 8 : NULLIFY (my_CG)
332 8 : CALL reallocate(my_CG, 1, max_s, 1, max_s, 1, max_s_harm)
333 8 : CALL create_my_CG_cneo(my_CG, MAX(llmax, 2*maxl, 1), maxl, llmax)
334 :
335 : ! initialize harmonics
336 8 : CALL allocate_harmonics_atom(harmonics)
337 8 : CALL create_harmonics_atom_cneo(harmonics, my_CG, llmax, max_s, max_s_harm)
338 8 : DEALLOCATE (my_CG)
339 8 : CALL get_maxl_CG_cneo(harmonics, nuc_basis, llmax, max_s_harm)
340 :
341 8 : CALL set_cneo_potential(potential, harmonics=harmonics)
342 :
343 : ! initialize my own rad2l and oorad2l
344 : ! copied from qs_grid_atom::create_grid_atom
345 8 : nr = grid_atom%nr
346 8 : NULLIFY (rad2l, oorad2l)
347 8 : CALL reallocate(rad2l, 1, nr, 0, llmax + 1)
348 8 : CALL reallocate(oorad2l, 1, nr, 0, llmax + 1)
349 408 : rad2l(:, 0) = 1._dp
350 408 : oorad2l(:, 0) = 1._dp
351 48 : DO l = 1, llmax + 1
352 4040 : rad2l(:, l) = rad2l(:, l - 1)*grid_atom%rad(:)
353 4048 : oorad2l(:, l) = oorad2l(:, l - 1)/grid_atom%rad(:)
354 : END DO
355 8 : CALL set_cneo_potential(potential, rad2l=rad2l, oorad2l=oorad2l)
356 : ! still need to bump lmax in grid_atom as qs_rho0_types::calculate_g0 uses it
357 8 : IF (SIZE(rad2l, 2) > SIZE(grid_atom%rad2l, 2)) THEN
358 2 : CPASSERT(SIZE(rad2l, 1) == SIZE(grid_atom%rad2l, 1))
359 2 : DEALLOCATE (grid_atom%rad2l)
360 2 : NULLIFY (grid_atom%rad2l)
361 2 : CALL reallocate(grid_atom%rad2l, 1, nr, 0, llmax + 1)
362 1226 : grid_atom%rad2l = rad2l
363 : END IF
364 8 : IF (SIZE(oorad2l, 2) > SIZE(grid_atom%oorad2l, 2)) THEN
365 2 : CPASSERT(SIZE(oorad2l, 1) == SIZE(grid_atom%oorad2l, 1))
366 2 : DEALLOCATE (grid_atom%oorad2l)
367 2 : NULLIFY (grid_atom%oorad2l)
368 2 : CALL reallocate(grid_atom%oorad2l, 1, nr, 0, llmax + 1)
369 1226 : grid_atom%oorad2l = oorad2l
370 : END IF
371 :
372 : ! distance matrices
373 72 : ALLOCATE (distance(nsgf, nsgf, 3), dist(nsotot, nsotot, 3))
374 13280 : distance = 0.0_dp
375 8 : dist = 0.0_dp
376 : ! initialize gg and vgg
377 : ! mostly copied from qs_rho_atom_methods::calculate_rho_atom
378 8 : max_iso_not0 = harmonics%max_iso_not0
379 8 : lmax_expansion = indso(1, max_iso_not0)
380 8 : my_CG => harmonics%my_CG
381 72 : ALLOCATE (g1(nr), g2(nr), gg0(nr), gg(nr, 0:2*maxl, npgf_sum*(npgf_sum + 1)/2))
382 56 : ALLOCATE (erf_zet12(nr), vgg(nr, 0:2*maxl, 0:indso(1, max_iso_not0), npgf_sum*(npgf_sum + 1)/2))
383 32 : ALLOCATE (done_vgg(0:2*maxl, 0:indso(1, max_iso_not0)))
384 24 : ALLOCATE (int1(nr), int2(nr))
385 48 : ALLOCATE (cg_list(2, nsoset(maxl)**2, max_s_harm), cg_n_list(max_s_harm))
386 :
387 8 : j = 0
388 8 : m1 = 0
389 80 : DO iset1 = 1, nset
390 72 : n1 = nsoset(lmax(iset1))
391 72 : m2 = 0
392 432 : DO iset2 = 1, iset1
393 360 : n2 = nsoset(lmax(iset2))
394 :
395 : CALL get_none0_cg_list(my_CG, lmin(iset1), lmax(iset1), lmin(iset2), lmax(iset2), &
396 360 : max_s_harm, lmax_expansion, cg_list, cg_n_list, max_iso_not0_local)
397 360 : CPASSERT(max_iso_not0_local <= max_iso_not0)
398 :
399 720 : DO ipgf1 = 1, npgf(iset1)
400 18360 : g1(1:nr) = EXP(-zet(ipgf1, iset1)*grid_atom%rad2(1:nr))
401 :
402 360 : IF (iset2 == iset1) THEN
403 : npgf2 = ipgf1
404 : ELSE
405 288 : npgf2 = npgf(iset2)
406 : END IF
407 1080 : DO ipgf2 = 1, npgf2
408 360 : zet12 = zet(ipgf1, iset1) + zet(ipgf2, iset2)
409 :
410 : ! distance part
411 : ! -1 -> y -> 2, 0 -> z -> 3, 1 -> x -> 1
412 1440 : DO m = -1, 1
413 1080 : k = m + 3
414 1080 : IF (m == 1) k = 1
415 1080 : iso = indso_inv(1, m)
416 2256 : DO icg = 1, cg_n_list(iso)
417 816 : is1 = cg_list(1, icg, iso)
418 816 : is2 = cg_list(2, icg, iso)
419 :
420 816 : iso1 = is1 + n1*(ipgf1 - 1) + m1
421 816 : iso2 = is2 + n2*(ipgf2 - 1) + m2
422 :
423 816 : l = indso(1, is1) + indso(1, is2)
424 : dist(iso1, iso2, k) = dist(iso1, iso2, k) + my_CG(is1, is2, iso)* &
425 : pi*dfac(l + 2)/ &
426 816 : ((2.0_dp*zet12)**((l + 3)/2)*SQRT(3.0_dp*zet12))
427 1896 : dist(iso2, iso1, k) = dist(iso1, iso2, k) ! symmetric
428 : END DO !icg
429 : END DO
430 :
431 : ! gg and vgg part
432 360 : j = j + 1
433 18360 : g2(1:nr) = EXP(-zet(ipgf2, iset2)*grid_atom%rad2(1:nr))
434 360 : lmin12 = lmin(iset1) + lmin(iset2)
435 360 : lmax12 = lmax(iset1) + lmax(iset2)
436 :
437 360 : root_zet12 = SQRT(zet12)
438 18360 : DO ir = 1, nr
439 18360 : erf_zet12(ir) = erf(root_zet12*grid_atom%rad(ir))
440 : END DO
441 :
442 92160 : gg(:, :, j) = 0.0_dp
443 461160 : vgg(:, :, :, j) = 0.0_dp
444 360 : done_vgg = .FALSE.
445 : ! reduce the number of terms in the expansion local densities
446 720 : IF (lmin12 <= lmax_expansion) THEN
447 360 : IF (lmin12 == 0) THEN
448 4080 : gg(1:nr, lmin12, j) = g1(1:nr)*g2(1:nr)
449 4080 : gg0(1:nr) = gg(1:nr, lmin12, j)
450 : ELSE
451 14280 : gg0(1:nr) = g1(1:nr)*g2(1:nr)
452 28280 : gg(1:nr, lmin12, j) = rad2l(1:nr, lmin12)*g1(1:nr)*g2(1:nr)
453 : END IF
454 :
455 : ! reduce the number of terms in the expansion local densities
456 360 : IF (lmax12 > lmax_expansion) lmax12 = lmax_expansion
457 :
458 360 : DO l = lmin12 + 1, lmax12
459 360 : gg(1:nr, l, j) = grid_atom%rad(1:nr)*gg(1:nr, l - 1, j)
460 : END DO
461 :
462 360 : c2 = SQRT(pi*pi*pi/(zet12*zet12*zet12))
463 :
464 3200 : DO iso = 1, max_iso_not0_local
465 2840 : l_iso = indso(1, iso)
466 2840 : c1 = fourpi/(2._dp*REAL(l_iso, dp) + 1._dp)
467 7704 : DO icg = 1, cg_n_list(iso)
468 4504 : iso1 = cg_list(1, icg, iso)
469 4504 : iso2 = cg_list(2, icg, iso)
470 :
471 4504 : l = indso(1, iso1) + indso(1, iso2)
472 4504 : CPASSERT(l <= lmax_expansion)
473 4504 : IF (done_vgg(l, l_iso)) CYCLE
474 504 : L_sum = l + l_iso
475 504 : L_sub = l - l_iso
476 :
477 504 : IF (l_sum == 0) THEN
478 8080 : vgg(1:nr, l, l_iso, j) = erf_zet12(1:nr)*oorad2l(1:nr, 1)*c2
479 : ELSE
480 424 : CALL whittaker_c0a(int1, grid_atom%rad, gg0, erf_zet12, zet12, l, l_iso, nr)
481 424 : CALL whittaker_ci(int2, grid_atom%rad, gg0, zet12, L_sub, nr)
482 :
483 21624 : DO ir = 1, nr
484 21200 : int2(ir) = rad2l(ir, l_iso)*int2(ir)
485 21624 : vgg(ir, l, l_iso, j) = c1*(int1(ir) + int2(ir))
486 : END DO
487 : END IF
488 7344 : done_vgg(l, l_iso) = .TRUE.
489 : END DO
490 : END DO
491 : END IF ! lmax_expansion
492 :
493 : END DO ! ipgf2
494 : END DO ! ipgf1
495 792 : m2 = m2 + maxso
496 : END DO ! iset2
497 80 : m1 = m1 + maxso
498 : END DO ! iset1
499 :
500 8 : DEALLOCATE (g1, g2, gg0, erf_zet12, int1, int2, done_vgg)
501 8 : DEALLOCATE (cg_list, cg_n_list)
502 :
503 24 : ALLOCATE (work(nsotot, nsgf))
504 32 : DO k = 1, 3
505 : CALL dgemm("N", "N", nsotot, nsgf, nsotot, 1.0_dp, dist(:, :, k), nsotot, my_gcc_h, &
506 24 : nsotot, 0.0_dp, work, nsotot)
507 : CALL dgemm("T", "N", nsgf, nsgf, nsotot, 1.0_dp, my_gcc_h, nsotot, work, &
508 32 : nsotot, 0.0_dp, distance(:, :, k), nsgf)
509 : END DO
510 8 : DEALLOCATE (work, dist)
511 8 : CALL set_cneo_potential(potential, distance=distance, gg=gg, vgg=vgg)
512 :
513 : ! Index transformation OLD-NEW
514 : ! copied from paw_proj_set_types::build_projector
515 24 : ALLOCATE (o2nindex(nsotot))
516 16 : ALLOCATE (n2oindex(nsotot))
517 656 : o2nindex = 0
518 656 : n2oindex = 0
519 : ico = 1
520 80 : DO iset = 1, nset
521 72 : iso_set = (iset - 1)*maxso + 1
522 72 : nsox = nsoset(lmax(iset))
523 152 : DO ipgf = 1, npgf(iset)
524 72 : iso_pgf = iso_set + (ipgf - 1)*nsox
525 72 : iso = iso_pgf + nsoset(lmin(iset) - 1)
526 216 : DO l = lmin(iset), lmax(iset)
527 328 : DO k = 1, nso(l)
528 184 : n2oindex(ico) = iso
529 184 : o2nindex(iso) = ico
530 184 : iso = iso + 1
531 256 : ico = ico + 1
532 : END DO
533 : END DO
534 : END DO
535 : END DO
536 8 : npsgf = ico - 1
537 8 : CALL set_cneo_potential(potential, npsgf=npsgf, n2oindex=n2oindex, o2nindex=o2nindex)
538 :
539 8 : CALL timestop(handle)
540 :
541 32 : END SUBROUTINE init_cneo_potential_internals
542 :
543 : ! **************************************************************************************************
544 : !> \brief ...
545 : !> \param rhoz_cneo_set ...
546 : !> \param atomic_kind_set ...
547 : !> \param qs_kind_set ...
548 : !> \param qs_env ...
549 : ! **************************************************************************************************
550 16 : SUBROUTINE allocate_rhoz_cneo_internals(rhoz_cneo_set, atomic_kind_set, &
551 : qs_kind_set, qs_env)
552 :
553 : TYPE(rhoz_cneo_type), DIMENSION(:), POINTER :: rhoz_cneo_set
554 : TYPE(atomic_kind_type), DIMENSION(:), POINTER :: atomic_kind_set
555 : TYPE(qs_kind_type), DIMENSION(:), POINTER :: qs_kind_set
556 : TYPE(qs_environment_type), POINTER :: qs_env
557 :
558 : CHARACTER(len=*), PARAMETER :: routineN = 'allocate_rhoz_cneo_internals'
559 :
560 : INTEGER :: bo(2), handle, iat, iatom, ikind, &
561 : max_iso_not0, mepos, nat, natom, &
562 : npsgf, nr, nsgf, nsotot, num_pe
563 8 : INTEGER, DIMENSION(:), POINTER :: atom_list
564 : LOGICAL :: paw_atom
565 : TYPE(cneo_potential_type), POINTER :: cneo_potential
566 : TYPE(mp_para_env_type), POINTER :: para_env
567 :
568 8 : CALL timeset(routineN, handle)
569 :
570 8 : CALL get_atomic_kind_set(atomic_kind_set, natom=natom)
571 :
572 8 : CALL allocate_rhoz_cneo_set(rhoz_cneo_set, natom)
573 :
574 8 : NULLIFY (para_env)
575 8 : CALL get_qs_env(qs_env, para_env=para_env)
576 :
577 22 : DO ikind = 1, SIZE(atomic_kind_set)
578 :
579 14 : NULLIFY (cneo_potential)
580 : CALL get_qs_kind(qs_kind_set(ikind), &
581 : ngrid_rad=nr, &
582 : paw_atom=paw_atom, &
583 14 : cneo_potential=cneo_potential)
584 :
585 22 : IF (ASSOCIATED(cneo_potential)) THEN
586 8 : CPASSERT(paw_atom)
587 :
588 8 : NULLIFY (atom_list)
589 8 : CALL get_atomic_kind(atomic_kind_set(ikind), atom_list=atom_list, natom=nat)
590 :
591 8 : nsgf = cneo_potential%nsgf
592 8 : npsgf = cneo_potential%npsgf
593 8 : nsotot = cneo_potential%nsotot
594 :
595 22 : DO iat = 1, nat
596 14 : iatom = atom_list(iat)
597 :
598 : ! density matrices, core and soft vmat will be broadcast to all processes
599 : ALLOCATE (rhoz_cneo_set(iatom)%pmat(1:nsgf, 1:nsgf), &
600 : rhoz_cneo_set(iatom)%cpc_h(1:npsgf, 1:npsgf), &
601 : rhoz_cneo_set(iatom)%cpc_s(1:npsgf, 1:npsgf), &
602 : rhoz_cneo_set(iatom)%core(1:nsgf, 1:nsgf), &
603 182 : rhoz_cneo_set(iatom)%vmat(1:nsgf, 1:nsgf))
604 7742 : rhoz_cneo_set(iatom)%pmat = 0.0_dp
605 7742 : rhoz_cneo_set(iatom)%cpc_h = 0.0_dp
606 7742 : rhoz_cneo_set(iatom)%cpc_s = 0.0_dp
607 7742 : rhoz_cneo_set(iatom)%core = 0.0_dp
608 7750 : rhoz_cneo_set(iatom)%vmat = 0.0_dp
609 : END DO
610 :
611 8 : max_iso_not0 = cneo_potential%harmonics%max_iso_not0
612 8 : num_pe = para_env%num_pe
613 8 : mepos = para_env%mepos
614 8 : bo = get_limit(nat, num_pe, mepos)
615 15 : DO iat = bo(1), bo(2)
616 7 : iatom = atom_list(iat)
617 :
618 : ALLOCATE (rhoz_cneo_set(iatom)%fmat(1:nsgf, 1:nsgf), &
619 42 : rhoz_cneo_set(iatom)%wfn(1:nsgf, 1:nsgf))
620 3871 : rhoz_cneo_set(iatom)%fmat = 0.0_dp
621 3871 : rhoz_cneo_set(iatom)%wfn = 0.0_dp
622 :
623 : ALLOCATE (rhoz_cneo_set(iatom)%rho_rad_h(1:nr, 1:max_iso_not0), &
624 : rhoz_cneo_set(iatom)%rho_rad_s(1:nr, 1:max_iso_not0), &
625 : rhoz_cneo_set(iatom)%vrho_rad_h(1:nr, 1:max_iso_not0), &
626 70 : rhoz_cneo_set(iatom)%vrho_rad_s(1:nr, 1:max_iso_not0))
627 8932 : rhoz_cneo_set(iatom)%rho_rad_h = 0.0_dp
628 8932 : rhoz_cneo_set(iatom)%rho_rad_s = 0.0_dp
629 8932 : rhoz_cneo_set(iatom)%vrho_rad_h = 0.0_dp
630 8932 : rhoz_cneo_set(iatom)%vrho_rad_s = 0.0_dp
631 :
632 7 : NULLIFY (rhoz_cneo_set(iatom)%ga_Vlocal_gb_h)
633 7 : CALL reallocate(rhoz_cneo_set(iatom)%ga_Vlocal_gb_h, 1, nsotot, 1, nsotot)
634 46501 : rhoz_cneo_set(iatom)%ga_Vlocal_gb_h = 0.0_dp
635 7 : NULLIFY (rhoz_cneo_set(iatom)%ga_Vlocal_gb_s)
636 7 : CALL reallocate(rhoz_cneo_set(iatom)%ga_Vlocal_gb_s, 1, nsotot, 1, nsotot)
637 46509 : rhoz_cneo_set(iatom)%ga_Vlocal_gb_s = 0.0_dp
638 : END DO ! iat
639 : END IF
640 :
641 : END DO
642 :
643 8 : CALL timestop(handle)
644 :
645 8 : END SUBROUTINE allocate_rhoz_cneo_internals
646 :
647 : ! **************************************************************************************************
648 : !> \brief ...
649 : !> \param qs_env ...
650 : !> \param calculate_forces ...
651 : !> \param nder ...
652 : ! **************************************************************************************************
653 18707 : SUBROUTINE cneo_core_matrices(qs_env, calculate_forces, nder)
654 : TYPE(qs_environment_type), POINTER :: qs_env
655 : LOGICAL, INTENT(IN) :: calculate_forces
656 : INTEGER, INTENT(IN) :: nder
657 :
658 : LOGICAL :: use_virial
659 18707 : TYPE(atomic_kind_type), DIMENSION(:), POINTER :: atomic_kind_set
660 : TYPE(distribution_1d_type), POINTER :: distribution_1d
661 : TYPE(mp_para_env_type), POINTER :: para_env
662 : TYPE(neighbor_list_set_p_type), DIMENSION(:), &
663 18707 : POINTER :: sab_cneo
664 18707 : TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
665 18707 : TYPE(qs_force_type), DIMENSION(:), POINTER :: force
666 18707 : TYPE(qs_kind_type), DIMENSION(:), POINTER :: qs_kind_set
667 18707 : TYPE(rhoz_cneo_type), DIMENSION(:), POINTER :: rhoz_cneo_set
668 : TYPE(virial_type), POINTER :: virial
669 :
670 18707 : NULLIFY (rhoz_cneo_set)
671 18707 : CALL get_qs_env(qs_env=qs_env, rhoz_cneo_set=rhoz_cneo_set)
672 :
673 18707 : IF (ASSOCIATED(rhoz_cneo_set)) THEN
674 14 : NULLIFY (force, virial)
675 : ! force
676 14 : IF (calculate_forces) CALL get_qs_env(qs_env=qs_env, force=force)
677 : ! virial
678 14 : CALL get_qs_env(qs_env=qs_env, virial=virial)
679 14 : use_virial = virial%pv_availability .AND. (.NOT. virial%pv_numer)
680 :
681 14 : NULLIFY (qs_kind_set, atomic_kind_set, particle_set, distribution_1d, para_env, sab_cneo)
682 : CALL get_qs_env(qs_env=qs_env, qs_kind_set=qs_kind_set, atomic_kind_set=atomic_kind_set, &
683 : particle_set=particle_set, local_particles=distribution_1d, &
684 14 : para_env=para_env, sab_cneo=sab_cneo)
685 : CALL build_core_cneo(rhoz_cneo_set, force, virial, calculate_forces, use_virial, nder, &
686 : qs_kind_set, atomic_kind_set, particle_set, distribution_1d, &
687 14 : sab_cneo, para_env)
688 : END IF
689 :
690 18707 : END SUBROUTINE cneo_core_matrices
691 :
692 : ! **************************************************************************************************
693 : !> \brief ...
694 : !> \param rhoz_cneo_set ...
695 : !> \param force ...
696 : !> \param virial ...
697 : !> \param calculate_forces ...
698 : !> \param use_virial ...
699 : !> \param nder ...
700 : !> \param qs_kind_set ...
701 : !> \param atomic_kind_set ...
702 : !> \param particle_set ...
703 : !> \param distribution_1d ...
704 : !> \param sab_cneo ...
705 : !> \param para_env ...
706 : ! **************************************************************************************************
707 14 : SUBROUTINE build_core_cneo(rhoz_cneo_set, force, virial, calculate_forces, use_virial, nder, &
708 : qs_kind_set, atomic_kind_set, particle_set, distribution_1d, &
709 : sab_cneo, para_env)
710 : TYPE(rhoz_cneo_type), DIMENSION(:), POINTER :: rhoz_cneo_set
711 : TYPE(qs_force_type), DIMENSION(:), POINTER :: force
712 : TYPE(virial_type), POINTER :: virial
713 : LOGICAL, INTENT(IN) :: calculate_forces, use_virial
714 : INTEGER, INTENT(IN) :: nder
715 : TYPE(qs_kind_type), DIMENSION(:), POINTER :: qs_kind_set
716 : TYPE(atomic_kind_type), DIMENSION(:), POINTER :: atomic_kind_set
717 : TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
718 : TYPE(distribution_1d_type), POINTER :: distribution_1d
719 : TYPE(neighbor_list_set_p_type), DIMENSION(:), &
720 : POINTER :: sab_cneo
721 : TYPE(mp_para_env_type), POINTER :: para_env
722 :
723 : CHARACTER(LEN=*), PARAMETER :: routineN = 'build_core_cneo'
724 :
725 : INTEGER :: atom_a, handle, iat, iatom, ikind, iset, jatom, jkind, jset, ldai, ldsab, maxco, &
726 : maxl, maxnset, maxsgf, mepos, na_plus, nat, natom, nb_plus, ncoa, ncob, nij, nkind, nset, &
727 : nthread, sgfa, sgfb
728 14 : INTEGER, ALLOCATABLE, DIMENSION(:) :: atom_of_kind, kind_of
729 14 : INTEGER, DIMENSION(:), POINTER :: atom_list, lmax, lmin, npgf, nsgf
730 14 : INTEGER, DIMENSION(:, :), POINTER :: first_sgf
731 : REAL(KIND=dp) :: alpha_c, core_charge, core_radius, dab, &
732 : f0, rab2, zeta_i, zeta_j
733 14 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: ff
734 14 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :) :: habd, work
735 14 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :) :: hab, pab, verf, vnuc
736 : REAL(KIND=dp), DIMENSION(3) :: force_a, force_b, force_i, rab
737 : REAL(KIND=dp), DIMENSION(3, 3) :: pv_thread
738 : TYPE(neighbor_list_iterator_p_type), &
739 14 : DIMENSION(:), POINTER :: ap_iterator
740 : TYPE(gto_basis_set_type), POINTER :: basis_set
741 : TYPE(cneo_potential_type), POINTER :: cneo_potential, cneo_tmp
742 14 : REAL(KIND=dp), DIMENSION(:, :), POINTER :: core, pmat, rpgf, sphi, zet
743 14 : REAL(KIND=dp), DIMENSION(:), POINTER :: set_radius
744 28 : REAL(KIND=dp), DIMENSION(3, SIZE(particle_set)) :: force_thread
745 :
746 28 : IF (calculate_forces) THEN
747 6 : CALL timeset(routineN//"_forces", handle)
748 : ELSE
749 8 : CALL timeset(routineN, handle)
750 : END IF
751 :
752 14 : nkind = SIZE(atomic_kind_set)
753 14 : natom = SIZE(particle_set)
754 :
755 166 : force_thread = 0.0_dp
756 14 : pv_thread = 0.0_dp
757 :
758 : ! re-initialize core matrices to zero, as later will use para_env%sum to broadcast
759 40 : DO ikind = 1, nkind
760 26 : NULLIFY (cneo_potential)
761 26 : CALL get_qs_kind(qs_kind_set(ikind), cneo_potential=cneo_potential)
762 :
763 40 : IF (ASSOCIATED(cneo_potential)) THEN
764 14 : NULLIFY (atom_list)
765 14 : CALL get_atomic_kind(atomic_kind_set(ikind), atom_list=atom_list, natom=nat)
766 40 : DO iat = 1, nat
767 26 : iatom = atom_list(iat)
768 14392 : rhoz_cneo_set(iatom)%core = 0.0_dp
769 : END DO
770 : END IF
771 : END DO
772 :
773 : CALL get_qs_kind_set(qs_kind_set, basis_type="NUC", &
774 14 : maxco=maxco, maxlgto=maxl, maxsgf=maxsgf, maxnset=maxnset)
775 14 : CALL init_orbital_pointers(maxl + nder + 1)
776 14 : ldsab = MAX(maxco, maxsgf)
777 14 : ldai = ncoset(maxl + nder + 1)
778 :
779 : nthread = 1
780 14 : !$ nthread = omp_get_max_threads()
781 :
782 14 : CALL neighbor_list_iterator_create(ap_iterator, sab_cneo, search=.TRUE., nthread=nthread)
783 :
784 : !$OMP PARALLEL &
785 : !$OMP DEFAULT (NONE) &
786 : !$OMP SHARED (rhoz_cneo_set, ap_iterator, distribution_1d, calculate_forces, use_virial, &
787 : !$OMP qs_kind_set, nthread, ncoset, nkind, iat, ldsab, maxnset, ldai, nder, maxl, &
788 : !$OMP maxco, para_env) &
789 : !$OMP PRIVATE (ikind, jkind, iatom, jatom, basis_set, first_sgf, lmax, lmin, npgf, nset, &
790 : !$OMP nsgf, rpgf, sphi, zet, set_radius, zeta_i, zeta_j, alpha_c, core_charge, &
791 : !$OMP core_radius, rab, rab2, dab, core, pmat, iset, ncoa, sgfa, jset, ncob, sgfb, &
792 : !$OMP work, pab, hab, na_plus, nb_plus, verf, vnuc, force_a, force_b, force_i, &
793 : !$OMP mepos, habd, f0, nij, ff, cneo_potential, cneo_tmp) &
794 14 : !$OMP REDUCTION (+ : pv_thread, force_thread )
795 :
796 : mepos = 0
797 : !$ mepos = omp_get_thread_num()
798 :
799 : ALLOCATE (hab(ldsab, ldsab, maxnset*(maxnset + 1)/2), work(ldsab, ldsab))
800 : ALLOCATE (verf(ldai, ldai, 2*maxl + nder + 1), vnuc(ldai, ldai, 2*maxl + nder + 1), ff(0:2*maxl + nder))
801 : IF (calculate_forces) THEN
802 : ALLOCATE (pab(maxco, maxco, maxnset*(maxnset + 1)/2))
803 : END IF
804 :
805 : DO ikind = 1, nkind
806 : NULLIFY (cneo_potential)
807 : CALL get_qs_kind(qs_kind_set(ikind), basis_set=basis_set, basis_type="NUC", &
808 : cneo_potential=cneo_potential, zeff=zeta_i)
809 : IF (ASSOCIATED(cneo_potential)) THEN
810 : CPASSERT(ASSOCIATED(basis_set))
811 : first_sgf => basis_set%first_sgf
812 : lmax => basis_set%lmax
813 : lmin => basis_set%lmin
814 : npgf => basis_set%npgf
815 : nset = basis_set%nset
816 : nsgf => basis_set%nsgf_set
817 : rpgf => basis_set%pgf_radius
818 : set_radius => basis_set%set_radius
819 : sphi => basis_set%sphi
820 : zet => basis_set%zet
821 :
822 : !$OMP DO SCHEDULE(GUIDED)
823 : DO iat = 1, distribution_1d%n_el(ikind)
824 : iatom = distribution_1d%list(ikind)%array(iat)
825 : core => rhoz_cneo_set(iatom)%core
826 : CPASSERT(ASSOCIATED(core))
827 : core = cneo_potential%kin ! copy kinetic matrix to core
828 : IF (calculate_forces) THEN
829 : CPASSERT(rhoz_cneo_set(iatom)%ready)
830 : pmat => rhoz_cneo_set(iatom)%pmat
831 : CPASSERT(ASSOCIATED(pmat))
832 : ! *** Decontract density matrix ***
833 : DO iset = 1, nset
834 : ncoa = npgf(iset)*ncoset(lmax(iset))
835 : sgfa = first_sgf(1, iset)
836 : DO jset = 1, iset
837 : ncob = npgf(jset)*ncoset(lmax(jset))
838 : sgfb = first_sgf(1, jset)
839 : nij = jset + (iset - 1)*iset/2
840 : work(1:ncoa, 1:nsgf(jset)) = MATMUL(sphi(1:ncoa, sgfa:sgfa + nsgf(iset) - 1), &
841 : pmat(sgfa:sgfa + nsgf(iset) - 1, sgfb:sgfb + nsgf(jset) - 1))
842 : pab(1:ncoa, 1:ncob, nij) = MATMUL(work(1:ncoa, 1:nsgf(jset)), &
843 : TRANSPOSE(sphi(1:ncob, sgfb:sgfb + nsgf(jset) - 1)))
844 : END DO
845 : END DO
846 : END IF
847 :
848 : hab = 0._dp
849 : DO jkind = 1, nkind
850 : NULLIFY (cneo_tmp)
851 : CALL get_qs_kind(qs_kind_set(jkind), cneo_potential=cneo_tmp)
852 : IF (.NOT. ASSOCIATED(cneo_tmp)) THEN
853 : CALL get_qs_kind(qs_kind_set(jkind), &
854 : alpha_core_charge=alpha_c, zeff=zeta_j, &
855 : ccore_charge=core_charge, core_charge_radius=core_radius)
856 : CALL nl_set_sub_iterator(ap_iterator, ikind, jkind, iatom, mepos=mepos)
857 :
858 : DO WHILE (nl_sub_iterate(ap_iterator, mepos=mepos) == 0)
859 : CALL get_iterator_info(ap_iterator, jatom=jatom, r=rab, mepos=mepos)
860 : rab2 = SUM(rab*rab)
861 : dab = SQRT(rab2)
862 : IF (MAXVAL(set_radius(:)) + core_radius < dab) CYCLE
863 : DO iset = 1, nset
864 : IF (set_radius(iset) + core_radius < dab) CYCLE
865 : ncoa = npgf(iset)*ncoset(lmax(iset))
866 : sgfa = first_sgf(1, iset)
867 : DO jset = 1, iset ! symmetric
868 : IF (set_radius(jset) + core_radius < dab) CYCLE
869 : ncob = npgf(jset)*ncoset(lmax(jset))
870 : sgfb = first_sgf(1, jset)
871 : nij = jset + (iset - 1)*iset/2
872 : IF (calculate_forces) THEN
873 : IF (jset == iset) THEN
874 : f0 = -zeta_i
875 : ELSE
876 : f0 = -2.0_dp*zeta_i
877 : END IF
878 : na_plus = npgf(iset)*ncoset(lmax(iset) + nder)
879 : nb_plus = npgf(jset)*ncoset(lmax(jset))
880 : ALLOCATE (habd(na_plus, nb_plus))
881 : habd = 0._dp
882 : CALL verfc( &
883 : lmax(iset) + nder, npgf(iset), zet(:, iset), rpgf(:, iset), lmin(iset), &
884 : lmax(jset), npgf(jset), zet(:, jset), rpgf(:, jset), lmin(jset), &
885 : alpha_c, core_radius, zeta_j, core_charge, &
886 : [0.0_dp, 0.0_dp, 0.0_dp], 0.0_dp, rab, rab2, rab2, &
887 : hab(:, :, nij), verf, vnuc, ff(0:), nder, habd)
888 :
889 : ! *** The derivatives w.r.t. atomic center b are ***
890 : ! *** calculated using the translational invariance ***
891 : ! *** of the first derivatives ***
892 : CALL verfc_force(habd, pab(:, :, nij), force_a, force_b, nder, &
893 : lmax(iset), lmin(iset), npgf(iset), zet(:, iset), &
894 : lmax(jset), lmin(jset), npgf(jset), zet(:, jset), &
895 : [0.0_dp, 0.0_dp, 0.0_dp])
896 :
897 : DEALLOCATE (habd)
898 : force_i = force_a + force_b
899 :
900 : force_thread(1, iatom) = force_thread(1, iatom) + f0*force_i(1)
901 : force_thread(2, iatom) = force_thread(2, iatom) + f0*force_i(2)
902 : force_thread(3, iatom) = force_thread(3, iatom) + f0*force_i(3)
903 :
904 : force_thread(1, jatom) = force_thread(1, jatom) - f0*force_i(1)
905 : force_thread(2, jatom) = force_thread(2, jatom) - f0*force_i(2)
906 : force_thread(3, jatom) = force_thread(3, jatom) - f0*force_i(3)
907 :
908 : IF (use_virial) THEN
909 : CALL virial_pair_force(pv_thread, f0, force_i, rab)
910 : END IF
911 : ELSE
912 : CALL verfc( &
913 : lmax(iset), npgf(iset), zet(:, iset), rpgf(:, iset), lmin(iset), &
914 : lmax(jset), npgf(jset), zet(:, jset), rpgf(:, jset), lmin(jset), &
915 : alpha_c, core_radius, zeta_j, core_charge, &
916 : [0.0_dp, 0.0_dp, 0.0_dp], 0.0_dp, rab, rab2, rab2, &
917 : hab(:, :, nij), verf, vnuc, ff(0:))
918 : END IF
919 : END DO
920 : END DO
921 : END DO
922 : END IF
923 : END DO
924 : ! *** Contract nuclear repulsion integrals
925 : DO iset = 1, nset
926 : ncoa = npgf(iset)*ncoset(lmax(iset))
927 : sgfa = first_sgf(1, iset)
928 : DO jset = 1, iset
929 : ncob = npgf(jset)*ncoset(lmax(jset))
930 : sgfb = first_sgf(1, jset)
931 : nij = jset + (iset - 1)*iset/2
932 : work(1:ncoa, 1:nsgf(jset)) = MATMUL(hab(1:ncoa, 1:ncob, nij), &
933 : sphi(1:ncob, sgfb:sgfb + nsgf(jset) - 1))
934 : core(sgfa:sgfa + nsgf(iset) - 1, sgfb:sgfb + nsgf(jset) - 1) = &
935 : core(sgfa:sgfa + nsgf(iset) - 1, sgfb:sgfb + nsgf(jset) - 1) - zeta_i* &
936 : MATMUL(TRANSPOSE(sphi(1:ncoa, sgfa:sgfa + nsgf(iset) - 1)), work(1:ncoa, 1:nsgf(jset)))
937 : ! symmetrize core matrix
938 : IF (iset /= jset) THEN
939 : core(sgfb:sgfb + nsgf(jset) - 1, sgfa:sgfa + nsgf(iset) - 1) = &
940 : TRANSPOSE(core(sgfa:sgfa + nsgf(iset) - 1, sgfb:sgfb + nsgf(jset) - 1))
941 : END IF
942 : END DO
943 : END DO
944 : END DO
945 : END IF
946 : END DO
947 :
948 : DEALLOCATE (hab, work, verf, vnuc, ff)
949 : IF (calculate_forces) THEN
950 : DEALLOCATE (pab)
951 : END IF
952 :
953 : !$OMP END PARALLEL
954 :
955 14 : CALL neighbor_list_iterator_release(ap_iterator)
956 :
957 14 : IF (calculate_forces) THEN
958 : CALL get_atomic_kind_set(atomic_kind_set, atom_of_kind=atom_of_kind, &
959 6 : kind_of=kind_of)
960 : !$OMP DO
961 : DO iatom = 1, natom
962 18 : atom_a = atom_of_kind(iatom)
963 18 : ikind = kind_of(iatom)
964 : force(ikind)%cneo_potential(:, atom_a) = force(ikind)%cneo_potential(:, atom_a) + &
965 72 : force_thread(:, iatom)
966 : END DO
967 : !$OMP END DO
968 : END IF
969 :
970 14 : IF (calculate_forces .AND. use_virial) THEN
971 0 : virial%pv_ppl = virial%pv_ppl + pv_thread
972 0 : virial%pv_virial = virial%pv_virial + pv_thread
973 : END IF
974 :
975 : ! broadcast core matrices
976 40 : DO ikind = 1, nkind
977 26 : NULLIFY (cneo_potential)
978 26 : CALL get_qs_kind(qs_kind_set(ikind), cneo_potential=cneo_potential)
979 :
980 40 : IF (ASSOCIATED(cneo_potential)) THEN
981 14 : NULLIFY (atom_list)
982 14 : CALL get_atomic_kind(atomic_kind_set(ikind), atom_list=atom_list, natom=nat)
983 40 : DO iat = 1, nat
984 26 : iatom = atom_list(iat)
985 28744 : CALL para_env%sum(rhoz_cneo_set(iatom)%core)
986 : END DO
987 : END IF
988 : END DO
989 :
990 14 : CALL timestop(handle)
991 :
992 28 : END SUBROUTINE build_core_cneo
993 :
994 : ! **************************************************************************************************
995 : !> \brief ...
996 : !> \param rho ...
997 : !> \param potential ...
998 : !> \param cg_list ...
999 : !> \param cg_n_list ...
1000 : !> \param nset ...
1001 : !> \param npgf ...
1002 : !> \param lmin ...
1003 : !> \param lmax ...
1004 : !> \param maxl ...
1005 : !> \param maxso ...
1006 : ! **************************************************************************************************
1007 46 : SUBROUTINE calculate_rhoz_cneo(rho, potential, cg_list, cg_n_list, nset, npgf, &
1008 : lmin, lmax, maxl, maxso)
1009 :
1010 : TYPE(rhoz_cneo_type), POINTER :: rho
1011 : TYPE(cneo_potential_type), POINTER :: potential
1012 : INTEGER, DIMENSION(:, :, :), INTENT(INOUT) :: cg_list
1013 : INTEGER, DIMENSION(:), INTENT(INOUT) :: cg_n_list
1014 : INTEGER, INTENT(IN) :: nset
1015 : INTEGER, DIMENSION(:), POINTER :: npgf, lmin, lmax
1016 : INTEGER, INTENT(IN) :: maxl, maxso
1017 :
1018 : CHARACTER(len=*), PARAMETER :: routineN = 'calculate_rhoz_cneo'
1019 :
1020 : INTEGER :: handle, i, i1, i2, icg, ipgf1, ipgf2, iset1, iset2, iso, iso1, iso1_first, &
1021 : iso1_last, iso2, iso2_first, iso2_last, iter, j, l, l1, l2, l_iso, lmax_expansion, m1s, &
1022 : m2s, max_iso_not0, max_iso_not0_local, max_iter, max_s_harm, n1s, n2s, nne, npgf2, npsgf, &
1023 : nsgf, nsotot, size1, size2
1024 46 : INTEGER, DIMENSION(:), POINTER :: n2oindex, o2nindex
1025 : REAL(KIND=dp) :: det, df_norm, factor, g0, g0p, g1, step, &
1026 : zeff
1027 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: ener
1028 46 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :) :: CPCH_sphere, CPCS_sphere, work
1029 : REAL(KIND=dp), DIMENSION(3) :: df, f_tmp, r, r_tmp
1030 : REAL(KIND=dp), DIMENSION(3, 3) :: jac, jac_inv
1031 : REAL(KIND=dp), DIMENSION(:), POINTER :: f
1032 46 : REAL(KIND=dp), DIMENSION(:, :), POINTER :: core, cpc_h, cpc_s, fmat, int_local_h, &
1033 46 : int_local_s, my_gcc_h, my_gcc_s, pmat, rho_rad_h, rho_rad_s, utrans, vmat, vrho_rad_h, &
1034 46 : vrho_rad_s, wfn
1035 46 : REAL(KIND=dp), DIMENSION(:, :, :), POINTER :: distance, gg, my_CG
1036 46 : REAL(KIND=dp), DIMENSION(:, :, :, :), POINTER :: vgg
1037 : TYPE(harmonics_atom_type), POINTER :: harmonics
1038 :
1039 0 : CPASSERT(ASSOCIATED(rho))
1040 46 : CPASSERT(ASSOCIATED(potential))
1041 :
1042 46 : CALL timeset(routineN, handle)
1043 :
1044 : ! convert ga_Vlocal_gb to compressed form V_Hartree
1045 : ! use fmat to store V_Hartree
1046 46 : NULLIFY (utrans, my_gcc_h, my_gcc_s, distance, n2oindex, o2nindex)
1047 : CALL get_cneo_potential(potential, zeff=zeff, nsgf=nsgf, nne=nne, npsgf=npsgf, &
1048 : nsotot=nsotot, my_gcc_h=my_gcc_h, my_gcc_s=my_gcc_s, &
1049 : utrans=utrans, distance=distance, n2oindex=n2oindex, &
1050 46 : o2nindex=o2nindex)
1051 46 : fmat => rho%fmat
1052 46 : int_local_h => rho%ga_Vlocal_gb_h
1053 46 : int_local_s => rho%ga_Vlocal_gb_s
1054 184 : ALLOCATE (work(nsotot, nsgf))
1055 : CALL dgemm("N", "N", nsotot, nsgf, nsotot, 1.0_dp, int_local_h, nsotot, my_gcc_h, &
1056 46 : nsotot, 0.0_dp, work, nsotot)
1057 : CALL dgemm("T", "N", nsgf, nsgf, nsotot, 1.0_dp, my_gcc_h, nsotot, work, &
1058 46 : nsotot, 0.0_dp, fmat, nsgf)
1059 : CALL dgemm("N", "N", nsotot, nsgf, nsotot, 1.0_dp, int_local_s, nsotot, my_gcc_s, &
1060 46 : nsotot, 0.0_dp, work, nsotot)
1061 : CALL dgemm("T", "N", nsgf, nsgf, nsotot, -1.0_dp, my_gcc_s, nsotot, work, &
1062 46 : nsotot, 1.0_dp, fmat, nsgf)
1063 : ! add the soft basis FFT grid part
1064 46 : vmat => rho%vmat
1065 50830 : fmat = fmat + vmat
1066 :
1067 46 : core => rho%core
1068 46 : wfn => rho%wfn
1069 46 : pmat => rho%pmat
1070 46 : f => rho%f
1071 138 : ALLOCATE (ener(nne))
1072 : ! build the fock matrix: F = T + V_core + V_Hartree
1073 50830 : fmat = fmat + core
1074 : ! conduct the constrained optimization with F + f*x
1075 : ! initial guess of f is taken from the result of last iteration
1076 46 : CALL atom_solve_cneo(fmat, f, utrans, wfn, ener, pmat, r, distance, nsgf, nne)
1077 : ! test if zero initial guess is better
1078 322 : IF (NORM2(r) > 1.e-12_dp .AND. DOT_PRODUCT(f, f) /= 0.0_dp) THEN
1079 : CALL atom_solve_cneo(fmat, [0.0_dp, 0.0_dp, 0.0_dp], utrans, wfn, &
1080 39 : ener, pmat, r_tmp, distance, nsgf, nne)
1081 273 : IF (DOT_PRODUCT(r_tmp, r_tmp) < DOT_PRODUCT(r, r)) THEN
1082 24 : f = 0.0_dp
1083 6 : r = r_tmp
1084 : END IF
1085 : END IF
1086 46 : max_iter = 20
1087 46 : iter = 0
1088 : ! using Newton's method to solve for f
1089 884 : DO WHILE (NORM2(r) > 1.e-12_dp)
1090 140 : iter = iter + 1
1091 : ! construct numerical Jacobian with one-side finite difference
1092 560 : DO i = 1, 3
1093 1680 : f_tmp = f
1094 420 : f_tmp(i) = f(i) + SIGN(1.e-4_dp, r(i)) ! forward or backward based on the sign of r
1095 420 : CALL atom_solve_cneo(fmat, f_tmp, utrans, wfn, ener, pmat, r_tmp, distance, nsgf, nne)
1096 1820 : DO j = 1, 3
1097 1680 : jac(j, i) = (r_tmp(j) - r(j))*SIGN(1.e4_dp, r(i))
1098 : END DO
1099 : END DO
1100 140 : CALL invert_matrix_3x3(jac, jac_inv, det)
1101 140 : IF (ABS(det) < 1.0E-8_dp) THEN
1102 : CALL cp_warn(__LOCATION__, "Determinant of the CNEO position Jacobian is small! "// &
1103 0 : TRIM(cp_to_string(det))//" Trying central difference.")
1104 : ! construct numerical Jacobian with central finite difference
1105 0 : DO i = 1, 3
1106 0 : f_tmp = f
1107 0 : f_tmp(i) = f(i) - SIGN(1.e-4_dp, r(i))
1108 0 : CALL atom_solve_cneo(fmat, f_tmp, utrans, wfn, ener, pmat, r_tmp, distance, nsgf, nne)
1109 0 : DO j = 1, 3
1110 : jac(j, i) = (jac(j, i)*SIGN(1.e-4_dp, r(i)) + r(j) - r_tmp(j)) &
1111 0 : /SIGN(2.e-4_dp, r(i))
1112 : END DO
1113 : END DO
1114 0 : CALL invert_matrix_3x3(jac, jac_inv, det)
1115 0 : IF (ABS(det) < 1.0E-8_dp) THEN
1116 : CALL cp_warn(__LOCATION__, "Determinant of the CNEO position Jacobian is small! "// &
1117 0 : "(Central difference) "//TRIM(cp_to_string(det))//" Using pseudoinverse.")
1118 : END IF
1119 0 : CALL invert_matrix_3x3(jac, jac_inv, det, try_svd=.TRUE.)
1120 : END IF
1121 2380 : df = -RESHAPE(MATMUL(jac_inv, RESHAPE(r, [3, 1])), [3])
1122 560 : df_norm = NORM2(df)
1123 560 : f_tmp = f
1124 140 : r_tmp = r
1125 560 : g0 = NORM2(r_tmp)
1126 560 : f = f_tmp + df
1127 140 : CALL atom_solve_cneo(fmat, f, utrans, wfn, ener, pmat, r, distance, nsgf, nne)
1128 560 : g1 = NORM2(r)
1129 140 : step = 1.0_dp
1130 140 : DO WHILE (g1 >= g0)
1131 : ! line search
1132 0 : IF (step < 0.0101_dp) THEN
1133 0 : CPWARN("CNEO nuclear position constraint solver line search failure.")
1134 0 : EXIT
1135 : END IF
1136 0 : g0p = -g0/(step*df_norm)
1137 0 : step = step*MAX(-g0p/(2.0_dp*(g1 - g0 - g0p)), 0.1_dp)
1138 0 : f = f_tmp + step*df
1139 0 : CALL atom_solve_cneo(fmat, f, utrans, wfn, ener, pmat, r, distance, nsgf, nne)
1140 140 : g1 = NORM2(r)
1141 : END DO
1142 280 : IF (iter >= max_iter) THEN
1143 : CALL cp_warn(__LOCATION__, "CNEO nuclear position constraint solver failed to "// &
1144 : "converge in "//TRIM(cp_to_string(max_iter))//" steps. "// &
1145 : "Nuclear position error (x,y,z): "//TRIM(cp_to_string(r(1)))// &
1146 : ", "//TRIM(cp_to_string(r(2)))//", "//TRIM(cp_to_string(r(3)))// &
1147 0 : ". This does not hurt as long as it is not the final SCF iteration.")
1148 0 : EXIT
1149 : END IF
1150 : END DO
1151 46 : DEALLOCATE (ener)
1152 46 : rho%e_core = trace_r_AxB(core, nsgf, pmat, nsgf, nsgf, nsgf)
1153 :
1154 : ! decontract the density matrix
1155 : ! first use ga_Vlocal_gb to store the decompressed form
1156 : CALL dgemm("N", "N", nsotot, nsgf, nsgf, 1.0_dp, my_gcc_h, nsotot, pmat, nsgf, &
1157 46 : 0.0_dp, work, nsotot)
1158 : CALL dgemm("N", "T", nsotot, nsotot, nsgf, 1.0_dp, work, nsotot, my_gcc_h, nsotot, &
1159 46 : 0.0_dp, int_local_h, nsotot)
1160 : CALL dgemm("N", "N", nsotot, nsgf, nsgf, 1.0_dp, my_gcc_s, nsotot, pmat, nsgf, &
1161 46 : 0.0_dp, work, nsotot)
1162 : CALL dgemm("N", "T", nsotot, nsotot, nsgf, 1.0_dp, work, nsotot, my_gcc_s, nsotot, &
1163 46 : 0.0_dp, int_local_s, nsotot)
1164 46 : DEALLOCATE (work)
1165 : ! compress the density matrix
1166 46 : cpc_h => rho%cpc_h
1167 46 : cpc_s => rho%cpc_s
1168 46 : CALL cneo_gather(int_local_h, cpc_h, npsgf, n2oindex)
1169 46 : CALL cneo_gather(int_local_s, cpc_s, npsgf, n2oindex)
1170 : ! restore ga_Vlocal_gb to zeros
1171 305578 : int_local_h = 0.0_dp
1172 305578 : int_local_s = 0.0_dp
1173 :
1174 : ! construct the nuclear density and its Hartree potential
1175 : ! rho_rad_h and vrho_rad_h should contain the -Zeff factor
1176 : ! mostly copied from qs_rho_atom_methods::calculate_rho_atom
1177 46 : NULLIFY (harmonics, gg, vgg)
1178 46 : CALL get_cneo_potential(potential, harmonics=harmonics, gg=gg, vgg=vgg)
1179 46 : rho_rad_h => rho%rho_rad_h
1180 46 : rho_rad_s => rho%rho_rad_s
1181 58696 : rho_rad_h = 0.0_dp
1182 58696 : rho_rad_s = 0.0_dp
1183 46 : vrho_rad_h => rho%vrho_rad_h
1184 46 : vrho_rad_s => rho%vrho_rad_s
1185 58696 : vrho_rad_h = 0.0_dp
1186 58696 : vrho_rad_s = 0.0_dp
1187 46 : my_CG => harmonics%my_CG
1188 46 : max_iso_not0 = harmonics%max_iso_not0
1189 46 : max_s_harm = harmonics%max_s_harm
1190 46 : lmax_expansion = indso(1, max_iso_not0)
1191 :
1192 184 : ALLOCATE (CPCH_sphere(nsoset(maxl), nsoset(maxl)))
1193 138 : ALLOCATE (CPCS_sphere(nsoset(maxl), nsoset(maxl)))
1194 46 : j = 0
1195 46 : m1s = 0
1196 460 : DO iset1 = 1, nset
1197 414 : m2s = 0
1198 414 : n1s = nsoset(lmax(iset1))
1199 2484 : DO iset2 = 1, iset1
1200 :
1201 : CALL get_none0_cg_list(my_CG, lmin(iset1), lmax(iset1), lmin(iset2), lmax(iset2), &
1202 2070 : max_s_harm, lmax_expansion, cg_list, cg_n_list, max_iso_not0_local)
1203 2070 : CPASSERT(max_iso_not0_local <= max_iso_not0)
1204 :
1205 2070 : n2s = nsoset(lmax(iset2))
1206 4140 : DO ipgf1 = 1, npgf(iset1)
1207 2070 : iso1_first = nsoset(lmin(iset1) - 1) + 1 + n1s*(ipgf1 - 1) + m1s
1208 2070 : iso1_last = nsoset(lmax(iset1)) + n1s*(ipgf1 - 1) + m1s
1209 2070 : size1 = iso1_last - iso1_first + 1
1210 2070 : iso1_first = o2nindex(iso1_first)
1211 2070 : iso1_last = o2nindex(iso1_last)
1212 2070 : i1 = iso1_last - iso1_first + 1
1213 2070 : CPASSERT(size1 == i1)
1214 2070 : i1 = nsoset(lmin(iset1) - 1) + 1
1215 :
1216 2070 : IF (iset2 == iset1) THEN
1217 : npgf2 = ipgf1
1218 : ELSE
1219 1656 : npgf2 = npgf(iset2)
1220 : END IF
1221 6210 : DO ipgf2 = 1, npgf2
1222 2070 : j = j + 1
1223 2070 : iso2_first = nsoset(lmin(iset2) - 1) + 1 + n2s*(ipgf2 - 1) + m2s
1224 2070 : iso2_last = nsoset(lmax(iset2)) + n2s*(ipgf2 - 1) + m2s
1225 2070 : size2 = iso2_last - iso2_first + 1
1226 2070 : iso2_first = o2nindex(iso2_first)
1227 2070 : iso2_last = o2nindex(iso2_last)
1228 2070 : i2 = iso2_last - iso2_first + 1
1229 2070 : CPASSERT(size2 == i2)
1230 2070 : i2 = nsoset(lmin(iset2) - 1) + 1
1231 :
1232 2070 : IF (iset2 == iset1 .AND. ipgf2 == ipgf1) THEN
1233 414 : factor = -zeff
1234 : ELSE
1235 1656 : factor = -2.0_dp*zeff
1236 : END IF
1237 :
1238 2070 : CPCH_sphere = 0.0_dp
1239 2070 : CPCS_sphere = 0.0_dp
1240 19826 : CPCH_sphere(i1:i1 + size1 - 1, i2:i2 + size2 - 1) = cpc_h(iso1_first:iso1_last, iso2_first:iso2_last)
1241 19826 : CPCS_sphere(i1:i1 + size1 - 1, i2:i2 + size2 - 1) = cpc_s(iso1_first:iso1_last, iso2_first:iso2_last)
1242 20470 : DO iso = 1, max_iso_not0_local
1243 16330 : l_iso = indso(1, iso)
1244 44298 : DO icg = 1, cg_n_list(iso)
1245 25898 : iso1 = cg_list(1, icg, iso)
1246 25898 : iso2 = cg_list(2, icg, iso)
1247 :
1248 25898 : l1 = indso(1, iso1)
1249 25898 : l2 = indso(1, iso2)
1250 :
1251 25898 : l = indso(1, iso1) + indso(1, iso2)
1252 25898 : CPASSERT(l <= lmax_expansion)
1253 :
1254 : rho_rad_h(:, iso) = rho_rad_h(:, iso) + gg(:, l, j)* &
1255 2615698 : CPCH_sphere(iso1, iso2)*my_CG(iso1, iso2, iso)*factor
1256 :
1257 : rho_rad_s(:, iso) = rho_rad_s(:, iso) + gg(:, l, j)* &
1258 2615698 : CPCS_sphere(iso1, iso2)*my_CG(iso1, iso2, iso)*factor
1259 :
1260 : vrho_rad_h(:, iso) = vrho_rad_h(:, iso) + vgg(:, l, l_iso, j)* &
1261 2615698 : CPCH_sphere(iso1, iso2)*my_CG(iso1, iso2, iso)*factor
1262 :
1263 : vrho_rad_s(:, iso) = vrho_rad_s(:, iso) + vgg(:, l, l_iso, j)* &
1264 2632028 : CPCS_sphere(iso1, iso2)*my_CG(iso1, iso2, iso)*factor
1265 : END DO ! icg
1266 : END DO ! iso
1267 : END DO ! ipgf2
1268 : END DO ! ipgf1
1269 2484 : m2s = m2s + maxso
1270 : END DO ! iset2
1271 460 : m1s = m1s + maxso
1272 : END DO ! iset1
1273 46 : DEALLOCATE (CPCH_sphere, CPCS_sphere)
1274 :
1275 46 : CALL timestop(handle)
1276 :
1277 92 : END SUBROUTINE calculate_rhoz_cneo
1278 :
1279 : ! **************************************************************************************************
1280 : !> \brief Mostly copied from hartree_local_methods::Vh_1c_atom_integrals
1281 : !> \param rhoz_cneo ...
1282 : !> \param zeff ...
1283 : !> \param aVh1b_hh ...
1284 : !> \param aVh1b_ss ...
1285 : !> \param aVh1b_00 ...
1286 : !> \param Vh1_h ...
1287 : !> \param Vh1_s ...
1288 : !> \param max_iso_not0_elec ...
1289 : !> \param max_iso_not0_nuc ...
1290 : !> \param max_s_harm ...
1291 : !> \param llmax ...
1292 : !> \param cg_list ...
1293 : !> \param cg_n_list ...
1294 : !> \param nset ...
1295 : !> \param npgf ...
1296 : !> \param lmin ...
1297 : !> \param lmax ...
1298 : !> \param nsotot ...
1299 : !> \param maxso ...
1300 : !> \param nchan_0 ...
1301 : !> \param gsph ...
1302 : !> \param g0_h_w ...
1303 : !> \param my_CG ...
1304 : !> \param Qlm_gg ...
1305 : ! **************************************************************************************************
1306 46 : SUBROUTINE Vh_1c_nuc_integrals(rhoz_cneo, zeff, &
1307 46 : aVh1b_hh, aVh1b_ss, aVh1b_00, Vh1_h, Vh1_s, &
1308 : max_iso_not0_elec, max_iso_not0_nuc, &
1309 46 : max_s_harm, llmax, cg_list, cg_n_list, &
1310 : nset, npgf, lmin, lmax, nsotot, maxso, nchan_0, gsph, &
1311 46 : g0_h_w, my_CG, Qlm_gg)
1312 :
1313 : TYPE(rhoz_cneo_type), POINTER :: rhoz_cneo
1314 : REAL(KIND=dp), INTENT(IN) :: zeff
1315 : REAL(KIND=dp), DIMENSION(:, :) :: aVh1b_hh, aVh1b_ss, aVh1b_00
1316 : REAL(KIND=dp), DIMENSION(:, :), POINTER :: Vh1_h, Vh1_s
1317 : INTEGER, INTENT(IN) :: max_iso_not0_elec, max_iso_not0_nuc, &
1318 : max_s_harm, llmax
1319 : INTEGER, DIMENSION(:, :, :) :: cg_list
1320 : INTEGER, DIMENSION(:) :: cg_n_list
1321 : INTEGER, INTENT(IN) :: nset
1322 : INTEGER, DIMENSION(:), POINTER :: npgf, lmin, lmax
1323 : INTEGER, INTENT(IN) :: nsotot, maxso, nchan_0
1324 : REAL(KIND=dp), DIMENSION(:, :), POINTER :: gsph
1325 : REAL(KIND=dp), DIMENSION(:, 0:) :: g0_h_w
1326 : REAL(KIND=dp), DIMENSION(:, :, :), POINTER :: my_CG, Qlm_gg
1327 :
1328 : INTEGER :: icg, ipgf1, ipgf2, ir, is1, is2, iset1, &
1329 : iset2, iso, iso1, iso2, l_ang, m1, m2, &
1330 : max_iso_not0_local, n1, n2, nr
1331 : REAL(KIND=dp) :: gVg_0, gVg_h, gVg_s
1332 :
1333 : ! Calculate the integrals of the potential with 2 primitives
1334 305578 : aVh1b_hh = 0.0_dp
1335 305578 : aVh1b_ss = 0.0_dp
1336 305578 : aVh1b_00 = 0.0_dp
1337 :
1338 46 : nr = SIZE(gsph, 1)
1339 :
1340 46 : m1 = 0
1341 460 : DO iset1 = 1, nset
1342 414 : n1 = nsoset(lmax(iset1))
1343 414 : m2 = 0
1344 4140 : DO iset2 = 1, nset
1345 : CALL get_none0_cg_list(my_CG, lmin(iset1), lmax(iset1), lmin(iset2), lmax(iset2), &
1346 3726 : max_s_harm, llmax, cg_list, cg_n_list, max_iso_not0_local)
1347 :
1348 3726 : n2 = nsoset(lmax(iset2))
1349 7452 : DO ipgf1 = 1, npgf(iset1)
1350 11178 : DO ipgf2 = 1, npgf(iset2)
1351 37260 : DO iso = 1, MIN(max_iso_not0_elec, max_iso_not0_nuc)
1352 62376 : DO icg = 1, cg_n_list(iso)
1353 25116 : is1 = cg_list(1, icg, iso)
1354 25116 : is2 = cg_list(2, icg, iso)
1355 :
1356 25116 : iso1 = is1 + n1*(ipgf1 - 1) + m1
1357 25116 : iso2 = is2 + n2*(ipgf2 - 1) + m2
1358 25116 : gVg_h = 0.0_dp
1359 25116 : gVg_s = 0.0_dp
1360 :
1361 1280916 : DO ir = 1, nr
1362 1255800 : gVg_h = gVg_h + gsph(ir, iso1)*gsph(ir, iso2)*Vh1_h(ir, iso)
1363 1280916 : gVg_s = gVg_s + gsph(ir, iso1)*gsph(ir, iso2)*Vh1_s(ir, iso)
1364 : END DO ! ir
1365 :
1366 25116 : aVh1b_hh(iso1, iso2) = aVh1b_hh(iso1, iso2) + gVg_h*my_CG(is1, is2, iso)
1367 58650 : aVh1b_ss(iso1, iso2) = aVh1b_ss(iso1, iso2) + gVg_s*my_CG(is1, is2, iso)
1368 :
1369 : END DO !icg
1370 : END DO ! iso
1371 63342 : DO iso = max_iso_not0_elec + 1, max_iso_not0_nuc
1372 81742 : DO icg = 1, cg_n_list(iso)
1373 18400 : is1 = cg_list(1, icg, iso)
1374 18400 : is2 = cg_list(2, icg, iso)
1375 :
1376 18400 : iso1 = is1 + n1*(ipgf1 - 1) + m1
1377 18400 : iso2 = is2 + n2*(ipgf2 - 1) + m2
1378 18400 : gVg_s = 0.0_dp
1379 :
1380 938400 : DO ir = 1, nr
1381 938400 : gVg_s = gVg_s + gsph(ir, iso1)*gsph(ir, iso2)*Vh1_s(ir, iso)
1382 : END DO ! ir
1383 :
1384 78016 : aVh1b_ss(iso1, iso2) = aVh1b_ss(iso1, iso2) + gVg_s*my_CG(is1, is2, iso)
1385 :
1386 : END DO !icg
1387 : END DO ! iso
1388 40986 : DO iso = 1, MIN(nchan_0, max_iso_not0_nuc)
1389 33534 : l_ang = indso(1, iso)
1390 1710234 : gVg_0 = SUM(Vh1_s(:, iso)*g0_h_w(:, l_ang))
1391 62376 : DO icg = 1, cg_n_list(iso)
1392 25116 : is1 = cg_list(1, icg, iso)
1393 25116 : is2 = cg_list(2, icg, iso)
1394 :
1395 25116 : iso1 = is1 + n1*(ipgf1 - 1) + m1
1396 25116 : iso2 = is2 + n2*(ipgf2 - 1) + m2
1397 :
1398 58650 : aVh1b_00(iso1, iso2) = aVh1b_00(iso1, iso2) + gVg_0*Qlm_gg(iso1, iso2, iso)
1399 :
1400 : END DO !icg
1401 : END DO ! iso
1402 : END DO ! ipgf2
1403 : END DO ! ipgf1
1404 4140 : m2 = m2 + maxso
1405 : END DO ! iset2
1406 460 : m1 = m1 + maxso
1407 : END DO !iset1
1408 :
1409 46 : CALL daxpy(nsotot*nsotot, -zeff, aVh1b_hh, 1, rhoz_cneo%ga_Vlocal_gb_h, 1)
1410 46 : CALL daxpy(nsotot*nsotot, -zeff, aVh1b_ss, 1, rhoz_cneo%ga_Vlocal_gb_s, 1)
1411 46 : CALL daxpy(nsotot*nsotot, zeff, aVh1b_00, 1, rhoz_cneo%ga_Vlocal_gb_h, 1)
1412 46 : CALL daxpy(nsotot*nsotot, zeff, aVh1b_00, 1, rhoz_cneo%ga_Vlocal_gb_s, 1)
1413 :
1414 46 : END SUBROUTINE Vh_1c_nuc_integrals
1415 :
1416 : ! **************************************************************************************************
1417 : !> \brief Analytical inversion of a 3x3 matrix
1418 : !> \param matrix ...
1419 : !> \param inv_matrix ...
1420 : !> \param det ...
1421 : !> \param try_svd ...
1422 : ! **************************************************************************************************
1423 140 : SUBROUTINE invert_matrix_3x3(matrix, inv_matrix, det, try_svd)
1424 : REAL(KIND=dp), DIMENSION(3, 3), INTENT(IN) :: matrix
1425 : REAL(KIND=dp), DIMENSION(3, 3), INTENT(OUT) :: inv_matrix
1426 : REAL(KIND=dp), INTENT(OUT) :: det
1427 : LOGICAL, INTENT(IN), OPTIONAL :: try_svd
1428 :
1429 : LOGICAL :: my_try_svd
1430 :
1431 140 : my_try_svd = .FALSE.
1432 140 : IF (PRESENT(try_svd)) my_try_svd = try_svd
1433 :
1434 : det = matrix(1, 1)*(matrix(2, 2)*matrix(3, 3) - matrix(2, 3)*matrix(3, 2)) &
1435 : - matrix(1, 2)*(matrix(2, 1)*matrix(3, 3) - matrix(2, 3)*matrix(3, 1)) &
1436 140 : + matrix(1, 3)*(matrix(2, 1)*matrix(3, 2) - matrix(2, 2)*matrix(3, 1))
1437 140 : IF (ABS(det) < 1.0E-8_dp) THEN
1438 0 : IF (my_try_svd) THEN
1439 : ! pseudo inverse using SVD
1440 0 : CALL get_pseudo_inverse_svd(matrix, inv_matrix, 1.0E-6_dp, det)
1441 : ELSE
1442 0 : inv_matrix = 0.0_dp
1443 : END IF
1444 : ELSE
1445 140 : inv_matrix(1, 1) = matrix(2, 2)*matrix(3, 3) - matrix(2, 3)*matrix(3, 2)
1446 140 : inv_matrix(1, 2) = matrix(1, 3)*matrix(3, 2) - matrix(1, 2)*matrix(3, 3)
1447 140 : inv_matrix(1, 3) = matrix(1, 2)*matrix(2, 3) - matrix(1, 3)*matrix(2, 2)
1448 140 : inv_matrix(2, 1) = matrix(2, 3)*matrix(3, 1) - matrix(2, 1)*matrix(3, 3)
1449 140 : inv_matrix(2, 2) = matrix(1, 1)*matrix(3, 3) - matrix(1, 3)*matrix(3, 1)
1450 140 : inv_matrix(2, 3) = matrix(1, 3)*matrix(2, 1) - matrix(1, 1)*matrix(2, 3)
1451 140 : inv_matrix(3, 1) = matrix(2, 1)*matrix(3, 2) - matrix(2, 2)*matrix(3, 1)
1452 140 : inv_matrix(3, 2) = matrix(1, 2)*matrix(3, 1) - matrix(1, 1)*matrix(3, 2)
1453 140 : inv_matrix(3, 3) = matrix(1, 1)*matrix(2, 2) - matrix(1, 2)*matrix(2, 1)
1454 1820 : inv_matrix = inv_matrix/det
1455 : END IF
1456 140 : END SUBROUTINE invert_matrix_3x3
1457 :
1458 : END MODULE qs_cneo_methods
|