(git:e7e05ae)
pao_ml_descriptor.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 Feature vectors for describing chemical environments in a rotationally invariant fashion.
10 !> \author Ole Schuett
11 ! **************************************************************************************************
14  USE basis_set_types, ONLY: gto_basis_set_type
15  USE cell_types, ONLY: cell_type,&
16  pbc
17  USE kinds, ONLY: dp
18  USE mathconstants, ONLY: fourpi,&
19  rootpi
20  USE mathlib, ONLY: diamat_all
21  USE pao_input, ONLY: pao_ml_desc_overlap,&
25  USE pao_types, ONLY: pao_env_type
26  USE particle_types, ONLY: particle_type
27  USE qs_kind_types, ONLY: get_qs_kind,&
28  pao_descriptor_type,&
29  qs_kind_type
30  USE util, ONLY: sort
31 #include "./base/base_uses.f90"
32 
33  IMPLICIT NONE
34 
35  PRIVATE
36 
37  CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'pao_ml_descriptor'
38 
39  PUBLIC :: pao_ml_calc_descriptor
40 
41 CONTAINS
42 
43 ! **************************************************************************************************
44 !> \brief Calculates a descriptor for chemical environment of given atom
45 !> \param pao ...
46 !> \param particle_set ...
47 !> \param qs_kind_set ...
48 !> \param cell ...
49 !> \param iatom ...
50 !> \param descriptor ...
51 !> \param descr_grad ...
52 !> \param forces ...
53 ! **************************************************************************************************
54  SUBROUTINE pao_ml_calc_descriptor(pao, particle_set, qs_kind_set, cell, iatom, descriptor, descr_grad, forces)
55  TYPE(pao_env_type), POINTER :: pao
56  TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
57  TYPE(qs_kind_type), DIMENSION(:), POINTER :: qs_kind_set
58  TYPE(cell_type), POINTER :: cell
59  INTEGER, INTENT(IN) :: iatom
60  REAL(dp), ALLOCATABLE, DIMENSION(:), OPTIONAL :: descriptor
61  REAL(dp), DIMENSION(:), INTENT(IN), OPTIONAL :: descr_grad
62  REAL(dp), DIMENSION(:, :), INTENT(INOUT), OPTIONAL :: forces
63 
64  CHARACTER(len=*), PARAMETER :: routinen = 'pao_ml_calc_descriptor'
65 
66  INTEGER :: handle
67 
68  CALL timeset(routinen, handle)
69 
70  cpassert(PRESENT(forces) .EQV. PRESENT(descr_grad))
71 
72  SELECT CASE (pao%ml_descriptor)
73  CASE (pao_ml_desc_pot)
74  CALL calc_descriptor_pot(particle_set, qs_kind_set, cell, iatom, descriptor, descr_grad, forces)
75  CASE (pao_ml_desc_overlap)
76  CALL calc_descriptor_overlap(particle_set, qs_kind_set, cell, iatom, descriptor, descr_grad, forces)
77  CASE (pao_ml_desc_r12)
78  CALL calc_descriptor_r12(particle_set, qs_kind_set, cell, iatom, descriptor, descr_grad, forces)
79  CASE DEFAULT
80  cpabort("PAO: unknown descriptor")
81  END SELECT
82 
83  CALL timestop(handle)
84  END SUBROUTINE pao_ml_calc_descriptor
85 
86 ! **************************************************************************************************
87 !> \brief Calculates a descriptor based on the eigenvalues of V_neighbors
88 !> \param particle_set ...
89 !> \param qs_kind_set ...
90 !> \param cell ...
91 !> \param iatom ...
92 !> \param descriptor ...
93 !> \param descr_grad ...
94 !> \param forces ...
95 ! **************************************************************************************************
96  SUBROUTINE calc_descriptor_pot(particle_set, qs_kind_set, cell, iatom, descriptor, descr_grad, forces)
97  TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
98  TYPE(qs_kind_type), DIMENSION(:), POINTER :: qs_kind_set
99  TYPE(cell_type), POINTER :: cell
100  INTEGER, INTENT(IN) :: iatom
101  REAL(dp), ALLOCATABLE, DIMENSION(:), OPTIONAL :: descriptor
102  REAL(dp), DIMENSION(:), INTENT(IN), OPTIONAL :: descr_grad
103  REAL(dp), DIMENSION(:, :), INTENT(INOUT), OPTIONAL :: forces
104 
105  CHARACTER(len=*), PARAMETER :: routinen = 'calc_descriptor_pot'
106 
107  INTEGER :: handle, i, idesc, ikind, jatom, jkind, &
108  k, n, natoms, ndesc
109  REAL(dp) :: beta, w, weight
110  REAL(dp), ALLOCATABLE, DIMENSION(:) :: v_evals
111  REAL(dp), ALLOCATABLE, DIMENSION(:, :) :: block_m, block_v, v_evecs
112  REAL(dp), ALLOCATABLE, DIMENSION(:, :, :) :: block_d
113  REAL(dp), DIMENSION(3) :: ra, rab, rb
114  TYPE(gto_basis_set_type), POINTER :: basis_set
115  TYPE(pao_descriptor_type), DIMENSION(:), POINTER :: pao_descriptors
116 
117  CALL timeset(routinen, handle)
118 
119  CALL get_atomic_kind(particle_set(iatom)%atomic_kind, kind_number=ikind)
120  CALL get_qs_kind(qs_kind_set(ikind), basis_set=basis_set, pao_descriptors=pao_descriptors)
121  n = basis_set%nsgf
122  natoms = SIZE(particle_set)
123  ndesc = SIZE(pao_descriptors)
124  IF (ndesc == 0) cpabort("No PAO_DESCRIPTOR section found")
125 
126  ALLOCATE (block_v(n, n), v_evecs(n, n), v_evals(n))
127  IF (PRESENT(descriptor)) ALLOCATE (descriptor(n*ndesc))
128  IF (PRESENT(forces)) ALLOCATE (block_d(n, n, 3), block_m(n, n))
129 
130  DO idesc = 1, ndesc
131 
132  ! construct matrix V_block from neighboring atoms
133  block_v = 0.0_dp
134  DO jatom = 1, natoms
135  IF (jatom == iatom) cycle
136  ra = particle_set(iatom)%r
137  rb = particle_set(jatom)%r
138  rab = pbc(ra, rb, cell)
139  CALL get_atomic_kind(particle_set(jatom)%atomic_kind, kind_number=jkind)
140  CALL get_qs_kind(qs_kind_set(jkind), pao_descriptors=pao_descriptors)
141  IF (SIZE(pao_descriptors) /= ndesc) &
142  cpabort("Not all KINDs have the same number of PAO_DESCRIPTOR sections")
143  weight = pao_descriptors(idesc)%weight
144  beta = pao_descriptors(idesc)%beta
145  CALL pao_calc_gaussian(basis_set, block_v=block_v, rab=rab, lpot=0, beta=beta, weight=weight)
146  END DO
147 
148  ! diagonalize block_V
149  v_evecs(:, :) = block_v(:, :)
150  CALL diamat_all(v_evecs, v_evals)
151 
152  ! use eigenvalues of V_block as descriptor
153  IF (PRESENT(descriptor)) &
154  descriptor((idesc - 1)*n + 1:idesc*n) = v_evals(:)
155 
156  ! FORCES ----------------------------------------------------------------------------------
157  IF (PRESENT(forces)) THEN
158  cpassert(PRESENT(descr_grad))
159  block_m = 0.0_dp
160  DO k = 1, n
161  w = descr_grad((idesc - 1)*n + k)
162  block_m(:, :) = block_m(:, :) + w*matmul(v_evecs(:, k:k), transpose(v_evecs(:, k:k)))
163  END DO
164  DO jatom = 1, natoms
165  IF (jatom == iatom) cycle
166  ra = particle_set(iatom)%r
167  rb = particle_set(jatom)%r
168  rab = pbc(ra, rb, cell)
169  CALL get_atomic_kind(particle_set(jatom)%atomic_kind, kind_number=jkind)
170  CALL get_qs_kind(qs_kind_set(jkind), pao_descriptors=pao_descriptors)
171  weight = pao_descriptors(idesc)%weight
172  beta = pao_descriptors(idesc)%beta
173  block_d = 0.0_dp
174  CALL pao_calc_gaussian(basis_set, block_d=block_d, rab=rab, lpot=0, beta=beta, weight=weight)
175  DO i = 1, 3
176  forces(iatom, i) = forces(iatom, i) - sum(block_m*block_d(:, :, i))
177  forces(jatom, i) = forces(jatom, i) + sum(block_m*block_d(:, :, i))
178  END DO
179  END DO
180  END IF
181 
182  END DO
183 
184  CALL timestop(handle)
185  END SUBROUTINE calc_descriptor_pot
186 
187 ! **************************************************************************************************
188 !> \brief Calculates a descriptor based on the eigenvalues of local overlap matrix
189 !> \param particle_set ...
190 !> \param qs_kind_set ...
191 !> \param cell ...
192 !> \param iatom ...
193 !> \param descriptor ...
194 !> \param descr_grad ...
195 !> \param forces ...
196 ! **************************************************************************************************
197  SUBROUTINE calc_descriptor_overlap(particle_set, qs_kind_set, cell, iatom, descriptor, descr_grad, forces)
198  TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
199  TYPE(qs_kind_type), DIMENSION(:), POINTER :: qs_kind_set
200  TYPE(cell_type), POINTER :: cell
201  INTEGER, INTENT(IN) :: iatom
202  REAL(dp), ALLOCATABLE, DIMENSION(:), OPTIONAL :: descriptor
203  REAL(dp), DIMENSION(:), INTENT(IN), OPTIONAL :: descr_grad
204  REAL(dp), DIMENSION(:, :), INTENT(INOUT), OPTIONAL :: forces
205 
206  CHARACTER(len=*), PARAMETER :: routinen = 'calc_descriptor_overlap'
207 
208  INTEGER :: handle, idesc, ikind, j, jatom, jkind, &
209  k, katom, kkind, n, natoms, ndesc
210  INTEGER, ALLOCATABLE, DIMENSION(:) :: neighbor_order
211  REAL(dp) :: beta_sum, deriv, exponent, integral, jbeta, jweight, kbeta, kweight, &
212  normalization, rij2, rik2, rjk2, sbeta, screening_radius, screening_volume, w
213  REAL(dp), ALLOCATABLE, DIMENSION(:) :: s_evals
214  REAL(dp), ALLOCATABLE, DIMENSION(:, :) :: block_m, block_s, s_evecs
215  REAL(dp), DIMENSION(3) :: ri, rij, rik, rj, rjk, rk
216  REAL(kind=dp), ALLOCATABLE, DIMENSION(:) :: neighbor_dist
217  TYPE(pao_descriptor_type), DIMENSION(:), POINTER :: ipao_descriptors, jpao_descriptors, &
218  kpao_descriptors
219 
220  CALL timeset(routinen, handle)
221 
222  CALL get_atomic_kind(particle_set(iatom)%atomic_kind, kind_number=ikind)
223  CALL get_qs_kind(qs_kind_set(ikind), pao_descriptors=ipao_descriptors)
224 
225  natoms = SIZE(particle_set)
226  ndesc = SIZE(ipao_descriptors)
227  IF (ndesc == 0) cpabort("No PAO_DESCRIPTOR section found")
228 
229  ! determine largest screening radius
230  screening_radius = 0.0_dp
231  DO idesc = 1, ndesc
232  screening_radius = max(screening_radius, ipao_descriptors(idesc)%screening_radius)
233  END DO
234 
235  ! estimate maximum number of neighbors within screening
236  screening_volume = fourpi/3.0_dp*screening_radius**3
237  n = int(screening_volume/35.0_dp) ! rule of thumb
238 
239  ALLOCATE (block_s(n, n), s_evals(n), s_evecs(n, n))
240  IF (PRESENT(descriptor)) ALLOCATE (descriptor(n*ndesc))
241  IF (PRESENT(forces)) ALLOCATE (block_m(n, n))
242 
243  !find neighbors
244  !TODO: this is a quadratic algorithm, use a neighbor-list instead
245  ALLOCATE (neighbor_dist(natoms), neighbor_order(natoms))
246  ri = particle_set(iatom)%r
247  DO jatom = 1, natoms
248  rj = particle_set(jatom)%r
249  rij = pbc(ri, rj, cell)
250  neighbor_dist(jatom) = sqrt(sum(rij**2))
251  END DO
252  CALL sort(neighbor_dist, natoms, neighbor_order)
253  cpassert(neighbor_order(1) == iatom) !central atom should be closesd to itself
254 
255  ! check if N was chosen large enough
256  IF (natoms > n) THEN
257  IF (neighbor_dist(n + 1) < screening_radius) &
258  cpabort("PAO heuristic for descriptor size broke down")
259  END IF
260 
261  DO idesc = 1, ndesc
262  sbeta = ipao_descriptors(idesc)%screening
263 
264  ! construct matrix S_block from neighboring atoms
265  block_s = 0.0_dp
266  DO j = 1, min(natoms, n)
267  DO k = 1, min(natoms, n)
268  jatom = neighbor_order(j)
269  katom = neighbor_order(k)
270 
271  ! get weigths and betas
272  CALL get_atomic_kind(particle_set(jatom)%atomic_kind, kind_number=jkind)
273  CALL get_qs_kind(qs_kind_set(jkind), pao_descriptors=jpao_descriptors)
274  CALL get_atomic_kind(particle_set(katom)%atomic_kind, kind_number=kkind)
275  CALL get_qs_kind(qs_kind_set(kkind), pao_descriptors=kpao_descriptors)
276  IF (SIZE(jpao_descriptors) /= ndesc .OR. SIZE(kpao_descriptors) /= ndesc) &
277  cpabort("Not all KINDs have the same number of PAO_DESCRIPTOR sections")
278  jweight = jpao_descriptors(idesc)%weight
279  jbeta = jpao_descriptors(idesc)%beta
280  kweight = kpao_descriptors(idesc)%weight
281  kbeta = kpao_descriptors(idesc)%beta
282  beta_sum = sbeta + jbeta + kbeta
283 
284  ! get distances
285  rj = particle_set(jatom)%r
286  rk = particle_set(katom)%r
287  rij = pbc(ri, rj, cell)
288  rik = pbc(ri, rk, cell)
289  rjk = pbc(rj, rk, cell)
290  rij2 = sum(rij**2)
291  rik2 = sum(rik**2)
292  rjk2 = sum(rjk**2)
293 
294  ! calculate integral over three Gaussians
295  exponent = -(sbeta*jbeta*rij2 + sbeta*kbeta*rik2 + jbeta*kbeta*rjk2)/beta_sum
296  integral = exp(exponent)*rootpi/sqrt(beta_sum)
297  normalization = sqrt(jbeta*kbeta)/rootpi**2
298  block_s(j, k) = jweight*kweight*normalization*integral
299  END DO
300  END DO
301 
302  ! diagonalize V_block
303  s_evecs(:, :) = block_s(:, :)
304  CALL diamat_all(s_evecs, s_evals)
305 
306  ! use eigenvalues of S_block as descriptor
307  IF (PRESENT(descriptor)) &
308  descriptor((idesc - 1)*n + 1:idesc*n) = s_evals(:)
309 
310  ! FORCES ----------------------------------------------------------------------------------
311  IF (PRESENT(forces)) THEN
312  cpassert(PRESENT(descr_grad))
313  block_m = 0.0_dp
314  DO k = 1, n
315  w = descr_grad((idesc - 1)*n + k)
316  block_m(:, :) = block_m(:, :) + w*matmul(s_evecs(:, k:k), transpose(s_evecs(:, k:k)))
317  END DO
318 
319  DO j = 1, min(natoms, n)
320  DO k = 1, min(natoms, n)
321  jatom = neighbor_order(j)
322  katom = neighbor_order(k)
323 
324  ! get weigths and betas
325  CALL get_atomic_kind(particle_set(jatom)%atomic_kind, kind_number=jkind)
326  CALL get_qs_kind(qs_kind_set(jkind), pao_descriptors=jpao_descriptors)
327  CALL get_atomic_kind(particle_set(katom)%atomic_kind, kind_number=kkind)
328  CALL get_qs_kind(qs_kind_set(kkind), pao_descriptors=kpao_descriptors)
329  jweight = jpao_descriptors(idesc)%weight
330  jbeta = jpao_descriptors(idesc)%beta
331  kweight = kpao_descriptors(idesc)%weight
332  kbeta = kpao_descriptors(idesc)%beta
333  beta_sum = sbeta + jbeta + kbeta
334 
335  ! get distances
336  rj = particle_set(jatom)%r
337  rk = particle_set(katom)%r
338  rij = pbc(ri, rj, cell)
339  rik = pbc(ri, rk, cell)
340  rjk = pbc(rj, rk, cell)
341  rij2 = sum(rij**2)
342  rik2 = sum(rik**2)
343  rjk2 = sum(rjk**2)
344 
345  ! calculate integral over three Gaussians
346  exponent = -(sbeta*jbeta*rij2 + sbeta*kbeta*rik2 + jbeta*kbeta*rjk2)/beta_sum
347  integral = exp(exponent)*rootpi/sqrt(beta_sum)
348  normalization = sqrt(jbeta*kbeta)/rootpi**2
349  deriv = 2.0_dp/beta_sum*block_m(j, k)
350  w = jweight*kweight*normalization*integral*deriv
351  forces(iatom, :) = forces(iatom, :) - sbeta*jbeta*rij*w
352  forces(jatom, :) = forces(jatom, :) + sbeta*jbeta*rij*w
353  forces(iatom, :) = forces(iatom, :) - sbeta*kbeta*rik*w
354  forces(katom, :) = forces(katom, :) + sbeta*kbeta*rik*w
355  forces(jatom, :) = forces(jatom, :) - jbeta*kbeta*rjk*w
356  forces(katom, :) = forces(katom, :) + jbeta*kbeta*rjk*w
357  END DO
358  END DO
359  END IF
360  END DO
361 
362  CALL timestop(handle)
363  END SUBROUTINE calc_descriptor_overlap
364 
365 ! **************************************************************************************************
366 !> \brief Calculates a descriptor based on distance between two atoms
367 !> \param particle_set ...
368 !> \param qs_kind_set ...
369 !> \param cell ...
370 !> \param iatom ...
371 !> \param descriptor ...
372 !> \param descr_grad ...
373 !> \param forces ...
374 ! **************************************************************************************************
375  SUBROUTINE calc_descriptor_r12(particle_set, qs_kind_set, cell, iatom, descriptor, descr_grad, forces)
376  TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
377  TYPE(qs_kind_type), DIMENSION(:), POINTER :: qs_kind_set
378  TYPE(cell_type), POINTER :: cell
379  INTEGER, INTENT(IN) :: iatom
380  REAL(dp), ALLOCATABLE, DIMENSION(:), OPTIONAL :: descriptor
381  REAL(dp), DIMENSION(:), INTENT(IN), OPTIONAL :: descr_grad
382  REAL(dp), DIMENSION(:, :), INTENT(INOUT), OPTIONAL :: forces
383 
384  REAL(dp), DIMENSION(3) :: g, r1, r12, r2
385 
386  cpassert(SIZE(particle_set) == 2)
387 
388  mark_used(qs_kind_set)
389  mark_used(iatom)
390  mark_used(cell)
391 
392  r1 = particle_set(1)%r
393  r2 = particle_set(2)%r
394  r12 = pbc(r1, r2, cell)
395 
396  IF (PRESENT(descriptor)) THEN
397  ALLOCATE (descriptor(1))
398  descriptor(1) = sqrt(sum(r12**2))
399  END IF
400 
401  IF (PRESENT(forces)) THEN
402  cpassert(PRESENT(descr_grad))
403  g = r12/sqrt(sum(r12**2))*descr_grad(1)
404  forces(1, :) = forces(1, :) + g
405  forces(2, :) = forces(2, :) - g
406  END IF
407  END SUBROUTINE calc_descriptor_r12
408 
409 END MODULE pao_ml_descriptor
subroutine pbc(r, r_pbc, s, s_pbc, a, b, c, alpha, beta, gamma, debug, info, pbc0, h, hinv)
...
Definition: dumpdcd.F:1203
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), parameter, public rootpi
real(kind=dp), parameter, public fourpi
Collection of simple mathematical functions and subroutines.
Definition: mathlib.F:15
subroutine, public diamat_all(a, eigval, dac)
Diagonalize the symmetric n by n matrix a using the LAPACK library. Only the upper triangle of matrix...
Definition: mathlib.F:376
integer, parameter, public pao_ml_desc_pot
Definition: pao_input.F:45
integer, parameter, public pao_ml_desc_r12
Definition: pao_input.F:45
integer, parameter, public pao_ml_desc_overlap
Definition: pao_input.F:45
Feature vectors for describing chemical environments in a rotationally invariant fashion.
subroutine, public pao_ml_calc_descriptor(pao, particle_set, qs_kind_set, cell, iatom, descriptor, descr_grad, forces)
Calculates a descriptor for chemical environment of given atom.
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...
Types used by the PAO machinery.
Definition: pao_types.F:12
Define the data structure for the particle information.
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.
All kind of helpful little routines.
Definition: util.F:14