(git:e7e05ae)
pao_potentials.F
Go to the documentation of this file.
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 !> \brief Factory routines for potentials used e.g. by pao_param_exp and pao_ml
10 !> \author Ole Schuett
11 ! **************************************************************************************************
13  USE ai_overlap, ONLY: overlap_aab
14  USE ao_util, ONLY: exp_radius
16  USE basis_set_types, ONLY: gto_basis_set_type
17  USE cell_types, ONLY: cell_type,&
18  pbc
19  USE kinds, ONLY: dp
20  USE mathconstants, ONLY: gamma1
21  USE mathlib, ONLY: multinomial
22  USE orbital_pointers, ONLY: indco,&
23  ncoset,&
24  orbital_pointers_maxl => current_maxl
25  USE particle_types, ONLY: particle_type
26  USE qs_environment_types, ONLY: get_qs_env,&
27  qs_environment_type
28  USE qs_kind_types, ONLY: get_qs_kind,&
29  qs_kind_type
30 #include "./base/base_uses.f90"
31 
32  IMPLICIT NONE
33 
34  PRIVATE
35 
36  CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'pao_potentials'
37 
39 
40 CONTAINS
41 
42 ! **************************************************************************************************
43 !> \brief Makes an educated guess for the initial potential based on positions of neighboring atoms
44 !> \param qs_env ...
45 !> \param iatom ...
46 !> \param block_V ...
47 ! **************************************************************************************************
48  SUBROUTINE pao_guess_initial_potential(qs_env, iatom, block_V)
49  TYPE(qs_environment_type), POINTER :: qs_env
50  INTEGER, INTENT(IN) :: iatom
51  REAL(dp), DIMENSION(:, :), INTENT(OUT) :: block_v
52 
53  CHARACTER(len=*), PARAMETER :: routinen = 'pao_guess_initial_potential'
54 
55  INTEGER :: handle, ikind, jatom, natoms
56  REAL(dp), DIMENSION(3) :: ra, rab, rb
57  TYPE(cell_type), POINTER :: cell
58  TYPE(gto_basis_set_type), POINTER :: basis_set
59  TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
60  TYPE(qs_kind_type), DIMENSION(:), POINTER :: qs_kind_set
61 
62  CALL timeset(routinen, handle)
63 
64  CALL get_qs_env(qs_env, &
65  cell=cell, &
66  particle_set=particle_set, &
67  qs_kind_set=qs_kind_set, &
68  natom=natoms)
69 
70  CALL get_atomic_kind(particle_set(iatom)%atomic_kind, kind_number=ikind)
71  CALL get_qs_kind(qs_kind_set(ikind), basis_set=basis_set)
72 
73  ! construct matrix block_V from neighboring atoms
74  block_v = 0.0_dp
75  DO jatom = 1, natoms
76  IF (jatom == iatom) cycle
77  ra = particle_set(iatom)%r
78  rb = particle_set(jatom)%r
79  rab = pbc(ra, rb, cell)
80  CALL pao_calc_gaussian(basis_set, block_v, rab=rab, lpot=0, beta=1.0_dp, weight=-1.0_dp)
81  END DO
82 
83  CALL timestop(handle)
84  END SUBROUTINE pao_guess_initial_potential
85 
86 ! **************************************************************************************************
87 !> \brief Calculates potential term of the form r**lpot * Exp(-beta*r**2)
88 !> One needs to call init_orbital_pointers(lpot) before calling pao_calc_gaussian().
89 !> \param basis_set ...
90 !> \param block_V potential term that is returned
91 !> \param block_D derivative of potential term wrt to Rab
92 !> \param Rab ...
93 !> \param lpot polynomial prefactor, r**lpot
94 !> \param beta exponent of the Gaussian
95 !> \param weight ...
96 !> \param min_shell ...
97 !> \param max_shell ...
98 !> \param min_l ...
99 !> \param max_l ...
100 ! **************************************************************************************************
101  SUBROUTINE pao_calc_gaussian(basis_set, block_V, block_D, Rab, lpot, beta, weight, min_shell, max_shell, min_l, max_l)
102  TYPE(gto_basis_set_type), POINTER :: basis_set
103  REAL(dp), DIMENSION(:, :), INTENT(OUT), OPTIONAL :: block_v
104  REAL(dp), DIMENSION(:, :, :), INTENT(OUT), &
105  OPTIONAL :: block_d
106  REAL(dp), DIMENSION(3) :: rab
107  INTEGER, INTENT(IN) :: lpot
108  REAL(dp), INTENT(IN) :: beta, weight
109  INTEGER, INTENT(IN), OPTIONAL :: min_shell, max_shell, min_l, max_l
110 
111  CHARACTER(len=*), PARAMETER :: routinen = 'pao_calc_gaussian'
112 
113  INTEGER :: handle, i, ic, iset, ishell, ishell_abs, jset, jshell, jshell_abs, la1_max, &
114  la1_min, la2_max, la2_min, lb_max, lb_min, n, na1, na2, nb, ncfga1, ncfga2, ncfgb, &
115  npgfa1, npgfa2, npgfb
116  REAL(dp) :: coeff, norm2
117  REAL(dp), DIMENSION(:), POINTER :: rpgfa1, rpgfa2, rpgfb, zeta1, zeta2, zetb
118  REAL(dp), DIMENSION(:, :), POINTER :: new_block_v, sab
119  REAL(dp), DIMENSION(:, :, :), POINTER :: dab, new_block_d, saab
120  REAL(dp), DIMENSION(:, :, :, :), POINTER :: daab
121 
122  CALL timeset(routinen, handle)
123 
124  cpassert(PRESENT(block_v) .NEQV. PRESENT(block_d)) ! just to keep the code simpler
125  cpassert(PRESENT(min_shell) .EQV. PRESENT(max_shell))
126  cpassert(PRESENT(min_l) .EQV. PRESENT(max_l))
127 
128  cpassert(mod(lpot, 2) == 0) ! otherwise it's not rotationally invariant
129  cpassert(orbital_pointers_maxl >= lpot) ! can't call init_orbital_pointers here, it's not thread-safe
130 
131  n = basis_set%nsgf ! primary basis-size
132 
133  IF (PRESENT(block_v)) THEN
134  cpassert(SIZE(block_v, 1) == n .AND. SIZE(block_v, 2) == n)
135  ALLOCATE (new_block_v(n, n))
136  new_block_v = 0.0_dp
137  END IF
138  IF (PRESENT(block_d)) THEN
139  cpassert(SIZE(block_d, 1) == n .AND. SIZE(block_d, 2) == n .AND. SIZE(block_d, 3) == 3)
140  ALLOCATE (new_block_d(n, n, 3))
141  new_block_d = 0.0_dp
142  END IF
143 
144  ! setup description of potential
145  lb_min = lpot
146  lb_max = lpot
147  ncfgb = ncoset(lb_max) - ncoset(lb_min - 1)
148  npgfb = 1 ! number of exponents
149  nb = npgfb*ncfgb
150 
151  ! initialize exponents
152  ALLOCATE (rpgfb(npgfb), zetb(npgfb))
153  rpgfb(1) = exp_radius(0, beta, 1.0e-12_dp, 1.0_dp) ! TODO get the EPS parameter from somewhere / precompute this elsewhere
154  zetb(1) = beta
155 
156  ! loop over all set/shell combination and fill block_V
157  DO iset = 1, basis_set%nset
158  DO jset = 1, basis_set%nset
159  DO ishell = 1, basis_set%nshell(iset)
160  DO jshell = 1, basis_set%nshell(jset)
161  IF (PRESENT(min_shell) .AND. PRESENT(max_shell)) THEN
162  ishell_abs = sum(basis_set%nshell(1:iset - 1)) + ishell
163  jshell_abs = sum(basis_set%nshell(1:jset - 1)) + jshell
164  IF (min(ishell_abs, jshell_abs) /= min_shell) cycle
165  IF (max(ishell_abs, jshell_abs) /= max_shell) cycle
166  END IF
167  IF (PRESENT(min_l) .AND. PRESENT(min_l)) THEN
168  IF (min(basis_set%l(ishell, iset), basis_set%l(jshell, jset)) /= min_l) cycle
169  IF (max(basis_set%l(ishell, iset), basis_set%l(jshell, jset)) /= max_l) cycle
170  END IF
171 
172  ! setup iset
173  la1_max = basis_set%l(ishell, iset)
174  la1_min = basis_set%l(ishell, iset)
175  npgfa1 = basis_set%npgf(iset)
176  ncfga1 = ncoset(la1_max) - ncoset(la1_min - 1)
177  na1 = npgfa1*ncfga1
178  zeta1 => basis_set%zet(:, iset)
179  rpgfa1 => basis_set%pgf_radius(:, iset)
180 
181  ! setup jset
182  la2_max = basis_set%l(jshell, jset)
183  la2_min = basis_set%l(jshell, jset)
184  npgfa2 = basis_set%npgf(jset)
185  ncfga2 = ncoset(la2_max) - ncoset(la2_min - 1)
186  na2 = npgfa2*ncfga2
187  zeta2 => basis_set%zet(:, jset)
188  rpgfa2 => basis_set%pgf_radius(:, jset)
189 
190  ! calculate integrals
191  IF (PRESENT(block_v)) THEN
192  ALLOCATE (saab(na1, na2, nb))
193  saab = 0.0_dp
194  CALL overlap_aab(la1_max=la1_max, la1_min=la1_min, npgfa1=npgfa1, rpgfa1=rpgfa1, zeta1=zeta1, &
195  la2_max=la2_max, la2_min=la2_min, npgfa2=npgfa2, rpgfa2=rpgfa2, zeta2=zeta2, &
196  lb_max=lb_max, lb_min=lb_min, npgfb=npgfb, rpgfb=rpgfb, zetb=zetb, &
197  rab=rab, saab=saab)
198  END IF
199 
200  IF (PRESENT(block_d)) THEN
201  ALLOCATE (daab(na1, na2, nb, 3))
202  daab = 0.0_dp
203  CALL overlap_aab(la1_max=la1_max, la1_min=la1_min, npgfa1=npgfa1, rpgfa1=rpgfa1, zeta1=zeta1, &
204  la2_max=la2_max, la2_min=la2_min, npgfa2=npgfa2, rpgfa2=rpgfa2, zeta2=zeta2, &
205  lb_max=lb_max, lb_min=lb_min, npgfb=npgfb, rpgfb=rpgfb, zetb=zetb, &
206  rab=rab, daab=daab)
207  END IF
208 
209  ! sum potential terms: POW(x**2 + y**2 + z**2, lpot/2)
210  IF (PRESENT(block_v)) THEN
211  ALLOCATE (sab(na1, na2))
212  sab = 0.0_dp
213  DO ic = 1, ncfgb
214  coeff = multinomial(lpot/2, indco(:, ncoset(lpot - 1) + ic)/2)
215  sab = sab + coeff*saab(:, :, ic)
216  END DO
217  CALL my_contract(sab=sab, block=new_block_v, basis_set=basis_set, &
218  iset=iset, ishell=ishell, jset=jset, jshell=jshell)
219  DEALLOCATE (sab, saab)
220  END IF
221 
222  IF (PRESENT(block_d)) THEN
223  ALLOCATE (dab(na1, na2, 3))
224  dab = 0.0_dp
225  DO ic = 1, ncfgb
226  coeff = multinomial(lpot/2, indco(:, ncoset(lpot - 1) + ic)/2)
227  dab = dab + coeff*daab(:, :, ic, :)
228  END DO
229  DO i = 1, 3
230  CALL my_contract(sab=dab(:, :, i), block=new_block_d(:, :, i), basis_set=basis_set, &
231  iset=iset, ishell=ishell, jset=jset, jshell=jshell)
232  END DO
233  DEALLOCATE (dab, daab)
234  END IF
235  END DO
236  END DO
237  END DO
238  END DO
239 
240  DEALLOCATE (rpgfb, zetb)
241 
242  ! post-processing
243  norm2 = (2.0_dp*beta)**(-0.5_dp - lpot)*gamma1(lpot)
244  IF (PRESENT(block_v)) THEN
245  block_v = block_v + weight*new_block_v/sqrt(norm2)
246  DEALLOCATE (new_block_v)
247  block_v = 0.5_dp*(block_v + transpose(block_v)) ! symmetrize
248  END IF
249 
250  IF (PRESENT(block_d)) THEN
251  block_d = block_d + weight*new_block_d/sqrt(norm2)
252  DEALLOCATE (new_block_d)
253  DO i = 1, 3
254  block_d(:, :, i) = 0.5_dp*(block_d(:, :, i) + transpose(block_d(:, :, i))) ! symmetrize
255  END DO
256  END IF
257 
258  CALL timestop(handle)
259  END SUBROUTINE pao_calc_gaussian
260 
261 ! **************************************************************************************************
262 !> \brief Helper routine, contracts a basis block
263 !> \param sab ...
264 !> \param block ...
265 !> \param basis_set ...
266 !> \param iset ...
267 !> \param ishell ...
268 !> \param jset ...
269 !> \param jshell ...
270 ! **************************************************************************************************
271  SUBROUTINE my_contract(sab, block, basis_set, iset, ishell, jset, jshell)
272  REAL(dp), DIMENSION(:, :), INTENT(IN), TARGET :: sab
273  REAL(dp), DIMENSION(:, :), INTENT(OUT), TARGET :: block
274  TYPE(gto_basis_set_type), POINTER :: basis_set
275  INTEGER, INTENT(IN) :: iset, ishell, jset, jshell
276 
277  INTEGER :: a, b, c, d, ipgf, jpgf, l1, l2, n1, n2, &
278  nn1, nn2, sgfa1, sgfa2, sgla1, sgla2
279  REAL(dp), DIMENSION(:, :), POINTER :: s, t1, t2, v
280 
281  ! first and last indices of given shell in block.
282  ! This matrix is in the contracted spherical basis.
283  sgfa1 = basis_set%first_sgf(ishell, iset)
284  sgla1 = basis_set%last_sgf(ishell, iset)
285  sgfa2 = basis_set%first_sgf(jshell, jset)
286  sgla2 = basis_set%last_sgf(jshell, jset)
287 
288  ! prepare the result matrix
289  v => block(sgfa1:sgla1, sgfa2:sgla2)
290 
291  ! Calculate strides of sphi matrix.
292  ! This matrix is in the uncontraced cartesian basis.
293  ! It contains all shells of the set.
294  ! Its index runs over all primitive gaussians of the set
295  ! and then for each gaussian over all configurations of *the entire set*. (0->lmax)
296  nn1 = ncoset(basis_set%lmax(iset))
297  nn2 = ncoset(basis_set%lmax(jset))
298 
299  ! Calculate strides of sab matrix
300  ! This matrix is also in the uncontraced cartensian basis,
301  ! however it contains only a single shell.
302  ! Its index runs over all primitive gaussians of the set
303  ! and then for each gaussian over all configrations of *the given shell*.
304  l1 = basis_set%l(ishell, iset)
305  l2 = basis_set%l(jshell, jset)
306  n1 = ncoset(l1) - ncoset(l1 - 1)
307  n2 = ncoset(l2) - ncoset(l2 - 1)
308 
309  DO ipgf = 1, basis_set%npgf(iset)
310  DO jpgf = 1, basis_set%npgf(jset)
311  ! prepare first trafo-matrix
312  a = (ipgf - 1)*nn1 + ncoset(l1 - 1) + 1
313  t1 => basis_set%sphi(a:a + n1 - 1, sgfa1:sgla1)
314 
315  ! prepare second trafo-matrix
316  b = (jpgf - 1)*nn2 + ncoset(l2 - 1) + 1
317  t2 => basis_set%sphi(b:b + n2 - 1, sgfa2:sgla2)
318 
319  ! prepare SAB matrix
320  c = (ipgf - 1)*n1 + 1
321  d = (jpgf - 1)*n2 + 1
322  s => sab(c:c + n1 - 1, d:d + n2 - 1)
323 
324  ! do the transformation
325  v = v + matmul(transpose(t1), matmul(s, t2))
326  END DO
327  END DO
328 
329  END SUBROUTINE my_contract
330 
331 END MODULE pao_potentials
subroutine pbc(r, r_pbc, s, s_pbc, a, b, c, alpha, beta, gamma, debug, info, pbc0, h, hinv)
...
Definition: dumpdcd.F:1203
Calculation of the overlap integrals over Cartesian Gaussian-type functions.
Definition: ai_overlap.F:18
subroutine, public overlap_aab(la1_max, la1_min, npgfa1, rpgfa1, zeta1, la2_max, la2_min, npgfa2, rpgfa2, zeta2, lb_max, lb_min, npgfb, rpgfb, zetb, rab, saab, daab, saba, daba)
Calculation of the two-center overlap integrals [aa|b] over Cartesian Gaussian-type functions.
Definition: ai_overlap.F:967
All kind of helpful little routines.
Definition: ao_util.F:14
real(kind=dp) function, public exp_radius(l, alpha, threshold, prefactor, epsabs, epsrel, rlow)
The radius of a primitive Gaussian function for a given threshold is calculated. g(r) = prefactor*r**...
Definition: ao_util.F:96
Define the atomic kind types and their sub types.
subroutine, public get_atomic_kind(atomic_kind, fist_potential, element_symbol, name, mass, kind_number, natom, atom_list, rcov, rvdw, z, qeff, apol, cpol, mm_radius, shell, shell_active, damping)
Get attributes of an atomic kind.
Handles all functions related to the CELL.
Definition: cell_types.F:15
Defines the basic variable types.
Definition: kinds.F:23
integer, parameter, public dp
Definition: kinds.F:34
Definition of mathematical constants and functions.
Definition: mathconstants.F:16
real(kind=dp), dimension(0:maxfac), parameter, public gamma1
Definition: mathconstants.F:95
Collection of simple mathematical functions and subroutines.
Definition: mathlib.F:15
pure real(kind=dp) function, public multinomial(n, k)
Calculates the multinomial coefficients.
Definition: mathlib.F:257
Provides Cartesian and spherical orbital pointers and indices.
integer, save, public current_maxl
integer, dimension(:), allocatable, public ncoset
integer, dimension(:, :), allocatable, public indco
Factory routines for potentials used e.g. by pao_param_exp and pao_ml.
subroutine, public pao_calc_gaussian(basis_set, block_V, block_D, Rab, lpot, beta, weight, min_shell, max_shell, min_l, max_l)
Calculates potential term of the form r**lpot * Exp(-beta*r**2) One needs to call init_orbital_pointe...
subroutine, public pao_guess_initial_potential(qs_env, iatom, block_V)
Makes an educated guess for the initial potential based on positions of neighboring atoms.
Define the data structure for the particle information.
subroutine, public get_qs_env(qs_env, atomic_kind_set, qs_kind_set, cell, super_cell, cell_ref, use_ref_cell, kpoints, dft_control, mos, sab_orb, sab_all, qmmm, qmmm_periodic, sac_ae, sac_ppl, sac_lri, sap_ppnl, sab_vdw, sab_scp, sap_oce, sab_lrc, sab_se, sab_xtbe, sab_tbe, sab_core, sab_xb, sab_xtb_nonbond, sab_almo, sab_kp, sab_kp_nosym, particle_set, energy, force, matrix_h, matrix_h_im, matrix_ks, matrix_ks_im, matrix_vxc, run_rtp, rtp, matrix_h_kp, matrix_h_im_kp, matrix_ks_kp, matrix_ks_im_kp, matrix_vxc_kp, kinetic_kp, matrix_s_kp, matrix_w_kp, matrix_s_RI_aux_kp, matrix_s, matrix_s_RI_aux, matrix_w, matrix_p_mp2, matrix_p_mp2_admm, rho, rho_xc, pw_env, ewald_env, ewald_pw, active_space, mpools, input, para_env, blacs_env, scf_control, rel_control, kinetic, qs_charges, vppl, rho_core, rho_nlcc, rho_nlcc_g, ks_env, ks_qmmm_env, wf_history, scf_env, local_particles, local_molecules, distribution_2d, dbcsr_dist, molecule_kind_set, molecule_set, subsys, cp_subsys, oce, local_rho_set, rho_atom_set, task_list, task_list_soft, rho0_atom_set, rho0_mpole, rhoz_set, ecoul_1c, rho0_s_rs, rho0_s_gs, do_kpoints, has_unit_metric, requires_mo_derivs, mo_derivs, mo_loc_history, nkind, natom, nelectron_total, nelectron_spin, efield, neighbor_list_id, linres_control, xas_env, virial, cp_ddapc_env, cp_ddapc_ewald, outer_scf_history, outer_scf_ihistory, x_data, et_coupling, dftb_potential, results, se_taper, se_store_int_env, se_nddo_mpole, se_nonbond_env, admm_env, lri_env, lri_density, exstate_env, ec_env, dispersion_env, gcp_env, vee, rho_external, external_vxc, mask, mp2_env, bs_env, kg_env, WannierCentres, atprop, ls_scf_env, do_transport, transport_env, v_hartree_rspace, s_mstruct_changed, rho_changed, potential_changed, forces_up_to_date, mscfg_env, almo_scf_env, gradient_history, variable_history, embed_pot, spin_embed_pot, polar_env, mos_last_converged, rhs)
Get the QUICKSTEP environment.
Define the quickstep kind type and their sub types.
Definition: qs_kind_types.F:23
subroutine, public get_qs_kind(qs_kind, basis_set, basis_type, ncgf, nsgf, all_potential, tnadd_potential, gth_potential, sgp_potential, upf_potential, se_parameter, dftb_parameter, xtb_parameter, dftb3_param, zeff, elec_conf, mao, lmax_dftb, alpha_core_charge, ccore_charge, core_charge, core_charge_radius, paw_proj_set, paw_atom, hard_radius, hard0_radius, max_rad_local, covalent_radius, vdw_radius, gpw_r3d_rs_type_forced, harmonics, max_iso_not0, max_s_harm, grid_atom, ngrid_ang, ngrid_rad, lmax_rho0, dft_plus_u_atom, l_of_dft_plus_u, n_of_dft_plus_u, u_minus_j, U_of_dft_plus_u, J_of_dft_plus_u, alpha_of_dft_plus_u, beta_of_dft_plus_u, J0_of_dft_plus_u, occupation_of_dft_plus_u, dispersion, bs_occupation, magnetization, no_optimize, addel, laddel, naddel, orbitals, max_scf, eps_scf, smear, u_ramping, u_minus_j_target, eps_u_ramping, init_u_ramping_each_scf, reltmat, ghost, floating, name, element_symbol, pao_basis_size, pao_potentials, pao_descriptors, nelec)
Get attributes of an atomic kind.