(git:15c1bfc)
Loading...
Searching...
No Matches
qs_cneo_utils.F
Go to the documentation of this file.
1!--------------------------------------------------------------------------------------------------!
2! CP2K: A general program to perform molecular dynamics simulations !
3! Copyright 2000-2025 CP2K developers group <https://cp2k.org> !
4! !
5! SPDX-License-Identifier: GPL-2.0-or-later !
6!--------------------------------------------------------------------------------------------------!
7
8! **************************************************************************************************
9!> \brief Utility functions for 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! **************************************************************************************************
16 USE ao_util, ONLY: trace_r_axb
19 USE kinds, ONLY: dp
21 USE orbital_pointers, ONLY: indso,&
22 nsoset
28#include "./base/base_uses.f90"
29
30 IMPLICIT NONE
31
32 PRIVATE
33
34 ! *** Global parameters ***
35 CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qs_cneo_utils'
36
37 ! *** Public subroutines ***
40
41CONTAINS
42
43! **************************************************************************************************
44!> \brief Mostly copied from qs_rho_atom_methods::init_rho_atom
45!> \param my_CG ...
46!> \param lcleb ...
47!> \param maxl ...
48!> \param llmax ...
49! **************************************************************************************************
50 SUBROUTINE create_my_cg_cneo(my_CG, lcleb, maxl, llmax)
51
52 REAL(kind=dp), DIMENSION(:, :, :), POINTER :: my_cg
53 INTEGER, INTENT(IN) :: lcleb, maxl, llmax
54
55 INTEGER :: il, iso, iso1, iso2, l1, l1l2, l2, lc1, &
56 lc2, lp, m1, m2, mm, mp
57 REAL(kind=dp), ALLOCATABLE, DIMENSION(:, :) :: rga
58
59! *** allocate calculate the CG coefficients up to the maxl ***
60 CALL clebsch_gordon_init(lcleb)
61
62 ALLOCATE (rga(lcleb, 2))
63 DO lc1 = 0, maxl
64 DO iso1 = nsoset(lc1 - 1) + 1, nsoset(lc1)
65 l1 = indso(1, iso1)
66 m1 = indso(2, iso1)
67 DO lc2 = 0, maxl
68 DO iso2 = nsoset(lc2 - 1) + 1, nsoset(lc2)
69 l2 = indso(1, iso2)
70 m2 = indso(2, iso2)
71 CALL clebsch_gordon(l1, m1, l2, m2, rga)
72 IF (l1 + l2 > llmax) THEN
73 l1l2 = llmax
74 ELSE
75 l1l2 = l1 + l2
76 END IF
77 mp = m1 + m2
78 mm = m1 - m2
79 IF (m1*m2 < 0 .OR. (m1*m2 == 0 .AND. (m1 < 0 .OR. m2 < 0))) THEN
80 mp = -abs(mp)
81 mm = -abs(mm)
82 ELSE
83 mp = abs(mp)
84 mm = abs(mm)
85 END IF
86 DO lp = mod(l1 + l2, 2), l1l2, 2
87 il = lp/2 + 1
88 IF (abs(mp) <= lp) THEN
89 IF (mp >= 0) THEN
90 iso = nsoset(lp - 1) + lp + 1 + mp
91 ELSE
92 iso = nsoset(lp - 1) + lp + 1 - abs(mp)
93 END IF
94 my_cg(iso1, iso2, iso) = rga(il, 1)
95 END IF
96 IF (mp /= mm .AND. abs(mm) <= lp) THEN
97 IF (mm >= 0) THEN
98 iso = nsoset(lp - 1) + lp + 1 + mm
99 ELSE
100 iso = nsoset(lp - 1) + lp + 1 - abs(mm)
101 END IF
102 my_cg(iso1, iso2, iso) = rga(il, 2)
103 END IF
104 END DO
105 END DO ! iso2
106 END DO ! lc2
107 END DO ! iso1
108 END DO ! lc1
109 DEALLOCATE (rga)
111
112 END SUBROUTINE create_my_cg_cneo
113
114! **************************************************************************************************
115!> \brief Mostly copied from qs_harmonics_atom::create_harmonics_atom
116!> \param harmonics ...
117!> \param my_CG ...
118!> \param llmax ...
119!> \param maxs ...
120!> \param max_s_harm ...
121! **************************************************************************************************
122 SUBROUTINE create_harmonics_atom_cneo(harmonics, my_CG, llmax, maxs, max_s_harm)
123
124 TYPE(harmonics_atom_type), POINTER :: harmonics
125 REAL(kind=dp), DIMENSION(:, :, :), POINTER :: my_cg
126 INTEGER, INTENT(IN) :: llmax, maxs, max_s_harm
127
128 INTEGER :: i, is
129
130 cpassert(ASSOCIATED(harmonics))
131
132 harmonics%max_s_harm = max_s_harm
133 harmonics%llmax = llmax
134
135 NULLIFY (harmonics%my_CG, harmonics%my_CG_dxyz, harmonics%my_CG_dxyz_asym)
136 CALL reallocate(harmonics%my_CG, 1, maxs, 1, maxs, 1, max_s_harm)
137
138 DO i = 1, max_s_harm
139 DO is = 1, maxs
140 harmonics%my_CG(1:maxs, is, i) = my_cg(1:maxs, is, i)
141 END DO
142 END DO
143
144 END SUBROUTINE create_harmonics_atom_cneo
145
146! **************************************************************************************************
147!> \brief Mostly copied from qs_harmonics_atom::get_maxl_CG
148!> \param harmonics ...
149!> \param orb_basis ...
150!> \param llmax ...
151!> \param max_s_harm ...
152! **************************************************************************************************
153 SUBROUTINE get_maxl_cg_cneo(harmonics, orb_basis, llmax, max_s_harm)
154
155 TYPE(harmonics_atom_type), POINTER :: harmonics
156 TYPE(gto_basis_set_type), POINTER :: orb_basis
157 INTEGER, INTENT(IN) :: llmax, max_s_harm
158
159 INTEGER :: is1, is2, itmp, max_iso_not0, nset
160 INTEGER, DIMENSION(:), POINTER :: lmax, lmin
161
162 cpassert(ASSOCIATED(harmonics))
163
164 CALL get_gto_basis_set(gto_basis_set=orb_basis, lmax=lmax, lmin=lmin, nset=nset)
165
166 ! *** Assign indices for the non null CG coefficients ***
167 max_iso_not0 = 0
168 DO is1 = 1, nset
169 DO is2 = 1, nset
170 CALL get_none0_cg_list(harmonics%my_CG, &
171 lmin(is1), lmax(is1), lmin(is2), lmax(is2), &
172 max_s_harm, llmax, max_iso_not0=itmp)
173 max_iso_not0 = max(max_iso_not0, itmp)
174 END DO ! is2
175 END DO ! is1
176 harmonics%max_iso_not0 = max_iso_not0
177
178 END SUBROUTINE get_maxl_cg_cneo
179
180! **************************************************************************************************
181!> \brief Mostly copied from atom_utils::atom_solve
182!> \param hmat ...
183!> \param f ...
184!> \param umat ...
185!> \param orb ...
186!> \param ener ...
187!> \param pmat ...
188!> \param r ...
189!> \param dist ...
190!> \param nb ...
191!> \param nv ...
192! **************************************************************************************************
193 SUBROUTINE atom_solve_cneo(hmat, f, umat, orb, ener, pmat, r, dist, nb, nv)
194
195 REAL(kind=dp), DIMENSION(:, :), INTENT(IN) :: hmat
196 REAL(kind=dp), DIMENSION(3), INTENT(IN) :: f
197 REAL(kind=dp), DIMENSION(:, :), INTENT(IN) :: umat
198 REAL(kind=dp), DIMENSION(:, :), INTENT(INOUT) :: orb
199 REAL(kind=dp), DIMENSION(:), INTENT(INOUT) :: ener
200 REAL(kind=dp), DIMENSION(:, :), INTENT(INOUT) :: pmat
201 REAL(kind=dp), DIMENSION(3), INTENT(INOUT) :: r
202 REAL(kind=dp), DIMENSION(:, :, :), INTENT(IN) :: dist
203 INTEGER, INTENT(IN) :: nb, nv
204
205 INTEGER :: info, lwork, m, n
206 REAL(kind=dp), ALLOCATABLE, DIMENSION(:) :: w, work
207 REAL(kind=dp), ALLOCATABLE, DIMENSION(:, :) :: a, b, h_fx
208
209 cpassert(nb >= nv)
210
211 orb = 0._dp
212 n = nb
213 m = nv
214 IF (n > 0 .AND. m > 0) THEN
215 lwork = max(n*n, n + 100)
216 ALLOCATE (a(m, m), b(n, m), w(m), work(lwork))
217 IF (dot_product(f, f) /= 0.0_dp) THEN
218 ALLOCATE (h_fx(n, n))
219 h_fx(1:n, 1:n) = hmat(1:n, 1:n) + f(1)*dist(1:n, 1:n, 1) + &
220 f(2)*dist(1:n, 1:n, 2) + f(3)*dist(1:n, 1:n, 3)
221 CALL dgemm("N", "N", n, m, n, 1.0_dp, h_fx, n, umat, n, 0.0_dp, b, n)
222 DEALLOCATE (h_fx)
223 ELSE
224 CALL dgemm("N", "N", n, m, n, 1.0_dp, hmat, n, umat, n, 0.0_dp, b, n)
225 END IF
226 CALL dgemm("T", "N", m, m, n, 1.0_dp, umat, n, b, n, 0.0_dp, a, m)
227 CALL dsyev("V", "U", m, a, m, w, work, lwork, info)
228 CALL dgemm("N", "N", n, m, m, 1.0_dp, umat, n, a, m, 0.0_dp, b, n)
229
230 m = min(m, SIZE(orb, 2))
231 orb(1:n, 1:m) = b(1:n, 1:m)
232 ener(1:m) = w(1:m)
233
234 DEALLOCATE (a, b, w, work)
235
236 ! calculate the density matrix using the orbital with the lowest orbital energy
237 pmat = 0.0_dp
238 CALL dger(n, n, 1.0_dp, orb(:, 1), 1, orb(:, 1), 1, pmat, n)
239 ! calculate the expectation position (basis center as the origin)
240 r = (/trace_r_axb(dist(1:n, 1:n, 1), n, pmat, n, n, n), &
241 trace_r_axb(dist(1:n, 1:n, 2), n, pmat, n, n, n), &
242 trace_r_axb(dist(1:n, 1:n, 3), n, pmat, n, n, n)/)
243 END IF
244
245 END SUBROUTINE atom_solve_cneo
246
247! **************************************************************************************************
248!> \brief Mostly copied from qs_oce_methods::prj_gather
249!> \param ain ...
250!> \param aout ...
251!> \param nbas ...
252!> \param n2oindex ...
253! **************************************************************************************************
254 SUBROUTINE cneo_gather(ain, aout, nbas, n2oindex)
255
256 REAL(kind=dp), DIMENSION(:, :), INTENT(IN) :: ain
257 REAL(kind=dp), DIMENSION(:, :), INTENT(INOUT) :: aout
258 INTEGER, INTENT(IN) :: nbas
259 INTEGER, DIMENSION(:), POINTER :: n2oindex
260
261 INTEGER :: i, ip, j, jp
262
263 DO i = 1, nbas
264 ip = n2oindex(i)
265 DO j = 1, nbas
266 jp = n2oindex(j)
267 aout(j, i) = ain(jp, ip)
268 END DO
269 END DO
270
271 END SUBROUTINE cneo_gather
272
273! **************************************************************************************************
274!> \brief Mostly copied from qs_oce_methods::prj_scatter
275!> \param ain ...
276!> \param aout ...
277!> \param nbas ...
278!> \param n2oindex ...
279! **************************************************************************************************
280 SUBROUTINE cneo_scatter(ain, aout, nbas, n2oindex)
281
282 REAL(kind=dp), DIMENSION(:, :), INTENT(IN) :: ain
283 REAL(kind=dp), DIMENSION(:, :), INTENT(INOUT) :: aout
284 INTEGER, INTENT(IN) :: nbas
285 INTEGER, DIMENSION(:), POINTER :: n2oindex
286
287 INTEGER :: i, ip, j, jp
288
289 DO i = 1, nbas
290 ip = n2oindex(i)
291 DO j = 1, nbas
292 jp = n2oindex(j)
293 aout(jp, ip) = aout(jp, ip) + ain(j, i)
294 END DO
295 END DO
296
297 END SUBROUTINE cneo_scatter
298
299END MODULE qs_cneo_utils
static void dgemm(const char transa, const char transb, const int m, const int n, const int k, const double alpha, const double *a, const int lda, const double *b, const int ldb, const double beta, double *c, const int ldc)
Convenient wrapper to hide Fortran nature of dgemm_, swapping a and b.
All kind of helpful little routines.
Definition ao_util.F:14
pure real(dp) function, public trace_r_axb(a, lda, b, ldb, m, n)
...
Definition ao_util.F:331
subroutine, public get_gto_basis_set(gto_basis_set, name, aliases, norm_type, kind_radius, ncgf, nset, nsgf, cgf_symbol, sgf_symbol, norm_cgf, set_radius, lmax, lmin, lx, ly, lz, m, ncgf_set, npgf, nsgf_set, nshell, cphi, pgf_radius, sphi, scon, zet, first_cgf, first_sgf, l, last_cgf, last_sgf, n, gcc, maxco, maxl, maxpgf, maxsgf_set, maxshell, maxso, nco_sum, npgf_sum, nshell_sum, maxder, short_kind_radius, npgf_seg_sum)
...
Defines the basic variable types.
Definition kinds.F:23
integer, parameter, public dp
Definition kinds.F:34
Utility routines for the memory handling.
Provides Cartesian and spherical orbital pointers and indices.
integer, dimension(:), allocatable, public nsoset
integer, dimension(:, :), allocatable, public indso
Utility functions for CNEO-DFT (see J. Chem. Theory Comput. 2025, 21, 16, 7865–7877)
subroutine, public get_maxl_cg_cneo(harmonics, orb_basis, llmax, max_s_harm)
Mostly copied from qs_harmonics_atom::get_maxl_CG.
subroutine, public create_my_cg_cneo(my_cg, lcleb, maxl, llmax)
Mostly copied from qs_rho_atom_methods::init_rho_atom.
subroutine, public cneo_scatter(ain, aout, nbas, n2oindex)
Mostly copied from qs_oce_methods::prj_scatter.
subroutine, public atom_solve_cneo(hmat, f, umat, orb, ener, pmat, r, dist, nb, nv)
Mostly copied from atom_utils::atom_solve.
subroutine, public cneo_gather(ain, aout, nbas, n2oindex)
Mostly copied from qs_oce_methods::prj_gather.
subroutine, public create_harmonics_atom_cneo(harmonics, my_cg, llmax, maxs, max_s_harm)
Mostly copied from qs_harmonics_atom::create_harmonics_atom.
Calculate spherical harmonics.
subroutine, public clebsch_gordon_init(l)
...
subroutine, public clebsch_gordon_deallocate()
...