(git:5e7fe52)
Loading...
Searching...
No Matches
gw_optimize_ri_rs_grid.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 Local-environment optimizer for atom-centred real-space RI grids.
10!> \author Jan Wilhelm
11! **************************************************************************************************
14 USE cell_types, ONLY: cell_type,&
15 get_cell,&
16 pbc,&
18 USE cp_lbfgs, ONLY: setulb
27 USE kinds, ONLY: dp
28 USE libint_2c_3c, ONLY: libint_potential_type
31 USE physcon, ONLY: angstrom
36#include "./base/base_uses.f90"
37
38 IMPLICIT NONE
39 PRIVATE
40
41 CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'gw_optimize_ri_rs_grid'
42 REAL(KIND=dp), PARAMETER, PRIVATE :: optimizer_accuracy = 1.0e-9_dp
43 REAL(KIND=dp), PARAMETER, PRIVATE :: truncated_coulomb_cutoff = 3.0_dp/angstrom
44
45 TYPE :: local_cluster_type
46 INTEGER, ALLOCATABLE :: atoms(:)
47 REAL(KIND=dp), ALLOCATABLE :: three_center(:, :, :)
48 END TYPE local_cluster_type
49
50 PUBLIC :: optimize_ri_rs_grid
51
52CONTAINS
53
54! **************************************************************************************************
55!> \brief Optimize the selected RI-RS grids stored in a GW band-structure environment.
56!> \param qs_env Quickstep environment used by the upstream three-center-integral context.
57!> \param bs_env GW environment containing all configuration, basis, geometry, parallel, and grid data.
58! **************************************************************************************************
59 SUBROUTINE optimize_ri_rs_grid(qs_env, bs_env)
60 TYPE(qs_environment_type), POINTER :: qs_env
61 TYPE(post_scf_bandstructure_type), POINTER :: bs_env
62
63 CHARACTER(len=*), PARAMETER :: routinen = 'optimize_ri_rs_grid'
64
65 INTEGER :: handle, iatom, ikind, n_variable, &
66 periodic(3), unit_nr
67 INTEGER, ALLOCATABLE :: ao_size(:), grid_offsets(:), ri_size(:)
68 LOGICAL :: successful
69 REAL(kind=dp) :: f, maximum_absolute_error
70 REAL(kind=dp), ALLOCATABLE :: g(:), lower(:), upper(:), x(:)
71 TYPE(cell_type), POINTER :: cell
72 TYPE(gw_3c_ctx_type) :: integral_context
73 TYPE(local_cluster_type), ALLOCATABLE :: clusters(:)
74 TYPE(mp_para_env_type), POINTER :: para_env
75 TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
76
77 CALL timeset(routinen, handle)
78 NULLIFY (cell, para_env, particle_set)
79 cell => bs_env%ri_rs%cell
80 particle_set => bs_env%ri_rs%particle_set
81 para_env => bs_env%para_env
82 cpassert(ASSOCIATED(cell))
83 cpassert(ASSOCIATED(particle_set))
84 cpassert(ASSOCIATED(para_env))
85 cpassert(ALLOCATED(bs_env%basis_set_AO))
86 cpassert(ALLOCATED(bs_env%basis_set_RI))
87 cpassert(ALLOCATED(bs_env%ri_rs%grid_cache))
88
89 IF (bs_env%ri_rs%grid_opt%max_iter < 1) THEN
90 cpabort("GRID_OPTIMIZATION%MAX_ITER must be positive")
91 END IF
92 IF (bs_env%ri_rs%grid_opt%cutoff_atomic_cluster <= 0.0_dp) THEN
93 cpabort("GRID_OPTIMIZATION%CUTOFF_ATOMIC_CLUSTER must be positive")
94 END IF
95 IF (bs_env%ri_rs%tikhonov < 0.0_dp) THEN
96 cpabort("RI_RS%TIKHONOV must not be negative")
97 END IF
98
99 CALL get_cell(cell, periodic=periodic)
100 IF (any(periodic /= use_perd_none)) THEN
101 cpabort("GRID_OPTIMIZATION currently supports nonperiodic local environments only")
102 END IF
103
104 unit_nr = bs_env%unit_nr
105 ALLOCATE (ao_size(SIZE(particle_set)), ri_size(SIZE(particle_set)))
106 DO iatom = 1, SIZE(particle_set)
107 ikind = particle_set(iatom)%atomic_kind%kind_number
108 cpassert(ASSOCIATED(bs_env%basis_set_AO(ikind)%gto_basis_set))
109 cpassert(ASSOCIATED(bs_env%basis_set_RI(ikind)%gto_basis_set))
110 ao_size(iatom) = bs_env%basis_set_AO(ikind)%gto_basis_set%nsgf
111 ri_size(iatom) = bs_env%basis_set_RI(ikind)%gto_basis_set%nsgf
112 END DO
113 IF (any(ao_size < 1) .OR. any(ri_size < 1)) THEN
114 cpabort("Every atom in GRID_OPTIMIZATION needs ORB and RI_AUX functions")
115 END IF
116
117 cpassert(SIZE(bs_env%ri_rs%grid_cache) == SIZE(particle_set))
118 ALLOCATE (grid_offsets(SIZE(bs_env%ri_rs%grid_cache)))
119 n_variable = 0
120 DO iatom = 1, SIZE(bs_env%ri_rs%grid_cache)
121 grid_offsets(iatom) = n_variable
122 n_variable = n_variable + 3*SIZE(bs_env%ri_rs%grid_cache(iatom)%raw_points, 2)
123 END DO
124 block
125 TYPE(libint_potential_type) :: potential
126 potential%potential_type = do_potential_truncated
127 potential%cutoff_radius = truncated_coulomb_cutoff
128 potential%omega = 0.0_dp
129 potential%filename = "t_c_g.dat"
130 CALL gw_3c_ctx_create(integral_context, qs_env, potential, &
131 bs_env%basis_set_AO, bs_env%basis_set_AO, bs_env%basis_set_RI)
132 END block
133 CALL build_local_clusters(integral_context, particle_set, cell, ao_size, ri_size, &
134 bs_env%ri_rs%grid_opt%cutoff_atomic_cluster, para_env, clusters)
135
136 ALLOCATE (x(n_variable), g(n_variable), lower(n_variable), upper(n_variable))
137 CALL pack_atom_grids(bs_env%ri_rs%grid_cache, grid_offsets, x)
138 lower(:) = x - 100.0_dp/angstrom
139 upper(:) = x + 100.0_dp/angstrom
140 CALL optimize_grid_coordinates(x, lower, upper, optimizer_accuracy, &
141 bs_env%ri_rs%grid_opt%max_iter, bs_env, clusters, grid_offsets)
142 CALL grid_objective(x, bs_env, clusters, grid_offsets, f, g, &
143 maximum_absolute_error, successful)
144 IF (.NOT. successful) cpabort("RI-RS grid optimization produced no regularized fit")
145
146 IF (unit_nr > 0) THEN
147 WRITE (unit_nr, '(/,T2,A)') 'RI-RS grid optimization terminated'
148 WRITE (unit_nr, '(T2,A,T72,ES9.1)') 'Normalized 3C error:', f
149 WRITE (unit_nr, '(T2,A,T72,ES9.1)') &
150 'Maximum absolute 3C error:', maximum_absolute_error
151 END IF
152
153 DO iatom = 1, SIZE(bs_env%ri_rs%grid_cache)
154 bs_env%ri_rs%grid_cache(iatom)%npts = &
155 SIZE(bs_env%ri_rs%grid_cache(iatom)%raw_points, 2)
156 END DO
157 IF (unit_nr > 0) FLUSH (unit_nr)
158
159 bs_env%ri_rs%Z_lP_exists = .false.
160 CALL gw_3c_ctx_release(integral_context)
161 CALL timestop(handle)
162
163 END SUBROUTINE optimize_ri_rs_grid
164
165! **************************************************************************************************
166!> \brief Evaluate the regularized three-centre-integral fitting error.
167!> \param coordinates Flattened atom-relative grid coordinates.
168!> \param bs_env GW environment containing RI-RS configuration and grid data.
169!> \param clusters Rank-local clusters and their exact three-centre integrals.
170!> \param grid_offsets Starting coordinate offset for each atom.
171!> \param value Mean normalized squared three-centre-integral error.
172!> \param gradient Derivative of value with respect to coordinates.
173!> \param maximum_absolute_error Largest absolute three-centre-integral error.
174!> \param valid Whether every local-cluster evaluation succeeded.
175! **************************************************************************************************
176 SUBROUTINE grid_objective(coordinates, bs_env, clusters, grid_offsets, value, gradient, &
177 maximum_absolute_error, valid)
178 REAL(kind=dp), DIMENSION(:), INTENT(IN) :: coordinates
179 TYPE(post_scf_bandstructure_type), POINTER :: bs_env
180 TYPE(local_cluster_type), DIMENSION(:), INTENT(IN) :: clusters
181 INTEGER, DIMENSION(:), INTENT(IN) :: grid_offsets
182 REAL(kind=dp), INTENT(OUT) :: value
183 REAL(kind=dp), DIMENSION(:), INTENT(OUT) :: gradient
184 REAL(kind=dp), INTENT(OUT) :: maximum_absolute_error
185 LOGICAL, INTENT(OUT) :: valid
186
187 INTEGER :: all_valid, icluster, successful_clusters
188 REAL(kind=dp) :: cluster_maximum_absolute_error, &
189 cluster_value
190 REAL(kind=dp), ALLOCATABLE :: cluster_gradient(:, :)
191 TYPE(cell_type), POINTER :: cell
192 TYPE(mp_para_env_type), POINTER :: para_env
193 TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
194
195 cell => bs_env%ri_rs%cell
196 particle_set => bs_env%ri_rs%particle_set
197 para_env => bs_env%para_env
198 CALL unpack_atom_grids(coordinates, bs_env%ri_rs%grid_cache, grid_offsets)
199 value = 0.0_dp
200 gradient = 0.0_dp
201 successful_clusters = 0
202 maximum_absolute_error = 0.0_dp
203 valid = .true.
204 DO icluster = 1, SIZE(clusters)
205 CALL evaluate_local_cluster(clusters(icluster), bs_env%ri_rs%grid_cache, &
206 bs_env, particle_set, cell, &
207 cluster_value, cluster_gradient, &
208 cluster_maximum_absolute_error, valid)
209 IF (.NOT. valid) THEN
210 IF (ALLOCATED(cluster_gradient)) DEALLOCATE (cluster_gradient)
211 EXIT
212 END IF
213 value = value + cluster_value
214 CALL accumulate_atom_gradient(clusters(icluster)%atoms, bs_env%ri_rs%grid_cache, &
215 grid_offsets, cluster_gradient, gradient)
216 successful_clusters = successful_clusters + 1
217 maximum_absolute_error = &
218 max(maximum_absolute_error, cluster_maximum_absolute_error)
219 DEALLOCATE (cluster_gradient)
220 END DO
221 all_valid = merge(1, 0, valid)
222 CALL para_env%sum(value)
223 CALL para_env%sum(gradient)
224 CALL para_env%sum(successful_clusters)
225 CALL para_env%sum(all_valid)
226 CALL para_env%max(maximum_absolute_error)
227 valid = successful_clusters == SIZE(particle_set) .AND. all_valid == para_env%num_pe
228 IF (.NOT. valid) THEN
229 value = huge(value)
230 gradient = 0.0_dp
231 RETURN
232 END IF
233 value = value/real(SIZE(particle_set), dp)
234 gradient = gradient/real(SIZE(particle_set), dp)
235 END SUBROUTINE grid_objective
236
237! **************************************************************************************************
238!> \brief Minimize the RI-RS grid objective with CP2K's bound-constrained L-BFGS implementation.
239!> \param x Coordinates on entry and best coordinates found on return.
240!> \param lower Lower bound for each coordinate.
241!> \param upper Upper bound for each coordinate.
242!> \param accuracy Projected-gradient convergence threshold.
243!> \param max_evaluations Maximum number of objective evaluations.
244!> \param bs_env GW environment containing RI-RS configuration and grid data.
245!> \param clusters Rank-local clusters and their exact three-centre integrals.
246!> \param grid_offsets Starting coordinate offset for each atom.
247! **************************************************************************************************
248 SUBROUTINE optimize_grid_coordinates(x, lower, upper, accuracy, max_evaluations, &
249 bs_env, clusters, grid_offsets)
250 REAL(kind=dp), DIMENSION(:), INTENT(INOUT) :: x
251 REAL(kind=dp), DIMENSION(:), INTENT(IN) :: lower, upper
252 REAL(kind=dp), INTENT(IN) :: accuracy
253 INTEGER, INTENT(IN) :: max_evaluations
254 TYPE(post_scf_bandstructure_type), POINTER :: bs_env
255 TYPE(local_cluster_type), DIMENSION(:), INTENT(IN) :: clusters
256 INTEGER, DIMENSION(:), INTENT(IN) :: grid_offsets
257
258 INTEGER, PARAMETER :: memory = 7
259
260 CHARACTER(LEN=60) :: csave, task
261 INTEGER :: evaluations
262 REAL(kind=dp), DIMENSION(29) :: dsave
263 REAL(kind=dp), DIMENSION(2*memory*SIZE(x)+5*SIZE(x& )+11*memory**2+8*memory) :: wa
264 REAL(kind=dp) :: best_f, f, maximum_absolute_error
265 LOGICAL, DIMENSION(4) :: lsave
266 LOGICAL :: evaluation_ok, have_best
267 INTEGER, DIMENSION(SIZE(x)) :: bound_type
268 INTEGER, DIMENSION(44) :: isave
269 INTEGER, DIMENSION(3*SIZE(x)) :: iwa
270 REAL(kind=dp), DIMENSION(SIZE(x)) :: best_x, g
271
272 cpassert(SIZE(x) > 0)
273 cpassert(all(shape(lower) == shape(x)) .AND. all(shape(upper) == shape(x)))
274 cpassert(all(lower <= upper))
275 cpassert(accuracy > 0.0_dp .AND. max_evaluations > 0)
276
277 bound_type = 2
278 task = 'START'
279 csave = ''
280 f = huge(f)
281 g = 0.0_dp
282 wa = 0.0_dp
283 iwa = 0
284 lsave = .false.
285 isave = 0
286 dsave = 0.0_dp
287 evaluations = 0
288 have_best = .false.
289 best_f = huge(best_f)
290 best_x = x
291
292 DO
293 CALL setulb(SIZE(x), memory, x, lower, upper, bound_type, f, g, &
294 0.0_dp, accuracy, wa, iwa, task, -1, csave, lsave, isave, dsave, -1.0_dp)
295 IF (task(1:2) == 'FG') THEN
296 IF (evaluations >= max_evaluations) EXIT
297 CALL grid_objective(x, bs_env, clusters, grid_offsets, f, g, &
298 maximum_absolute_error, evaluation_ok)
299 evaluations = evaluations + 1
300 IF (.NOT. evaluation_ok) EXIT
301 IF (.NOT. have_best .OR. f < best_f) THEN
302 have_best = .true.
303 best_f = f
304 best_x = x
305 END IF
306 ELSE IF (task(1:5) == 'NEW_X') THEN
307 cycle
308 ELSE
309 EXIT
310 END IF
311 END DO
312 IF (have_best) x = best_x
313 END SUBROUTINE optimize_grid_coordinates
314
315! **************************************************************************************************
316!> \brief Build local clusters and precompute exact (mu nu|P) values on their owning rank.
317!> \param context Three-centre-integral evaluation context.
318!> \param particle_set Atomic positions and kinds.
319!> \param cell Simulation cell.
320!> \param ao_size Number of orbital basis functions on each atom.
321!> \param ri_size Number of auxiliary basis functions on each atom.
322!> \param cutoff Radius of each atom-centred local cluster.
323!> \param para_env MPI environment used to distribute cluster ownership.
324!> \param clusters Rank-local clusters and their exact three-centre integrals.
325! **************************************************************************************************
326 SUBROUTINE build_local_clusters(context, particle_set, cell, ao_size, ri_size, cutoff, &
327 para_env, clusters)
328 TYPE(gw_3c_ctx_type), INTENT(IN) :: context
329 TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
330 TYPE(cell_type), POINTER :: cell
331 INTEGER, DIMENSION(:), INTENT(IN) :: ao_size, ri_size
332 REAL(kind=dp), INTENT(IN) :: cutoff
333 TYPE(mp_para_env_type), POINTER :: para_env
334 TYPE(local_cluster_type), ALLOCATABLE, INTENT(OUT) :: clusters(:)
335
336 INTEGER :: center, ia, iatom, ja, jatom, ka, katom, &
337 n_ao, n_cluster, n_ri
338 INTEGER, ALLOCATABLE :: ao_offset(:), atom_buffer(:), &
339 ri_offset(:)
340 LOGICAL :: screened
341 TYPE(gw_3c_ws_type) :: workspace
342
343 n_cluster = count([(mod(center - 1, para_env%num_pe) == para_env%mepos, &
344 center=1, SIZE(particle_set))])
345 ALLOCATE (clusters(n_cluster), atom_buffer(SIZE(particle_set)), &
346 ao_offset(SIZE(particle_set)), ri_offset(SIZE(particle_set)))
347 CALL gw_3c_ws_create(workspace, context)
348 n_cluster = 0
349 DO center = 1, SIZE(particle_set)
350 IF (mod(center - 1, para_env%num_pe) /= para_env%mepos) cycle
351 n_cluster = n_cluster + 1
352 ia = 0
353 DO iatom = 1, SIZE(particle_set)
354 IF (sum(pbc(particle_set(iatom)%r - particle_set(center)%r, cell)**2) <= cutoff**2) THEN
355 ia = ia + 1
356 atom_buffer(ia) = iatom
357 END IF
358 END DO
359 ALLOCATE (clusters(n_cluster)%atoms(ia), source=atom_buffer(1:ia))
360 ao_offset = 0
361 ri_offset = 0
362 n_ao = 0
363 n_ri = 0
364 DO ia = 1, SIZE(clusters(n_cluster)%atoms)
365 iatom = clusters(n_cluster)%atoms(ia)
366 ao_offset(iatom) = n_ao
367 ri_offset(iatom) = n_ri
368 n_ao = n_ao + ao_size(iatom)
369 n_ri = n_ri + ri_size(iatom)
370 END DO
371 ALLOCATE (clusters(n_cluster)%three_center(n_ao, n_ao, n_ri), source=0.0_dp)
372 DO ia = 1, SIZE(clusters(n_cluster)%atoms)
373 iatom = clusters(n_cluster)%atoms(ia)
374 DO ka = 1, SIZE(clusters(n_cluster)%atoms)
375 katom = clusters(n_cluster)%atoms(ka)
376 DO ja = 1, SIZE(clusters(n_cluster)%atoms)
377 jatom = clusters(n_cluster)%atoms(ja)
378 CALL build_3c_integral_block_ctx( &
379 clusters(n_cluster)%three_center, context, workspace, &
380 atom_j=jatom, atom_k=katom, atom_i=iatom, &
381 j_offset=ao_offset(jatom), k_offset=ao_offset(katom), &
382 i_offset=ri_offset(iatom), screened=screened)
383 END DO
384 END DO
385 END DO
386 END DO
387 CALL gw_3c_ws_release(workspace)
388 END SUBROUTINE build_local_clusters
389
390! **************************************************************************************************
391!> \brief Evaluate one complete cluster and return derivatives for its physical grid points.
392!> \param cluster Local atoms and exact three-centre integrals.
393!> \param grids Atom-centred RI-RS grids.
394!> \param bs_env GW environment containing orbital basis sets and RI-RS parameters.
395!> \param particle_set Atomic positions and kinds.
396!> \param cell Simulation cell.
397!> \param value Normalized squared three-centre-integral error.
398!> \param gradient Derivative with respect to the cluster's physical grid coordinates.
399!> \param maximum_absolute_error Largest absolute three-centre-integral error.
400!> \param successful Whether the regularized fitting equations were solved.
401! **************************************************************************************************
402 SUBROUTINE evaluate_local_cluster(cluster, grids, bs_env, particle_set, cell, &
403 value, gradient, maximum_absolute_error, successful)
404 TYPE(local_cluster_type), INTENT(IN) :: cluster
405 TYPE(rirs_grid_type), DIMENSION(:), INTENT(IN) :: grids
406 TYPE(post_scf_bandstructure_type), POINTER :: bs_env
407 TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
408 TYPE(cell_type), POINTER :: cell
409 REAL(kind=dp), INTENT(OUT) :: value
410 REAL(kind=dp), ALLOCATABLE, INTENT(OUT) :: gradient(:, :)
411 REAL(kind=dp), INTENT(OUT) :: maximum_absolute_error
412 LOGICAL, INTENT(OUT) :: successful
413
414 INTEGER :: ao_offset, ia, iatom, ikind, n_ao, &
415 n_atom_ao, n_grid, point_offset
416 REAL(kind=dp), ALLOCATABLE :: dphi(:, :, :), phi(:, :), points(:, :)
417 TYPE(gto_basis_set_type), POINTER :: basis
418
419 n_ao = SIZE(cluster%three_center, 1)
420 n_grid = 0
421 DO ia = 1, SIZE(cluster%atoms)
422 iatom = cluster%atoms(ia)
423 n_grid = n_grid + SIZE(grids(iatom)%raw_points, 2)
424 END DO
425 ALLOCATE (points(3, n_grid), phi(n_grid, n_ao), &
426 dphi(3, n_grid, n_ao), gradient(3, n_grid))
427 phi = 0.0_dp
428 dphi = 0.0_dp
429 point_offset = 0
430 DO ia = 1, SIZE(cluster%atoms)
431 iatom = cluster%atoms(ia)
432 points(:, point_offset + 1:point_offset + SIZE(grids(iatom)%raw_points, 2)) = &
433 spread(particle_set(iatom)%r, 2, SIZE(grids(iatom)%raw_points, 2)) + &
434 grids(iatom)%raw_points
435 point_offset = point_offset + SIZE(grids(iatom)%raw_points, 2)
436 END DO
437 ao_offset = 0
438 DO ia = 1, SIZE(cluster%atoms)
439 iatom = cluster%atoms(ia)
440 ikind = particle_set(iatom)%atomic_kind%kind_number
441 basis => bs_env%basis_set_AO(ikind)%gto_basis_set
442 n_atom_ao = basis%nsgf
443 CALL evaluate_ao_basis_on_points( &
444 phi(:, ao_offset + 1:ao_offset + n_atom_ao), points, basis, &
445 particle_set(iatom)%r, cell, &
446 dphi=dphi(:, :, ao_offset + 1:ao_offset + n_atom_ao))
447 ao_offset = ao_offset + n_atom_ao
448 END DO
449 CALL evaluate_rirs_grid_cluster(phi, dphi, cluster%three_center, bs_env%ri_rs%tikhonov, &
450 value, gradient, maximum_absolute_error, successful)
451 END SUBROUTINE evaluate_local_cluster
452
453! **************************************************************************************************
454!> \brief Evaluate the regularized local-cluster three-centre fit and its coordinate gradient.
455!>
456!> The solve applies the same column Jacobi scaling and Tikhonov parameter as the production
457!> Z_lP construction. The objective contains only the normalized three-centre-integral residual.
458!> \param phi AO values, indexed (l,mu).
459!> \param dphi Cartesian derivatives of AO values, indexed (alpha,l,mu).
460!> \param three_center Exact three-centre integrals, indexed (mu,nu,P).
461!> \param tikhonov Tikhonov parameter used by the production RI-RS solve.
462!> \param value Normalized squared residual for this cluster.
463!> \param gradient Analytic derivative d value/d r(alpha,l).
464!> \param maximum_absolute_error Largest absolute error in an unweighted three-centre integral.
465!> \param successful False if the regularized normal equations cannot be solved.
466! **************************************************************************************************
467 SUBROUTINE evaluate_rirs_grid_cluster(phi, dphi, three_center, tikhonov, value, gradient, &
468 maximum_absolute_error, successful)
469 REAL(kind=dp), DIMENSION(:, :), INTENT(IN) :: phi
470 REAL(kind=dp), DIMENSION(:, :, :), INTENT(IN) :: dphi, three_center
471 REAL(kind=dp), INTENT(IN) :: tikhonov
472 REAL(kind=dp), INTENT(OUT) :: value
473 REAL(kind=dp), DIMENSION(:, :), INTENT(OUT) :: gradient
474 REAL(kind=dp), INTENT(OUT) :: maximum_absolute_error
475 LOGICAL, INTENT(OUT) :: successful
476
477 CHARACTER(len=*), PARAMETER :: routinen = 'evaluate_rirs_grid_cluster'
478 REAL(kind=dp), PARAMETER :: jacobi_floor = 1.0e-16_dp
479
480 INTEGER :: alpha, handle, info, ipair, l, mu, n_ao, &
481 n_grid, n_pair, n_ri, nu, p
482 INTEGER, ALLOCATABLE :: pair_mu(:), pair_nu(:)
483 REAL(kind=dp) :: absolute_error, column_norm2, d_a, &
484 denom, factor, projection, scale
485 REAL(kind=dp), ALLOCATABLE :: a_matrix(:, :), a_scaled(:, :), b_matrix(:, :), &
486 derivative_a(:, :), derivative_scaled_a(:), gram(:, :), residual(:, :), rhs(:, :), &
487 scale_columns(:), y_matrix(:, :), yz_matrix(:, :), z_matrix(:, :)
488
489 CALL timeset(routinen, handle)
490
491 n_grid = SIZE(phi, 1)
492 n_ao = SIZE(phi, 2)
493 n_ri = SIZE(three_center, 3)
494 n_pair = n_ao*(n_ao + 1)/2
495
496 cpassert(SIZE(dphi, 1) == 3)
497 cpassert(SIZE(dphi, 2) == n_grid)
498 cpassert(SIZE(dphi, 3) == n_ao)
499 cpassert(SIZE(three_center, 1) == n_ao)
500 cpassert(SIZE(three_center, 2) == n_ao)
501 cpassert(SIZE(gradient, 1) == 3)
502 cpassert(SIZE(gradient, 2) == n_grid)
503 cpassert(tikhonov >= 0.0_dp)
504
505 value = huge(value)
506 gradient = 0.0_dp
507 maximum_absolute_error = huge(maximum_absolute_error)
508 successful = .false.
509 IF (n_grid < 1 .OR. n_ri < 1) THEN
510 CALL timestop(handle)
511 RETURN
512 END IF
513
514 ALLOCATE (a_matrix(n_pair, n_grid), a_scaled(n_pair, n_grid), &
515 b_matrix(n_pair, n_ri), pair_mu(n_pair), pair_nu(n_pair), &
516 scale_columns(n_grid))
517 ipair = 0
518 DO nu = 1, n_ao
519 DO mu = 1, nu
520 ipair = ipair + 1
521 pair_mu(ipair) = mu
522 pair_nu(ipair) = nu
523 factor = sqrt(real(2 - merge(1, 0, mu == nu), dp))
524 DO l = 1, n_grid
525 a_matrix(ipair, l) = factor*phi(l, mu)*phi(l, nu)
526 END DO
527 DO p = 1, n_ri
528 b_matrix(ipair, p) = factor*three_center(mu, nu, p)
529 END DO
530 END DO
531 END DO
532
533 denom = sum(b_matrix*b_matrix)
534 IF (denom <= tiny(1.0_dp)) THEN
535 DEALLOCATE (a_matrix, a_scaled, b_matrix, pair_mu, pair_nu, scale_columns)
536 CALL timestop(handle)
537 RETURN
538 END IF
539
540 ! Production Z_lP uses D'=d(A^T A)d+lambda I with d_l=1/sqrt((A^T A)_ll).
541 DO l = 1, n_grid
542 column_norm2 = sum(a_matrix(:, l)*a_matrix(:, l))
543 scale_columns(l) = 1.0_dp/sqrt(max(column_norm2, jacobi_floor))
544 a_scaled(:, l) = scale_columns(l)*a_matrix(:, l)
545 END DO
546 ALLOCATE (gram(n_grid, n_grid), rhs(n_grid, n_ri), z_matrix(n_grid, n_ri))
547 CALL dgemm('T', 'N', n_grid, n_grid, n_pair, 1.0_dp, a_scaled, n_pair, &
548 a_scaled, n_pair, 0.0_dp, gram, n_grid)
549 DO l = 1, n_grid
550 gram(l, l) = gram(l, l) + tikhonov
551 END DO
552 CALL dgemm('T', 'N', n_grid, n_ri, n_pair, 1.0_dp, a_scaled, n_pair, &
553 b_matrix, n_pair, 0.0_dp, rhs, n_grid)
554 CALL dpotrf('L', n_grid, gram, n_grid, info)
555 IF (info /= 0) THEN
556 DEALLOCATE (a_matrix, a_scaled, b_matrix, gram, pair_mu, pair_nu, rhs, &
557 scale_columns, z_matrix)
558 CALL timestop(handle)
559 RETURN
560 END IF
561 z_matrix(:, :) = rhs
562 CALL dpotrs('L', n_grid, n_ri, gram, n_grid, z_matrix, n_grid, info)
563 DEALLOCATE (rhs)
564 IF (info /= 0) THEN
565 DEALLOCATE (a_matrix, a_scaled, b_matrix, gram, pair_mu, pair_nu, &
566 scale_columns, z_matrix)
567 CALL timestop(handle)
568 RETURN
569 END IF
570
571 ALLOCATE (residual(n_pair, n_ri))
572 residual(:, :) = b_matrix
573 CALL dgemm('N', 'N', n_pair, n_ri, n_grid, -1.0_dp, a_scaled, n_pair, &
574 z_matrix, n_grid, 1.0_dp, residual, n_pair)
575 value = sum(residual*residual)/denom
576
577 ! For lambda > 0, the residual-only derivative includes the response of the regularized
578 ! coefficients. With Y=(A^T A+lambda I)^(-1) Z:
579 ! dE/dA = [-2 R Z^T - 2 lambda (R Y^T - A Y Z^T)] / ||B||^2.
580 ALLOCATE (y_matrix(n_grid, n_ri), derivative_a(n_pair, n_grid))
581 y_matrix(:, :) = z_matrix
582 CALL dpotrs('L', n_grid, n_ri, gram, n_grid, y_matrix, n_grid, info)
583 IF (info /= 0) THEN
584 DEALLOCATE (a_matrix, a_scaled, b_matrix, derivative_a, gram, pair_mu, pair_nu, &
585 residual, scale_columns, y_matrix, z_matrix)
586 CALL timestop(handle)
587 RETURN
588 END IF
589 CALL dgemm('N', 'T', n_pair, n_grid, n_ri, -2.0_dp/denom, residual, n_pair, &
590 z_matrix, n_grid, 0.0_dp, derivative_a, n_pair)
591 IF (tikhonov > 0.0_dp) THEN
592 CALL dgemm('N', 'T', n_pair, n_grid, n_ri, -2.0_dp*tikhonov/denom, residual, n_pair, &
593 y_matrix, n_grid, 1.0_dp, derivative_a, n_pair)
594 ALLOCATE (yz_matrix(n_grid, n_grid))
595 CALL dgemm('N', 'T', n_grid, n_grid, n_ri, 1.0_dp, y_matrix, n_grid, &
596 z_matrix, n_grid, 0.0_dp, yz_matrix, n_grid)
597 CALL dgemm('N', 'N', n_pair, n_grid, n_grid, 2.0_dp*tikhonov/denom, a_scaled, n_pair, &
598 yz_matrix, n_grid, 1.0_dp, derivative_a, n_pair)
599 DEALLOCATE (yz_matrix)
600 END IF
601
602 ALLOCATE (derivative_scaled_a(n_pair))
603 DO l = 1, n_grid
604 scale = scale_columns(l)
605 column_norm2 = sum(a_matrix(:, l)*a_matrix(:, l))
606 DO alpha = 1, 3
607 DO ipair = 1, n_pair
608 mu = pair_mu(ipair)
609 nu = pair_nu(ipair)
610 factor = sqrt(real(2 - merge(1, 0, mu == nu), dp))
611 d_a = factor*(dphi(alpha, l, mu)*phi(l, nu) + &
612 phi(l, mu)*dphi(alpha, l, nu))
613 derivative_scaled_a(ipair) = scale*d_a
614 END DO
615 IF (column_norm2 > jacobi_floor) THEN
616 projection = dot_product(a_matrix(:, l), derivative_scaled_a)/scale
617 derivative_scaled_a(:) = derivative_scaled_a - &
618 scale**3*a_matrix(:, l)*projection
619 END IF
620 gradient(alpha, l) = dot_product(derivative_a(:, l), derivative_scaled_a)
621 END DO
622 END DO
623
624 maximum_absolute_error = 0.0_dp
625 DO p = 1, n_ri
626 DO ipair = 1, n_pair
627 factor = sqrt(real(2 - merge(1, 0, pair_mu(ipair) == pair_nu(ipair)), dp))
628 absolute_error = abs(residual(ipair, p))/factor
629 maximum_absolute_error = max(maximum_absolute_error, absolute_error)
630 END DO
631 END DO
632
633 successful = .true.
634 DEALLOCATE (a_matrix, a_scaled, b_matrix, derivative_a, derivative_scaled_a, gram, &
635 pair_mu, pair_nu, residual, scale_columns, y_matrix, z_matrix)
636 CALL timestop(handle)
637 END SUBROUTINE evaluate_rirs_grid_cluster
638
639! **************************************************************************************************
640!> \brief Sum each physical occurrence into its atom-relative coordinate.
641!> \param atoms Atom indices in the local cluster.
642!> \param grids Atom-centred RI-RS grids.
643!> \param grid_offsets Starting coordinate offset for each atom.
644!> \param physical_gradient Gradient for the cluster's physical grid points.
645!> \param gradient Global flattened atom-relative gradient to update.
646! **************************************************************************************************
647 SUBROUTINE accumulate_atom_gradient(atoms, grids, grid_offsets, physical_gradient, gradient)
648 INTEGER, DIMENSION(:), INTENT(IN) :: atoms
649 TYPE(rirs_grid_type), DIMENSION(:), INTENT(IN) :: grids
650 INTEGER, DIMENSION(:), INTENT(IN) :: grid_offsets
651 REAL(kind=dp), DIMENSION(:, :), INTENT(IN) :: physical_gradient
652 REAL(kind=dp), DIMENSION(:), INTENT(INOUT) :: gradient
653
654 INTEGER :: alpha, ia, iatom, l, point_offset
655
656 point_offset = 0
657 DO ia = 1, SIZE(atoms)
658 iatom = atoms(ia)
659 DO l = 1, SIZE(grids(iatom)%raw_points, 2)
660 DO alpha = 1, 3
661 gradient(grid_offsets(iatom) + 3*(l - 1) + alpha) = &
662 gradient(grid_offsets(iatom) + 3*(l - 1) + alpha) + &
663 physical_gradient(alpha, point_offset + l)
664 END DO
665 END DO
666 point_offset = point_offset + SIZE(grids(iatom)%raw_points, 2)
667 END DO
668 END SUBROUTINE accumulate_atom_gradient
669
670! **************************************************************************************************
671!> \brief Flatten atom-relative Cartesian coordinates into the optimizer vector.
672!> \param grids Atom-centred RI-RS grids.
673!> \param grid_offsets Starting coordinate offset for each atom.
674!> \param coordinates Flattened atom-relative grid coordinates.
675! **************************************************************************************************
676 SUBROUTINE pack_atom_grids(grids, grid_offsets, coordinates)
677 TYPE(rirs_grid_type), DIMENSION(:), INTENT(IN) :: grids
678 INTEGER, DIMENSION(:), INTENT(IN) :: grid_offsets
679 REAL(kind=dp), DIMENSION(:), INTENT(OUT) :: coordinates
680
681 INTEGER :: iatom, n_coordinate
682
683 cpassert(SIZE(grid_offsets) == SIZE(grids))
684 DO iatom = 1, SIZE(grids)
685 n_coordinate = SIZE(grids(iatom)%raw_points)
686 coordinates(grid_offsets(iatom) + 1:grid_offsets(iatom) + n_coordinate) = &
687 reshape(grids(iatom)%raw_points, [n_coordinate])
688 END DO
689 END SUBROUTINE pack_atom_grids
690
691! **************************************************************************************************
692!> \brief Restore atom-relative Cartesian coordinates from the optimizer vector.
693!> \param coordinates Flattened atom-relative grid coordinates.
694!> \param grids Atom-centred RI-RS grids to update.
695!> \param grid_offsets Starting coordinate offset for each atom.
696! **************************************************************************************************
697 SUBROUTINE unpack_atom_grids(coordinates, grids, grid_offsets)
698 REAL(kind=dp), DIMENSION(:), INTENT(IN) :: coordinates
699 TYPE(rirs_grid_type), DIMENSION(:), INTENT(INOUT) :: grids
700 INTEGER, DIMENSION(:), INTENT(IN) :: grid_offsets
701
702 INTEGER :: iatom, n_coordinate
703
704 cpassert(SIZE(grid_offsets) == SIZE(grids))
705 DO iatom = 1, SIZE(grids)
706 n_coordinate = SIZE(grids(iatom)%raw_points)
707 grids(iatom)%raw_points(:, :) = reshape( &
708 coordinates(grid_offsets(iatom) + 1:grid_offsets(iatom) + n_coordinate), &
709 shape(grids(iatom)%raw_points))
710 END DO
711 END SUBROUTINE unpack_atom_grids
712
713END MODULE gw_optimize_ri_rs_grid
714
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.
Handles all functions related to the CELL.
Definition cell_types.F:15
subroutine, public get_cell(cell, alpha, beta, gamma, deth, orthorhombic, abc, periodic, h, h_inv, symmetry_id, tag)
Get informations about a simulation cell.
Definition cell_types.F:233
integer, parameter, public use_perd_none
Definition cell_types.F:42
LBFGS-B routine (version 3.0, April 25, 2011).
Definition cp_lbfgs.F:19
subroutine, public setulb(n, m, x, lower_bound, upper_bound, nbd, f, g, factr, pgtol, wa, iwa, task, iprint, csave, lsave, isave, dsave, trust_radius, spgr, iwunit)
This subroutine partitions the working arrays wa and iwa, and then uses the limited memory BFGS metho...
Definition cp_lbfgs.F:188
Utility method to build 3-center integrals for small cell GW.
subroutine, public build_3c_integral_block_ctx(int_3c, ctx, ws, atom_j, atom_k, atom_i, cell_j, cell_k, cell_i, j_offset, k_offset, i_offset, screened)
Computes the 3c integral block (mu(atom_j) nu(atom_k) | P(atom_i)) for ONE atom triple,...
subroutine, public gw_3c_ws_create(ws, ctx)
Creates a per-thread 3c workspace: libint object + LIBXSMM contraction buffers.
subroutine, public gw_3c_ws_release(ws)
Releases a per-thread 3c workspace.
subroutine, public gw_3c_ctx_release(ctx)
Releases the shared 3c-integral context.
subroutine, public gw_3c_ctx_create(ctx, qs_env, potential_parameter, basis_j, basis_k, basis_i)
Builds the shared 3c-integral context: screening radii, basis maxima, contracted sphi tables,...
Local-environment optimizer for atom-centred real-space RI grids.
subroutine, public optimize_ri_rs_grid(qs_env, bs_env)
Optimize the selected RI-RS grids stored in a GW band-structure environment.
collects all constants needed in input so that they can be used without circular dependencies
integer, parameter, public do_potential_truncated
Defines the basic variable types.
Definition kinds.F:23
integer, parameter, public dp
Definition kinds.F:34
2- and 3-center electron repulsion integral routines based on libint2 Currently available operators: ...
Interface to the message passing library MPI.
Define the data structure for the particle information.
Definition of physical constants:
Definition physcon.F:68
real(kind=dp), parameter, public angstrom
Definition physcon.F:144
Shared RI-RS grid I/O and contracted-Gaussian evaluation utilities.
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.
Type defining parameters related to the simulation cell.
Definition cell_types.F:60
Shared read-only context for repeated 3-center integral block builds: screening parameters,...
Per-thread workspace for 3-center integral block builds: libint object + contraction buffers....
stores all the informations relevant to an mpi environment