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 K-points and crystal symmetry routines
10 : !> \author jgh
11 : ! **************************************************************************************************
12 : MODULE cryssym
13 :
14 : USE bibliography, ONLY: Togo2018,&
15 : Worlton1972,&
16 : cite_reference
17 : USE kinds, ONLY: dp
18 : USE kpsym, ONLY: group1s
19 : USE mathlib, ONLY: inv_3x3
20 : USE spglib_f08, ONLY: spg_get_international,&
21 : spg_get_major_version,&
22 : spg_get_micro_version,&
23 : spg_get_minor_version,&
24 : spg_get_multiplicity,&
25 : spg_get_pointgroup,&
26 : spg_get_schoenflies,&
27 : spg_get_symmetry
28 : USE string_utilities, ONLY: strip_control_codes
29 : #include "./base/base_uses.f90"
30 :
31 : IMPLICIT NONE
32 : PRIVATE
33 : PUBLIC :: csym_type, release_csym_type, print_crys_symmetry, print_kp_symmetry
34 : PUBLIC :: crys_sym_gen, kpoint_gen, kpoint_gen_general
35 :
36 : CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'cryssym'
37 :
38 : ! **************************************************************************************************
39 : !> \brief CSM type
40 : !> \par Content:
41 : !>
42 : ! **************************************************************************************************
43 : TYPE csym_type
44 : LOGICAL :: symlib = .FALSE.
45 : LOGICAL :: fullgrid = .FALSE.
46 : LOGICAL :: inversion_only = .FALSE.
47 : LOGICAL :: spglib_reduction = .FALSE.
48 : LOGICAL :: spglib_backend = .FALSE.
49 : LOGICAL :: spglib_requested = .TRUE.
50 : INTEGER :: plevel = 0
51 : INTEGER :: punit = -1
52 : INTEGER :: istriz = -1
53 : REAL(KIND=dp) :: delta = 1.0e-8_dp
54 : REAL(KIND=dp), DIMENSION(3, 3) :: hmat = 0.0_dp
55 : ! KPOINTS
56 : REAL(KIND=dp), DIMENSION(3) :: wvk0 = 0.0_dp
57 : INTEGER, DIMENSION(3) :: mesh = 0
58 : INTEGER :: nkpoint = 0
59 : INTEGER :: nat = 0
60 : INTEGER, DIMENSION(:), ALLOCATABLE :: atype
61 : REAL(KIND=dp), DIMENSION(:, :), ALLOCATABLE :: scoord
62 : REAL(KIND=dp), DIMENSION(:, :), ALLOCATABLE :: xkpoint
63 : REAL(KIND=dp), DIMENSION(:), ALLOCATABLE :: wkpoint
64 : REAL(KIND=dp), DIMENSION(:, :), ALLOCATABLE :: kpmesh
65 : INTEGER, DIMENSION(:, :), ALLOCATABLE :: kplink
66 : INTEGER, DIMENSION(:), ALLOCATABLE :: kpop
67 : !SPGLIB
68 : CHARACTER(len=11) :: international_symbol = ""
69 : CHARACTER(len=6) :: pointgroup_symbol = ""
70 : CHARACTER(len=10) :: schoenflies = ""
71 : INTEGER :: n_operations = 0
72 : INTEGER, DIMENSION(:, :, :), ALLOCATABLE :: rotations
73 : REAL(KIND=dp), DIMENSION(:, :), ALLOCATABLE :: translations
74 : !K290
75 : REAL(KIND=dp), DIMENSION(:, :, :), ALLOCATABLE :: rt
76 : REAL(KIND=dp), DIMENSION(:, :), ALLOCATABLE :: vt
77 : INTEGER, ALLOCATABLE, DIMENSION(:, :) :: f0
78 : INTEGER :: nrtot = 0
79 : INTEGER, DIMENSION(:), ALLOCATABLE :: ibrot
80 : END TYPE csym_type
81 :
82 : CONTAINS
83 :
84 : ! **************************************************************************************************
85 : !> \brief Release the CSYM type
86 : !> \param csym The CSYM type
87 : ! **************************************************************************************************
88 3746 : SUBROUTINE release_csym_type(csym)
89 : TYPE(csym_type) :: csym
90 :
91 3746 : IF (ALLOCATED(csym%rotations)) THEN
92 3463 : DEALLOCATE (csym%rotations)
93 : END IF
94 3746 : IF (ALLOCATED(csym%translations)) THEN
95 3463 : DEALLOCATE (csym%translations)
96 : END IF
97 3746 : IF (ALLOCATED(csym%atype)) THEN
98 3746 : DEALLOCATE (csym%atype)
99 : END IF
100 3746 : IF (ALLOCATED(csym%scoord)) THEN
101 3746 : DEALLOCATE (csym%scoord)
102 : END IF
103 3746 : IF (ALLOCATED(csym%xkpoint)) THEN
104 3456 : DEALLOCATE (csym%xkpoint)
105 : END IF
106 3746 : IF (ALLOCATED(csym%wkpoint)) THEN
107 3456 : DEALLOCATE (csym%wkpoint)
108 : END IF
109 3746 : IF (ALLOCATED(csym%kpmesh)) THEN
110 3456 : DEALLOCATE (csym%kpmesh)
111 : END IF
112 3746 : IF (ALLOCATED(csym%kplink)) THEN
113 3456 : DEALLOCATE (csym%kplink)
114 : END IF
115 3746 : IF (ALLOCATED(csym%kpop)) THEN
116 3456 : DEALLOCATE (csym%kpop)
117 : END IF
118 3746 : IF (ALLOCATED(csym%rt)) THEN
119 3456 : DEALLOCATE (csym%rt)
120 : END IF
121 3746 : IF (ALLOCATED(csym%vt)) THEN
122 3456 : DEALLOCATE (csym%vt)
123 : END IF
124 3746 : IF (ALLOCATED(csym%f0)) THEN
125 3456 : DEALLOCATE (csym%f0)
126 : END IF
127 3746 : IF (ALLOCATED(csym%ibrot)) THEN
128 3456 : DEALLOCATE (csym%ibrot)
129 : END IF
130 :
131 3746 : END SUBROUTINE release_csym_type
132 :
133 : ! **************************************************************************************************
134 : !> \brief ...
135 : !> \param csym ...
136 : !> \param scoor ...
137 : !> \param types ...
138 : !> \param hmat ...
139 : !> \param delta ...
140 : !> \param iounit ...
141 : !> \param use_spglib ...
142 : ! **************************************************************************************************
143 3746 : SUBROUTINE crys_sym_gen(csym, scoor, types, hmat, delta, iounit, use_spglib)
144 : TYPE(csym_type) :: csym
145 : REAL(KIND=dp), DIMENSION(:, :), INTENT(IN) :: scoor
146 : INTEGER, DIMENSION(:), INTENT(IN) :: types
147 : REAL(KIND=dp), INTENT(IN) :: hmat(3, 3)
148 : REAL(KIND=dp), INTENT(IN), OPTIONAL :: delta
149 : INTEGER, INTENT(IN), OPTIONAL :: iounit
150 : LOGICAL, INTENT(IN), OPTIONAL :: use_spglib
151 :
152 : CHARACTER(LEN=*), PARAMETER :: routineN = 'crys_sym_gen'
153 :
154 : INTEGER :: handle, ierr, major, micro, minor, nat, &
155 : nop, tra_mat(3, 3)
156 : LOGICAL :: my_use_spglib, spglib
157 :
158 3746 : CALL timeset(routineN, handle)
159 :
160 : !..total number of atoms
161 3746 : nat = SIZE(scoor, 2)
162 3746 : csym%nat = nat
163 :
164 : ! output unit
165 3746 : IF (PRESENT(iounit)) THEN
166 3734 : csym%punit = iounit
167 : ELSE
168 12 : csym%punit = -1
169 : END IF
170 :
171 : ! accuracy for symmetry
172 3746 : IF (PRESENT(delta)) THEN
173 3746 : csym%delta = delta
174 : ELSE
175 0 : csym%delta = 1.e-6_dp
176 : END IF
177 :
178 : !..set cell values
179 48698 : csym%hmat = hmat
180 :
181 : ! atom types
182 11238 : ALLOCATE (csym%atype(nat))
183 24985 : csym%atype(1:nat) = types(1:nat)
184 :
185 : ! scaled coordinates
186 11238 : ALLOCATE (csym%scoord(3, nat))
187 88702 : csym%scoord(1:3, 1:nat) = scoor(1:3, 1:nat)
188 :
189 3746 : csym%n_operations = 0
190 :
191 : !..try spglib
192 3746 : my_use_spglib = .TRUE.
193 3746 : IF (PRESENT(use_spglib)) my_use_spglib = use_spglib
194 290 : csym%spglib_requested = my_use_spglib
195 3456 : IF (.NOT. my_use_spglib) THEN
196 : spglib = .FALSE.
197 : ELSE
198 3464 : major = spg_get_major_version()
199 3464 : minor = spg_get_minor_version()
200 3464 : micro = spg_get_micro_version()
201 3464 : IF (major == 0) THEN
202 0 : CALL cp_warn(__LOCATION__, "Symmetry library SPGLIB not available")
203 0 : spglib = .FALSE.
204 : ELSE
205 3464 : spglib = .TRUE.
206 3464 : CALL cite_reference(Togo2018)
207 3464 : ierr = spg_get_international(csym%international_symbol, TRANSPOSE(hmat), scoor, types, nat, delta)
208 3464 : IF (ierr == 0) THEN
209 1 : CALL cp_warn(__LOCATION__, "Symmetry Library SPGLIB failed")
210 1 : spglib = .FALSE.
211 : ELSE
212 3463 : nop = spg_get_multiplicity(TRANSPOSE(hmat), scoor, types, nat, delta)
213 17315 : ALLOCATE (csym%rotations(3, 3, nop), csym%translations(3, nop))
214 3463 : csym%n_operations = nop
215 : ierr = spg_get_symmetry(csym%rotations, csym%translations, nop, &
216 3463 : TRANSPOSE(hmat), scoor, types, nat, delta)
217 : ! Schoenflies Symbol
218 3463 : csym%schoenflies = ' '
219 3463 : ierr = spg_get_schoenflies(csym%schoenflies(1:7), TRANSPOSE(hmat), scoor, types, nat, delta)
220 : ! Point Group
221 3463 : csym%pointgroup_symbol = ' '
222 3463 : tra_mat = 0
223 : ierr = spg_get_pointgroup(csym%pointgroup_symbol, tra_mat, &
224 3463 : csym%rotations, csym%n_operations)
225 :
226 3463 : CALL strip_control_codes(csym%international_symbol)
227 3463 : CALL strip_control_codes(csym%schoenflies)
228 3463 : CALL strip_control_codes(csym%pointgroup_symbol)
229 : END IF
230 : END IF
231 : END IF
232 3746 : csym%symlib = spglib
233 :
234 3746 : CALL timestop(handle)
235 :
236 3746 : END SUBROUTINE crys_sym_gen
237 :
238 : ! **************************************************************************************************
239 : !> \brief ...
240 : !> \param csym ...
241 : !> \param nk ...
242 : !> \param symm ...
243 : !> \param shift ...
244 : !> \param full_grid ...
245 : !> \param gamma_centered ...
246 : !> \param inversion_symmetry_only ...
247 : !> \param use_spglib_reduction ...
248 : !> \param use_spglib_backend ...
249 : ! **************************************************************************************************
250 3430 : SUBROUTINE kpoint_gen(csym, nk, symm, shift, full_grid, gamma_centered, &
251 : inversion_symmetry_only, use_spglib_reduction, use_spglib_backend)
252 : TYPE(csym_type) :: csym
253 : INTEGER, INTENT(IN) :: nk(3)
254 : LOGICAL, INTENT(IN), OPTIONAL :: symm
255 : REAL(KIND=dp), INTENT(IN), OPTIONAL :: shift(3)
256 : LOGICAL, INTENT(IN), OPTIONAL :: full_grid, gamma_centered, &
257 : inversion_symmetry_only, &
258 : use_spglib_reduction, &
259 : use_spglib_backend
260 :
261 : CHARACTER(LEN=*), PARAMETER :: routineN = 'kpoint_gen'
262 :
263 : INTEGER :: handle, i, ik, j, nkp, nkpts
264 3430 : INTEGER, ALLOCATABLE, DIMENSION(:) :: kpop, rep_to_red
265 : LOGICAL :: fullmesh, gamma_mesh, inversion_only, &
266 : spglib_backend, spglib_reduction
267 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: wkp
268 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :) :: xkp
269 :
270 3430 : CALL timeset(routineN, handle)
271 :
272 3430 : IF (PRESENT(shift)) THEN
273 13720 : csym%wvk0 = shift
274 : ELSE
275 0 : csym%wvk0 = 0.0_dp
276 : END IF
277 :
278 3430 : csym%istriz = -1
279 3430 : IF (PRESENT(symm)) THEN
280 3430 : IF (symm) csym%istriz = 1
281 : END IF
282 :
283 3430 : IF (PRESENT(full_grid)) THEN
284 3418 : fullmesh = full_grid
285 : ELSE
286 : fullmesh = .FALSE.
287 : END IF
288 3430 : csym%fullgrid = fullmesh
289 :
290 3430 : IF (PRESENT(gamma_centered)) THEN
291 3418 : gamma_mesh = gamma_centered
292 : ELSE
293 12 : gamma_mesh = .FALSE.
294 : END IF
295 :
296 3430 : IF (PRESENT(inversion_symmetry_only)) THEN
297 3418 : inversion_only = inversion_symmetry_only
298 : ELSE
299 : inversion_only = .FALSE.
300 : END IF
301 3430 : csym%inversion_only = inversion_only
302 :
303 3430 : IF (PRESENT(use_spglib_reduction)) THEN
304 3418 : spglib_reduction = use_spglib_reduction
305 : ELSE
306 12 : spglib_reduction = .FALSE.
307 : END IF
308 3430 : csym%spglib_reduction = spglib_reduction
309 :
310 3430 : IF (PRESENT(use_spglib_backend)) THEN
311 3418 : spglib_backend = use_spglib_backend
312 : ELSE
313 : spglib_backend = .FALSE.
314 : END IF
315 3430 : csym%spglib_backend = spglib_backend
316 :
317 3430 : IF (spglib_backend .AND. .NOT. spglib_reduction) THEN
318 : CALL cp_abort(__LOCATION__, &
319 0 : "SYMMETRY_BACKEND SPGLIB requires SYMMETRY_REDUCTION_METHOD SPGLIB")
320 : END IF
321 : IF (csym%istriz == 1 .AND. .NOT. fullmesh .AND. .NOT. inversion_only .AND. &
322 3430 : (spglib_backend .OR. spglib_reduction) .AND. .NOT. csym%symlib) THEN
323 : CALL cp_abort(__LOCATION__, &
324 0 : "SPGLIB k-point symmetry was requested, but SPGLIB is not available")
325 : END IF
326 :
327 3430 : csym%nkpoint = 0
328 13720 : csym%mesh(1:3) = nk(1:3)
329 3430 : csym%nrtot = 0
330 3430 : IF (ALLOCATED(csym%rt)) DEALLOCATE (csym%rt)
331 3430 : IF (ALLOCATED(csym%vt)) DEALLOCATE (csym%vt)
332 3430 : IF (ALLOCATED(csym%ibrot)) DEALLOCATE (csym%ibrot)
333 3430 : IF (ALLOCATED(csym%f0)) DEALLOCATE (csym%f0)
334 6860 : ALLOCATE (csym%rt(3, 3, 0), csym%vt(3, 0), csym%ibrot(0), csym%f0(csym%nat, 0))
335 :
336 3430 : nkpts = nk(1)*nk(2)*nk(3)
337 24010 : ALLOCATE (xkp(3, nkpts), wkp(nkpts), kpop(nkpts))
338 : ! kp: link
339 10290 : ALLOCATE (csym%kplink(2, nkpts))
340 106834 : csym%kplink = 0
341 3430 : kpop = 0
342 :
343 : ! go through all the options
344 3430 : IF (csym%symlib) THEN
345 : ! symmetry library is available
346 3152 : IF (fullmesh) THEN
347 : ! full mesh requested
348 346 : CALL full_grid_gen(nk, xkp, wkp, shift, gamma_centered=gamma_mesh)
349 346 : IF (csym%istriz == 1) THEN
350 : ! use inversion symmetry
351 346 : CALL inversion_symm(xkp, wkp, csym%kplink(1, :))
352 : ELSE
353 : ! full kpoint mesh is used
354 : END IF
355 2806 : ELSE IF (csym%istriz /= 1 .OR. inversion_only) THEN
356 : ! use inversion symmetry
357 1108 : CALL full_grid_gen(nk, xkp, wkp, shift, gamma_centered=gamma_mesh)
358 1108 : CALL inversion_symm(xkp, wkp, csym%kplink(1, :))
359 : ELSE
360 : ! use symmetry library to reduce k-points
361 1698 : CALL full_grid_gen(nk, xkp, wkp, shift, gamma_centered=gamma_mesh)
362 1698 : IF (spglib_backend) THEN
363 760 : CALL kp_symmetry_spglib(csym, xkp, wkp, kpop)
364 : ELSE
365 938 : CALL kp_symmetry(csym, xkp, wkp, kpop, use_spglib_reduction=spglib_reduction)
366 : END IF
367 :
368 : END IF
369 : ELSE
370 : ! no symmetry library is available
371 278 : CALL full_grid_gen(nk, xkp, wkp, shift, gamma_centered=gamma_mesh)
372 278 : IF (csym%istriz == 1 .AND. .NOT. fullmesh .AND. .NOT. inversion_only) THEN
373 : ! fall back to the K290 atom mapping when SPGLIB is not linked
374 12 : CALL kp_symmetry(csym, xkp, wkp, kpop, use_spglib_reduction=.FALSE.)
375 266 : ELSE IF (csym%istriz /= 1 .AND. fullmesh) THEN
376 : ! full kpoint mesh is used
377 1148 : DO i = 1, nkpts
378 1148 : csym%kplink(1, i) = i
379 : END DO
380 : ELSE
381 : ! use inversion symmetry
382 164 : CALL inversion_symm(xkp, wkp, csym%kplink(1, :))
383 : END IF
384 : END IF
385 : ! count kpoints
386 3430 : nkp = 0
387 37898 : DO i = 1, nkpts
388 37898 : IF (wkp(i) > 0.0_dp) nkp = nkp + 1
389 : END DO
390 :
391 : ! store reduced kpoint set
392 3430 : csym%nkpoint = nkp
393 17150 : ALLOCATE (csym%xkpoint(3, nkp), csym%wkpoint(nkp))
394 6860 : ALLOCATE (rep_to_red(nkpts))
395 3430 : rep_to_red(:) = 0
396 3430 : j = 0
397 37898 : DO ik = 1, nkpts
398 37898 : IF (wkp(ik) > 0.0_dp) THEN
399 12316 : j = j + 1
400 12316 : csym%wkpoint(j) = wkp(ik)
401 49264 : csym%xkpoint(1:3, j) = xkp(1:3, ik)
402 12316 : rep_to_red(ik) = j
403 : END IF
404 : END DO
405 3430 : CPASSERT(j == nkp)
406 :
407 : ! kp: mesh
408 6860 : ALLOCATE (csym%kpmesh(3, nkpts))
409 141302 : csym%kpmesh(1:3, 1:nkpts) = xkp(1:3, 1:nkpts)
410 :
411 : ! kp: link
412 37898 : DO ik = 1, nkpts
413 34468 : i = csym%kplink(1, ik)
414 34468 : CPASSERT(i > 0 .AND. i <= nkpts)
415 34468 : csym%kplink(2, ik) = rep_to_red(i)
416 37898 : CPASSERT(csym%kplink(2, ik) > 0)
417 : END DO
418 3430 : DEALLOCATE (rep_to_red)
419 :
420 : ! kp: operations
421 6860 : ALLOCATE (csym%kpop(nkpts))
422 3430 : IF (csym%nrtot > 0 .AND. csym%istriz == 1 .AND. .NOT. fullmesh .AND. &
423 : .NOT. inversion_only) THEN
424 : ! atomic symmetry operations possible
425 21506 : csym%kpop(1:nkpts) = kpop(1:nkpts)
426 21506 : DO ik = 1, nkpts
427 21506 : CPASSERT(csym%kpop(ik) /= 0)
428 : END DO
429 : ELSE
430 : ! only time reversal symmetry
431 16392 : DO ik = 1, nkpts
432 16392 : IF (wkp(ik) > 0.0_dp) THEN
433 8146 : csym%kpop(ik) = 1
434 : ELSE
435 6524 : csym%kpop(ik) = 2
436 : END IF
437 : END DO
438 : END IF
439 :
440 3430 : DEALLOCATE (xkp, wkp, kpop)
441 :
442 3430 : CALL timestop(handle)
443 :
444 3430 : END SUBROUTINE kpoint_gen
445 :
446 : ! **************************************************************************************************
447 : !> \brief Reduce an explicitly supplied GENERAL k-point set.
448 : !> \param csym ...
449 : !> \param xkp_in explicit k-point coordinates in reciprocal lattice coordinates
450 : !> \param wkp_in explicit k-point weights
451 : !> \param symm ...
452 : !> \param full_grid ...
453 : !> \param inversion_symmetry_only ...
454 : !> \param use_spglib_reduction ...
455 : !> \param use_spglib_backend ...
456 : ! **************************************************************************************************
457 26 : SUBROUTINE kpoint_gen_general(csym, xkp_in, wkp_in, symm, full_grid, &
458 : inversion_symmetry_only, use_spglib_reduction, use_spglib_backend)
459 : TYPE(csym_type) :: csym
460 : REAL(KIND=dp), DIMENSION(:, :), INTENT(IN) :: xkp_in
461 : REAL(KIND=dp), DIMENSION(:), INTENT(IN) :: wkp_in
462 : LOGICAL, INTENT(IN), OPTIONAL :: symm, full_grid, &
463 : inversion_symmetry_only, &
464 : use_spglib_reduction, &
465 : use_spglib_backend
466 :
467 : CHARACTER(LEN=*), PARAMETER :: routineN = 'kpoint_gen_general'
468 :
469 : INTEGER :: handle, i, nfull
470 : LOGICAL :: atomic_symmetry, fullmesh, &
471 : inversion_only, spglib_backend, &
472 : spglib_reduction
473 : REAL(KIND=dp) :: weight_eps
474 :
475 26 : CALL timeset(routineN, handle)
476 :
477 26 : nfull = SIZE(wkp_in)
478 26 : CPASSERT(SIZE(xkp_in, 1) == 3)
479 26 : CPASSERT(SIZE(xkp_in, 2) == nfull)
480 :
481 26 : atomic_symmetry = .FALSE.
482 26 : IF (PRESENT(symm)) atomic_symmetry = symm
483 0 : csym%istriz = -1
484 26 : IF (atomic_symmetry) csym%istriz = 1
485 26 : fullmesh = .FALSE.
486 26 : IF (PRESENT(full_grid)) fullmesh = full_grid
487 26 : inversion_only = .FALSE.
488 26 : IF (PRESENT(inversion_symmetry_only)) inversion_only = inversion_symmetry_only
489 26 : spglib_reduction = .FALSE.
490 26 : IF (PRESENT(use_spglib_reduction)) spglib_reduction = use_spglib_reduction
491 26 : spglib_backend = .FALSE.
492 26 : IF (PRESENT(use_spglib_backend)) spglib_backend = use_spglib_backend
493 :
494 26 : csym%fullgrid = fullmesh
495 26 : csym%inversion_only = inversion_only
496 26 : csym%spglib_reduction = spglib_reduction
497 26 : csym%spglib_backend = spglib_backend
498 26 : csym%nkpoint = 0
499 104 : csym%mesh(1:3) = 0
500 26 : csym%nrtot = 0
501 26 : IF (ALLOCATED(csym%rt)) DEALLOCATE (csym%rt)
502 26 : IF (ALLOCATED(csym%vt)) DEALLOCATE (csym%vt)
503 26 : IF (ALLOCATED(csym%ibrot)) DEALLOCATE (csym%ibrot)
504 26 : IF (ALLOCATED(csym%f0)) DEALLOCATE (csym%f0)
505 52 : ALLOCATE (csym%rt(3, 3, 0), csym%vt(3, 0), csym%ibrot(0), csym%f0(csym%nat, 0))
506 26 : IF (ALLOCATED(csym%xkpoint)) DEALLOCATE (csym%xkpoint)
507 26 : IF (ALLOCATED(csym%wkpoint)) DEALLOCATE (csym%wkpoint)
508 26 : IF (ALLOCATED(csym%kpmesh)) DEALLOCATE (csym%kpmesh)
509 26 : IF (ALLOCATED(csym%kplink)) DEALLOCATE (csym%kplink)
510 26 : IF (ALLOCATED(csym%kpop)) DEALLOCATE (csym%kpop)
511 :
512 182 : ALLOCATE (csym%kpmesh(3, nfull), csym%kplink(2, nfull), csym%kpop(nfull))
513 858 : csym%kpmesh(1:3, 1:nfull) = xkp_in(1:3, 1:nfull)
514 650 : csym%kplink = 0
515 234 : csym%kpop = 1
516 :
517 26 : IF (.NOT. atomic_symmetry .OR. fullmesh) THEN
518 0 : csym%nkpoint = nfull
519 0 : ALLOCATE (csym%xkpoint(3, nfull), csym%wkpoint(nfull))
520 0 : csym%xkpoint(1:3, 1:nfull) = xkp_in(1:3, 1:nfull)
521 0 : csym%wkpoint(1:nfull) = wkp_in(1:nfull)
522 0 : DO i = 1, nfull
523 0 : csym%kplink(1:2, i) = i
524 : END DO
525 26 : ELSE IF (inversion_only) THEN
526 0 : CALL reduce_general_inversion(csym, xkp_in, wkp_in)
527 : ELSE
528 26 : weight_eps = MAX(1.e-12_dp, 10.0_dp*csym%delta)
529 234 : IF (ANY(ABS(wkp_in(1:nfull) - wkp_in(1)) > weight_eps)) THEN
530 : CALL cp_abort(__LOCATION__, &
531 0 : "KPOINTS%SYMMETRY with SCHEME GENERAL requires equal explicit weights.")
532 : END IF
533 26 : IF (spglib_backend) THEN
534 18 : IF (.NOT. csym%symlib) THEN
535 : CALL cp_abort(__LOCATION__, &
536 0 : "SCHEME GENERAL with SYMMETRY_BACKEND SPGLIB requires SPGLIB.")
537 : END IF
538 18 : CALL reduce_general_spglib(csym, xkp_in)
539 8 : ELSE IF (spglib_reduction) THEN
540 4 : IF (.NOT. csym%symlib) THEN
541 : CALL cp_abort(__LOCATION__, &
542 0 : "SCHEME GENERAL with SYMMETRY_REDUCTION_METHOD SPGLIB requires SPGLIB.")
543 : END IF
544 4 : CALL setup_k290_operations(csym)
545 4 : CALL reduce_general_spglib_k290(csym, xkp_in)
546 : ELSE
547 4 : CALL setup_k290_operations(csym)
548 4 : CALL reduce_general_k290(csym, xkp_in)
549 : END IF
550 : END IF
551 :
552 26 : CALL timestop(handle)
553 :
554 26 : END SUBROUTINE kpoint_gen_general
555 :
556 : ! **************************************************************************************************
557 : !> \brief ...
558 : !> \param csym ...
559 : !> \param xkp ...
560 : !> \param wkp ...
561 : !> \param kpop ...
562 : !> \param use_spglib_reduction ...
563 : ! **************************************************************************************************
564 950 : SUBROUTINE kp_symmetry(csym, xkp, wkp, kpop, use_spglib_reduction)
565 : TYPE(csym_type) :: csym
566 : REAL(KIND=dp), DIMENSION(:, :) :: xkp
567 : REAL(KIND=dp), DIMENSION(:) :: wkp
568 : INTEGER, DIMENSION(:) :: kpop
569 : LOGICAL, INTENT(IN), OPTIONAL :: use_spglib_reduction
570 :
571 : INTEGER :: nc, nrot
572 950 : INTEGER, ALLOCATABLE, DIMENSION(:, :, :) :: srot
573 : INTEGER, DIMENSION(48) :: ib
574 : LOGICAL :: spglib_reduction
575 : REAL(KIND=dp) :: alat
576 : REAL(KIND=dp), DIMENSION(3) :: a1, a2, a3, b1, b2, b3
577 : REAL(KIND=dp), DIMENSION(3, 3, 48) :: r
578 :
579 950 : IF (PRESENT(use_spglib_reduction)) THEN
580 950 : spglib_reduction = use_spglib_reduction
581 : ELSE
582 : spglib_reduction = .FALSE.
583 : END IF
584 :
585 950 : CALL detect_k290_symmetry(csym, a1, a2, a3, b1, b2, b3, alat, nc, ib, r)
586 950 : IF (spglib_reduction) CALL cite_reference(Togo2018)
587 :
588 950 : IF (csym%n_operations > nc .AND. .NOT. spglib_reduction) THEN
589 702 : ALLOCATE (srot(3, 3, csym%n_operations))
590 234 : CALL setup_spglib_operations(csym, srot, nrot)
591 234 : CALL reduce_spglib_kpoint_mesh(csym, xkp, wkp, kpop, srot, nrot)
592 468 : DEALLOCATE (srot)
593 708 : ELSE IF (spglib_reduction) THEN
594 48 : ALLOCATE (srot(3, 3, csym%n_operations))
595 16 : CALL setup_spglib_reduction_rotations(csym, srot, nrot)
596 : CALL reduce_spglib_kpoint_mesh_k290(csym, xkp, wkp, kpop, srot, nrot, &
597 16 : a1, a2, a3, b1, b2, b3, alat)
598 32 : DEALLOCATE (srot)
599 : ELSE
600 700 : CALL reduce_kpoint_mesh(csym, xkp, wkp, kpop, nc, ib, r, a1, a2, a3, b1, b2, b3, alat)
601 : END IF
602 :
603 950 : END SUBROUTINE kp_symmetry
604 :
605 : ! **************************************************************************************************
606 : !> \brief Reduce a CP2K Monkhorst-Pack mesh using SPGLIB symmetry operations
607 : !> \param csym ...
608 : !> \param xkp ...
609 : !> \param wkp ...
610 : !> \param kpop ...
611 : ! **************************************************************************************************
612 760 : SUBROUTINE kp_symmetry_spglib(csym, xkp, wkp, kpop)
613 : TYPE(csym_type) :: csym
614 : REAL(KIND=dp), DIMENSION(:, :) :: xkp
615 : REAL(KIND=dp), DIMENSION(:) :: wkp
616 : INTEGER, DIMENSION(:) :: kpop
617 :
618 : INTEGER :: iou, nrot
619 760 : INTEGER, ALLOCATABLE, DIMENSION(:, :, :) :: srot
620 :
621 760 : iou = csym%punit
622 760 : IF (iou > 0) THEN
623 : WRITE (iou, '(/,(T2,A79))') &
624 321 : "*******************************************************************************", &
625 321 : "** Special K-Point Generation by SPGLIB **", &
626 642 : "*******************************************************************************"
627 : END IF
628 760 : CALL cite_reference(Togo2018)
629 :
630 2280 : ALLOCATE (srot(3, 3, csym%n_operations))
631 760 : CALL setup_spglib_operations(csym, srot, nrot)
632 760 : CALL reduce_spglib_kpoint_mesh(csym, xkp, wkp, kpop, srot, nrot)
633 760 : DEALLOCATE (srot)
634 :
635 760 : IF (iou > 0) THEN
636 : WRITE (iou, '((T2,A79))') &
637 321 : "*******************************************************************************", &
638 321 : "** Finished SPGLIB **", &
639 642 : "*******************************************************************************"
640 : END IF
641 :
642 760 : END SUBROUTINE kp_symmetry_spglib
643 :
644 : ! **************************************************************************************************
645 : !> \brief Store K290 atomic symmetry operations.
646 : !> \param csym ...
647 : ! **************************************************************************************************
648 8 : SUBROUTINE setup_k290_operations(csym)
649 : TYPE(csym_type) :: csym
650 :
651 : INTEGER :: nc
652 : INTEGER, DIMENSION(48) :: ib
653 : REAL(KIND=dp) :: alat
654 : REAL(KIND=dp), DIMENSION(3) :: a1, a2, a3, b1, b2, b3
655 : REAL(KIND=dp), DIMENSION(3, 3, 48) :: r
656 :
657 8 : CALL detect_k290_symmetry(csym, a1, a2, a3, b1, b2, b3, alat, nc, ib, r)
658 :
659 8 : END SUBROUTINE setup_k290_operations
660 :
661 : ! **************************************************************************************************
662 : !> \brief Detect and store atomic symmetry operations with the K290/Worlton routines.
663 : !> \param csym crystal symmetry data
664 : !> \param a1 first lattice vector
665 : !> \param a2 second lattice vector
666 : !> \param a3 third lattice vector
667 : !> \param b1 first reciprocal lattice vector
668 : !> \param b2 second reciprocal lattice vector
669 : !> \param b3 third reciprocal lattice vector
670 : !> \param alat lattice scaling used by K290
671 : !> \param nc number of detected operations
672 : !> \param ib indices of the detected rotations
673 : !> \param r K290 rotation matrices
674 : ! **************************************************************************************************
675 958 : SUBROUTINE detect_k290_symmetry(csym, a1, a2, a3, b1, b2, b3, alat, nc, ib, r)
676 : TYPE(csym_type), INTENT(INOUT) :: csym
677 : REAL(KIND=dp), DIMENSION(3), INTENT(OUT) :: a1, a2, a3, b1, b2, b3
678 : REAL(KIND=dp), INTENT(OUT) :: alat
679 : INTEGER, INTENT(OUT) :: nc
680 : INTEGER, DIMENSION(48), INTENT(OUT) :: ib
681 : REAL(KIND=dp), DIMENSION(3, 3, 48), INTENT(OUT) :: r
682 :
683 : INTEGER :: i, ihc, ihg, indpg, iou, isy, li, nat, &
684 : ntvec
685 958 : INTEGER, ALLOCATABLE, DIMENSION(:) :: isc, ty
686 958 : INTEGER, ALLOCATABLE, DIMENSION(:, :) :: f0
687 958 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :) :: rx, tvec, xkapa
688 : REAL(KIND=dp), DIMENSION(3) :: origin
689 : REAL(KIND=dp), DIMENSION(3, 48) :: vt
690 :
691 958 : iou = csym%punit
692 958 : nat = csym%nat
693 958 : CALL setup_k290_lattice(csym, a1, a2, a3, b1, b2, b3, alat)
694 :
695 9580 : ALLOCATE (xkapa(3, nat), rx(3, nat), tvec(3, nat), ty(nat), isc(nat), f0(49, nat))
696 6050 : ty(1:nat) = csym%atype(1:nat)
697 6050 : DO i = 1, nat
698 87522 : xkapa(1:3, i) = MATMUL(csym%hmat, csym%scoord(1:3, i))
699 : END DO
700 :
701 958 : IF (iou > 0) THEN
702 : WRITE (iou, '(/,(T2,A79))') &
703 335 : "*******************************************************************************", &
704 335 : "** Crystal Symmetry Analysis by K290 **", &
705 670 : "*******************************************************************************"
706 : END IF
707 958 : CALL cite_reference(Worlton1972)
708 :
709 : CALL GROUP1s(iou, a1, a2, a3, nat, ty, xkapa, b1, b2, b3, &
710 : ihg, ihc, isy, li, nc, indpg, ib, ntvec, &
711 958 : vt, f0, r, tvec, origin, rx, isc, csym%delta)
712 :
713 958 : IF (iou > 0) THEN
714 : WRITE (iou, '((T2,A79))') &
715 335 : "*******************************************************************************", &
716 335 : "** Finished K290 **", &
717 670 : "*******************************************************************************"
718 : END IF
719 :
720 958 : csym%nrtot = nc
721 958 : IF (ALLOCATED(csym%rt)) DEALLOCATE (csym%rt)
722 958 : IF (ALLOCATED(csym%vt)) DEALLOCATE (csym%vt)
723 958 : IF (ALLOCATED(csym%ibrot)) DEALLOCATE (csym%ibrot)
724 958 : IF (ALLOCATED(csym%f0)) DEALLOCATE (csym%f0)
725 9580 : ALLOCATE (csym%rt(3, 3, nc), csym%vt(3, nc), csym%ibrot(nc), csym%f0(nat, nc))
726 65934 : csym%vt(1:3, 1:nc) = vt(1:3, 1:nc)
727 17202 : DO i = 1, nc
728 211172 : csym%rt(1:3, 1:3, i) = r(1:3, 1:3, ib(i))
729 92034 : csym%f0(1:nat, i) = f0(i, 1:nat)
730 : END DO
731 17202 : csym%ibrot(1:nc) = ib(1:nc)
732 :
733 958 : DEALLOCATE (xkapa, rx, tvec, ty, isc, f0)
734 :
735 958 : END SUBROUTINE detect_k290_symmetry
736 :
737 : ! **************************************************************************************************
738 : !> \brief Return K290 lattice vectors and reciprocal vectors.
739 : !> \param csym ...
740 : !> \param a1 first lattice vector
741 : !> \param a2 second lattice vector
742 : !> \param a3 third lattice vector
743 : !> \param b1 first reciprocal lattice vector
744 : !> \param b2 second reciprocal lattice vector
745 : !> \param b3 third reciprocal lattice vector
746 : !> \param alat lattice scaling used by K290
747 : ! **************************************************************************************************
748 966 : SUBROUTINE setup_k290_lattice(csym, a1, a2, a3, b1, b2, b3, alat)
749 : TYPE(csym_type), INTENT(IN) :: csym
750 : REAL(KIND=dp), DIMENSION(3), INTENT(OUT) :: a1, a2, a3, b1, b2, b3
751 : REAL(KIND=dp), INTENT(OUT) :: alat
752 :
753 : REAL(KIND=dp) :: volum
754 :
755 3864 : a1(1:3) = csym%hmat(1:3, 1)
756 3864 : a2(1:3) = csym%hmat(1:3, 2)
757 3864 : a3(1:3) = csym%hmat(1:3, 3)
758 3864 : alat = SQRT(SUM(a1**2))
759 : volum = a1(1)*a2(2)*a3(3) + a2(1)*a3(2)*a1(3) + &
760 : a3(1)*a1(2)*a2(3) - a1(3)*a2(2)*a3(1) - &
761 966 : a2(3)*a3(2)*a1(1) - a3(3)*a1(2)*a2(1)
762 966 : volum = ABS(volum)
763 966 : b1(1) = (a2(2)*a3(3) - a2(3)*a3(2))/volum
764 966 : b1(2) = (a2(3)*a3(1) - a2(1)*a3(3))/volum
765 966 : b1(3) = (a2(1)*a3(2) - a2(2)*a3(1))/volum
766 966 : b2(1) = (a3(2)*a1(3) - a3(3)*a1(2))/volum
767 966 : b2(2) = (a3(3)*a1(1) - a3(1)*a1(3))/volum
768 966 : b2(3) = (a3(1)*a1(2) - a3(2)*a1(1))/volum
769 966 : b3(1) = (a1(2)*a2(3) - a1(3)*a2(2))/volum
770 966 : b3(2) = (a1(3)*a2(1) - a1(1)*a2(3))/volum
771 966 : b3(3) = (a1(1)*a2(2) - a1(2)*a2(1))/volum
772 :
773 966 : END SUBROUTINE setup_k290_lattice
774 :
775 : ! **************************************************************************************************
776 : !> \brief Store usable SPGLIB space-group operations for k-point symmetry
777 : !> \param csym ...
778 : !> \param srot integer rotations in fractional coordinates
779 : !> \param nrot number of stored rotations
780 : ! **************************************************************************************************
781 1012 : SUBROUTINE setup_spglib_operations(csym, srot, nrot)
782 : TYPE(csym_type) :: csym
783 : INTEGER, DIMENSION(:, :, :), INTENT(OUT) :: srot
784 : INTEGER, INTENT(OUT) :: nrot
785 :
786 : INTEGER :: iop, jop, pass
787 1012 : INTEGER, ALLOCATABLE, DIMENSION(:) :: perm
788 : INTEGER, DIMENSION(3, 3) :: eye, frot, irot
789 : LOGICAL :: duplicate, identity, valid, &
790 : zero_translation
791 : REAL(KIND=dp) :: eps
792 : REAL(KIND=dp), DIMENSION(3, 3) :: h_inv, rfrac
793 :
794 1012 : CPASSERT(csym%symlib)
795 :
796 652156 : srot = 0
797 1012 : csym%nrtot = 0
798 1012 : IF (ALLOCATED(csym%rt)) DEALLOCATE (csym%rt)
799 1012 : IF (ALLOCATED(csym%vt)) DEALLOCATE (csym%vt)
800 1012 : IF (ALLOCATED(csym%ibrot)) DEALLOCATE (csym%ibrot)
801 1012 : IF (ALLOCATED(csym%f0)) DEALLOCATE (csym%f0)
802 5060 : ALLOCATE (csym%rt(3, 3, csym%n_operations), csym%vt(3, csym%n_operations))
803 6072 : ALLOCATE (csym%ibrot(csym%n_operations), csym%f0(csym%nat, csym%n_operations))
804 652156 : csym%rt = 0.0_dp
805 201364 : csym%vt = 0.0_dp
806 51100 : csym%ibrot = 0
807 417604 : csym%f0 = 0
808 :
809 1012 : eps = MAX(1.e-12_dp, 10.0_dp*csym%delta)
810 1012 : h_inv = inv_3x3(csym%hmat)
811 3036 : ALLOCATE (perm(csym%nat))
812 :
813 1012 : eye = 0
814 1012 : eye(1, 1) = 1
815 1012 : eye(2, 2) = 1
816 1012 : eye(3, 3) = 1
817 :
818 1012 : nrot = 0
819 : ! Operation 1 is used as the untransformed representative k-point.
820 : ! Prefer integer translations before fractional alternatives with the same rotation.
821 5060 : DO pass = 1, 4
822 205412 : DO iop = 1, csym%n_operations
823 2604576 : irot(1:3, 1:3) = csym%rotations(1:3, 1:3, iop)
824 2604576 : frot(1:3, 1:3) = TRANSPOSE(irot(1:3, 1:3))
825 458128 : identity = ALL(frot == eye)
826 : zero_translation = ALL(ABS(csym%translations(1:3, iop) - &
827 346456 : ANINT(csym%translations(1:3, iop))) <= eps)
828 200352 : IF (pass == 1 .AND. (.NOT. identity .OR. .NOT. zero_translation)) CYCLE
829 151276 : IF (pass == 2 .AND. (identity .OR. .NOT. zero_translation)) CYCLE
830 110490 : IF (pass == 3 .AND. (.NOT. identity .OR. zero_translation)) CYCLE
831 61202 : IF (pass == 4 .AND. (identity .OR. zero_translation)) CYCLE
832 :
833 50088 : duplicate = .FALSE.
834 1141146 : DO jop = 1, nrot
835 2786168 : IF (ALL(frot == srot(:, :, jop))) THEN
836 : duplicate = .TRUE.
837 : EXIT
838 : END IF
839 : END DO
840 50088 : IF (duplicate) CYCLE
841 :
842 16776 : CALL spglib_atom_permutation(csym, frot, csym%translations(:, iop), perm, valid)
843 16776 : IF (.NOT. valid) CYCLE
844 :
845 16776 : nrot = nrot + 1
846 :
847 218088 : srot(1:3, 1:3, nrot) = frot(1:3, 1:3)
848 218088 : rfrac(1:3, 1:3) = REAL(frot(1:3, 1:3), KIND=dp)
849 1526616 : csym%rt(1:3, 1:3, nrot) = MATMUL(csym%hmat, MATMUL(rfrac, h_inv))
850 67104 : csym%vt(1:3, nrot) = csym%translations(1:3, iop)
851 16776 : csym%ibrot(nrot) = nrot
852 123136 : csym%f0(1:csym%nat, nrot) = perm(1:csym%nat)
853 : END DO
854 : END DO
855 :
856 1012 : DEALLOCATE (perm)
857 1012 : csym%nrtot = nrot
858 1012 : IF (nrot == 0) CALL cp_abort(__LOCATION__, "SPGLIB did not return usable symmetry operations")
859 :
860 1012 : END SUBROUTINE setup_spglib_operations
861 :
862 : ! **************************************************************************************************
863 : !> \brief Store unique SPGLIB rotations for K290-backend diagnostic reduction
864 : !> \param csym ...
865 : !> \param srot integer rotations in fractional coordinates
866 : !> \param nrot number of stored rotations
867 : ! **************************************************************************************************
868 20 : SUBROUTINE setup_spglib_reduction_rotations(csym, srot, nrot)
869 : TYPE(csym_type) :: csym
870 : INTEGER, DIMENSION(:, :, :), INTENT(OUT) :: srot
871 : INTEGER, INTENT(OUT) :: nrot
872 :
873 : INTEGER :: iop, jop, pass
874 : INTEGER, DIMENSION(3, 3) :: eye, frot, irot
875 : LOGICAL :: duplicate, identity
876 :
877 20 : CPASSERT(csym%symlib)
878 :
879 30388 : srot = 0
880 20 : eye = 0
881 20 : eye(1, 1) = 1
882 20 : eye(2, 2) = 1
883 20 : eye(3, 3) = 1
884 :
885 20 : nrot = 0
886 : ! Keep the identity first, matching the representative k-point operation.
887 60 : DO pass = 1, 2
888 4732 : DO iop = 1, csym%n_operations
889 60736 : irot(1:3, 1:3) = csym%rotations(1:3, 1:3, iop)
890 60736 : frot(1:3, 1:3) = TRANSPOSE(irot(1:3, 1:3))
891 10096 : identity = ALL(frot == eye)
892 4672 : IF (pass == 1 .AND. .NOT. identity) CYCLE
893 2392 : IF (pass == 2 .AND. identity) CYCLE
894 :
895 2336 : duplicate = .FALSE.
896 56528 : DO jop = 1, nrot
897 140872 : IF (ALL(frot == srot(:, :, jop))) THEN
898 : duplicate = .TRUE.
899 : EXIT
900 : END IF
901 : END DO
902 2336 : IF (duplicate) CYCLE
903 :
904 608 : nrot = nrot + 1
905 9728 : srot(1:3, 1:3, nrot) = frot(1:3, 1:3)
906 : END DO
907 : END DO
908 :
909 20 : IF (nrot == 0) CALL cp_abort(__LOCATION__, "SPGLIB did not return usable symmetry rotations")
910 :
911 20 : END SUBROUTINE setup_spglib_reduction_rotations
912 :
913 : ! **************************************************************************************************
914 : !> \brief Determine the atom permutation generated by a SPGLIB space-group operation
915 : !> \param csym ...
916 : !> \param rot integer rotation in fractional coordinates
917 : !> \param trans fractional translation
918 : !> \param perm atom permutation
919 : !> \param valid whether all atoms were mapped
920 : ! **************************************************************************************************
921 16776 : SUBROUTINE spglib_atom_permutation(csym, rot, trans, perm, valid)
922 : TYPE(csym_type) :: csym
923 : INTEGER, DIMENSION(3, 3), INTENT(IN) :: rot
924 : REAL(KIND=dp), DIMENSION(3), INTENT(IN) :: trans
925 : INTEGER, DIMENSION(:), INTENT(OUT) :: perm
926 : LOGICAL, INTENT(OUT) :: valid
927 :
928 : INTEGER :: i, j, nat
929 : LOGICAL :: found
930 16776 : LOGICAL, ALLOCATABLE, DIMENSION(:) :: used
931 : REAL(KIND=dp) :: eps
932 : REAL(KIND=dp), DIMENSION(3) :: diff, spos
933 : REAL(KIND=dp), DIMENSION(3, 3) :: rfrac
934 :
935 16776 : nat = csym%nat
936 16776 : eps = MAX(1.e-12_dp, 10.0_dp*csym%delta)
937 218088 : rfrac(1:3, 1:3) = REAL(rot(1:3, 1:3), KIND=dp)
938 50328 : ALLOCATE (used(nat))
939 16776 : used = .FALSE.
940 119088 : perm = 0
941 16776 : valid = .TRUE.
942 :
943 119088 : DO i = 1, nat
944 1636992 : spos(1:3) = MATMUL(rfrac(1:3, 1:3), csym%scoord(1:3, i)) + trans(1:3)
945 459292 : found = .FALSE.
946 459292 : DO j = 1, nat
947 459292 : IF (used(j)) CYCLE
948 251210 : IF (csym%atype(i) /= csym%atype(j)) CYCLE
949 1004840 : diff(1:3) = spos(1:3) - csym%scoord(1:3, j)
950 1004840 : diff(1:3) = diff(1:3) - ANINT(diff(1:3))
951 577170 : IF (ALL(ABS(diff(1:3)) < eps)) THEN
952 102312 : perm(i) = j
953 102312 : used(j) = .TRUE.
954 : found = .TRUE.
955 : EXIT
956 : END IF
957 : END DO
958 16776 : IF (.NOT. found) THEN
959 0 : valid = .FALSE.
960 0 : EXIT
961 : END IF
962 : END DO
963 :
964 16776 : DEALLOCATE (used)
965 :
966 16776 : END SUBROUTINE spglib_atom_permutation
967 :
968 : ! **************************************************************************************************
969 : !> \brief Reduce a k-point mesh with SPGLIB direct-space operations
970 : !> \param csym ...
971 : !> \param xkp full k-point mesh in reciprocal lattice coordinates
972 : !> \param wkp reduced k-point weights
973 : !> \param kpop symmetry operation mapping the representative k-point to a mesh point
974 : !> \param srot integer rotations in fractional coordinates
975 : !> \param nrot number of stored rotations
976 : ! **************************************************************************************************
977 994 : SUBROUTINE reduce_spglib_kpoint_mesh(csym, xkp, wkp, kpop, srot, nrot)
978 : TYPE(csym_type) :: csym
979 : REAL(KIND=dp), DIMENSION(:, :), INTENT(IN) :: xkp
980 : REAL(KIND=dp), DIMENSION(:) :: wkp
981 : INTEGER, DIMENSION(:) :: kpop
982 : INTEGER, DIMENSION(:, :, :), INTENT(IN) :: srot
983 : INTEGER, INTENT(IN) :: nrot
984 :
985 : INTEGER :: i, iop, isign, j, kr, nkpts
986 994 : INTEGER, ALLOCATABLE, DIMENSION(:) :: kscore, op_score
987 994 : INTEGER, ALLOCATABLE, DIMENSION(:, :, :) :: krot
988 : REAL(KIND=dp) :: eps
989 : REAL(KIND=dp), DIMENSION(3) :: rr
990 :
991 994 : nkpts = SIZE(wkp)
992 994 : eps = MAX(1.e-12_dp, 10.0_dp*csym%delta)
993 6958 : ALLOCATE (kscore(nkpts), op_score(nrot), krot(3, 3, nrot))
994 :
995 16906 : DO iop = 1, nrot
996 15912 : kr = csym%ibrot(iop)
997 206856 : krot(1:3, 1:3, iop) = reciprocal_rotation(srot(1:3, 1:3, kr))
998 16906 : op_score(iop) = spglib_operation_score(csym, iop, srot(1:3, 1:3, kr))
999 : END DO
1000 :
1001 14048 : wkp = 0.0_dp
1002 14048 : kpop = 0
1003 14048 : csym%kplink(1, :) = 0
1004 14048 : kscore = HUGE(0)
1005 :
1006 14048 : DO i = 1, nkpts
1007 13054 : IF (csym%kplink(1, i) /= 0) CYCLE
1008 :
1009 2436 : csym%kplink(1, i) = i
1010 2436 : wkp(i) = 1.0_dp
1011 2436 : kpop(i) = 1
1012 2436 : kscore(i) = 0
1013 :
1014 43584 : DO iop = 1, nrot
1015 133516 : DO isign = 1, 2
1016 2007700 : rr(1:3) = MATMUL(REAL(krot(1:3, 1:3, iop), KIND=dp), xkp(1:3, i))
1017 80308 : kr = csym%ibrot(iop)
1018 80308 : IF (isign == 2) THEN
1019 160616 : rr(1:3) = -rr(1:3)
1020 40154 : kr = -kr
1021 : END IF
1022 :
1023 80308 : j = regular_kpoint_index(rr, xkp(1:3, 1), csym%mesh, eps)
1024 80308 : IF (j == 0) CYCLE
1025 113566 : IF (csym%kplink(1, j) == 0) THEN
1026 10618 : csym%kplink(1, j) = i
1027 10618 : wkp(i) = wkp(i) + 1.0_dp
1028 10618 : kpop(j) = kr
1029 10618 : kscore(j) = op_score(iop)
1030 : ELSE
1031 62794 : CPASSERT(csym%kplink(1, j) == i)
1032 62794 : IF (op_score(iop) < kscore(j)) THEN
1033 3516 : kpop(j) = kr
1034 3516 : kscore(j) = op_score(iop)
1035 : END IF
1036 : END IF
1037 : END DO
1038 : END DO
1039 : END DO
1040 :
1041 14048 : DO i = 1, nkpts
1042 13054 : CPASSERT(csym%kplink(1, i) /= 0)
1043 14048 : CPASSERT(kpop(i) /= 0)
1044 : END DO
1045 994 : DEALLOCATE (kscore, op_score, krot)
1046 :
1047 994 : END SUBROUTINE reduce_spglib_kpoint_mesh
1048 :
1049 : ! **************************************************************************************************
1050 : !> \brief Reduce an explicit k-point set by inversion/time-reversal.
1051 : !> \param csym ...
1052 : !> \param xkp_full explicit k-point coordinates
1053 : !> \param wkp_full explicit k-point weights
1054 : ! **************************************************************************************************
1055 0 : SUBROUTINE reduce_general_inversion(csym, xkp_full, wkp_full)
1056 : TYPE(csym_type) :: csym
1057 : REAL(KIND=dp), DIMENSION(:, :), INTENT(IN) :: xkp_full
1058 : REAL(KIND=dp), DIMENSION(:), INTENT(IN) :: wkp_full
1059 :
1060 : INTEGER :: i, j, nfull, nred
1061 0 : INTEGER, ALLOCATABLE, DIMENSION(:) :: rep
1062 0 : LOGICAL, ALLOCATABLE, DIMENSION(:) :: used
1063 : REAL(KIND=dp) :: eps
1064 0 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: wred
1065 : REAL(KIND=dp), DIMENSION(3) :: diff
1066 :
1067 0 : nfull = SIZE(wkp_full)
1068 0 : eps = MAX(1.e-12_dp, 10.0_dp*csym%delta)
1069 0 : ALLOCATE (rep(nfull), used(nfull), wred(nfull))
1070 0 : used = .FALSE.
1071 0 : rep = 0
1072 0 : wred = 0.0_dp
1073 0 : nred = 0
1074 :
1075 0 : DO i = 1, nfull
1076 0 : IF (used(i)) CYCLE
1077 0 : nred = nred + 1
1078 0 : rep(nred) = i
1079 0 : used(i) = .TRUE.
1080 0 : csym%kplink(1, i) = i
1081 0 : csym%kpop(i) = 1
1082 0 : wred(nred) = wkp_full(i)
1083 0 : DO j = i + 1, nfull
1084 0 : IF (used(j)) CYCLE
1085 0 : diff(1:3) = xkp_full(1:3, j) + xkp_full(1:3, i)
1086 0 : diff(1:3) = diff(1:3) - ANINT(diff(1:3))
1087 0 : IF (ALL(ABS(diff(1:3)) < eps)) THEN
1088 0 : IF (ABS(wkp_full(j) - wkp_full(i)) > eps) THEN
1089 : CALL cp_abort(__LOCATION__, &
1090 : "KPOINTS%INVERSION_SYMMETRY_ONLY with SCHEME GENERAL requires "// &
1091 0 : "equal weights for inversion-related k-points.")
1092 : END IF
1093 0 : used(j) = .TRUE.
1094 0 : csym%kplink(1, j) = i
1095 0 : csym%kpop(j) = -1
1096 0 : wred(nred) = wred(nred) + wkp_full(j)
1097 : END IF
1098 : END DO
1099 : END DO
1100 :
1101 0 : csym%nkpoint = nred
1102 0 : ALLOCATE (csym%xkpoint(3, nred), csym%wkpoint(nred))
1103 0 : DO i = 1, nred
1104 0 : csym%xkpoint(1:3, i) = xkp_full(1:3, rep(i))
1105 0 : csym%wkpoint(i) = wred(i)
1106 : END DO
1107 0 : DO i = 1, nfull
1108 0 : DO j = 1, nred
1109 0 : IF (csym%kplink(1, i) == rep(j)) THEN
1110 0 : csym%kplink(2, i) = j
1111 0 : EXIT
1112 : END IF
1113 : END DO
1114 : END DO
1115 :
1116 0 : DEALLOCATE (rep, used, wred)
1117 :
1118 0 : END SUBROUTINE reduce_general_inversion
1119 :
1120 : ! **************************************************************************************************
1121 : !> \brief Reduce an explicit k-point set with K290 symmetry operations.
1122 : !> \param csym ...
1123 : !> \param xkp_full explicit k-point coordinates
1124 : ! **************************************************************************************************
1125 4 : SUBROUTINE reduce_general_k290(csym, xkp_full)
1126 : TYPE(csym_type) :: csym
1127 : REAL(KIND=dp), DIMENSION(:, :), INTENT(IN) :: xkp_full
1128 :
1129 : INTEGER :: i, ibsign, iop, j, kr, nfull, nred
1130 : INTEGER, ALLOCATABLE, DIMENSION(:) :: rep
1131 : LOGICAL :: found
1132 4 : LOGICAL, ALLOCATABLE, DIMENSION(:) :: used
1133 : REAL(KIND=dp) :: alat, eps
1134 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: wred
1135 : REAL(KIND=dp), DIMENSION(3) :: a1, a2, a3, b1, b2, b3, diff, rr, wcart
1136 :
1137 4 : nfull = SIZE(xkp_full, 2)
1138 4 : eps = MAX(1.e-12_dp, 10.0_dp*csym%delta)
1139 4 : CALL setup_k290_lattice(csym, a1, a2, a3, b1, b2, b3, alat)
1140 :
1141 24 : ALLOCATE (rep(nfull), used(nfull), wred(nfull))
1142 4 : used = .FALSE.
1143 4 : rep = 0
1144 4 : wred = 0.0_dp
1145 4 : nred = 0
1146 :
1147 36 : DO i = 1, nfull
1148 32 : IF (used(i)) CYCLE
1149 4 : nred = nred + 1
1150 4 : rep(nred) = i
1151 4 : used(i) = .TRUE.
1152 4 : csym%kplink(1, i) = i
1153 4 : csym%kpop(i) = 1
1154 4 : wred(nred) = 1.0_dp
1155 :
1156 200 : DO iop = 1, csym%nrtot
1157 608 : DO ibsign = 1, 2
1158 384 : kr = csym%ibrot(iop)
1159 : wcart(1:3) = alat*(xkp_full(1, i)*b1(1:3) + &
1160 : xkp_full(2, i)*b2(1:3) + &
1161 1536 : xkp_full(3, i)*b3(1:3))
1162 1536 : wcart(1:3) = kp_apply_operation(wcart(1:3), csym%rt(1:3, 1:3, iop))
1163 384 : IF (ibsign == 2) THEN
1164 768 : wcart(1:3) = -wcart(1:3)
1165 192 : kr = -kr
1166 : END IF
1167 1536 : rr(1) = DOT_PRODUCT(a1(1:3), wcart(1:3))/alat
1168 1536 : rr(2) = DOT_PRODUCT(a2(1:3), wcart(1:3))/alat
1169 1536 : rr(3) = DOT_PRODUCT(a3(1:3), wcart(1:3))/alat
1170 :
1171 384 : found = .FALSE.
1172 1728 : DO j = 1, nfull
1173 6912 : diff(1:3) = xkp_full(1:3, j) - rr(1:3)
1174 6912 : diff(1:3) = diff(1:3) - ANINT(diff(1:3))
1175 3648 : IF (ALL(ABS(diff(1:3)) < eps)) THEN
1176 384 : found = .TRUE.
1177 384 : IF (.NOT. used(j)) THEN
1178 28 : used(j) = .TRUE.
1179 28 : csym%kplink(1, j) = i
1180 28 : csym%kpop(j) = kr
1181 28 : wred(nred) = wred(nred) + 1.0_dp
1182 : ELSE
1183 356 : CPASSERT(csym%kplink(1, j) == i)
1184 : END IF
1185 : EXIT
1186 : END IF
1187 : END DO
1188 192 : IF (.NOT. found) THEN
1189 : CALL cp_abort(__LOCATION__, &
1190 : "KPOINTS%SYMMETRY with SCHEME GENERAL requires the explicit k-point set "// &
1191 0 : "to be closed under the K290 symmetry operations.")
1192 : END IF
1193 : END DO
1194 : END DO
1195 : END DO
1196 :
1197 4 : CALL store_general_reduction(csym, xkp_full, rep, wred, nred)
1198 :
1199 4 : DEALLOCATE (rep, used, wred)
1200 :
1201 4 : END SUBROUTINE reduce_general_k290
1202 :
1203 : ! **************************************************************************************************
1204 : !> \brief Reduce an explicit k-point set with SPGLIB symmetry operations.
1205 : !> \param csym ...
1206 : !> \param xkp_full explicit k-point coordinates
1207 : ! **************************************************************************************************
1208 18 : SUBROUTINE reduce_general_spglib(csym, xkp_full)
1209 : TYPE(csym_type) :: csym
1210 : REAL(KIND=dp), DIMENSION(:, :), INTENT(IN) :: xkp_full
1211 :
1212 : INTEGER :: i, iop, isign, j, kr, nfull, nred, nrot
1213 : INTEGER, ALLOCATABLE, DIMENSION(:) :: rep
1214 : INTEGER, ALLOCATABLE, DIMENSION(:, :, :) :: srot
1215 : INTEGER, DIMENSION(3, 3) :: krot
1216 : LOGICAL :: found
1217 18 : LOGICAL, ALLOCATABLE, DIMENSION(:) :: used
1218 : REAL(KIND=dp) :: eps
1219 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: wred
1220 : REAL(KIND=dp), DIMENSION(3) :: diff, rr
1221 :
1222 18 : nfull = SIZE(xkp_full, 2)
1223 18 : eps = MAX(1.e-12_dp, 10.0_dp*csym%delta)
1224 54 : ALLOCATE (srot(3, 3, csym%n_operations))
1225 18 : CALL setup_spglib_operations(csym, srot, nrot)
1226 :
1227 108 : ALLOCATE (rep(nfull), used(nfull), wred(nfull))
1228 18 : used = .FALSE.
1229 18 : rep = 0
1230 18 : wred = 0.0_dp
1231 18 : nred = 0
1232 :
1233 162 : DO i = 1, nfull
1234 144 : IF (used(i)) CYCLE
1235 18 : nred = nred + 1
1236 18 : rep(nred) = i
1237 18 : used(i) = .TRUE.
1238 18 : csym%kplink(1, i) = i
1239 18 : csym%kpop(i) = 1
1240 18 : wred(nred) = 1.0_dp
1241 :
1242 900 : DO iop = 1, nrot
1243 864 : kr = csym%ibrot(iop)
1244 864 : krot = reciprocal_rotation(srot(:, :, kr))
1245 2736 : DO isign = 1, 2
1246 43200 : rr(1:3) = MATMUL(REAL(krot(1:3, 1:3), KIND=dp), xkp_full(1:3, i))
1247 1728 : IF (isign == 2) THEN
1248 3456 : rr(1:3) = -rr(1:3)
1249 864 : kr = -csym%ibrot(iop)
1250 : ELSE
1251 864 : kr = csym%ibrot(iop)
1252 : END IF
1253 :
1254 1728 : found = .FALSE.
1255 7776 : DO j = 1, nfull
1256 31104 : diff(1:3) = xkp_full(1:3, j) - rr(1:3)
1257 31104 : diff(1:3) = diff(1:3) - ANINT(diff(1:3))
1258 16416 : IF (ALL(ABS(diff(1:3)) < eps)) THEN
1259 1728 : found = .TRUE.
1260 1728 : IF (.NOT. used(j)) THEN
1261 126 : used(j) = .TRUE.
1262 126 : csym%kplink(1, j) = i
1263 126 : csym%kpop(j) = kr
1264 126 : wred(nred) = wred(nred) + 1.0_dp
1265 : ELSE
1266 1602 : CPASSERT(csym%kplink(1, j) == i)
1267 : END IF
1268 : EXIT
1269 : END IF
1270 : END DO
1271 864 : IF (.NOT. found) THEN
1272 : CALL cp_abort(__LOCATION__, &
1273 : "KPOINTS%SYMMETRY with SCHEME GENERAL requires the explicit k-point set "// &
1274 0 : "to be closed under the requested symmetry operations.")
1275 : END IF
1276 : END DO
1277 : END DO
1278 : END DO
1279 :
1280 18 : CALL store_general_reduction(csym, xkp_full, rep, wred, nred)
1281 :
1282 18 : DEALLOCATE (rep, srot, used, wred)
1283 :
1284 18 : END SUBROUTINE reduce_general_spglib
1285 :
1286 : ! **************************************************************************************************
1287 : !> \brief Reduce an explicit k-point set with SPGLIB rotations and K290 operations.
1288 : !> \param csym ...
1289 : !> \param xkp_full explicit k-point coordinates
1290 : ! **************************************************************************************************
1291 4 : SUBROUTINE reduce_general_spglib_k290(csym, xkp_full)
1292 : TYPE(csym_type) :: csym
1293 : REAL(KIND=dp), DIMENSION(:, :), INTENT(IN) :: xkp_full
1294 :
1295 : INTEGER :: i, iop, isign, j, k290_op, nfull, nred, &
1296 : nrot, nskipped
1297 : INTEGER, ALLOCATABLE, DIMENSION(:) :: rep
1298 : INTEGER, ALLOCATABLE, DIMENSION(:, :, :) :: srot
1299 : INTEGER, DIMENSION(3, 3) :: krot
1300 : LOGICAL :: found, valid
1301 4 : LOGICAL, ALLOCATABLE, DIMENSION(:) :: used
1302 : REAL(KIND=dp) :: alat, eps
1303 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: wred
1304 : REAL(KIND=dp), DIMENSION(3) :: a1, a2, a3, b1, b2, b3, diff, rr
1305 :
1306 4 : nfull = SIZE(xkp_full, 2)
1307 4 : eps = MAX(1.e-12_dp, 10.0_dp*csym%delta)
1308 4 : CALL setup_k290_lattice(csym, a1, a2, a3, b1, b2, b3, alat)
1309 12 : ALLOCATE (srot(3, 3, csym%n_operations))
1310 4 : CALL setup_spglib_reduction_rotations(csym, srot, nrot)
1311 :
1312 24 : ALLOCATE (rep(nfull), used(nfull), wred(nfull))
1313 4 : used = .FALSE.
1314 4 : rep = 0
1315 4 : wred = 0.0_dp
1316 4 : nred = 0
1317 4 : nskipped = 0
1318 :
1319 36 : DO i = 1, nfull
1320 32 : IF (used(i)) CYCLE
1321 4 : nred = nred + 1
1322 4 : rep(nred) = i
1323 4 : used(i) = .TRUE.
1324 4 : csym%kplink(1, i) = i
1325 4 : csym%kpop(i) = 1
1326 4 : wred(nred) = 1.0_dp
1327 :
1328 200 : DO iop = 1, nrot
1329 192 : krot = reciprocal_rotation(srot(:, :, iop))
1330 608 : DO isign = 1, 2
1331 9600 : rr(1:3) = MATMUL(REAL(krot(1:3, 1:3), KIND=dp), xkp_full(1:3, i))
1332 960 : IF (isign == 2) rr(1:3) = -rr(1:3)
1333 :
1334 1728 : found = .FALSE.
1335 1728 : DO j = 1, nfull
1336 6912 : diff(1:3) = xkp_full(1:3, j) - rr(1:3)
1337 6912 : diff(1:3) = diff(1:3) - ANINT(diff(1:3))
1338 3648 : IF (ALL(ABS(diff(1:3)) < eps)) THEN
1339 384 : found = .TRUE.
1340 : CALL find_k290_kpoint_operation(csym, xkp_full(1:3, i), xkp_full(1:3, j), &
1341 : a1, a2, a3, b1, b2, b3, alat, &
1342 384 : k290_op, valid)
1343 384 : IF (.NOT. valid) THEN
1344 0 : nskipped = nskipped + 1
1345 : EXIT
1346 : END IF
1347 384 : IF (.NOT. used(j)) THEN
1348 28 : used(j) = .TRUE.
1349 28 : csym%kplink(1, j) = i
1350 28 : csym%kpop(j) = k290_op
1351 28 : wred(nred) = wred(nred) + 1.0_dp
1352 : ELSE
1353 356 : CPASSERT(csym%kplink(1, j) == i)
1354 : END IF
1355 : EXIT
1356 : END IF
1357 : END DO
1358 192 : IF (.NOT. found) THEN
1359 : CALL cp_abort(__LOCATION__, &
1360 : "KPOINTS%SYMMETRY with SCHEME GENERAL requires the explicit k-point set "// &
1361 0 : "to be closed under the SPGLIB symmetry operations.")
1362 : END IF
1363 : END DO
1364 : END DO
1365 : END DO
1366 :
1367 4 : IF (nskipped > 0) THEN
1368 : CALL cp_warn(__LOCATION__, &
1369 : "Some SPGLIB k-point mappings are not represented by the K290 backend; "// &
1370 0 : "the GENERAL k-point set was reduced only by the compatible mappings.")
1371 : END IF
1372 :
1373 4 : CALL store_general_reduction(csym, xkp_full, rep, wred, nred)
1374 :
1375 4 : DEALLOCATE (rep, srot, used, wred)
1376 :
1377 8 : END SUBROUTINE reduce_general_spglib_k290
1378 :
1379 : ! **************************************************************************************************
1380 : !> \brief Store reduced GENERAL k-point representatives.
1381 : !> \param csym ...
1382 : !> \param xkp_full explicit k-point coordinates
1383 : !> \param rep representative indices
1384 : !> \param wred representative multiplicities
1385 : !> \param nred number of reduced representatives
1386 : ! **************************************************************************************************
1387 26 : SUBROUTINE store_general_reduction(csym, xkp_full, rep, wred, nred)
1388 : TYPE(csym_type) :: csym
1389 : REAL(KIND=dp), DIMENSION(:, :), INTENT(IN) :: xkp_full
1390 : INTEGER, DIMENSION(:), INTENT(IN) :: rep
1391 : REAL(KIND=dp), DIMENSION(:), INTENT(IN) :: wred
1392 : INTEGER, INTENT(IN) :: nred
1393 :
1394 : INTEGER :: i, j, nfull
1395 :
1396 26 : nfull = SIZE(xkp_full, 2)
1397 26 : csym%nkpoint = nred
1398 130 : ALLOCATE (csym%xkpoint(3, nred), csym%wkpoint(nred))
1399 52 : DO i = 1, nred
1400 104 : csym%xkpoint(1:3, i) = xkp_full(1:3, rep(i))
1401 52 : csym%wkpoint(i) = wred(i)
1402 : END DO
1403 234 : DO i = 1, nfull
1404 208 : DO j = 1, nred
1405 208 : IF (csym%kplink(1, i) == rep(j)) THEN
1406 208 : csym%kplink(2, i) = j
1407 208 : EXIT
1408 : END IF
1409 : END DO
1410 234 : CPASSERT(csym%kplink(2, i) /= 0)
1411 : END DO
1412 :
1413 26 : END SUBROUTINE store_general_reduction
1414 :
1415 : ! **************************************************************************************************
1416 : !> \brief Reduce a k-point mesh with SPGLIB rotations and K290 operations
1417 : !> \param csym ...
1418 : !> \param xkp full k-point mesh in reciprocal lattice coordinates
1419 : !> \param wkp reduced k-point weights
1420 : !> \param kpop K290 operation mapping the representative k-point to a mesh point
1421 : !> \param srot SPGLIB integer rotations in fractional coordinates
1422 : !> \param nrot number of stored rotations
1423 : !> \param a1 first lattice vector
1424 : !> \param a2 second lattice vector
1425 : !> \param a3 third lattice vector
1426 : !> \param b1 first reciprocal lattice vector
1427 : !> \param b2 second reciprocal lattice vector
1428 : !> \param b3 third reciprocal lattice vector
1429 : !> \param alat lattice scaling used by K290
1430 : ! **************************************************************************************************
1431 16 : SUBROUTINE reduce_spglib_kpoint_mesh_k290(csym, xkp, wkp, kpop, srot, nrot, &
1432 : a1, a2, a3, b1, b2, b3, alat)
1433 : TYPE(csym_type) :: csym
1434 : REAL(KIND=dp), DIMENSION(:, :), INTENT(IN) :: xkp
1435 : REAL(KIND=dp), DIMENSION(:) :: wkp
1436 : INTEGER, DIMENSION(:) :: kpop
1437 : INTEGER, DIMENSION(:, :, :), INTENT(IN) :: srot
1438 : INTEGER, INTENT(IN) :: nrot
1439 : REAL(KIND=dp), DIMENSION(3), INTENT(IN) :: a1, a2, a3, b1, b2, b3
1440 : REAL(KIND=dp), INTENT(IN) :: alat
1441 :
1442 : INTEGER :: i, iop, isign, j, k290_op, nkpts, &
1443 : nskipped
1444 : INTEGER, DIMENSION(3, 3) :: krot
1445 : LOGICAL :: valid
1446 : REAL(KIND=dp) :: eps
1447 : REAL(KIND=dp), DIMENSION(3) :: rr
1448 :
1449 16 : nkpts = SIZE(wkp)
1450 16 : eps = MAX(1.e-12_dp, 10.0_dp*csym%delta)
1451 16 : nskipped = 0
1452 :
1453 368 : wkp = 0.0_dp
1454 368 : kpop = 0
1455 368 : csym%kplink(1, :) = 0
1456 :
1457 368 : DO i = 1, nkpts
1458 352 : IF (csym%kplink(1, i) /= 0) CYCLE
1459 :
1460 64 : csym%kplink(1, i) = i
1461 64 : wkp(i) = 1.0_dp
1462 64 : kpop(i) = 1
1463 :
1464 688 : DO iop = 1, nrot
1465 608 : krot = reciprocal_rotation(srot(:, :, iop))
1466 2176 : DO isign = 1, 2
1467 30400 : rr(1:3) = MATMUL(REAL(krot(1:3, 1:3), KIND=dp), xkp(1:3, i))
1468 3040 : IF (isign == 2) rr(1:3) = -rr(1:3)
1469 :
1470 1216 : j = regular_kpoint_index(rr, xkp(1:3, 1), csym%mesh, eps)
1471 1216 : IF (j == 0 .OR. j == i) CYCLE
1472 1024 : IF (csym%kplink(1, j) /= 0) THEN
1473 736 : CPASSERT(csym%kplink(1, j) == i)
1474 : CYCLE
1475 : END IF
1476 :
1477 : CALL find_k290_kpoint_operation(csym, xkp(1:3, i), xkp(1:3, j), &
1478 : a1, a2, a3, b1, b2, b3, alat, &
1479 288 : k290_op, valid)
1480 288 : IF (.NOT. valid) THEN
1481 0 : nskipped = nskipped + 1
1482 0 : CYCLE
1483 : END IF
1484 288 : csym%kplink(1, j) = i
1485 288 : wkp(i) = wkp(i) + 1.0_dp
1486 896 : kpop(j) = k290_op
1487 : END DO
1488 : END DO
1489 : END DO
1490 :
1491 368 : DO i = 1, nkpts
1492 352 : CPASSERT(csym%kplink(1, i) /= 0)
1493 368 : CPASSERT(kpop(i) /= 0)
1494 : END DO
1495 16 : IF (nskipped > 0) THEN
1496 : CALL cp_warn(__LOCATION__, &
1497 : "Some SPGLIB k-point mappings are not represented by the K290 backend; "// &
1498 0 : "the mesh was reduced only by the compatible mappings.")
1499 : END IF
1500 :
1501 16 : END SUBROUTINE reduce_spglib_kpoint_mesh_k290
1502 :
1503 : ! **************************************************************************************************
1504 : !> \brief Find a K290 operation that maps one fractional k-point to another
1505 : !> \param csym ...
1506 : !> \param xref representative k-point
1507 : !> \param xtarget target k-point
1508 : !> \param a1 first lattice vector
1509 : !> \param a2 second lattice vector
1510 : !> \param a3 third lattice vector
1511 : !> \param b1 first reciprocal lattice vector
1512 : !> \param b2 second reciprocal lattice vector
1513 : !> \param b3 third reciprocal lattice vector
1514 : !> \param alat lattice scaling used by K290
1515 : !> \param k290_op K290 operation identifier
1516 : !> \param valid whether a matching K290 operation was found
1517 : ! **************************************************************************************************
1518 672 : SUBROUTINE find_k290_kpoint_operation(csym, xref, xtarget, a1, a2, a3, b1, b2, b3, alat, &
1519 : k290_op, valid)
1520 : TYPE(csym_type) :: csym
1521 : REAL(KIND=dp), DIMENSION(3), INTENT(IN) :: xref, xtarget, a1, a2, a3, b1, b2, b3
1522 : REAL(KIND=dp), INTENT(IN) :: alat
1523 : INTEGER, INTENT(OUT) :: k290_op
1524 : LOGICAL, INTENT(OUT) :: valid
1525 :
1526 : INTEGER :: ibsign, iop, kr
1527 : REAL(KIND=dp) :: eps
1528 : REAL(KIND=dp), DIMENSION(3) :: diff, rr, wcart
1529 :
1530 672 : eps = MAX(1.e-12_dp, 10.0_dp*csym%delta)
1531 672 : k290_op = 0
1532 672 : valid = .FALSE.
1533 :
1534 1616 : DO iop = 1, csym%nrtot
1535 1616 : IF (iop > SIZE(csym%rt, 3)) CYCLE
1536 1616 : IF (csym%ibrot(iop) == 0) CYCLE
1537 3872 : DO ibsign = 1, 2
1538 11712 : wcart(1:3) = alat*(xref(1)*b1(1:3) + xref(2)*b2(1:3) + xref(3)*b3(1:3))
1539 11712 : wcart(1:3) = kp_apply_operation(wcart(1:3), csym%rt(1:3, 1:3, iop))
1540 2928 : IF (ibsign == 2) THEN
1541 5248 : wcart(1:3) = -wcart(1:3)
1542 1312 : kr = -csym%ibrot(iop)
1543 : ELSE
1544 1616 : kr = csym%ibrot(iop)
1545 : END IF
1546 11712 : rr(1) = DOT_PRODUCT(a1(1:3), wcart(1:3))/alat
1547 11712 : rr(2) = DOT_PRODUCT(a2(1:3), wcart(1:3))/alat
1548 11712 : rr(3) = DOT_PRODUCT(a3(1:3), wcart(1:3))/alat
1549 :
1550 11712 : diff(1:3) = xtarget(1:3) - rr(1:3)
1551 11712 : diff(1:3) = diff(1:3) - ANINT(diff(1:3))
1552 7056 : IF (ALL(ABS(diff(1:3)) < eps)) THEN
1553 672 : k290_op = kr
1554 672 : valid = .TRUE.
1555 672 : RETURN
1556 : END IF
1557 : END DO
1558 : END DO
1559 :
1560 : END SUBROUTINE find_k290_kpoint_operation
1561 :
1562 : ! **************************************************************************************************
1563 : !> \brief Score SPGLIB operations to choose stable atom transformations
1564 : !> \param csym ...
1565 : !> \param iop operation index
1566 : !> \param srot integer rotation in fractional coordinates
1567 : !> \return score, lower values are preferred
1568 : ! **************************************************************************************************
1569 15912 : FUNCTION spglib_operation_score(csym, iop, srot) RESULT(score)
1570 : TYPE(csym_type), INTENT(IN) :: csym
1571 : INTEGER, INTENT(IN) :: iop
1572 : INTEGER, DIMENSION(3, 3), INTENT(IN) :: srot
1573 : INTEGER :: score
1574 :
1575 : INTEGER :: i, nat
1576 : INTEGER, DIMENSION(3, 3) :: eye, r2
1577 : REAL(KIND=dp) :: eps
1578 :
1579 15912 : eps = MAX(1.e-12_dp, 10.0_dp*csym%delta)
1580 15912 : nat = SIZE(csym%f0, 1)
1581 15912 : score = 0
1582 111312 : DO i = 1, nat
1583 111312 : IF (csym%f0(i, iop) /= i) score = score + 100
1584 : END DO
1585 45682 : IF (ANY(ABS(csym%vt(1:3, iop) - ANINT(csym%vt(1:3, iop))) > eps)) score = score + 10
1586 :
1587 15912 : eye = 0
1588 15912 : eye(1, 1) = 1
1589 15912 : eye(2, 2) = 1
1590 15912 : eye(3, 3) = 1
1591 636480 : r2(1:3, 1:3) = MATMUL(srot(1:3, 1:3), srot(1:3, 1:3))
1592 112720 : IF (ANY(r2(1:3, 1:3) /= eye(1:3, 1:3))) score = score + 1
1593 :
1594 15912 : END FUNCTION spglib_operation_score
1595 :
1596 : ! **************************************************************************************************
1597 : !> \brief Reciprocal-space rotation corresponding to a fractional direct-space rotation
1598 : !> \param rot direct-space rotation
1599 : !> \return reciprocal-space rotation
1600 : ! **************************************************************************************************
1601 17576 : FUNCTION reciprocal_rotation(rot) RESULT(krot)
1602 : INTEGER, DIMENSION(3, 3), INTENT(IN) :: rot
1603 : INTEGER, DIMENSION(3, 3) :: krot
1604 :
1605 : REAL(KIND=dp), DIMENSION(3, 3) :: rinv
1606 :
1607 228488 : rinv = inv_3x3(REAL(rot(1:3, 1:3), KIND=dp))
1608 228488 : krot(1:3, 1:3) = NINT(TRANSPOSE(rinv(1:3, 1:3)))
1609 :
1610 17576 : END FUNCTION reciprocal_rotation
1611 :
1612 : ! **************************************************************************************************
1613 : !> \brief Reduce a CP2K Monkhorst-Pack mesh using K290 symmetry operations
1614 : !> \param csym ...
1615 : !> \param xkp full k-point mesh in reciprocal lattice coordinates
1616 : !> \param wkp reduced k-point weights
1617 : !> \param kpop symmetry operation mapping the representative k-point to a mesh point
1618 : !> \param nc number of point group operations
1619 : !> \param ib K290 operation identifiers
1620 : !> \param r K290 rotation matrices
1621 : !> \param a1 first lattice vector
1622 : !> \param a2 second lattice vector
1623 : !> \param a3 third lattice vector
1624 : !> \param b1 first reciprocal lattice vector
1625 : !> \param b2 second reciprocal lattice vector
1626 : !> \param b3 third reciprocal lattice vector
1627 : !> \param alat lattice scaling used by K290
1628 : ! **************************************************************************************************
1629 700 : SUBROUTINE reduce_kpoint_mesh(csym, xkp, wkp, kpop, nc, ib, r, a1, a2, a3, b1, b2, b3, alat)
1630 : TYPE(csym_type) :: csym
1631 : REAL(KIND=dp), DIMENSION(:, :), INTENT(IN) :: xkp
1632 : REAL(KIND=dp), DIMENSION(:) :: wkp
1633 : INTEGER, DIMENSION(:) :: kpop
1634 : INTEGER, INTENT(IN) :: nc
1635 : INTEGER, DIMENSION(48), INTENT(IN) :: ib
1636 : REAL(KIND=dp), DIMENSION(3, 3, 48), INTENT(IN) :: r
1637 : REAL(KIND=dp), DIMENSION(3), INTENT(IN) :: a1, a2, a3, b1, b2, b3
1638 : REAL(KIND=dp), INTENT(IN) :: alat
1639 :
1640 : INTEGER :: i, ibsign, iop, j, kr, nkpts, &
1641 : nskipped_overlaps
1642 : REAL(KIND=dp) :: eps
1643 : REAL(KIND=dp), DIMENSION(3) :: rr, wcart
1644 :
1645 700 : nkpts = SIZE(wkp)
1646 700 : eps = MAX(1.e-12_dp, 10.0_dp*csym%delta)
1647 700 : nskipped_overlaps = 0
1648 :
1649 7146 : wkp = 0.0_dp
1650 7146 : kpop = 0
1651 7146 : csym%kplink(1, :) = 0
1652 :
1653 7146 : DO i = 1, nkpts
1654 6446 : IF (csym%kplink(1, i) /= 0) CYCLE
1655 :
1656 1684 : csym%kplink(1, i) = i
1657 1684 : wkp(i) = 1.0_dp
1658 1684 : kpop(i) = 1
1659 :
1660 25580 : DO iop = 1, nc
1661 76034 : DO ibsign = 1, 2
1662 46392 : kr = ib(iop)
1663 185568 : wcart(1:3) = alat*(xkp(1, i)*b1(1:3) + xkp(2, i)*b2(1:3) + xkp(3, i)*b3(1:3))
1664 185568 : wcart(1:3) = kp_apply_operation(wcart(1:3), r(1:3, 1:3, kr))
1665 46392 : IF (ibsign == 2) THEN
1666 92784 : wcart(1:3) = -wcart(1:3)
1667 23196 : kr = -kr
1668 : END IF
1669 185568 : rr(1) = DOT_PRODUCT(a1(1:3), wcart(1:3))/alat
1670 185568 : rr(2) = DOT_PRODUCT(a2(1:3), wcart(1:3))/alat
1671 185568 : rr(3) = DOT_PRODUCT(a3(1:3), wcart(1:3))/alat
1672 :
1673 46392 : j = regular_kpoint_index(rr, xkp(1:3, 1), csym%mesh, eps)
1674 : ! Some point-group operations are incompatible with the requested Monkhorst-Pack mesh.
1675 46392 : IF (j == 0) CYCLE
1676 68856 : IF (csym%kplink(1, j) == 0) THEN
1677 4762 : csym%kplink(1, j) = i
1678 4762 : wkp(i) = wkp(i) + 1.0_dp
1679 4762 : kpop(j) = kr
1680 40898 : ELSE IF (csym%kplink(1, j) /= i) THEN
1681 : ! Approximate K290 operation sets need not be closed for structures whose
1682 : ! coordinates lie close to several symmetry tolerances. Keep the existing
1683 : ! disjoint orbit instead of aborting or double-counting this mesh point.
1684 16 : nskipped_overlaps = nskipped_overlaps + 1
1685 : END IF
1686 : END DO
1687 : END DO
1688 : END DO
1689 :
1690 700 : IF (nskipped_overlaps > 0) THEN
1691 56 : wkp = 1.0_dp
1692 2 : CALL inversion_symm(xkp, wkp, csym%kplink(1, :))
1693 56 : DO i = 1, nkpts
1694 56 : IF (wkp(i) > 0.0_dp) THEN
1695 28 : kpop(i) = 1
1696 : ELSE
1697 26 : kpop(i) = 2
1698 : END IF
1699 : END DO
1700 2 : csym%nrtot = 0
1701 2 : csym%inversion_only = .TRUE.
1702 : CALL cp_warn(__LOCATION__, &
1703 : "The K290 k-point operations produced overlapping, non-closed mesh orbits; "// &
1704 : "falling back to inversion/time-reversal symmetry. Use SYMMETRY_BACKEND SPGLIB "// &
1705 2 : "for full reduction by a closed crystallographic symmetry group.")
1706 : ELSE
1707 7090 : DO i = 1, nkpts
1708 6392 : CPASSERT(csym%kplink(1, i) /= 0)
1709 7090 : CPASSERT(kpop(i) /= 0)
1710 : END DO
1711 : END IF
1712 :
1713 700 : END SUBROUTINE reduce_kpoint_mesh
1714 :
1715 : ! **************************************************************************************************
1716 : !> \brief Return the flat index of a point on a regular Monkhorst-Pack mesh.
1717 : !> \param x target k-point in reciprocal lattice coordinates
1718 : !> \param origin first point of the generated mesh
1719 : !> \param mesh mesh dimensions
1720 : !> \param eps coordinate tolerance
1721 : !> \return flat mesh index, or zero if x is not on the mesh
1722 : ! **************************************************************************************************
1723 127916 : PURE FUNCTION regular_kpoint_index(x, origin, mesh, eps) RESULT(index)
1724 : REAL(KIND=dp), DIMENSION(3), INTENT(IN) :: x, origin
1725 : INTEGER, DIMENSION(3), INTENT(IN) :: mesh
1726 : REAL(KIND=dp), INTENT(IN) :: eps
1727 : INTEGER :: index
1728 :
1729 : INTEGER :: idim
1730 : INTEGER, DIMENSION(3) :: icoord, istep
1731 : REAL(KIND=dp) :: scaled
1732 :
1733 127916 : index = 0
1734 511664 : IF (ANY(mesh <= 0)) RETURN
1735 494764 : DO idim = 1, 3
1736 374476 : scaled = (x(idim) - origin(idim))*REAL(mesh(idim), KIND=dp)
1737 374476 : istep(idim) = NINT(scaled)
1738 374476 : IF (ABS(scaled - REAL(istep(idim), KIND=dp)) > eps*REAL(mesh(idim), KIND=dp)) RETURN
1739 487136 : icoord(idim) = MODULO(istep(idim), mesh(idim)) + 1
1740 : END DO
1741 :
1742 120288 : index = ((icoord(1) - 1)*mesh(2) + icoord(2) - 1)*mesh(3) + icoord(3)
1743 :
1744 120288 : END FUNCTION regular_kpoint_index
1745 :
1746 : ! **************************************************************************************************
1747 : !> \brief ...
1748 : !> \param nk ...
1749 : !> \param xkp ...
1750 : !> \param wkp ...
1751 : !> \param shift ...
1752 : !> \param gamma_centered ...
1753 : ! **************************************************************************************************
1754 3430 : SUBROUTINE full_grid_gen(nk, xkp, wkp, shift, gamma_centered)
1755 : INTEGER, INTENT(IN) :: nk(3)
1756 : REAL(KIND=dp), DIMENSION(:, :) :: xkp
1757 : REAL(KIND=dp), DIMENSION(:) :: wkp
1758 : REAL(KIND=dp), INTENT(IN) :: shift(3)
1759 : LOGICAL, INTENT(IN), OPTIONAL :: gamma_centered
1760 :
1761 : INTEGER :: i, idim, ix, iy, iz
1762 : INTEGER, DIMENSION(3) :: ik
1763 : LOGICAL :: gamma_mesh
1764 : REAL(KIND=dp) :: kpt_latt(3)
1765 :
1766 3430 : IF (PRESENT(gamma_centered)) THEN
1767 3430 : gamma_mesh = gamma_centered
1768 : ELSE
1769 : gamma_mesh = .FALSE.
1770 : END IF
1771 :
1772 37898 : wkp = 0.0_dp
1773 3430 : i = 0
1774 10212 : DO ix = 1, nk(1)
1775 24560 : DO iy = 1, nk(2)
1776 55598 : DO iz = 1, nk(3)
1777 34468 : i = i + 1
1778 34468 : ik(1) = ix
1779 34468 : ik(2) = iy
1780 34468 : ik(3) = iz
1781 137872 : DO idim = 1, 3
1782 137872 : IF (gamma_mesh .AND. MOD(nk(idim), 2) == 0) THEN
1783 : kpt_latt(idim) = REAL(2*ik(idim) - nk(idim), KIND=dp)/ &
1784 2148 : (2._dp*REAL(nk(idim), KIND=dp))
1785 : ELSE
1786 : kpt_latt(idim) = REAL(2*ik(idim) - nk(idim) - 1, KIND=dp)/ &
1787 101256 : (2._dp*REAL(nk(idim), KIND=dp))
1788 : END IF
1789 : END DO
1790 137872 : xkp(1:3, i) = kpt_latt(1:3)
1791 48816 : wkp(i) = 1.0_dp
1792 : END DO
1793 : END DO
1794 : END DO
1795 37898 : DO i = 1, nk(1)*nk(2)*nk(3)
1796 141302 : xkp(1:3, i) = xkp(1:3, i) + shift(1:3)
1797 : END DO
1798 :
1799 3430 : END SUBROUTINE full_grid_gen
1800 :
1801 : ! **************************************************************************************************
1802 : !> \brief ...
1803 : !> \param xkp ...
1804 : !> \param wkp ...
1805 : !> \param link ...
1806 : ! **************************************************************************************************
1807 1620 : SUBROUTINE inversion_symm(xkp, wkp, link)
1808 : REAL(KIND=dp), DIMENSION(:, :) :: xkp
1809 : REAL(KIND=dp), DIMENSION(:) :: wkp
1810 : INTEGER, DIMENSION(:) :: link
1811 :
1812 : INTEGER :: i, j, nkpts
1813 : REAL(KIND=dp), DIMENSION(3) :: diff
1814 :
1815 1620 : nkpts = SIZE(wkp, 1)
1816 :
1817 15244 : link(:) = 0
1818 15244 : DO i = 1, nkpts
1819 13624 : IF (link(i) == 0) link(i) = i
1820 171284 : DO j = i + 1, nkpts
1821 162564 : IF (wkp(j) == 0) CYCLE
1822 444112 : diff(1:3) = xkp(1:3, i) + xkp(1:3, j)
1823 444112 : diff(1:3) = diff(1:3) - ANINT(diff(1:3))
1824 166770 : IF (ALL(ABS(diff(1:3)) < 1.e-12_dp)) THEN
1825 6524 : wkp(i) = wkp(i) + wkp(j)
1826 6524 : wkp(j) = 0.0_dp
1827 6524 : link(j) = i
1828 6524 : EXIT
1829 : END IF
1830 : END DO
1831 : END DO
1832 :
1833 1620 : END SUBROUTINE inversion_symm
1834 :
1835 : ! **************************************************************************************************
1836 : !> \brief ...
1837 : !> \param x ...
1838 : !> \param r ...
1839 : !> \return ...
1840 : ! **************************************************************************************************
1841 49704 : FUNCTION kp_apply_operation(x, r) RESULT(y)
1842 : REAL(KIND=dp), INTENT(IN) :: x(3), r(3, 3)
1843 : REAL(KIND=dp) :: y(3)
1844 :
1845 49704 : y(1) = r(1, 1)*x(1) + r(1, 2)*x(2) + r(1, 3)*x(3)
1846 49704 : y(2) = r(2, 1)*x(1) + r(2, 2)*x(2) + r(2, 3)*x(3)
1847 49704 : y(3) = r(3, 1)*x(1) + r(3, 2)*x(2) + r(3, 3)*x(3)
1848 :
1849 49704 : END FUNCTION kp_apply_operation
1850 :
1851 : ! **************************************************************************************************
1852 : !> \brief ...
1853 : !> \param csym ...
1854 : ! **************************************************************************************************
1855 3468 : SUBROUTINE print_crys_symmetry(csym)
1856 : TYPE(csym_type) :: csym
1857 :
1858 : INTEGER :: i, iunit, j, plevel
1859 :
1860 3468 : iunit = csym%punit
1861 3468 : IF (iunit >= 0) THEN
1862 1469 : plevel = csym%plevel
1863 1469 : WRITE (iunit, "(/,T2,A)") "Crystal Symmetry Information"
1864 1469 : IF (csym%symlib) THEN
1865 1467 : WRITE (iunit, '(A,T71,A10)') " International Symbol: ", ADJUSTR(TRIM(csym%international_symbol))
1866 1467 : WRITE (iunit, '(A,T71,A10)') " Point Group Symbol: ", ADJUSTR(TRIM(csym%pointgroup_symbol))
1867 1467 : WRITE (iunit, '(A,T71,A10)') " Schoenflies Symbol: ", ADJUSTR(TRIM(csym%schoenflies))
1868 : !
1869 1467 : WRITE (iunit, '(A,T71,I10)') " Number of Symmetry Operations: ", csym%n_operations
1870 1467 : IF (plevel > 0) THEN
1871 0 : DO i = 1, csym%n_operations
1872 : WRITE (iunit, '(A,i4,T51,3I10,/,T51,3I10,/,T51,3I10)') &
1873 0 : " Rotation #: ", i, (csym%rotations(j, :, i), j=1, 3)
1874 0 : WRITE (iunit, '(T36,3F15.7)') csym%translations(:, i)
1875 : END DO
1876 : END IF
1877 : ELSE
1878 2 : IF (csym%spglib_requested) THEN
1879 1 : WRITE (iunit, "(T2,A)") "SPGLIB for Crystal Symmetry Information determination is not available"
1880 : ELSE
1881 1 : WRITE (iunit, "(T2,A)") "SPGLIB Crystal Symmetry Information was not requested"
1882 : END IF
1883 : END IF
1884 : END IF
1885 :
1886 3468 : END SUBROUTINE print_crys_symmetry
1887 :
1888 : ! **************************************************************************************************
1889 : !> \brief ...
1890 : !> \param csym ...
1891 : ! **************************************************************************************************
1892 3178 : SUBROUTINE print_kp_symmetry(csym)
1893 : TYPE(csym_type), INTENT(IN) :: csym
1894 :
1895 : INTEGER :: i, iunit, nat, nmesh, plevel
1896 :
1897 3178 : iunit = csym%punit
1898 3178 : IF (iunit >= 0) THEN
1899 1179 : plevel = csym%plevel
1900 1179 : WRITE (iunit, "(/,T2,A)") "K-point Symmetry Information"
1901 1179 : WRITE (iunit, '(A,T67,I14)') " Number of Special K-points: ", csym%nkpoint
1902 1179 : WRITE (iunit, '(T19,A,T74,A)') " Wavevector Basis ", " Weight"
1903 4569 : DO i = 1, csym%nkpoint
1904 4569 : WRITE (iunit, '(T2,i10,3F10.5,T71,I10)') i, csym%xkpoint(1:3, i), NINT(csym%wkpoint(i))
1905 : END DO
1906 1179 : nmesh = csym%mesh(1)*csym%mesh(2)*csym%mesh(3)
1907 1179 : IF (nmesh > 0) THEN
1908 1171 : WRITE (iunit, '(/,A,T63,3I6)') " K-point Mesh: ", csym%mesh(1), csym%mesh(2), csym%mesh(3)
1909 : ELSE
1910 8 : nmesh = SIZE(csym%kpmesh, 2)
1911 8 : WRITE (iunit, '(/,A,T70,I10)') " Explicit K-point Set: ", nmesh
1912 : END IF
1913 1179 : WRITE (iunit, '(T19,A,T54,A)') " Wavevector Basis ", " Special Points Rotation"
1914 11262 : DO i = 1, nmesh
1915 10083 : WRITE (iunit, '(T2,i10,3F10.5,T45,3I12)') i, csym%kpmesh(1:3, i), &
1916 21345 : csym%kplink(1:2, i), csym%kpop(i)
1917 : END DO
1918 1179 : IF (csym%nrtot > 0) THEN
1919 662 : WRITE (iunit, '(/,A)') " Atom Transformation Table"
1920 662 : nat = SIZE(csym%f0, 1)
1921 7568 : DO i = 1, csym%nrtot
1922 7568 : WRITE (iunit, '(T10,A,I5,(T21,12I5))') " Rot=", csym%ibrot(i), csym%f0(1:nat, i)
1923 : END DO
1924 : END IF
1925 : END IF
1926 :
1927 3178 : END SUBROUTINE print_kp_symmetry
1928 :
1929 0 : END MODULE cryssym
|