28#include "./base/base_uses.f90"
32 CHARACTER(len=*),
PARAMETER,
PRIVATE :: moduleN =
'gw_ri_rs_grid_initialization'
107 CHARACTER(LEN=*),
PARAMETER :: routinen =
'initialize_ri_rs_grid'
108 INTEGER,
PARAMETER :: l_additional = 2, radial_quadrature =
do_gapw_log
109 REAL(kind=
dp),
PARAMETER :: minimum_candidate_ratio = 30.0_dp
111 INTEGER :: handle, ikind
112 REAL(kind=
dp) :: candidate_ratio
115 CALL timeset(routinen, handle)
117 candidate_ratio = max(minimum_candidate_ratio, 2.0_dp*bs_env%ri_rs%grid_opt%rs_ao_ratio)
120 ALLOCATE (radial_lebedev_grids(
SIZE(bs_env%basis_set_AO)))
121 DO ikind = 1,
SIZE(bs_env%basis_set_AO)
122 CALL build_lebedev_grid(bs_env%basis_set_AO(ikind)%gto_basis_set, &
123 bs_env%basis_set_RI(ikind)%gto_basis_set, &
124 candidate_ratio, l_additional, radial_quadrature, &
125 radial_lebedev_grids(ikind))
129 CALL cholesky_selection_and_voronoi_filtering(bs_env, radial_lebedev_grids)
131 CALL broadcast_ri_rs_grids(bs_env)
133 CALL timestop(handle)
146 SUBROUTINE build_lebedev_grid(ao, ri, ratio, l_additional, radial_quadrature, grid)
148 REAL(kind=
dp),
INTENT(IN) :: ratio
149 INTEGER,
INTENT(IN) :: l_additional, radial_quadrature
152 INTEGER :: degree, ir, nang, nrad, offset, rule
155 cpassert(
ASSOCIATED(ao) .AND.
ASSOCIATED(ri))
156 degree = 2*maxval(ao%lmax) + maxval(ri%lmax) + l_additional
159 nrad = max(2, ceiling(ratio*real(ao%nsgf,
dp)/real(nang,
dp)))
161 NULLIFY (radial_grid)
164 grid%npts = nrad*nang
165 ALLOCATE (grid%raw_points(3, grid%npts))
167 offset = (ir - 1)*nang
168 grid%raw_points(:, offset + 1:offset + nang) = &
172 END SUBROUTINE build_lebedev_grid
179 SUBROUTINE cholesky_selection_and_voronoi_filtering(bs_env, radial_lebedev_grids)
183 INTEGER :: atom_mpi_rank, iatom, ikind, npoints
185 cpassert(.NOT.
ALLOCATED(bs_env%ri_rs%atomic_grids))
186 ALLOCATE (bs_env%ri_rs%atomic_grids(bs_env%n_atom))
187 DO iatom = 1, bs_env%n_atom
188 ikind = bs_env%ri_rs%particle_set(iatom)%atomic_kind%kind_number
189 npoints = ceiling(bs_env%ri_rs%grid_opt%rs_ao_ratio* &
190 bs_env%basis_set_AO(ikind)%gto_basis_set%nsgf)
191 bs_env%ri_rs%atomic_grids(iatom)%npts = npoints
192 ALLOCATE (bs_env%ri_rs%atomic_grids(iatom)%raw_points(3, npoints))
194 atom_mpi_rank = mod(iatom - 1, bs_env%para_env%num_pe)
195 IF (atom_mpi_rank == bs_env%para_env%mepos)
THEN
196 CALL select_cholesky_grid_iatom(bs_env, radial_lebedev_grids, iatom)
199 END SUBROUTINE cholesky_selection_and_voronoi_filtering
207 SUBROUTINE select_cholesky_grid_iatom(bs_env, radial_lebedev_grids, iatom)
210 INTEGER,
INTENT(IN) :: iatom
212 CHARACTER(LEN=3*default_string_length) :: failure
213 INTEGER :: igrid_point, npoints, nretained
214 INTEGER,
ALLOCATABLE :: ao_point_indices(:), atom_n_ao(:), atom_point_offsets(:), &
215 atom_value_offsets(:), cluster_atoms(:), selected_indices(:)
216 LOGICAL,
ALLOCATABLE :: inside_voronoi(:)
217 REAL(kind=
dp),
ALLOCATABLE :: ao_values(:), cluster_points(:, :)
220 bs_env%ri_rs%grid_opt%cutoff_atomic_cluster, cluster_atoms)
221 CALL collect_cluster_lebedev_points(bs_env, radial_lebedev_grids, iatom, &
222 cluster_atoms, cluster_points)
223 npoints =
SIZE(cluster_points, 2)
224 ALLOCATE (inside_voronoi(npoints))
227 IF (count(inside_voronoi) < bs_env%ri_rs%atomic_grids(iatom)%npts)
THEN
228 WRITE (failure,
'(A,I0,A,I0,A,I0,A)')
'Atom ', iatom,
': only ', count(inside_voronoi), &
229 ' Voronoi grid points for ', bs_env%ri_rs%atomic_grids(iatom)%npts, &
230 ' points; reduce RS_AO_RATIO.'
231 cpabort(trim(failure))
234 CALL evaluate_cluster_ao_values(bs_env, iatom, cluster_atoms, cluster_points, &
235 ao_point_indices, atom_point_offsets, atom_value_offsets, &
236 atom_n_ao, ao_values)
237 ALLOCATE (selected_indices(bs_env%ri_rs%atomic_grids(iatom)%npts))
238 CALL select_cholesky_grid_points(ao_point_indices, atom_point_offsets, atom_value_offsets, &
239 atom_n_ao, ao_values, npoints, &
240 inside_voronoi, selected_indices)
241 nretained = count(selected_indices > 0)
242 IF (nretained == 0)
THEN
243 WRITE (failure,
'(A,I0,A)')
'Atom ', iatom, &
244 ': Cholesky selection found no numerically independent point.'
245 cpabort(trim(failure))
246 ELSE IF (nretained <
SIZE(selected_indices))
THEN
247 CALL complete_grid_by_maximin_distance(cluster_points, inside_voronoi, selected_indices)
249 DO igrid_point = 1,
SIZE(selected_indices)
250 bs_env%ri_rs%atomic_grids(iatom)%raw_points(:, igrid_point) = &
251 cluster_points(:, selected_indices(igrid_point))
253 END SUBROUTINE select_cholesky_grid_iatom
261 SUBROUTINE complete_grid_by_maximin_distance(cluster_points, inside_voronoi, selected_indices)
262 REAL(kind=
dp),
INTENT(IN) :: cluster_points(:, :)
263 LOGICAL,
INTENT(IN) :: inside_voronoi(:)
264 INTEGER,
INTENT(INOUT) :: selected_indices(:)
266 INTEGER :: igrid_point, inew_point, iselected, &
268 LOGICAL,
ALLOCATABLE :: unselected_inside(:)
269 REAL(kind=
dp) :: distance_sq, largest_distance_sq
270 REAL(kind=
dp),
ALLOCATABLE :: nearest_distance_sq(:)
272 cpassert(
SIZE(cluster_points, 2) ==
SIZE(inside_voronoi))
273 cpassert(count(inside_voronoi) >=
SIZE(selected_indices))
275 nretained = count(selected_indices > 0)
276 cpassert(nretained > 0)
277 ALLOCATE (unselected_inside(
SIZE(inside_voronoi)), &
278 nearest_distance_sq(
SIZE(inside_voronoi)))
279 unselected_inside(:) = inside_voronoi
280 nearest_distance_sq(:) = huge(1.0_dp)
283 DO iselected = 1, nretained
284 unselected_inside(selected_indices(iselected)) = .false.
285 DO igrid_point = 1,
SIZE(inside_voronoi)
286 IF (.NOT. unselected_inside(igrid_point)) cycle
287 distance_sq = sum((cluster_points(:, igrid_point) - &
288 cluster_points(:, selected_indices(iselected)))**2)
289 nearest_distance_sq(igrid_point) = &
290 min(nearest_distance_sq(igrid_point), distance_sq)
294 DO WHILE (nretained <
SIZE(selected_indices))
296 largest_distance_sq = -1.0_dp
297 DO igrid_point = 1,
SIZE(inside_voronoi)
298 IF (.NOT. unselected_inside(igrid_point)) cycle
300 IF (nearest_distance_sq(igrid_point) > largest_distance_sq)
THEN
301 largest_distance_sq = nearest_distance_sq(igrid_point)
302 inew_point = igrid_point
305 cpassert(inew_point > 0)
307 nretained = nretained + 1
308 selected_indices(nretained) = inew_point
309 unselected_inside(inew_point) = .false.
310 DO igrid_point = 1,
SIZE(inside_voronoi)
311 IF (.NOT. unselected_inside(igrid_point)) cycle
312 distance_sq = sum((cluster_points(:, igrid_point) - &
313 cluster_points(:, inew_point))**2)
314 nearest_distance_sq(igrid_point) = &
315 min(nearest_distance_sq(igrid_point), distance_sq)
318 END SUBROUTINE complete_grid_by_maximin_distance
328 SUBROUTINE collect_cluster_lebedev_points(bs_env, radial_lebedev_grids, iatom, &
329 cluster_atoms, cluster_points)
332 INTEGER,
INTENT(IN) :: iatom, cluster_atoms(:)
333 REAL(kind=
dp),
ALLOCATABLE,
INTENT(OUT) :: cluster_points(:, :)
335 INTEGER :: cluster_iatom, i_cluster_atom, ikind, n, &
339 DO i_cluster_atom = 1,
SIZE(cluster_atoms)
340 ikind = bs_env%ri_rs%particle_set(cluster_atoms(i_cluster_atom))%atomic_kind%kind_number
341 npoints = npoints + radial_lebedev_grids(ikind)%npts
343 ALLOCATE (cluster_points(3, npoints))
346 DO i_cluster_atom = 1,
SIZE(cluster_atoms)
347 cluster_iatom = cluster_atoms(i_cluster_atom)
348 ikind = bs_env%ri_rs%particle_set(cluster_iatom)%atomic_kind%kind_number
349 n = radial_lebedev_grids(ikind)%npts
350 cluster_points(:, offset + 1:offset + n) = radial_lebedev_grids(ikind)%raw_points + &
351 spread(bs_env%ri_rs%particle_set(cluster_iatom)%r - &
352 bs_env%ri_rs%particle_set(iatom)%r, 2, n)
355 END SUBROUTINE collect_cluster_lebedev_points
372 SUBROUTINE evaluate_cluster_ao_values(bs_env, iatom, cluster_atoms, cluster_points, &
373 ao_point_indices, atom_point_offsets, atom_value_offsets, &
374 atom_n_ao, ao_values)
376 INTEGER,
INTENT(IN) :: iatom, cluster_atoms(:)
377 REAL(kind=
dp),
INTENT(IN) :: cluster_points(:, :)
378 INTEGER,
ALLOCATABLE,
INTENT(OUT) :: ao_point_indices(:), &
379 atom_point_offsets(:), &
380 atom_value_offsets(:), atom_n_ao(:)
381 REAL(kind=
dp),
ALLOCATABLE,
INTENT(OUT) :: ao_values(:)
383 INTEGER :: cluster_iatom, first_point, first_value, i_cluster_atom, igrid_point, ikind, &
384 last_point, last_value, nactive, npoints
385 INTEGER,
ALLOCATABLE :: point_indices(:)
386 LOGICAL,
ALLOCATABLE :: active(:)
387 REAL(kind=
dp),
ALLOCATABLE :: absolute_points(:, :), &
388 atom_points(:, :), atom_values(:, :)
391 npoints =
SIZE(cluster_points, 2)
392 ALLOCATE (absolute_points(3, npoints))
393 absolute_points(:, :) = cluster_points + &
394 spread(bs_env%ri_rs%particle_set(iatom)%r, 2, npoints)
395 ALLOCATE (point_indices(npoints))
396 point_indices(:) = [(igrid_point, igrid_point=1, npoints)]
397 ALLOCATE (active(npoints), atom_n_ao(
SIZE(cluster_atoms)), &
398 atom_point_offsets(
SIZE(cluster_atoms) + 1), &
399 atom_value_offsets(
SIZE(cluster_atoms) + 1))
401 atom_point_offsets(1) = 1
402 atom_value_offsets(1) = 1
403 DO i_cluster_atom = 1,
SIZE(cluster_atoms)
404 cluster_iatom = cluster_atoms(i_cluster_atom)
405 ikind = bs_env%ri_rs%particle_set(cluster_iatom)%atomic_kind%kind_number
406 ao => bs_env%basis_set_AO(ikind)%gto_basis_set
407 cpassert(ao%kind_radius > 0.0_dp)
408 active(:) = sum((absolute_points - &
409 spread(bs_env%ri_rs%particle_set(cluster_iatom)%r, 2, npoints))**2, dim=1) &
411 nactive = count(active)
412 atom_n_ao(i_cluster_atom) = ao%nsgf
413 atom_point_offsets(i_cluster_atom + 1) = atom_point_offsets(i_cluster_atom) + nactive
414 atom_value_offsets(i_cluster_atom + 1) = atom_value_offsets(i_cluster_atom) + &
415 nactive*atom_n_ao(i_cluster_atom)
418 ALLOCATE (ao_point_indices(atom_point_offsets(
SIZE(cluster_atoms) + 1) - 1), &
419 ao_values(atom_value_offsets(
SIZE(cluster_atoms) + 1) - 1))
420 DO i_cluster_atom = 1,
SIZE(cluster_atoms)
421 cluster_iatom = cluster_atoms(i_cluster_atom)
422 ikind = bs_env%ri_rs%particle_set(cluster_iatom)%atomic_kind%kind_number
423 ao => bs_env%basis_set_AO(ikind)%gto_basis_set
424 active(:) = sum((absolute_points - &
425 spread(bs_env%ri_rs%particle_set(cluster_iatom)%r, 2, npoints))**2, dim=1) &
427 first_point = atom_point_offsets(i_cluster_atom)
428 last_point = atom_point_offsets(i_cluster_atom + 1) - 1
429 first_value = atom_value_offsets(i_cluster_atom)
430 last_value = atom_value_offsets(i_cluster_atom + 1) - 1
431 nactive = last_point - first_point + 1
432 ao_point_indices(first_point:last_point) = pack(point_indices, active)
433 ALLOCATE (atom_points(3, nactive), atom_values(nactive, ao%nsgf))
434 atom_points(:, :) = reshape(pack(absolute_points, spread(active, 1, 3)), [3, nactive])
435 atom_values(:, :) = 0.0_dp
437 bs_env%ri_rs%particle_set(cluster_iatom)%r, bs_env%ri_rs%cell)
438 ao_values(first_value:last_value) = reshape(atom_values, [nactive*ao%nsgf])
439 DEALLOCATE (atom_points, atom_values)
441 END SUBROUTINE evaluate_cluster_ao_values
454 SUBROUTINE select_cholesky_grid_points(ao_point_indices, atom_point_offsets, atom_value_offsets, &
455 atom_n_ao, ao_values, npoints, inside_voronoi, &
457 INTEGER,
INTENT(IN) :: ao_point_indices(:), &
458 atom_point_offsets(:), &
459 atom_value_offsets(:), atom_n_ao(:)
460 REAL(kind=
dp),
CONTIGUOUS,
INTENT(IN),
TARGET :: ao_values(:)
461 INTEGER,
INTENT(IN) :: npoints
462 LOGICAL,
INTENT(IN) :: inside_voronoi(npoints)
463 INTEGER,
INTENT(OUT) :: selected_indices(:)
465 INTEGER :: capacity, first_point, first_value, iblock, igrid_point, irow, last_point, &
466 last_value, n_ao, new_capacity, nretained, nrows, nselected, selected_point
467 REAL(kind=
dp) :: selected_diagonal
468 REAL(kind=
dp),
ALLOCATABLE :: diagonal(:), factor(:, :), grown(:, :), initial_diagonal(:), &
469 selected_ao_values(:), selected_factor_values(:), selection_matrix_column(:), values(:)
470 REAL(kind=
dp),
POINTER :: atom_ao_values(:, :)
472 ALLOCATE (diagonal(npoints), initial_diagonal(npoints), &
473 selection_matrix_column(npoints), values(npoints))
477 DO iblock = 1,
SIZE(atom_n_ao)
478 first_point = atom_point_offsets(iblock)
479 last_point = atom_point_offsets(iblock + 1) - 1
480 first_value = atom_value_offsets(iblock)
481 last_value = atom_value_offsets(iblock + 1) - 1
482 nrows = last_point - first_point + 1
483 atom_ao_values(1:nrows, 1:atom_n_ao(iblock)) => ao_values(first_value:last_value)
485 igrid_point = ao_point_indices(first_point + irow - 1)
486 diagonal(igrid_point) = diagonal(igrid_point) + sum(atom_ao_values(irow, :)**2)
489 diagonal(:) = diagonal**2
490 initial_diagonal(:) = diagonal
492 capacity = min(32, npoints)
493 ALLOCATE (factor(npoints, capacity), selected_ao_values(maxval(atom_n_ao)), &
494 selected_factor_values(npoints))
495 selected_indices(:) = 0
498 DO WHILE (nretained <
SIZE(selected_indices) .AND. nselected < npoints)
499 selected_point = maxloc(diagonal, dim=1)
500 selected_diagonal = diagonal(selected_point)
501 IF (selected_diagonal <= 0.0_dp)
EXIT
503 IF (nselected == capacity)
THEN
504 new_capacity = min(npoints, capacity + max(32, capacity/2))
505 ALLOCATE (grown(npoints, new_capacity))
506 grown(:, :capacity) = factor(:, :capacity)
507 CALL move_alloc(grown, factor)
508 capacity = new_capacity
512 selection_matrix_column(:) = 0.0_dp
513 DO iblock = 1,
SIZE(atom_n_ao)
514 first_point = atom_point_offsets(iblock)
515 last_point = atom_point_offsets(iblock + 1) - 1
516 nrows = last_point - first_point + 1
517 IF (nrows == 0) cycle
518 irow =
locate(ao_point_indices(first_point:last_point), selected_point)
520 first_value = atom_value_offsets(iblock)
521 last_value = atom_value_offsets(iblock + 1) - 1
522 n_ao = atom_n_ao(iblock)
523 atom_ao_values(1:nrows, 1:n_ao) => ao_values(first_value:last_value)
524 selected_ao_values(:n_ao) = atom_ao_values(irow, :)
525 CALL dgemv(
'N', nrows, n_ao, 1.0_dp, atom_ao_values, nrows, &
526 selected_ao_values, 1, 0.0_dp, values, 1)
528 igrid_point = ao_point_indices(first_point + irow - 1)
529 selection_matrix_column(igrid_point) = &
530 selection_matrix_column(igrid_point) + values(irow)
533 selection_matrix_column(:) = selection_matrix_column**2
536 IF (nselected > 0)
THEN
537 selected_factor_values(:nselected) = factor(selected_point, :nselected)
538 CALL dgemv(
'N', npoints, nselected, -1.0_dp, factor, npoints, &
539 selected_factor_values, 1, 1.0_dp, selection_matrix_column, 1)
541 nselected = nselected + 1
542 factor(:, nselected) = selection_matrix_column/sqrt(selected_diagonal)
543 diagonal(:) = max(0.0_dp, diagonal - factor(:, nselected)**2)
544 WHERE (diagonal <= 64.0_dp*epsilon(1.0_dp)*initial_diagonal) diagonal = 0.0_dp
545 diagonal(selected_point) = 0.0_dp
547 IF (inside_voronoi(selected_point))
THEN
548 nretained = nretained + 1
549 selected_indices(nretained) = selected_point
552 END SUBROUTINE select_cholesky_grid_points
558 SUBROUTINE broadcast_ri_rs_grids(bs_env)
561 INTEGER :: atom_mpi_rank, iatom
563 DO iatom = 1, bs_env%n_atom
564 atom_mpi_rank = mod(iatom - 1, bs_env%para_env%num_pe)
565 CALL bs_env%para_env%bcast(bs_env%ri_rs%atomic_grids(iatom)%raw_points, atom_mpi_rank)
567 END SUBROUTINE broadcast_ri_rs_grids
Initialize atom-owned RI-RS grids by Cholesky selection from Lebedev grids.
subroutine, public initialize_ri_rs_grid(bs_env)
Construct the initial RI-RS grid of every atom.
Common setup operations used by the periodic and non-periodic GW RI-RS implementations.
subroutine, public get_rirs_cluster_atoms(particle_set, cell, icenter_atom, radius, atom_indices)
Form C_A from nuclei within the specified radius, in global atom order.
subroutine, public filter_grid_to_voronoi(points, icenter_atom, particle_set, mask, atom_indices)
Retain source-grid points inside the Voronoi volume of one atom.
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.
Defines the basic variable types.
integer, parameter, public dp
integer, parameter, public default_string_length
Generation of the spherical Lebedev grids. All Lebedev grids were generated with a precision of at le...
type(oh_grid), dimension(nlg), target, public lebedev_grid
integer function, public get_number_of_lebedev_grid(l, n)
Get the number of the Lebedev grid, which has the requested angular momentum quantnum number l or siz...
subroutine, public deallocate_grid_atom(grid_atom)
Deallocate a Gaussian-type orbital (GTO) basis set data set.
subroutine, public allocate_grid_atom(grid_atom)
Initialize components of the grid_atom_type structure.
subroutine, public create_grid_atom(grid_atom, nr, na, llmax, ll, quadrature)
...
All kind of helpful little routines.
pure integer function, public locate(array, x)
Purpose: Given an array array(1:n), and given a value x, a value x_index is returned which is the ind...