(git:f2099e5)
Loading...
Searching...
No Matches
topology_symmetry_unittest.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!--------------------------------------------------------------------------------------------------!
8 USE ieee_arithmetic, ONLY: ieee_quiet_nan,&
9 ieee_value
10 USE iso_fortran_env, ONLY: output_unit
11 USE kinds, ONLY: dp
16
17 IMPLICIT NONE
18 COMPLEX(KIND=dp) :: table(6, 3), group_chars(6), metric(2, 2), coeff(4, 4), phase(2), tmp(4)
19 REAL(kind=dp) :: error, energy_error, energies(4)
20 INTEGER :: multiplicities(3), status, counts(2), odd(8), ebr(2, 8), a, k, sign, strong, weak(3), z4, io_unit
21 LOGICAL :: signed_atomic, nonnegative_atomic
22
23 io_unit = output_unit
24 ! Complete C3v/S3 character table per element, including a two-dimensional irrep.
25 table(:, 1) = cmplx([1, 1, 1, 1, 1, 1], 0, dp)
26 table(:, 2) = cmplx([1, 1, 1, -1, -1, -1], 0, dp)
27 table(:, 3) = cmplx([2, -1, -1, 0, 0, 0], 0, dp)
28 group_chars = table(:, 1) + 2*table(:, 3)
29 CALL character_multiplicities(group_chars, table, multiplicities, 1.e-10_dp, status)
30 IF (status /= 0 .OR. any(multiplicities /= [1, 0, 2])) error stop 'C3v decomposition failed'
31 group_chars(2) = group_chars(2) + 0.1_dp
32 CALL character_multiplicities(group_chars, table, multiplicities, 1.e-10_dp, status)
33 IF (status == 0) error stop 'Invalid character accepted'
34 metric = cmplx(0, 0, dp)
35 metric(1, 1) = 2.0_dp
36 metric(2, 2) = 0.5_dp
37 coeff = cmplx(0, 0, dp)
38 coeff(1, 1) = sqrt(0.5_dp)
39 coeff(2, 2) = sqrt(2.0_dp)
40 coeff(3, 3) = sqrt(0.5_dp)
41 coeff(4, 4) = sqrt(2.0_dp)
42 phase = cmplx([1, -1], 0, dp)
43 energies = 0.0_dp
44 CALL inversion_representation(metric, coeff, [1, 2], phase, energies, .true., &
45 1.e-9_dp, 1.e-9_dp, counts, error, energy_error, status)
46 IF (status /= 0 .OR. any(counts /= [2, 2])) error stop 'Metric/spinor parity failed'
47 tmp = coeff(:, 1)
48 coeff(:, 1) = (tmp + cmplx(0, 1, dp)*coeff(:, 2))/sqrt(2.0_dp)
49 coeff(:, 2) = (cmplx(0, 1, dp)*tmp + coeff(:, 2))/sqrt(2.0_dp)
50 CALL inversion_representation(metric, coeff, [1, 2], phase, energies, .true., &
51 1.e-9_dp, 1.e-9_dp, counts, error, energy_error, status)
52 IF (status /= 0 .OR. any(counts /= [2, 2])) error stop 'Degenerate-gauge parity failed'
53 CALL inversion_representation(metric, coeff(:, :1), [1, 2], phase, energies(:1), .false., &
54 1.e-9_dp, 1.e-9_dp, counts, error, energy_error, status)
55 IF (status == 0) error stop 'Nonclosed parity subspace accepted'
56 CALL inversion_representation(metric, coeff(:, :2), [1, 2], phase, energies(:2), .true., &
57 1.e-9_dp, 1.e-9_dp, counts, error, energy_error, status)
58 IF (status == 0) error stop 'Broken physical time reversal accepted'
59 energies(2) = 1.0_dp
60 CALL inversion_representation(metric, coeff, [1, 2], phase, energies, .true., &
61 1.e-9_dp, 1.e-9_dp, counts, error, energy_error, status)
62 IF (status == 0) error stop 'Noncommuting eigenspace accepted'
63 ! Scalar two-site inversion with a genuinely off-diagonal AO metric.
64 metric = cmplx(0.2_dp, 0, dp)
65 metric(1, 1) = 1.0_dp
66 metric(2, 2) = 1.0_dp
67 coeff(:2, 1) = cmplx([1.0_dp, 1.0_dp]/sqrt(2.4_dp), 0, dp)
68 coeff(:2, 2) = cmplx([1.0_dp, -1.0_dp]/sqrt(1.6_dp), 0, dp)
69 phase = cmplx(1, 0, dp)
70 CALL inversion_representation(metric, coeff(:2, :2), [2, 1], phase, energies(:2), .false., &
71 1.e-9_dp, 1.e-9_dp, counts, error, energy_error, status)
72 IF (status /= 0 .OR. any(counts /= [1, 1])) error stop 'Scalar two-site inversion failed'
73 CALL inversion_representation(metric, coeff(:2, :1), [2, 1], -phase, energies(:1), .false., &
74 1.e-9_dp, 1.e-9_dp, counts, error, energy_error, status)
75 IF (status /= 0 .OR. any(counts /= [0, 1])) error stop 'Zone-boundary inversion phase failed'
76 metric(1, 2) = cmplx(0.2_dp, 0.01_dp, dp)
77 CALL inversion_representation(metric, coeff(:2, :2), [2, 1], phase, energies(:2), .false., &
78 1.e-9_dp, 1.e-9_dp, counts, error, energy_error, status)
79 IF (status == 0) error stop 'Invalid metric accepted'
80 metric(1, 2) = cmplx(ieee_value(0.0_dp, ieee_quiet_nan), 0, dp)
81 CALL inversion_representation(metric, coeff(:2, :2), [2, 1], phase, energies(:2), .false., &
82 1.e-9_dp, 1.e-9_dp, counts, error, energy_error, status)
83 IF (status == 0) error stop 'Nonfinite metric accepted'
84 DO a = 0, 7
85 DO sign = -1, 1, 2
86 DO k = 0, 7
87 odd(k + 1) = (1 - sign*(-1)**popcnt(iand(a, k)))/2
88 END DO
89 CALL inversion_indicators(odd, 1, 3, strong, weak, z4, status)
90 IF (status /= 0 .OR. strong /= 0 .OR. any(weak /= 0) .OR. z4 /= 0) error stop 'Atomic indicator failed'
91 CALL inversion_ebr_signature(odd, 1, signed_atomic, nonnegative_atomic, ebr, status)
92 IF (status /= 0 .OR. .NOT. nonnegative_atomic .OR. .NOT. signed_atomic) error stop 'Atomic EBR failed'
93 IF (sum(ebr) /= 1) error stop 'EBR rank failed'
94 END DO
95 END DO
96 odd = 0
97 odd(1) = 1
98 CALL inversion_indicators(odd, 1, 3, strong, weak, z4, status)
99 IF (status /= 0 .OR. strong /= 1 .OR. z4 /= 1) error stop 'Strong index failed'
100 CALL inversion_ebr_signature(odd, 1, signed_atomic, nonnegative_atomic, ebr, status)
101 IF (status /= 0 .OR. signed_atomic .OR. nonnegative_atomic) error stop 'Stable obstruction missed'
102 odd(1) = 2
103 CALL inversion_indicators(odd, 2, 3, strong, weak, z4, status)
104 IF (status /= 0 .OR. strong /= 0 .OR. z4 /= 2) error stop 'Inversion Z4=2 missed'
105 odd(1) = 4
106 CALL inversion_ebr_signature(odd, 4, signed_atomic, nonnegative_atomic, ebr, status)
107 IF (status /= 0 .OR. .NOT. signed_atomic .OR. nonnegative_atomic) error stop 'Signed-only EBR missed'
108 odd = -1
109 CALL inversion_ebr_signature(odd, 4, signed_atomic, nonnegative_atomic, ebr, status)
110 IF (status == 0) error stop 'Invalid multiplicity accepted'
113 WRITE (io_unit, *) 'Native characters, parity, inversion indicators and EBR tests passed.'
114CONTAINS
115
116! **************************************************************************************************
117!> \brief Compare the exact solver against independent enumeration of rank-two atomic sums.
118!> \param DIMENSION Dimension of the inversion subgroup
119! **************************************************************************************************
120 SUBROUTINE exhaustive_signatures(DIMENSION)
121 INTEGER, INTENT(IN) :: dimension
122
123 INTEGER :: code, digit, i, ierr, indicator, indices(3), j, n, nu, x, y, &
124 values(2**DIMENSION), signatures(2**DIMENSION, 2**(DIMENSION + 1)), &
125 reconstructed(2**DIMENSION), coefficients(2, 2**DIMENSION)
126 LOGICAL :: indicators_zero, nonnegative_ok, possible(0:3**(2**DIMENSION) - 1), signed_ok
127
128 n = 2**dimension
129 DO x = 0, n - 1
130 DO i = 0, n - 1
131 signatures(i + 1, 2*x + 1) = (1 - (-1)**popcnt(iand(x, i)))/2
132 signatures(i + 1, 2*x + 2) = 1 - signatures(i + 1, 2*x + 1)
133 END DO
134 END DO
135 possible = .false.
136 DO x = 1, 2*n
137 DO y = 1, 2*n
138 code = sum((signatures(:, x) + signatures(:, y))*[(3**i, i=0, n - 1)])
139 possible(code) = .true.
140 END DO
141 END DO
142 DO code = 0, 3**n - 1
143 digit = code
144 DO i = 1, n
145 values(i) = mod(digit, 3)
146 digit = digit/3
147 END DO
148 CALL inversion_ebr_signature(values, 2, signed_ok, nonnegative_ok, coefficients, ierr)
149 IF (ierr /= 0 .OR. (nonnegative_ok .NEQV. possible(code))) error stop 'Enumerated EBR mismatch'
150 CALL inversion_indicators(values, 2, dimension, nu, indices, indicator, ierr)
151 IF (ierr /= 0) error stop 'Enumerated indicator failure'
152 indicators_zero = nu == 0
153 IF (dimension == 3) indicators_zero = indicator == 0 .AND. all(indices == 0)
154 IF (signed_ok .NEQV. indicators_zero) error stop 'Indicator/atomic-lattice mismatch'
155 IF (.NOT. nonnegative_ok) cycle
156 reconstructed = 0
157 DO j = 1, n
158 reconstructed = reconstructed + coefficients(1, j)*signatures(:, 2*j - 1) + &
159 coefficients(2, j)*signatures(:, 2*j)
160 END DO
161 IF (any(reconstructed /= values) .OR. sum(coefficients) /= 2) error stop 'EBR reconstruction failed'
162 END DO
163 END SUBROUTINE exhaustive_signatures
Defines the basic variable types.
Definition kinds.F:23
integer, parameter, public dp
Definition kinds.F:34
Native character decomposition and metric-aware inversion representations.
subroutine, public inversion_representation(metric, coeff, mapping, phase, energies, check_tr, tolerance, energy_tolerance, counts, error, energy_error, status, diagnostics)
Inversion irreps of an isolated scalar or spinor eigenspace in an AO metric.
subroutine, public character_multiplicities(character, table, multiplicities, tolerance, status)
Decompose a character against a complete unitary character table.
Exact inversion-subgroup EBR and symmetry-indicator analysis (spinful TR).
subroutine, public inversion_indicators(odd, pairs, dimension, strong, weak, z4, status)
Fu–Kane indices and inversion indicator with an explicit sign convention.
subroutine, public inversion_ebr_signature(odd, pairs, signed_atomic, nonnegative_atomic, coefficients, status)
Exact signed/nonnegative EBR-signature test for the inversion subgroup.
program topology_symmetry_unittest
subroutine exhaustive_signatures(dimension)
Compare the exact solver against independent enumeration of rank-two atomic sums.