(git:5e7fe52)
Loading...
Searching...
No Matches
rirs_grid_utils.F
Go to the documentation of this file.
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 Shared RI-RS grid I/O and contracted-Gaussian evaluation utilities.
10! **************************************************************************************************
13 USE cell_types, ONLY: cell_type,&
14 pbc
15 USE cp_files, ONLY: close_file,&
17 USE kinds, ONLY: default_path_length,&
19 dp
20 USE orbital_pointers, ONLY: indco,&
21 ncoset
23 USE qs_kind_types, ONLY: get_qs_kind,&
25#include "./base/base_uses.f90"
26
27 IMPLICIT NONE
28 PRIVATE
29
30 CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'rirs_grid_utils'
31
34
35CONTAINS
36
37! **************************************************************************************************
38!> \brief Construct the path of an RI-RS grid file.
39!> \param element_symbol ...
40!> \param grid_select ...
41!> \param grid_file_suffix ...
42!> \param filepath ...
43! **************************************************************************************************
44 SUBROUTINE get_rirs_grid_filepath(element_symbol, grid_select, grid_file_suffix, filepath)
45 CHARACTER(LEN=*), INTENT(IN) :: element_symbol
46 INTEGER, INTENT(IN) :: grid_select
47 CHARACTER(LEN=*), INTENT(IN) :: grid_file_suffix
48 CHARACTER(LEN=*), INTENT(OUT) :: filepath
49
50 CHARACTER(LEN=default_string_length) :: suffix
51
52 SELECT CASE (grid_select)
53 CASE (1)
54 suffix = "_def2-tzvp-rs.ion"
55 CASE (2)
56 suffix = "_cc-pvtz-rs.ion"
57 CASE (3)
58 IF (len_trim(grid_file_suffix) > 0) THEN
59 suffix = trim(grid_file_suffix)
60 ELSE
61 suffix = "_rirs.ion"
62 END IF
63 CASE DEFAULT
64 cpabort("Unknown grid_select (1=def2-TZVPP, 2=cc-pVTZ, 3=user-provided).")
65 END SELECT
66 filepath = "ri_rs_grid/"//trim(element_symbol)//trim(suffix)
67 END SUBROUTINE get_rirs_grid_filepath
68
69! **************************************************************************************************
70!> \brief Read the number of points from an RI-RS grid file.
71!> \param filename ...
72!> \return Number of grid points.
73! **************************************************************************************************
74 INTEGER FUNCTION read_rirs_grid_npoints(filename) RESULT(npoints)
75 CHARACTER(LEN=*), INTENT(IN) :: filename
76
77 INTEGER :: iunit
78
79 CALL open_file(file_name=trim(filename), unit_number=iunit, &
80 file_action='READ', file_status='OLD')
81 CALL read_rirs_grid_header(iunit, filename, npoints)
82 CALL close_file(unit_number=iunit)
83 END FUNCTION read_rirs_grid_npoints
84
85! **************************************************************************************************
86!> \brief Read Cartesian grid points from the existing CP2K RI-RS .ion format.
87!> \param filename Complete input filename; no suffix or element-name construction is performed.
88!> \param points Grid points in Bohr, indexed (alpha,l).
89! **************************************************************************************************
90 SUBROUTINE read_rirs_grid_file(filename, points)
91 CHARACTER(LEN=*), INTENT(IN) :: filename
92 REAL(kind=dp), ALLOCATABLE, DIMENSION(:, :), &
93 INTENT(OUT) :: points
94
95 CHARACTER(len=*), PARAMETER :: routinen = 'read_rirs_grid_file'
96
97 CHARACTER(LEN=default_path_length) :: line
98 INTEGER :: handle, ierr, iunit, l, npoints
99 LOGICAL :: found_points
100
101 CALL timeset(routinen, handle)
102 CALL open_file(file_name=trim(filename), unit_number=iunit, &
103 file_action='READ', file_status='OLD')
104
105 CALL read_rirs_grid_header(iunit, filename, npoints)
106
107 rewind(iunit)
108 found_points = .false.
109 DO
110 READ (iunit, '(A)', iostat=ierr) line
111 IF (ierr /= 0) EXIT
112 IF (index(line, '<grid_points>') > 0) THEN
113 found_points = .true.
114 EXIT
115 END IF
116 END DO
117 IF (.NOT. found_points) cpabort('RI-RS .ion file has no <grid_points> block: '//trim(filename))
118
119 ALLOCATE (points(3, npoints))
120 DO l = 1, npoints
121 READ (iunit, *, iostat=ierr) points(:, l)
122 IF (ierr /= 0) cpabort('Invalid grid point in RI-RS .ion file: '//trim(filename))
123 END DO
124 CALL close_file(unit_number=iunit)
125 CALL timestop(handle)
126 END SUBROUTINE read_rirs_grid_file
127
128! **************************************************************************************************
129!> \brief Read and validate the point count in an open RI-RS grid file.
130!> \param iunit ...
131!> \param filename ...
132!> \param npoints ...
133! **************************************************************************************************
134 SUBROUTINE read_rirs_grid_header(iunit, filename, npoints)
135 INTEGER, INTENT(IN) :: iunit
136 CHARACTER(LEN=*), INTENT(IN) :: filename
137 INTEGER, INTENT(OUT) :: npoints
138
139 CHARACTER(LEN=default_path_length) :: line
140 INTEGER :: colon, ierr
141 LOGICAL :: found_size
142
143 found_size = .false.
144 npoints = 0
145 DO
146 READ (iunit, '(A)', iostat=ierr) line
147 IF (ierr /= 0) EXIT
148 IF (index(line, 'n points') > 0) THEN
149 colon = index(line, ':')
150 IF (colon > 0) THEN
151 READ (line(colon + 1:), *, iostat=ierr) npoints
152 found_size = ierr == 0 .AND. npoints > 0
153 END IF
154 EXIT
155 END IF
156 END DO
157 IF (.NOT. found_size) cpabort('RI-RS .ion file has no valid n points field: '//trim(filename))
158 END SUBROUTINE read_rirs_grid_header
159
160! **************************************************************************************************
161!> \brief Build one deterministic atom-specific grid from a tabulated source grid.
162!> \param points Source-grid coordinates on entry and selected coordinates on return.
163!> \param n_select Number of requested points.
164!> \param center_atom Atom on which the relative source grid is centred.
165!> \param particle_set Molecular atom positions.
166!> \param n_voronoi_candidates Number of candidates available in the atom's Voronoi volume.
167!> \author Jan Wilhelm
168! **************************************************************************************************
169 SUBROUTINE initialize_rirs_grid(points, n_select, center_atom, particle_set, n_voronoi_candidates)
170 REAL(kind=dp), ALLOCATABLE, INTENT(INOUT) :: points(:, :)
171 INTEGER, INTENT(IN) :: n_select, center_atom
172 TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
173 INTEGER, INTENT(OUT) :: n_voronoi_candidates
174
175 REAL(kind=dp), ALLOCATABLE :: source_points(:, :)
176
177 cpassert(SIZE(points, 1) == 3)
178 cpassert(center_atom >= 1 .AND. center_atom <= SIZE(particle_set))
179 ALLOCATE (source_points, source=points)
180 CALL filter_grid_to_voronoi(points, center_atom, particle_set)
181 n_voronoi_candidates = SIZE(points, 2)
182 IF (n_voronoi_candidates < n_select) CALL move_alloc(source_points, points)
183 CALL select_grid_points(points, n_select)
184 END SUBROUTINE initialize_rirs_grid
185
186! **************************************************************************************************
187!> \brief Retain source-grid points inside the Voronoi volume of one atom.
188!> \param points Source-grid coordinates on entry and Voronoi-filtered coordinates on return.
189!> \param center_atom Atom whose Voronoi volume is retained.
190!> \param particle_set Molecular atom positions.
191! **************************************************************************************************
192 SUBROUTINE filter_grid_to_voronoi(points, center_atom, particle_set)
193 REAL(kind=dp), ALLOCATABLE, INTENT(INOUT) :: points(:, :)
194 INTEGER, INTENT(IN) :: center_atom
195 TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
196
197 INTEGER :: iatom, ipoint, n_keep
198 LOGICAL, ALLOCATABLE :: keep(:)
199 REAL(kind=dp) :: other_distance_squared, &
200 own_distance_squared, physical_point(3)
201 REAL(kind=dp), ALLOCATABLE :: filtered_points(:, :)
202
203 ALLOCATE (keep(SIZE(points, 2)), source=.true.)
204 DO ipoint = 1, SIZE(points, 2)
205 physical_point = particle_set(center_atom)%r + points(:, ipoint)
206 own_distance_squared = sum(points(:, ipoint)**2)
207 DO iatom = 1, SIZE(particle_set)
208 IF (iatom == center_atom) cycle
209 other_distance_squared = sum((physical_point - particle_set(iatom)%r)**2)
210 IF (other_distance_squared < own_distance_squared) THEN
211 keep(ipoint) = .false.
212 EXIT
213 END IF
214 END DO
215 END DO
216
217 n_keep = count(keep)
218 ALLOCATE (filtered_points(3, n_keep))
219 IF (n_keep > 0) filtered_points(:, :) = reshape(pack(points, spread(keep, 1, 3)), [3, n_keep])
220 CALL move_alloc(filtered_points, points)
221 END SUBROUTINE filter_grid_to_voronoi
222
223! **************************************************************************************************
224!> \brief Select a deterministic maximin subset from a source grid.
225!> \param points Candidate coordinates on entry and selected coordinates on return.
226!> \param n_select Number of points to select.
227! **************************************************************************************************
228 SUBROUTINE select_grid_points(points, n_select)
229 REAL(kind=dp), ALLOCATABLE, INTENT(INOUT) :: points(:, :)
230 INTEGER, INTENT(IN) :: n_select
231
232 INTEGER :: candidate, i, isel, n_source
233 LOGICAL, ALLOCATABLE :: available(:)
234 REAL(kind=dp) :: best_distance, distance_squared
235 REAL(kind=dp), ALLOCATABLE :: nearest_squared(:), selected_points(:, :)
236
237 n_source = SIZE(points, 2)
238 IF (n_select <= 0) cpabort("GRID_SIZE point counts must be positive.")
239 IF (n_select > n_source) THEN
240 cpabort("GRID_SIZE exceeds the number of available RI-RS source-grid points.")
241 END IF
242 IF (n_select == n_source) RETURN
243
244 ALLOCATE (available(n_source), nearest_squared(n_source), selected_points(3, n_select))
245 available = .true.
246
247 candidate = minloc(sum(points**2, dim=1), dim=1)
248 selected_points(:, 1) = points(:, candidate)
249 available(candidate) = .false.
250 nearest_squared(:) = sum((points - spread(selected_points(:, 1), 2, n_source))**2, dim=1)
251
252 DO isel = 2, n_select
253 candidate = 0
254 best_distance = -1.0_dp
255 DO i = 1, n_source
256 IF (available(i) .AND. nearest_squared(i) > best_distance) THEN
257 candidate = i
258 best_distance = nearest_squared(i)
259 END IF
260 END DO
261 cpassert(candidate > 0)
262 selected_points(:, isel) = points(:, candidate)
263 available(candidate) = .false.
264 DO i = 1, n_source
265 IF (available(i)) THEN
266 distance_squared = sum((points(:, i) - selected_points(:, isel))**2)
267 nearest_squared(i) = min(nearest_squared(i), distance_squared)
268 END IF
269 END DO
270 END DO
271
272 CALL move_alloc(selected_points, points)
273 END SUBROUTINE select_grid_points
274
275! **************************************************************************************************
276!> \brief Evaluate contracted spherical AOs, and optionally their grid-coordinate derivatives.
277!>
278!> For atom A and displacement d(alpha)=r_l(alpha)-R_A(alpha), the value is
279!>
280!> phi_mu(r_l) = sum_(p,c) S_(pc,mu) d_x^lx d_y^ly d_z^lz exp(-zeta_p |d|^2).
281!>
282!> The optional derivative is evaluated analytically as
283!>
284!> d phi_mu(r_l)/d r_(l,alpha)
285!> = sum_(p,c) S_(pc,mu) exp(-zeta_p |d|^2)
286!> [d polynomial_c/d d_alpha - 2 zeta_p d_alpha polynomial_c].
287!>
288!> The routine is shared by production GW RI-RS and grid optimization. Production callers can
289!> pass a cutoff_squared; the optimizer omits it so moving points never cross a discontinuous
290!> AO-screening boundary.
291!>
292!> \param phi AO values, accumulated into phi(l,mu).
293!> \param grid_points Cartesian grid points, indexed (alpha,l).
294!> \param atom_index Source atom whose contracted AOs are evaluated.
295!> \param particle_set Molecular particles.
296!> \param qs_kind_set Quickstep atomic kinds containing the ORB bases.
297!> \param cell Simulation cell used for the minimum-image displacement.
298!> \param dphi Optional AO derivatives, accumulated into dphi(alpha,l,mu).
299!> \param cutoff_squared Optional squared AO cutoff radius.
300! **************************************************************************************************
301 SUBROUTINE evaluate_ao_on_points(phi, grid_points, atom_index, particle_set, qs_kind_set, cell, &
302 dphi, cutoff_squared)
303 REAL(kind=dp), DIMENSION(:, :), INTENT(INOUT) :: phi
304 REAL(kind=dp), DIMENSION(:, :), INTENT(IN) :: grid_points
305 INTEGER, INTENT(IN) :: atom_index
306 TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
307 TYPE(qs_kind_type), DIMENSION(:), POINTER :: qs_kind_set
308 TYPE(cell_type), POINTER :: cell
309 REAL(kind=dp), DIMENSION(:, :, :), INTENT(INOUT), &
310 OPTIONAL :: dphi
311 REAL(kind=dp), INTENT(IN), OPTIONAL :: cutoff_squared
312
313 CHARACTER(len=*), PARAMETER :: routinen = 'evaluate_ao_on_points'
314
315 INTEGER :: handle, kind_index
316 TYPE(gto_basis_set_type), POINTER :: basis
317
318 CALL timeset(routinen, handle)
319 cpassert(SIZE(grid_points, 1) == 3)
320 cpassert(SIZE(phi, 1) == SIZE(grid_points, 2))
321 IF (PRESENT(dphi)) THEN
322 cpassert(SIZE(dphi, 1) == 3)
323 cpassert(SIZE(dphi, 2) == SIZE(phi, 1))
324 cpassert(SIZE(dphi, 3) == SIZE(phi, 2))
325 END IF
326
327 kind_index = particle_set(atom_index)%atomic_kind%kind_number
328 CALL get_qs_kind(qs_kind_set(kind_index), basis_set=basis, basis_type='ORB')
329 IF (.NOT. ASSOCIATED(basis)) THEN
330 CALL timestop(handle)
331 RETURN
332 END IF
333 CALL evaluate_ao_basis_on_points(phi, grid_points, basis, &
334 particle_set(atom_index)%r, cell, dphi, cutoff_squared)
335 CALL timestop(handle)
336 END SUBROUTINE evaluate_ao_on_points
337
338! **************************************************************************************************
339!> \brief Evaluate one explicitly supplied contracted Gaussian basis on Cartesian points.
340!> \param phi AO values, accumulated into phi(l,mu).
341!> \param grid_points Cartesian grid points, indexed (alpha,l).
342!> \param basis Contracted Gaussian basis to evaluate.
343!> \param source_position Centre of the basis.
344!> \param cell Simulation cell used for the minimum-image displacement.
345!> \param dphi Optional AO derivatives, accumulated into dphi(alpha,l,mu).
346!> \param cutoff_squared Optional squared AO cutoff radius.
347! **************************************************************************************************
348 SUBROUTINE evaluate_ao_basis_on_points(phi, grid_points, basis, source_position, cell, &
349 dphi, cutoff_squared)
350 REAL(kind=dp), DIMENSION(:, :), INTENT(INOUT) :: phi
351 REAL(kind=dp), DIMENSION(:, :), INTENT(IN) :: grid_points
352 TYPE(gto_basis_set_type), POINTER :: basis
353 REAL(kind=dp), DIMENSION(3), INTENT(IN) :: source_position
354 TYPE(cell_type), POINTER :: cell
355 REAL(kind=dp), DIMENSION(:, :, :), INTENT(INOUT), &
356 OPTIONAL :: dphi
357 REAL(kind=dp), INTENT(IN), OPTIONAL :: cutoff_squared
358
359 INTEGER :: alpha, first_sgf, ico, iend_co, ipgf, &
360 iset, isgf, ishell, istart_co, l, &
361 last_sgf, lx, ly, lz, n_cart_total, &
362 point, row_index
363 REAL(kind=dp) :: exponent, exponential, polynomial, &
364 polynomial_derivative(3), radius2, &
365 relative(3), weight
366
367 cpassert(ASSOCIATED(basis))
368 cpassert(SIZE(grid_points, 1) == 3)
369 cpassert(SIZE(phi, 1) == SIZE(grid_points, 2))
370 IF (PRESENT(dphi)) THEN
371 cpassert(SIZE(dphi, 1) == 3)
372 cpassert(SIZE(dphi, 2) == SIZE(phi, 1))
373 cpassert(SIZE(dphi, 3) == SIZE(phi, 2))
374 END IF
375
376 !$OMP PARALLEL DO DEFAULT(NONE) SCHEDULE(STATIC) &
377 !$OMP SHARED(phi, dphi, grid_points, cell, basis, source_position, cutoff_squared, ncoset, indco) &
378 !$OMP PRIVATE(point, relative, radius2, iset, n_cart_total, ishell, l, istart_co, &
379 !$OMP iend_co, first_sgf, last_sgf, ipgf, exponent, exponential, isgf, ico, &
380 !$OMP row_index, weight, lx, ly, lz, polynomial, polynomial_derivative, alpha)
381 DO point = 1, SIZE(grid_points, 2)
382 relative = pbc(grid_points(:, point) - source_position, cell)
383 radius2 = dot_product(relative, relative)
384 IF (PRESENT(cutoff_squared)) THEN
385 IF (radius2 > cutoff_squared) cycle
386 END IF
387
388 DO iset = 1, basis%nset
389 n_cart_total = ncoset(basis%lmax(iset))
390 DO ishell = 1, basis%nshell(iset)
391 l = basis%l(ishell, iset)
392 istart_co = ncoset(l - 1) + 1
393 iend_co = ncoset(l)
394 first_sgf = basis%first_sgf(ishell, iset)
395 last_sgf = basis%last_sgf(ishell, iset)
396 DO ipgf = 1, basis%npgf(iset)
397 exponent = basis%zet(ipgf, iset)
398 exponential = exp(-exponent*radius2)
399 DO isgf = first_sgf, last_sgf
400 DO ico = istart_co, iend_co
401 row_index = (ipgf - 1)*n_cart_total + ico
402 weight = basis%sphi(row_index, isgf)
403 lx = indco(1, ico)
404 ly = indco(2, ico)
405 lz = indco(3, ico)
406 polynomial = relative(1)**lx*relative(2)**ly*relative(3)**lz
407 phi(point, isgf) = phi(point, isgf) + weight*polynomial*exponential
408
409 IF (PRESENT(dphi)) THEN
410 polynomial_derivative = 0.0_dp
411 IF (lx > 0) polynomial_derivative(1) = real(lx, dp)*relative(1)**(lx - 1)* &
412 relative(2)**ly*relative(3)**lz
413 IF (ly > 0) polynomial_derivative(2) = real(ly, dp)*relative(1)**lx* &
414 relative(2)**(ly - 1)*relative(3)**lz
415 IF (lz > 0) polynomial_derivative(3) = real(lz, dp)*relative(1)**lx* &
416 relative(2)**ly*relative(3)**(lz - 1)
417 DO alpha = 1, 3
418 dphi(alpha, point, isgf) = dphi(alpha, point, isgf) + weight*exponential* &
419 (polynomial_derivative(alpha) - 2.0_dp*exponent*relative(alpha)*polynomial)
420 END DO
421 END IF
422 END DO
423 END DO
424 END DO
425 END DO
426 END DO
427 END DO
428 !$OMP END PARALLEL DO
429 END SUBROUTINE evaluate_ao_basis_on_points
430
431END MODULE rirs_grid_utils
double distance_squared(double *A, double *B)
Definition grpp_utils.c:68
Handles all functions related to the CELL.
Definition cell_types.F:15
Utility routines to open and close files. Tracking of preconnections.
Definition cp_files.F:16
subroutine, public open_file(file_name, file_status, file_form, file_action, file_position, file_pad, unit_number, debug, skip_get_unit_number, file_access)
Opens the requested file using a free unit number.
Definition cp_files.F:311
subroutine, public close_file(unit_number, file_status, keep_preconnection)
Close an open file given by its logical unit number. Optionally, keep the file and unit preconnected.
Definition cp_files.F:122
Defines the basic variable types.
Definition kinds.F:23
integer, parameter, public dp
Definition kinds.F:34
integer, parameter, public default_string_length
Definition kinds.F:57
integer, parameter, public default_path_length
Definition kinds.F:58
Provides Cartesian and spherical orbital pointers and indices.
integer, dimension(:), allocatable, public ncoset
integer, dimension(:, :), allocatable, public indco
Define the data structure for the particle information.
Define the quickstep kind type and their sub types.
subroutine, public get_qs_kind(qs_kind, basis_set, basis_type, ncgf, nsgf, all_potential, tnadd_potential, gth_potential, sgp_potential, upf_potential, cneo_potential, se_parameter, dftb_parameter, xtb_parameter, dftb3_param, zatom, 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_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, hund_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, proj_shell_charge, lr_atom, do_mtlr, u_j_loop, ao_coef, init_u_ramping_each_scf, reltmat, ghost, monovalent, floating, name, element_symbol, pao_basis_size, pao_model_file, pao_potentials, pao_descriptors, nelec)
Get attributes of an atomic kind.
Shared RI-RS grid I/O and contracted-Gaussian evaluation utilities.
integer function, public read_rirs_grid_npoints(filename)
Read the number of points from an RI-RS grid file.
subroutine, public get_rirs_grid_filepath(element_symbol, grid_select, grid_file_suffix, filepath)
Construct the path of an RI-RS grid file.
subroutine, public initialize_rirs_grid(points, n_select, center_atom, particle_set, n_voronoi_candidates)
Build one deterministic atom-specific grid from a tabulated source grid.
subroutine, public evaluate_ao_on_points(phi, grid_points, atom_index, particle_set, qs_kind_set, cell, dphi, cutoff_squared)
Evaluate contracted spherical AOs, and optionally their grid-coordinate derivatives.
subroutine, public evaluate_ao_basis_on_points(phi, grid_points, basis, source_position, cell, dphi, cutoff_squared)
Evaluate one explicitly supplied contracted Gaussian basis on Cartesian points.
subroutine, public read_rirs_grid_file(filename, points)
Read Cartesian grid points from the existing CP2K RI-RS .ion format.
Type defining parameters related to the simulation cell.
Definition cell_types.F:60
Provides all information about a quickstep kind.