Line data Source code
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 Inversion action on CP2K Gaussian Bloch coefficients, including lattice phases.
10 : ! **************************************************************************************************
11 : MODULE topology_inversion
12 : USE atomic_kind_types, ONLY: get_atomic_kind
13 : USE basis_set_types, ONLY: gto_basis_set_type
14 : USE cell_types, ONLY: cell_type,&
15 : pbc
16 : USE ieee_arithmetic, ONLY: ieee_is_finite
17 : USE kinds, ONLY: dp
18 : USE mathconstants, ONLY: twopi
19 : USE particle_types, ONLY: particle_type
20 : USE qs_environment_types, ONLY: get_qs_env,&
21 : qs_environment_type
22 : USE qs_kind_types, ONLY: get_qs_kind,&
23 : qs_kind_type
24 :
25 : IMPLICIT NONE
26 : PRIVATE
27 : PUBLIC :: gaussian_inversion_action
28 : CONTAINS
29 :
30 : ! **************************************************************************************************
31 : !> \brief Construct sparse AO inversion at a TRIM for the operation r -> 2*center-r.
32 : !> \param qs_env Electronic environment
33 : !> \param k Fractional reciprocal coordinate at a TRIM
34 : !> \param center Fractional inversion center in the user's cell setting
35 : !> \param mapping Target AO row for every source row
36 : !> \param phase AO parity times exp(+2*pi*i*k.L), with 2c-r_a=r_b+L
37 : !> \param tolerance Geometry tolerance in Bohr
38 : !> \param status Zero on success, negative if geometry/basis/periodicity is incompatible
39 : ! **************************************************************************************************
40 36 : SUBROUTINE gaussian_inversion_action(qs_env, k, center, mapping, phase, tolerance, status)
41 : TYPE(qs_environment_type), POINTER :: qs_env
42 : REAL(KIND=dp), INTENT(IN) :: k(3), center(3)
43 : INTEGER, INTENT(OUT) :: mapping(:)
44 : COMPLEX(KIND=dp), INTENT(OUT) :: phase(:)
45 : REAL(KIND=dp), INTENT(IN) :: tolerance
46 : INTEGER, INTENT(OUT) :: status
47 :
48 : INTEGER :: a, b, found, i, iset, l, n, shell, total
49 36 : INTEGER, ALLOCATABLE :: kind(:), offset(:), TARGET(:)
50 : REAL(KIND=dp) :: angle, delta(3), image(3)
51 36 : REAL(KIND=dp), ALLOCATABLE :: position(:, :)
52 : TYPE(cell_type), POINTER :: cell
53 : TYPE(gto_basis_set_type), POINTER :: basis
54 36 : TYPE(particle_type), POINTER :: particles(:)
55 36 : TYPE(qs_kind_type), POINTER :: kinds_set(:)
56 :
57 36 : status = -1
58 576 : mapping = 0
59 576 : phase = CMPLX(0, 0, dp)
60 36 : IF (tolerance <= 0.0_dp .OR. SIZE(phase) /= SIZE(mapping)) RETURN
61 144 : IF (.NOT. ieee_is_finite(tolerance) .OR. .NOT. ALL(ieee_is_finite(center))) RETURN
62 144 : IF (.NOT. ALL(ieee_is_finite(k))) RETURN
63 144 : IF (MAXVAL(ABS(2*k - NINT(2*k))) > 1.e-8_dp) RETURN
64 36 : CALL get_qs_env(qs_env, cell=cell, particle_set=particles, qs_kind_set=kinds_set)
65 144 : IF (ANY(cell%perd /= 1)) RETURN
66 36 : n = SIZE(particles)
67 252 : ALLOCATE (KIND(n), offset(n), TARGET(n), position(3, n))
68 80 : total = 0
69 80 : DO a = 1, n
70 44 : CALL get_atomic_kind(particles(a)%atomic_kind, kind_number=KIND(a))
71 44 : CALL get_qs_kind(kinds_set(KIND(a)), basis_set=basis)
72 44 : IF (.NOT. ASSOCIATED(basis)) RETURN
73 44 : offset(a) = total
74 44 : total = total + basis%nsgf
75 740 : position(:, a) = MATMUL(cell%h_inv, pbc(particles(a)%r, cell))
76 : END DO
77 36 : IF (total /= SIZE(mapping)) RETURN
78 80 : DO a = 1, n
79 : found = 0
80 104 : DO b = 1, n
81 60 : IF (KIND(a) /= KIND(b)) CYCLE
82 240 : delta = 2*center - position(:, a) - position(:, b)
83 1140 : IF (SQRT(SUM(MATMUL(cell%hmat, delta - NINT(delta))**2)) > tolerance) CYCLE
84 44 : found = found + 1
85 88 : TARGET(a) = b
86 : END DO
87 80 : IF (found /= 1) RETURN
88 : END DO
89 80 : DO a = 1, n
90 44 : b = TARGET(a)
91 44 : IF (TARGET(b) /= a) RETURN
92 176 : image = REAL(NINT(2*center - position(:, a) - position(:, b)), dp)
93 176 : angle = twopi*DOT_PRODUCT(k, image)
94 44 : CALL get_qs_kind(kinds_set(KIND(a)), basis_set=basis)
95 152 : DO iset = 1, basis%nset
96 328 : DO shell = 1, basis%nshell(iset)
97 212 : l = basis%l(shell, iset)
98 824 : DO i = basis%first_sgf(shell, iset), basis%last_sgf(shell, iset)
99 540 : mapping(offset(a) + i) = offset(b) + i
100 752 : phase(offset(a) + i) = (-1)**l*CMPLX(COS(angle), SIN(angle), dp)
101 : END DO
102 : END DO
103 : END DO
104 : END DO
105 576 : IF (ANY(mapping == 0)) RETURN
106 36 : status = 0
107 72 : END SUBROUTINE gaussian_inversion_action
108 : END MODULE topology_inversion
|