(git:6344619)
Loading...
Searching...
No Matches
wannier90_projections_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!--------------------------------------------------------------------------------------------------!
7
8! **************************************************************************************************
9!> \brief Test mesh-wide rank validation and unitary covariance of AO trial selection.
10!> \author Thomas D. Kuehne, tkuehne@cp2k.org
11! **************************************************************************************************
13#if defined (__HAS_IEEE_EXCEPTIONS)
14 USE ieee_exceptions, ONLY: ieee_all, ieee_divide_by_zero, ieee_invalid, ieee_overflow, &
15 ieee_get_halting_mode, ieee_set_halting_mode, ieee_support_halting
16#endif
17 USE kinds, ONLY: dp
18 USE message_passing, ONLY: mp_comm_type, &
27#include "./base/base_uses.f90"
28
29 IMPLICIT NONE
30
31 COMPLEX(KIND=dp), ALLOCATABLE :: candidates(:, :, :)
32 COMPLEX(KIND=dp), ALLOCATABLE :: hybrids(:, :, :), rotated_hybrids(:, :, :)
33 COMPLEX(KIND=dp) :: quartet(2, 4)
34 COMPLEX(KIND=dp) :: amn(2, 2, 2), reference(2, 2, 2), rotation(2, 2, 2)
35 COMPLEX(KIND=dp) :: repaired(2, 2, 3)
36 COMPLEX(KIND=dp) :: mixed_reference(4, 3, 2)
37 LOGICAL :: allowed(4)
38 INTEGER :: anchor, ik, nfail, pivots(2), reference_pivots(2)
39 INTEGER :: empty_groups(4, 0)
40 REAL(kind=dp) :: angle, min_svalue
41 TYPE(mp_comm_type) :: comm
42 TYPE(mp_para_env_type), POINTER :: para_env
43#if defined (__HAS_IEEE_EXCEPTIONS)
44 LOGICAL :: saved_halt(size(ieee_all)), expected_halt(size(ieee_all)), actual_halt(size(ieee_all))
45#endif
46
47 CALL mp_world_init(comm)
48 ALLOCATE (para_env)
49 CALL para_env%from_dup(comm)
50 nfail = 0
51#if defined (__HAS_IEEE_EXCEPTIONS)
52 CALL ieee_get_halting_mode(ieee_all, saved_halt)
53 IF (ieee_support_halting(ieee_invalid)) CALL ieee_set_halting_mode(ieee_invalid, .true.)
54 IF (ieee_support_halting(ieee_divide_by_zero)) CALL ieee_set_halting_mode(ieee_divide_by_zero, .true.)
55 IF (ieee_support_halting(ieee_overflow)) CALL ieee_set_halting_mode(ieee_overflow, .true.)
56 CALL ieee_get_halting_mode(ieee_all, expected_halt)
57#endif
58 IF (para_env%is_source()) THEN
59 ALLOCATE (candidates(2, 3, 2))
60 candidates = cmplx(0.0_dp, 0.0_dp, kind=dp)
61 ! The strongest stacked column vanishes at the second k-point.
62 candidates(1, 1, 1) = 5.0_dp
63 candidates(2, 2, :) = 2.0_dp
64 candidates(1, 3, :) = 0.4_dp
65 ELSE
66 ALLOCATE (candidates(0, 0, 0))
67 END IF
68 CALL wannier90_select_projections(candidates, para_env, amn, pivots, min_svalue, anchor_kpoint=0)
69 IF (min_svalue > 1.0e-14_dp) nfail = nfail + 1
70 CALL wannier90_select_projections(candidates, para_env, amn, pivots, min_svalue)
71 IF (abs(min_svalue - 0.4_dp) > 1.0e-14_dp) nfail = nfail + 1
72 IF (.NOT. all(pivots == [2, 3])) nfail = nfail + 1
73 reference = amn
74 reference_pivots = pivots
75
76 DO ik = 1, 2
77 angle = 0.31_dp*real(ik, kind=dp)
78 rotation(1, 1, ik) = cos(angle)
79 rotation(2, 2, ik) = cos(angle)
80 rotation(1, 2, ik) = cmplx(0.0_dp, sin(angle), kind=dp)
81 rotation(2, 1, ik) = cmplx(0.0_dp, sin(angle), kind=dp)
82 IF (para_env%is_source()) candidates(:, :, ik) = matmul(rotation(:, :, ik), candidates(:, :, ik))
83 END DO
84 CALL wannier90_select_projections(candidates, para_env, amn, pivots, min_svalue)
85 IF (abs(min_svalue - 0.4_dp) > 1.0e-14_dp) nfail = nfail + 1
86 IF (.NOT. all(pivots == reference_pivots)) nfail = nfail + 1
87 DO ik = 1, 2
88 IF (maxval(abs(amn(:, :, ik) - matmul(rotation(:, :, ik), reference(:, :, ik)))) > 1.0e-14_dp) THEN
89 nfail = nfail + 1
90 END IF
91 END DO
92 IF (para_env%is_source()) candidates(:, :, :) = cmplx(0.0_dp, 0.0_dp, kind=dp)
93 CALL wannier90_select_projections(candidates, para_env, amn, pivots, min_svalue)
94 IF (min_svalue /= 0.0_dp) nfail = nfail + 1
95 DEALLOCATE (candidates)
96 IF (para_env%is_source()) THEN
97 ALLOCATE (candidates(2, 5, 2))
98 DO ik = 1, 2
99 DO anchor = 1, 5
100 candidates(1, anchor, ik) = cmplx(0.1_dp*anchor, 0.2_dp*ik, kind=dp)
101 candidates(2, anchor, ik) = cmplx(-0.3_dp*anchor, 0.05_dp*ik*anchor, kind=dp)
102 END DO
103 END DO
104 ELSE
105 ALLOCATE (candidates(0, 0, 0))
106 END IF
107 CALL wannier90_hybrid_candidates(candidates, reshape([1, 2, 3, 4], [4, 1]), hybrids)
108 IF (para_env%is_source()) THEN
109 IF (.NOT. all(shape(hybrids) == [2, 5, 2])) nfail = nfail + 1
110 IF (maxval(abs(hybrids(:, 1, :) - candidates(:, 5, :))) > 1.0e-14_dp) nfail = nfail + 1
111 DO ik = 1, 2
112 ! A full tetrahedral quartet is a unitary change of the four AO trials.
113 quartet = hybrids(:, 2:5, ik)
114 IF (maxval(abs(matmul(quartet, conjg(transpose(quartet))) - &
115 matmul(candidates(:, 1:4, ik), conjg(transpose(candidates(:, 1:4, ik)))))) &
116 > 1.0e-14_dp) nfail = nfail + 1
117 candidates(:, :, ik) = matmul(rotation(:, :, ik), candidates(:, :, ik))
118 END DO
119 END IF
120 CALL wannier90_hybrid_candidates(candidates, reshape([1, 2, 3, 4], [4, 1]), rotated_hybrids)
121 IF (para_env%is_source()) THEN
122 DO ik = 1, 2
123 IF (maxval(abs(rotated_hybrids(:, :, ik) - matmul(rotation(:, :, ik), hybrids(:, :, ik)))) &
124 > 1.0e-14_dp) nfail = nfail + 1
125 END DO
126 ELSE
127 IF (SIZE(hybrids) /= 0 .OR. SIZE(rotated_hybrids) /= 0) nfail = nfail + 1
128 END IF
129 DEALLOCATE (hybrids, rotated_hybrids)
130 CALL wannier90_hybrid_candidates(candidates, reshape([1, 2, 3, 4, 5, 2, 3, 4], [4, 2]), hybrids)
131 IF (para_env%is_source()) THEN
132 IF (.NOT. all(shape(hybrids) == [2, 8, 2])) nfail = nfail + 1
133 DO ik = 1, 2
134 IF (maxval(abs(sum(hybrids(:, 1:4, ik), dim=2)*0.5_dp - candidates(:, 1, ik))) &
135 > 1.0e-14_dp) nfail = nfail + 1
136 IF (maxval(abs(sum(hybrids(:, 5:8, ik), dim=2)*0.5_dp - candidates(:, 5, ik))) &
137 > 1.0e-14_dp) nfail = nfail + 1
138 END DO
139 END IF
140 DEALLOCATE (hybrids)
141 CALL wannier90_hybrid_candidates(candidates, empty_groups, hybrids)
142 IF (para_env%is_source()) THEN
143 IF (maxval(abs(hybrids - candidates)) > 1.0e-14_dp) nfail = nfail + 1
144 END IF
145 DEALLOCATE (hybrids, candidates)
146 IF (para_env%is_source()) THEN
147 ALLOCATE (candidates(2, 4, 3))
148 candidates = cmplx(0.0_dp, 0.0_dp, kind=dp)
149 ! Every QR anchor chooses at least one column that vanishes elsewhere.
150 ! Exchanging both of those columns recovers the fixed full-rank pair.
151 candidates(1, 1, 1) = 10.0_dp
152 candidates(1, 1, 3) = 10.0_dp
153 candidates(2, 2, 2) = 10.0_dp
154 candidates(2, 2, 3) = 10.0_dp
155 candidates(1, 3, :) = 1.0_dp
156 candidates(2, 4, :) = 1.0_dp
157 ELSE
158 ALLOCATE (candidates(0, 0, 0))
159 END IF
160 DO anchor = 0, 3
161 CALL wannier90_select_projections(candidates, para_env, repaired, pivots, min_svalue, anchor)
162 IF (min_svalue > 1.0e-14_dp) nfail = nfail + 1
163 END DO
164 CALL wannier90_select_projections(candidates, para_env, repaired, pivots, min_svalue)
165 IF (abs(min_svalue - 1.0_dp) > 1.0e-14_dp) nfail = nfail + 1
166 IF (.NOT. all(pivots == [3, 4])) nfail = nfail + 1
167 DEALLOCATE (candidates)
168 IF (para_env%is_source()) THEN
169 ALLOCATE (candidates(2, 3, 2))
170 candidates = cmplx(0.0_dp, 0.0_dp, kind=dp)
171 candidates(1, 1, :) = 1.0_dp
172 candidates(1, 2, :) = 1.0_dp + 1.0e-14_dp
173 candidates(2, 3, :) = 1.0_dp
174 ELSE
175 ALLOCATE (candidates(0, 0, 0))
176 END IF
177 CALL wannier90_select_projections(candidates, para_env, amn, pivots, min_svalue)
178 IF (.NOT. all(pivots == [1, 3])) nfail = nfail + 1
179 IF (para_env%is_source()) THEN
180 DO ik = 1, 2
181 candidates(:, :, ik) = matmul(rotation(:, :, ik), candidates(:, :, ik))
182 END DO
183 END IF
184 CALL wannier90_select_projections(candidates, para_env, amn, pivots, min_svalue)
185 IF (.NOT. all(pivots == [1, 3])) nfail = nfail + 1
186 DEALLOCATE (candidates)
187 DO ik = 1, 2
188 DO anchor = 1, 3
189 mixed_reference(1, anchor, ik) = cmplx(0.1_dp*anchor, 0.2_dp*ik, kind=dp)
190 mixed_reference(2, anchor, ik) = cmplx(-0.3_dp*anchor, 0.05_dp*ik*anchor, kind=dp)
191 mixed_reference(3, anchor, ik) = cmplx(0.2_dp*anchor**2, 0.3_dp*ik, kind=dp)
192 mixed_reference(4, anchor, ik) = cmplx(0.7_dp, -0.1_dp*ik*anchor, kind=dp)
193 END DO
194 END DO
195 min_svalue = wannier90_projection_rank(mixed_reference)
196#if defined (__HAS_IEEE_EXCEPTIONS)
197 CALL ieee_get_halting_mode(ieee_all, actual_halt)
198 IF (any(actual_halt .NEQV. expected_halt)) nfail = nfail + 1
199 ! Also check that a caller with traps disabled is left unchanged.
200 CALL ieee_set_halting_mode(ieee_all, .false.)
201 IF (abs(wannier90_projection_rank(mixed_reference) - min_svalue) > 1.0e-14_dp) nfail = nfail + 1
202 CALL ieee_get_halting_mode(ieee_all, actual_halt)
203 IF (any(actual_halt)) nfail = nfail + 1
204 CALL ieee_set_halting_mode(ieee_all, expected_halt)
205#endif
206 CALL wannier90_window_mask([-2.0_dp, -1.0_dp, 1.0_dp, 2.0_dp], 2, &
207 [-1.5_dp, 1.5_dp, 0.0_dp, 0.0_dp], &
208 [.true., .true., .false., .false.], allowed)
209 IF (any(allowed .NEQV. [.false., .true., .true., .false.])) nfail = nfail + 1
210 CALL wannier90_window_mask([-2.0_dp, -1.0_dp, 1.0_dp, 2.0_dp], 2, &
211 [-3.0_dp, 3.0_dp, 0.0_dp, 0.0_dp], &
212 [.true., .true., .false., .true.], allowed)
213 IF (any(allowed .NEQV. [.true., .true., .false., .false.])) nfail = nfail + 1
214#if defined (__HAS_IEEE_EXCEPTIONS)
215 CALL ieee_get_halting_mode(ieee_all, actual_halt)
216 IF (any(actual_halt .NEQV. expected_halt)) nfail = nfail + 1
217 CALL ieee_set_halting_mode(ieee_all, saved_halt)
218#endif
219 CALL comm%sum(nfail)
220 cpassert(nfail == 0)
221 CALL mp_para_env_release(para_env)
222 CALL mp_world_finalize()
Defines the basic variable types.
Definition kinds.F:23
integer, parameter, public dp
Definition kinds.F:34
Interface to the message passing library MPI.
subroutine, public mp_world_init(mp_comm)
initializes the system default communicator
subroutine, public mp_para_env_release(para_env)
releases the para object (to be called when you don't want anymore the shared copy of this object)
subroutine, public mp_world_finalize()
Finalize the system default communicator and MPI when CP2K owns MPI.
Gauge-covariant selection of fixed trial orbitals for Wannier90.
subroutine, public wannier90_window_mask(eigenvalues, num_wann, windows, window_set, allowed)
Restrict fixed trial selection to the bands admitted by disentanglement windows.
real(kind=dp) function, public wannier90_projection_rank(amn, rank_defect)
Validate the trial rank independently at every k-point.
subroutine, public wannier90_select_projections(candidates, para_env, amn, pivots, min_svalue, anchor_kpoint)
Select the same trial orbitals at every k-point using a mesh-wide pivoted QR.
subroutine, public wannier90_hybrid_candidates(ao, groups, candidates)
Form tetrahedral s/p trials from the full AO bank before selecting projections.
stores all the informations relevant to an mpi environment
program wannier90_projections_unittest
Test mesh-wide rank validation and unitary covariance of AO trial selection.