(git:a90b72f)
Loading...
Searching...
No Matches
space_groups.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 Space Group Symmetry Module (version 1.0, January 16, 2020)
10!> \par History
11!> Pierre-André Cazade [pcazade] 01.2020 - University of Limerick
12!> \author Pierre-André Cazade (first version)
13! **************************************************************************************************
16 USE bibliography, ONLY: togo2018,&
17 cite_reference
18 USE cell_methods, ONLY: cell_create,&
20 USE cell_types, ONLY: cell_copy,&
21 cell_type,&
26 USE gopt_f_types, ONLY: gopt_f_type
32 USE kinds, ONLY: dp
33 USE mathlib, ONLY: det_3x3,&
34 inv_3x3,&
35 jacobi
37 USE physcon, ONLY: pascal
46#include "../base/base_uses.f90"
47
48 IMPLICIT NONE
49
50 PRIVATE
51
52 CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'space_groups'
53
57
58CONTAINS
59
60! **************************************************************************************************
61!> \brief routine creates the space group structure
62!> \param scoor ...
63!> \param types ...
64!> \param cell ...
65!> \param gopt_env ...
66!> \param eps_symmetry ...
67!> \param pol ...
68!> \param ranges ...
69!> \param nparticle ...
70!> \param n_atom ...
71!> \param n_core ...
72!> \param n_shell ...
73!> \param iunit ...
74!> \param print_atoms ...
75!> \par History
76!> 01.2020 created [pcazade]
77!> \author Pierre-André Cazade (first version)
78! **************************************************************************************************
79 SUBROUTINE spgr_create(scoor, types, cell, gopt_env, eps_symmetry, pol, ranges, &
80 nparticle, n_atom, n_core, n_shell, iunit, print_atoms)
81
82 REAL(kind=dp), DIMENSION(:, :), INTENT(IN) :: scoor
83 INTEGER, DIMENSION(:), INTENT(IN) :: types
84 TYPE(cell_type), INTENT(IN), POINTER :: cell
85 TYPE(gopt_f_type), INTENT(IN), POINTER :: gopt_env
86 REAL(kind=dp), INTENT(IN), OPTIONAL :: eps_symmetry
87 REAL(kind=dp), DIMENSION(3), INTENT(IN), OPTIONAL :: pol
88 INTEGER, DIMENSION(:, :), INTENT(IN), OPTIONAL :: ranges
89 INTEGER, INTENT(IN), OPTIONAL :: nparticle, n_atom, n_core, n_shell
90 INTEGER, INTENT(IN) :: iunit
91 LOGICAL, INTENT(IN) :: print_atoms
92
93 CHARACTER(LEN=*), PARAMETER :: routinen = 'spgr_create'
94#ifdef __SPGLIB
95 CHARACTER(LEN=1000) :: buffer
96 INTEGER :: ierr, nchars, nop, tra_mat(3, 3)
97#endif
98 INTEGER :: handle, i, j, n_sr_rep
99 INTEGER, ALLOCATABLE, DIMENSION(:) :: tmp_types
100 LOGICAL :: spglib
101 REAL(kind=dp), ALLOCATABLE, DIMENSION(:, :) :: tmp_coor
102 TYPE(spgr_type), POINTER :: spgr
103
104 CALL timeset(routinen, handle)
105
106 spgr => gopt_env%spgr
107 cpassert(ASSOCIATED(spgr))
108
109 CALL cleanup_spgr_type(spgr)
110
111 !..total number of particles (atoms plus shells)
112 IF (PRESENT(nparticle)) THEN
113 cpassert(nparticle == SIZE(scoor, 2))
114 spgr%nparticle = nparticle
115 ELSE
116 spgr%nparticle = SIZE(scoor, 2)
117 END IF
118
119 IF (PRESENT(n_atom)) THEN
120 spgr%n_atom = n_atom
121 ELSE IF (PRESENT(n_core)) THEN
122 spgr%n_atom = spgr%nparticle - n_core
123 ELSE IF (PRESENT(n_shell)) THEN
124 spgr%n_atom = spgr%nparticle - n_shell
125 ELSE
126 spgr%n_atom = spgr%nparticle
127 END IF
128
129 IF (PRESENT(n_core)) THEN
130 spgr%n_core = n_core
131 ELSE IF (PRESENT(n_shell)) THEN
132 spgr%n_core = n_shell
133 END IF
134
135 IF (PRESENT(n_shell)) THEN
136 spgr%n_shell = n_shell
137 ELSE IF (PRESENT(n_core)) THEN
138 spgr%n_shell = n_core
139 END IF
140
141 IF (.NOT. (spgr%nparticle == (spgr%n_atom + spgr%n_shell))) THEN
142 cpabort("spgr_create: nparticle not equal to natom + nshell.")
143 END IF
144
145 spgr%nparticle_sym = spgr%nparticle
146 spgr%n_atom_sym = spgr%n_atom
147 spgr%n_core_sym = spgr%n_core
148 spgr%n_shell_sym = spgr%n_shell
149
150 spgr%iunit = iunit
151 spgr%print_atoms = print_atoms
152
153 ! accuracy for symmetry
154 IF (PRESENT(eps_symmetry)) THEN
155 spgr%eps_symmetry = eps_symmetry
156 END IF
157
158 ! vector to test reduced symmetry
159 IF (PRESENT(pol)) THEN
160 spgr%pol(1) = pol(1)
161 spgr%pol(2) = pol(2)
162 spgr%pol(3) = pol(3)
163 END IF
164
165 ALLOCATE (spgr%lat(spgr%nparticle))
166 spgr%lat = .true.
167
168 IF (PRESENT(ranges)) THEN
169 n_sr_rep = SIZE(ranges, 2)
170 DO i = 1, n_sr_rep
171 DO j = ranges(1, i), ranges(2, i)
172 spgr%lat(j) = .false.
173 spgr%nparticle_sym = spgr%nparticle_sym - 1
174 IF (j <= spgr%n_atom) THEN
175 spgr%n_atom_sym = spgr%n_atom_sym - 1
176 ELSE IF (j > spgr%n_atom .AND. j <= spgr%nparticle) THEN
177 spgr%n_core_sym = spgr%n_core_sym - 1
178 spgr%n_shell_sym = spgr%n_shell_sym - 1
179 ELSE
180 cpabort("Symmetry exclusion range larger than actual number of particles.")
181 END IF
182 END DO
183 END DO
184 END IF
185
186 ALLOCATE (tmp_coor(3, spgr%n_atom_sym), tmp_types(spgr%n_atom_sym))
187
188 j = 0
189 DO i = 1, spgr%n_atom
190 IF (spgr%lat(i)) THEN
191 j = j + 1
192 tmp_coor(:, j) = scoor(:, i)
193 tmp_types(j) = types(i)
194 END IF
195 END DO
196
197 !..set cell values
198 NULLIFY (spgr%cell_ref)
199 CALL cell_create(spgr%cell_ref)
200 CALL cell_copy(cell, spgr%cell_ref, tag="CELL_OPT_REF")
201 SELECT CASE (gopt_env%type_id)
203 CALL init_cell(spgr%cell_ref, hmat=cell%hmat)
205 CALL init_cell(spgr%cell_ref, hmat=gopt_env%h_ref)
206 CASE DEFAULT
207 cpabort("SPACE_GROUP_SYMMETRY is not compatible with md.")
208 END SELECT
209
210 ! atom types
211 ALLOCATE (spgr%atype(spgr%nparticle))
212 spgr%atype(1:spgr%nparticle) = types(1:spgr%nparticle)
213
214 spgr%n_operations = 0
215
216#ifdef __SPGLIB
217 spglib = .true.
218 CALL cite_reference(togo2018)
219 spgr%space_group_number = spg_get_international(spgr%international_symbol, transpose(cell%hmat), tmp_coor, tmp_types, &
220 spgr%n_atom_sym, eps_symmetry)
221 buffer = ''
222 nchars = strlcpy_c2f(buffer, spgr%international_symbol)
223 spgr%international_symbol = buffer(1:nchars)
224 IF (spgr%space_group_number == 0) THEN
225 cpabort("Symmetry Library SPGLIB failed, most likely due a problem with the coordinates.")
226 spglib = .false.
227 ELSE
228 nop = spg_get_multiplicity(transpose(cell%hmat), tmp_coor, tmp_types, &
229 spgr%n_atom_sym, eps_symmetry)
230 ALLOCATE (spgr%rotations(3, 3, nop), spgr%translations(3, nop))
231 ALLOCATE (spgr%eqatom(nop, spgr%nparticle))
232 ALLOCATE (spgr%lop(nop))
233 spgr%n_operations = nop
234 spgr%lop = .true.
235 ierr = spg_get_symmetry(spgr%rotations, spgr%translations, nop, transpose(cell%hmat), &
236 tmp_coor, tmp_types, spgr%n_atom_sym, eps_symmetry)
237 ! Schoenflies Symbol
238 ierr = spg_get_schoenflies(spgr%schoenflies, transpose(cell%hmat), tmp_coor, tmp_types, &
239 spgr%n_atom_sym, eps_symmetry)
240 buffer = ''
241 nchars = strlcpy_c2f(buffer, spgr%schoenflies)
242 spgr%schoenflies = buffer(1:nchars)
243
244 ! Point Group
245 tra_mat = 0
246 ierr = spg_get_pointgroup(spgr%pointgroup_symbol, tra_mat, &
247 spgr%rotations, spgr%n_operations)
248 buffer = ''
249 nchars = strlcpy_c2f(buffer, spgr%pointgroup_symbol)
250 spgr%pointgroup_symbol = buffer(1:nchars)
251 END IF
252#else
253 cpabort("Symmetry library SPGLIB not available")
254 spglib = .false.
255#endif
256 spgr%symlib = spglib
257
258 DEALLOCATE (tmp_coor, tmp_types)
259
260 CALL timestop(handle)
261
262 END SUBROUTINE spgr_create
263
264! **************************************************************************************************
265!> \brief routine indentifies the space group and finds rotation matrices.
266!> \param subsys ...
267!> \param geo_section ...
268!> \param gopt_env ...
269!> \param iunit ...
270!> \par History
271!> 01.2020 created [pcazade]
272!> \author Pierre-André Cazade (first version)
273!> \note rotation matrices innclude translations and translation symmetry:
274!> it works with supercells as well.
275! **************************************************************************************************
276 SUBROUTINE identify_space_group(subsys, geo_section, gopt_env, iunit)
277
278 TYPE(cp_subsys_type), INTENT(IN), POINTER :: subsys
279 TYPE(section_vals_type), INTENT(IN), POINTER :: geo_section
280 TYPE(gopt_f_type), INTENT(IN), POINTER :: gopt_env
281 INTEGER, INTENT(IN) :: iunit
282
283 CHARACTER(LEN=*), PARAMETER :: routinen = 'identify_space_group'
284
285 INTEGER :: handle, i, k, n_atom, n_core, n_shell, &
286 n_sr_rep, nparticle, shell_index
287 INTEGER, ALLOCATABLE, DIMENSION(:) :: atype
288 INTEGER, ALLOCATABLE, DIMENSION(:, :) :: ranges
289 INTEGER, DIMENSION(:), POINTER :: tmp
290 LOGICAL :: print_atoms
291 REAL(kind=dp) :: eps_symmetry
292 REAL(kind=dp), ALLOCATABLE, DIMENSION(:, :) :: scoord
293 REAL(kind=dp), DIMENSION(:), POINTER :: pol
294 TYPE(cell_type), POINTER :: cell
295 TYPE(particle_list_type), POINTER :: core_particles, particles, &
296 shell_particles
297 TYPE(spgr_type), POINTER :: spgr
298
299 CALL timeset(routinen, handle)
300
301 n_sr_rep = 0
302 nparticle = 0
303 n_atom = 0
304 n_core = 0
305 n_shell = 0
306
307 NULLIFY (particles)
308 NULLIFY (core_particles)
309 NULLIFY (shell_particles)
310
311 NULLIFY (cell)
312 cell => subsys%cell
313 cpassert(ASSOCIATED(cell))
314
315 CALL cp_subsys_get(subsys, particles=particles, shell_particles=shell_particles, core_particles=core_particles)
316
317 cpassert(ASSOCIATED(particles))
318 n_atom = particles%n_els
319 ! Check if we have other kinds of particles in this subsystem
320 IF (ASSOCIATED(shell_particles)) THEN
321 n_shell = shell_particles%n_els
322 cpassert(ASSOCIATED(core_particles))
323 n_core = subsys%core_particles%n_els
324 ! The same number of shell and core particles is assumed
325 cpassert(n_core == n_shell)
326 ELSE IF (ASSOCIATED(core_particles)) THEN
327 ! This case should not occur at the moment
328 cpabort("Core particles should not be defined without corresponding shell particles.")
329 ELSE
330 n_core = 0
331 n_shell = 0
332 END IF
333
334 nparticle = n_atom + n_shell
335 ALLOCATE (scoord(3, nparticle), atype(nparticle))
336 DO i = 1, n_atom
337 shell_index = particles%els(i)%shell_index
338 IF (shell_index == 0) THEN
339 CALL real_to_scaled(scoord(1:3, i), particles%els(i)%r(1:3), cell)
340 CALL get_atomic_kind(atomic_kind=particles%els(i)%atomic_kind, kind_number=atype(i))
341 ELSE
342 CALL real_to_scaled(scoord(1:3, i), core_particles%els(shell_index)%r(1:3), cell)
343 CALL get_atomic_kind(atomic_kind=core_particles%els(shell_index)%atomic_kind, kind_number=atype(i))
344 k = n_atom + shell_index
345 CALL real_to_scaled(scoord(1:3, k), shell_particles%els(shell_index)%r(1:3), cell)
346 CALL get_atomic_kind(atomic_kind=shell_particles%els(shell_index)%atomic_kind, kind_number=atype(k))
347 END IF
348 END DO
349
350 CALL section_vals_val_get(geo_section, "SPGR_PRINT_ATOMS", l_val=print_atoms)
351 CALL section_vals_val_get(geo_section, "EPS_SYMMETRY", r_val=eps_symmetry)
352 CALL section_vals_val_get(geo_section, "SYMM_REDUCTION", r_vals=pol)
353 CALL section_vals_val_get(geo_section, "SYMM_EXCLUDE_RANGE", n_rep_val=n_sr_rep)
354 IF (n_sr_rep > 0) THEN
355 ALLOCATE (ranges(2, n_sr_rep))
356 DO i = 1, n_sr_rep
357 CALL section_vals_val_get(geo_section, "SYMM_EXCLUDE_RANGE", i_rep_val=i, i_vals=tmp)
358 ranges(:, i) = tmp(:)
359 END DO
360 CALL spgr_create(scoord, atype, cell, gopt_env, eps_symmetry=eps_symmetry, pol=pol(1:3), &
361 ranges=ranges, nparticle=nparticle, n_atom=n_atom, &
362 n_core=n_core, n_shell=n_shell, iunit=iunit, print_atoms=print_atoms)
363 DEALLOCATE (ranges)
364 ELSE
365 CALL spgr_create(scoord, atype, cell, gopt_env, eps_symmetry=eps_symmetry, pol=pol(1:3), &
366 nparticle=nparticle, n_atom=n_atom, &
367 n_core=n_core, n_shell=n_shell, iunit=iunit, print_atoms=print_atoms)
368 END IF
369
370 NULLIFY (spgr)
371 spgr => gopt_env%spgr
372
373 CALL spgr_find_equivalent_atoms(spgr, scoord)
374 CALL spgr_reduce_symm(spgr)
375 CALL spgr_rotations_subset(spgr)
376
377 DEALLOCATE (scoord, atype)
378
379 CALL timestop(handle)
380
381 END SUBROUTINE identify_space_group
382
383! **************************************************************************************************
384!> \brief routine indentifies the equivalent atoms for each rotation matrix.
385!> \param spgr ...
386!> \param scoord ...
387!> \par History
388!> 01.2020 created [pcazade]
389!> \author Pierre-André Cazade (first version)
390! **************************************************************************************************
391 SUBROUTINE spgr_find_equivalent_atoms(spgr, scoord)
392
393 TYPE(spgr_type), INTENT(INOUT), POINTER :: spgr
394 REAL(kind=dp), ALLOCATABLE, DIMENSION(:, :), &
395 INTENT(IN) :: scoord
396
397 CHARACTER(LEN=*), PARAMETER :: routinen = 'spgr_find_equivalent_atoms'
398
399 INTEGER :: handle, i, ia, ib, ir, j, natom, nop, &
400 nshell
401 REAL(kind=dp) :: diff
402 REAL(kind=dp), DIMENSION(3) :: rb, ri, ro, tr
403 REAL(kind=dp), DIMENSION(3, 3) :: rot
404
405 CALL timeset(routinen, handle)
406
407 nop = spgr%n_operations
408 natom = spgr%n_atom
409 nshell = spgr%n_shell
410
411 IF (.NOT. (spgr%nparticle == (natom + nshell))) THEN
412 cpabort("spgr_find_equivalent_atoms: nparticle not equal to natom + nshell.")
413 END IF
414
415 DO ia = 1, spgr%nparticle
416 spgr%eqatom(:, ia) = ia
417 END DO
418
419 !$OMP PARALLEL DO PRIVATE (ia,ib,ir,ri,rb,ro,rot,tr,diff) SHARED (spgr,scoord,natom,nop) DEFAULT(NONE)
420 DO ia = 1, natom
421 IF (.NOT. spgr%lat(ia)) cycle
422 ri(1:3) = scoord(1:3, ia)
423 DO ir = 1, nop
424 rot(1:3, 1:3) = spgr%rotations(1:3, 1:3, ir)
425 tr(1:3) = spgr%translations(1:3, ir)
426 DO ib = 1, natom
427 IF (.NOT. spgr%lat(ib)) cycle
428 rb(1:3) = scoord(1:3, ib)
429 ro(1) = real(rot(1, 1), dp)*rb(1) + real(rot(2, 1), dp)*rb(2) + real(rot(3, 1), dp)*rb(3) + tr(1)
430 ro(2) = real(rot(1, 2), dp)*rb(1) + real(rot(2, 2), dp)*rb(2) + real(rot(3, 2), dp)*rb(3) + tr(2)
431 ro(3) = real(rot(1, 3), dp)*rb(1) + real(rot(2, 3), dp)*rb(2) + real(rot(3, 3), dp)*rb(3) + tr(3)
432 ro(1) = ro(1) - real(nint(ro(1) - ri(1)), dp)
433 ro(2) = ro(2) - real(nint(ro(2) - ri(2)), dp)
434 ro(3) = ro(3) - real(nint(ro(3) - ri(3)), dp)
435 diff = norm2(ri(:) - ro(:))
436 IF ((diff < spgr%eps_symmetry) .AND. (spgr%atype(ia) == spgr%atype(ib))) THEN
437 spgr%eqatom(ir, ia) = ib
438 EXIT
439 END IF
440 END DO
441 END DO
442 END DO
443 !$OMP END PARALLEL DO
444
445 !$OMP PARALLEL DO PRIVATE (i,j,ia,ib,ir,ri,rb,ro,rot,tr,diff) SHARED (spgr,scoord,natom,nshell,nop) DEFAULT(NONE)
446 DO i = 1, nshell
447 ia = natom + i
448 IF (.NOT. spgr%lat(ia)) cycle
449 ri(1:3) = scoord(1:3, ia)
450 DO ir = 1, nop
451 rot(1:3, 1:3) = spgr%rotations(1:3, 1:3, ir)
452 tr(1:3) = spgr%translations(1:3, ir)
453 DO j = 1, nshell
454 ib = natom + j
455 IF (.NOT. spgr%lat(ib)) cycle
456 rb(1:3) = scoord(1:3, ib)
457 ro(1) = real(rot(1, 1), dp)*rb(1) + real(rot(2, 1), dp)*rb(2) + real(rot(3, 1), dp)*rb(3) + tr(1)
458 ro(2) = real(rot(1, 2), dp)*rb(1) + real(rot(2, 2), dp)*rb(2) + real(rot(3, 2), dp)*rb(3) + tr(2)
459 ro(3) = real(rot(1, 3), dp)*rb(1) + real(rot(2, 3), dp)*rb(2) + real(rot(3, 3), dp)*rb(3) + tr(3)
460 ro(1) = ro(1) - real(nint(ro(1) - ri(1)), dp)
461 ro(2) = ro(2) - real(nint(ro(2) - ri(2)), dp)
462 ro(3) = ro(3) - real(nint(ro(3) - ri(3)), dp)
463 diff = norm2(ri(:) - ro(:))
464 IF ((diff < spgr%eps_symmetry) .AND. (spgr%atype(ia) == spgr%atype(ib))) THEN
465 spgr%eqatom(ir, ia) = ib
466 EXIT
467 END IF
468 END DO
469 END DO
470 END DO
471 !$OMP END PARALLEL DO
472
473 CALL timestop(handle)
474
475 END SUBROUTINE spgr_find_equivalent_atoms
476
477! **************************************************************************************************
478!> \brief routine looks for operations compatible with efield
479!> \param spgr ...
480!> \par History
481!> 01.2020 created [pcazade]
482!> \author Pierre-André Cazade (first version)
483! **************************************************************************************************
484 SUBROUTINE spgr_reduce_symm(spgr)
485
486 TYPE(spgr_type), INTENT(INOUT), POINTER :: spgr
487
488 CHARACTER(LEN=*), PARAMETER :: routinen = 'spgr_reduce_symm'
489
490 INTEGER :: handle, ia, ib, ir, ja, jb, nop, nops, &
491 nparticle
492 REAL(kind=dp), ALLOCATABLE, DIMENSION(:) :: x, xold
493 REAL(kind=dp), DIMENSION(3) :: ri, ro
494 REAL(kind=dp), DIMENSION(3, 3) :: rot
495
496 CALL timeset(routinen, handle)
497
498 nop = spgr%n_operations
499 nparticle = spgr%nparticle
500 ALLOCATE (x(3*nparticle), xold(3*nparticle))
501 x = 0.0_dp
502 DO ia = 1, nparticle
503 ja = 3*(ia - 1)
504 x(ja + 1) = x(ja + 1) + spgr%pol(1)
505 x(ja + 2) = x(ja + 2) + spgr%pol(2)
506 x(ja + 3) = x(ja + 3) + spgr%pol(3)
507 END DO
508 xold(:) = x(:)
509
510 nops = 0
511 DO ir = 1, nop
512 x = 0.d0
513 spgr%lop(ir) = .true.
514 rot(1:3, 1:3) = spgr%rotations(1:3, 1:3, ir)
515 DO ia = 1, nparticle
516 IF (.NOT. spgr%lat(ia)) cycle
517 ja = 3*(ia - 1)
518 ri(1:3) = xold(ja + 1:ja + 3)
519 ro(1) = real(rot(1, 1), dp)*ri(1) + real(rot(2, 1), dp)*ri(2) + real(rot(3, 1), dp)*ri(3)
520 ro(2) = real(rot(1, 2), dp)*ri(1) + real(rot(2, 2), dp)*ri(2) + real(rot(3, 2), dp)*ri(3)
521 ro(3) = real(rot(1, 3), dp)*ri(1) + real(rot(2, 3), dp)*ri(2) + real(rot(3, 3), dp)*ri(3)
522 x(ja + 1:ja + 3) = ro(1:3)
523 END DO
524 DO ia = 1, nparticle
525 IF (.NOT. spgr%lat(ia)) cycle
526 ib = spgr%eqatom(ir, ia)
527 ja = 3*(ia - 1)
528 jb = 3*(ib - 1)
529 ro = x(jb + 1:jb + 3) - xold(ja + 1:ja + 3)
530 spgr%lop(ir) = (spgr%lop(ir) .AND. (abs(ro(1)) < spgr%eps_symmetry) &
531 .AND. (abs(ro(2)) < spgr%eps_symmetry) &
532 .AND. (abs(ro(3)) < spgr%eps_symmetry))
533 END DO
534 IF (spgr%lop(ir)) nops = nops + 1
535 END DO
536
537 spgr%n_reduced_operations = nops
538
539 DEALLOCATE (x, xold)
540 CALL timestop(handle)
541
542 END SUBROUTINE spgr_reduce_symm
543
544! **************************************************************************************************
545!> \brief routine looks for unique rotations
546!> \param spgr ...
547!> \par History
548!> 01.2020 created [pcazade]
549!> \author Pierre-André Cazade (first version)
550! **************************************************************************************************
551
552 SUBROUTINE spgr_rotations_subset(spgr)
553
554 TYPE(spgr_type), INTENT(INOUT), POINTER :: spgr
555
556 CHARACTER(LEN=*), PARAMETER :: routinen = 'spgr_rotations_subset'
557
558 INTEGER :: handle, i, j
559 INTEGER, DIMENSION(3, 3) :: d
560 LOGICAL, ALLOCATABLE, DIMENSION(:) :: mask
561
562 CALL timeset(routinen, handle)
563
564 ALLOCATE (mask(spgr%n_operations))
565 mask = .true.
566
567 DO i = 1, spgr%n_operations
568 IF (.NOT. spgr%lop(i)) mask(i) = .false.
569 END DO
570
571 DO i = 1, spgr%n_operations - 1
572 IF (.NOT. mask(i)) cycle
573 DO j = i + 1, spgr%n_operations
574 IF (.NOT. mask(j)) cycle
575 d(:, :) = spgr%rotations(:, :, j) - spgr%rotations(:, :, i)
576 IF (sum(abs(d)) == 0) mask(j) = .false.
577 END DO
578 END DO
579
580 spgr%n_operations_subset = 0
581 DO i = 1, spgr%n_operations
582 IF (mask(i)) spgr%n_operations_subset = spgr%n_operations_subset + 1
583 END DO
584
585 ALLOCATE (spgr%rotations_subset(3, 3, spgr%n_operations_subset))
586
587 j = 0
588 DO i = 1, spgr%n_operations
589 IF (mask(i)) THEN
590 j = j + 1
591 spgr%rotations_subset(:, :, j) = spgr%rotations(:, :, i)
592 END IF
593 END DO
594
595 DEALLOCATE (mask)
596 CALL timestop(handle)
597
598 END SUBROUTINE spgr_rotations_subset
599
600! **************************************************************************************************
601!> \brief routine applies the rotation matrices to the coordinates.
602!> \param spgr ...
603!> \param coord ...
604!> \par History
605!> 01.2020 created [pcazade]
606!> \author Pierre-André Cazade (first version)
607! **************************************************************************************************
608 SUBROUTINE spgr_apply_rotations_coord(spgr, coord)
609
610 TYPE(spgr_type), INTENT(IN), POINTER :: spgr
611 REAL(kind=dp), DIMENSION(:), INTENT(INOUT) :: coord
612
613 CHARACTER(LEN=*), PARAMETER :: routinen = 'spgr_apply_rotations_coord'
614
615 INTEGER :: handle, ia, ib, ir, ja, jb, nop, nops, &
616 nparticle
617 REAL(kind=dp), ALLOCATABLE, DIMENSION(:) :: cold
618 REAL(kind=dp), DIMENSION(3) :: rf, ri, rn, ro, tr
619 REAL(kind=dp), DIMENSION(3, 3) :: rot
620
621 CALL timeset(routinen, handle)
622
623 ALLOCATE (cold(SIZE(coord)))
624 cold(:) = coord(:)
625
626 nop = spgr%n_operations
627 nparticle = spgr%nparticle
628 nops = spgr%n_reduced_operations
629
630 !$OMP PARALLEL DO PRIVATE (ia,ib,ja,jb,ir,ri,ro,rf,rn,rot,tr) SHARED (spgr,coord,nparticle,nop,nops) DEFAULT(NONE)
631 DO ia = 1, nparticle
632 IF (.NOT. spgr%lat(ia)) cycle
633 ja = 3*(ia - 1)
634 CALL real_to_scaled(rf(1:3), coord(ja + 1:ja + 3), spgr%cell_ref)
635 rn(1:3) = 0.d0
636 DO ir = 1, nop
637 IF (.NOT. spgr%lop(ir)) cycle
638 ib = spgr%eqatom(ir, ia)
639 rot(1:3, 1:3) = spgr%rotations(1:3, 1:3, ir)
640 tr(1:3) = spgr%translations(1:3, ir)
641 jb = 3*(ib - 1)
642 CALL real_to_scaled(ri(1:3), coord(jb + 1:jb + 3), spgr%cell_ref)
643 ro(1) = real(rot(1, 1), dp)*ri(1) + real(rot(2, 1), dp)*ri(2) + real(rot(3, 1), dp)*ri(3) + tr(1)
644 ro(2) = real(rot(1, 2), dp)*ri(1) + real(rot(2, 2), dp)*ri(2) + real(rot(3, 2), dp)*ri(3) + tr(2)
645 ro(3) = real(rot(1, 3), dp)*ri(1) + real(rot(2, 3), dp)*ri(2) + real(rot(3, 3), dp)*ri(3) + tr(3)
646 ro(1) = ro(1) - real(nint(ro(1) - rf(1)), dp)
647 ro(2) = ro(2) - real(nint(ro(2) - rf(2)), dp)
648 ro(3) = ro(3) - real(nint(ro(3) - rf(3)), dp)
649 rn(1:3) = rn(1:3) + ro(1:3)
650 END DO
651 rn = rn/real(nops, dp)
652 CALL scaled_to_real(coord(ja + 1:ja + 3), rn(1:3), spgr%cell_ref)
653 END DO
654 !$OMP END PARALLEL DO
655
656 DEALLOCATE (cold)
657 CALL timestop(handle)
658
659 END SUBROUTINE spgr_apply_rotations_coord
660
661! **************************************************************************************************
662!> \brief routine applies the rotation matrices to the forces.
663!> \param spgr ...
664!> \param force ...
665!> \par History
666!> 01.2020 created [pcazade]
667!> \author Pierre-André Cazade (first version)
668! **************************************************************************************************
669 SUBROUTINE spgr_apply_rotations_force(spgr, force)
670
671 TYPE(spgr_type), INTENT(IN), POINTER :: spgr
672 REAL(kind=dp), DIMENSION(:), INTENT(INOUT) :: force
673
674 CHARACTER(LEN=*), PARAMETER :: routinen = 'spgr_apply_rotations_force'
675
676 INTEGER :: handle, ia, ib, ir, ja, jb, nop, nops, &
677 nparticle
678 REAL(kind=dp), ALLOCATABLE, DIMENSION(:) :: fold
679 REAL(kind=dp), DIMENSION(3) :: ri, rn, ro
680 REAL(kind=dp), DIMENSION(3, 3) :: rot
681
682 CALL timeset(routinen, handle)
683
684 ALLOCATE (fold(SIZE(force)))
685 fold(:) = force(:)
686
687 nop = spgr%n_operations
688 nparticle = spgr%nparticle
689 nops = spgr%n_reduced_operations
690
691 !$OMP PARALLEL DO PRIVATE (ia,ib,ja,jb,ir,ri,ro,rn,rot) SHARED (spgr,force,nparticle,nop,nops) DEFAULT(NONE)
692 DO ia = 1, nparticle
693 IF (.NOT. spgr%lat(ia)) cycle
694 ja = 3*(ia - 1)
695 rn(1:3) = 0.d0
696 DO ir = 1, nop
697 IF (.NOT. spgr%lop(ir)) cycle
698 ib = spgr%eqatom(ir, ia)
699 rot(1:3, 1:3) = spgr%rotations(1:3, 1:3, ir)
700 jb = 3*(ib - 1)
701 CALL real_to_scaled(ri(1:3), force(jb + 1:jb + 3), spgr%cell_ref)
702 ro(1) = real(rot(1, 1), dp)*ri(1) + real(rot(2, 1), dp)*ri(2) + real(rot(3, 1), dp)*ri(3)
703 ro(2) = real(rot(1, 2), dp)*ri(1) + real(rot(2, 2), dp)*ri(2) + real(rot(3, 2), dp)*ri(3)
704 ro(3) = real(rot(1, 3), dp)*ri(1) + real(rot(2, 3), dp)*ri(2) + real(rot(3, 3), dp)*ri(3)
705 rn(1:3) = rn(1:3) + ro(1:3)
706 END DO
707 rn = rn/real(nops, dp)
708 CALL scaled_to_real(force(ja + 1:ja + 3), rn(1:3), spgr%cell_ref)
709 END DO
710 !$OMP END PARALLEL DO
711
712 DEALLOCATE (fold)
713 CALL timestop(handle)
714
715 END SUBROUTINE spgr_apply_rotations_force
716
717! **************************************************************************************************
718!> \brief ...
719!> \param roti ...
720!> \param roto ...
721!> \param nop ...
722!> \param h1 ...
723!> \param h2 ...
724! **************************************************************************************************
725 SUBROUTINE spgr_change_basis(roti, roto, nop, h1, h2)
726
727 INTEGER, DIMENSION(:, :, :) :: roti
728 REAL(kind=dp), DIMENSION(:, :, :) :: roto
729 INTEGER :: nop
730 REAL(kind=dp), DIMENSION(3, 3) :: h1, h2
731
732 CHARACTER(LEN=*), PARAMETER :: routinen = 'spgr_change_basis'
733
734 INTEGER :: handle, ir
735 REAL(kind=dp), DIMENSION(3, 3) :: h1ih2, h2ih1, ih1, ih2, r, s
736
737 CALL timeset(routinen, handle)
738
739 ih1 = inv_3x3(h1)
740 ih2 = inv_3x3(h2)
741 h2ih1 = matmul(h2, ih1)
742 h1ih2 = matmul(h1, ih2)
743
744 DO ir = 1, nop
745 r(:, :) = roti(:, :, ir)
746 s = matmul(h2ih1, r)
747 r = matmul(s, h1ih2)
748 roto(:, :, ir) = r(:, :)
749 END DO
750
751 CALL timestop(handle)
752
753 END SUBROUTINE spgr_change_basis
754
755! **************************************************************************************************
756!> \brief routine applies the rotation matrices to the stress tensor.
757!> \param spgr ...
758!> \param cell ...
759!> \param stress ...
760!> \par History
761!> 01.2020 created [pcazade]
762!> \author Pierre-André Cazade (first version)
763! **************************************************************************************************
764 SUBROUTINE spgr_apply_rotations_stress(spgr, cell, stress)
765
766 TYPE(spgr_type), INTENT(IN), POINTER :: spgr
767 TYPE(cell_type), INTENT(IN), POINTER :: cell
768 REAL(kind=dp), DIMENSION(3, 3), INTENT(INOUT) :: stress
769
770 CHARACTER(LEN=*), PARAMETER :: routinen = 'spgr_apply_rotations_stress'
771
772 INTEGER :: handle, i, ir, j, k, l, nop
773 REAL(kind=dp), ALLOCATABLE, DIMENSION(:, :, :) :: roto
774 REAL(kind=dp), DIMENSION(3, 3) :: hmat1, hmat2, r, stin
775
776 CALL timeset(routinen, handle)
777
778 hmat1 = transpose(cell%hmat)
779
780 hmat2 = 0d0
781 hmat2(1, 1) = 1.d0
782 hmat2(2, 2) = 1.d0
783 hmat2(3, 3) = 1.d0
784
785 nop = spgr%n_operations_subset
786
787 ALLOCATE (roto(3, 3, nop))
788
789 CALL spgr_change_basis(spgr%rotations_subset, roto, spgr%n_operations_subset, hmat1, hmat2)
790
791 stin = stress
792 stress = 0.d0
793 DO ir = 1, nop
794 r(:, :) = roto(:, :, ir)
795 DO i = 1, 3
796 DO j = 1, 3
797 DO k = 1, 3
798 DO l = 1, 3
799 stress(i, j) = stress(i, j) + (r(k, i)*r(l, j)*stin(k, l))
800 END DO
801 END DO
802 END DO
803 END DO
804 END DO
805 stress = stress/real(nop, dp)
806
807 DEALLOCATE (roto)
808
809 CALL timestop(handle)
810
811 END SUBROUTINE spgr_apply_rotations_stress
812
813! **************************************************************************************************
814!> \brief routine prints Space Group Information.
815!> \param spgr ...
816!> \par History
817!> 01.2020 created [pcazade]
818!> \author Pierre-André Cazade (first version)
819! **************************************************************************************************
820 SUBROUTINE print_spgr(spgr)
821
822 TYPE(spgr_type), INTENT(IN), POINTER :: spgr
823
824 INTEGER :: i, j
825
826 IF (spgr%iunit > 0) THEN
827 WRITE (spgr%iunit, '(/,T2,A,A)') "----------------------------------------", &
828 "---------------------------------------"
829 WRITE (spgr%iunit, "(T2,A,T25,A,T77,A)") "----", "SPACE GROUP SYMMETRY INFORMATION", "----"
830 WRITE (spgr%iunit, '(T2,A,A)') "----------------------------------------", &
831 "---------------------------------------"
832 IF (spgr%symlib) THEN
833 WRITE (spgr%iunit, '(T2,A,T73,I8)') "SPGR| SPACE GROUP NUMBER:", &
834 spgr%space_group_number
835 WRITE (spgr%iunit, '(T2,A,T70,A11)') "SPGR| INTERNATIONAL SYMBOL:", &
836 trim(adjustr(spgr%international_symbol))
837 WRITE (spgr%iunit, '(T2,A,T75,A6)') "SPGR| POINT GROUP SYMBOL:", &
838 trim(adjustr(spgr%pointgroup_symbol))
839 WRITE (spgr%iunit, '(T2,A,T74,A7)') "SPGR| SCHOENFLIES SYMBOL:", &
840 trim(adjustr(spgr%schoenflies))
841 WRITE (spgr%iunit, '(T2,A,T73,I8)') "SPGR| NUMBER OF SYMMETRY OPERATIONS:", &
842 spgr%n_operations
843 WRITE (spgr%iunit, '(T2,A,T73,I8)') "SPGR| NUMBER OF UNIQUE ROTATIONS:", &
844 spgr%n_operations_subset
845 WRITE (spgr%iunit, '(T2,A,T73,I8)') "SPGR| NUMBER OF REDUCED SYMMETRY OPERATIONS:", &
846 spgr%n_reduced_operations
847 WRITE (spgr%iunit, '(T2,A,T65,I8,I8)') "SPGR| NUMBER OF PARTICLES AND SYMMETRIZED PARTICLES:", &
848 spgr%nparticle, spgr%nparticle_sym
849 WRITE (spgr%iunit, '(T2,A,T65,I8,I8)') "SPGR| NUMBER OF ATOMS AND SYMMETRIZED ATOMS:", &
850 spgr%n_atom, spgr%n_atom_sym
851 WRITE (spgr%iunit, '(T2,A,T65,I8,I8)') "SPGR| NUMBER OF CORES AND SYMMETRIZED CORES:", &
852 spgr%n_core, spgr%n_core_sym
853 WRITE (spgr%iunit, '(T2,A,T65,I8,I8)') "SPGR| NUMBER OF SHELLS AND SYMMETRIZED SHELLS:", &
854 spgr%n_shell, spgr%n_shell_sym
855 IF (spgr%print_atoms) THEN
856 WRITE (spgr%iunit, *) "SPGR| ACTIVE REDUCED SYMMETRY OPERATIONS:", spgr%lop
857 WRITE (spgr%iunit, '(/,T2,A,A)') "----------------------------------------", &
858 "---------------------------------------"
859 WRITE (spgr%iunit, '(T2,A,T34,A,T77,A)') "----", "EQUIVALENT ATOMS", "----"
860 WRITE (spgr%iunit, '(T2,A,A)') "----------------------------------------", &
861 "---------------------------------------"
862 DO i = 1, spgr%nparticle
863 DO j = 1, spgr%n_operations
864 WRITE (spgr%iunit, '(T2,A,T52,I8,I8,I8)') "SPGR| ATOM | SYMMETRY OPERATION | EQUIVALENT ATOM", &
865 i, j, spgr%eqatom(j, i)
866 END DO
867 END DO
868 WRITE (spgr%iunit, '(T2,A,A)') "----------------------------------------", &
869 "---------------------------------------"
870 DO i = 1, spgr%n_operations
871 WRITE (spgr%iunit, '(T2,A,T46,i4,T51,3I10,/,T51,3I10,/,T51,3I10)') &
872 "SPGR| SYMMETRY OPERATION #:", i, (spgr%rotations(j, :, i), j=1, 3)
873 WRITE (spgr%iunit, '(T51,3F10.5)') spgr%translations(:, i)
874 END DO
875 END IF
876 ELSE
877 WRITE (spgr%iunit, "(T2,A)") "SPGLIB for Crystal Symmetry Information determination is not availale"
878 END IF
879 END IF
880
881 END SUBROUTINE print_spgr
882
883! **************************************************************************************************
884!> \brief Variable precision output of the symmetrized stress tensor
885!>
886!> \param stress tensor ...
887!> \param spgr ...
888!> \par History
889!> 07.2020 adapted to spgr [pcazade]
890!> \author MK (26.08.2010).
891! **************************************************************************************************
892 SUBROUTINE spgr_write_stress_tensor(stress, spgr)
893
894 REAL(kind=dp), DIMENSION(3, 3), INTENT(IN) :: stress
895 TYPE(spgr_type), INTENT(IN), POINTER :: spgr
896
897 REAL(kind=dp), DIMENSION(3) :: eigval
898 REAL(kind=dp), DIMENSION(3, 3) :: eigvec, stress_tensor
899
900 stress_tensor(:, :) = stress(:, :)*pascal*1.0e-9_dp
901
902 IF (spgr%iunit > 0) THEN
903 WRITE (unit=spgr%iunit, fmt='(/,T2,A)') &
904 'SPGR STRESS| Symmetrized stress tensor [GPa]'
905 WRITE (unit=spgr%iunit, fmt='(T2,A,T19,3(19X,A1))') &
906 'SPGR STRESS|', 'x', 'y', 'z'
907 WRITE (unit=spgr%iunit, fmt='(T2,A,T26,3(1X,ES19.11))') &
908 'SPGR STRESS| x', stress_tensor(1, 1:3)
909 WRITE (unit=spgr%iunit, fmt='(T2,A,T26,3(1X,ES19.11))') &
910 'SPGR STRESS| y', stress_tensor(2, 1:3)
911 WRITE (unit=spgr%iunit, fmt='(T2,A,T26,3(1X,ES19.11))') &
912 'SPGR STRESS| z', stress_tensor(3, 1:3)
913 WRITE (unit=spgr%iunit, fmt='(T2,A,T66,ES20.11)') &
914 'SPGR STRESS| 1/3 Trace', (stress_tensor(1, 1) + &
915 stress_tensor(2, 2) + &
916 stress_tensor(3, 3))/3.0_dp
917 WRITE (unit=spgr%iunit, fmt='(T2,A,T66,ES20.11)') &
918 'SPGR STRESS| Determinant', det_3x3(stress_tensor(1:3, 1), &
919 stress_tensor(1:3, 2), &
920 stress_tensor(1:3, 3))
921 eigval(:) = 0.0_dp
922 eigvec(:, :) = 0.0_dp
923 CALL jacobi(stress_tensor, eigval, eigvec)
924 WRITE (unit=spgr%iunit, fmt='(/,T2,A)') &
925 'SPGR STRESS| Eigenvectors and eigenvalues of the symmetrized stress tensor [GPa]'
926 WRITE (unit=spgr%iunit, fmt='(T2,A,T19,3(1X,I19))') &
927 'SPGR STRESS|', 1, 2, 3
928 WRITE (unit=spgr%iunit, fmt='(T2,A,T26,3(1X,ES19.11))') &
929 'SPGR STRESS| Eigenvalues', eigval(1:3)
930 WRITE (unit=spgr%iunit, fmt='(T2,A,T26,3(1X,F19.12))') &
931 'SPGR STRESS| x', eigvec(1, 1:3)
932 WRITE (unit=spgr%iunit, fmt='(T2,A,T26,3(1X,F19.12))') &
933 'SPGR STRESS| y', eigvec(2, 1:3)
934 WRITE (unit=spgr%iunit, fmt='(T2,A,T26,3(1X,F19.12))') &
935 'SPGR STRESS| z', eigvec(3, 1:3)
936 END IF
937
938 END SUBROUTINE spgr_write_stress_tensor
939
940END MODULE space_groups
Define the atomic kind types and their sub types.
subroutine, public get_atomic_kind(atomic_kind, fist_potential, element_symbol, name, mass, kind_number, natom, atom_list, rcov, rvdw, z, qeff, apol, cpol, mm_radius, shell, shell_active, damping)
Get attributes of an atomic kind.
collects all references to literature in CP2K as new algorithms / method are included from literature...
integer, save, public togo2018
Handles all functions related to the CELL.
subroutine, public init_cell(cell, hmat, periodic)
Initialise/readjust a simulation cell after hmat has been changed.
subroutine, public cell_create(cell, hmat, periodic, tag)
allocates and initializes a cell
Handles all functions related to the CELL.
Definition cell_types.F:15
subroutine, public scaled_to_real(r, s, cell)
Transform scaled cell coordinates real coordinates. r=h*s.
Definition cell_types.F:565
subroutine, public real_to_scaled(s, r, cell)
Transform real to scaled cell coordinates. s=h_inv*r.
Definition cell_types.F:535
subroutine, public cell_copy(cell_in, cell_out, tag)
Copy cell variable.
Definition cell_types.F:137
types that represent a subsys, i.e. a part of the system
subroutine, public cp_subsys_get(subsys, ref_count, atomic_kinds, atomic_kind_set, particles, particle_set, local_particles, molecules, molecule_set, molecule_kinds, molecule_kind_set, local_molecules, para_env, colvar_p, shell_particles, core_particles, gci, multipoles, natom, nparticle, ncore, nshell, nkind, atprop, virial, results, cell, cell_ref, use_ref_cell)
returns information about various attributes of the given subsys
contains a functional that calculates the energy and its derivatives for the geometry optimizer
collects all constants needed in input so that they can be used without circular dependencies
integer, parameter, public default_cell_method_id
integer, parameter, public default_minimization_method_id
integer, parameter, public default_ts_method_id
objects that represent the structure of input sections and the data contained in an input section
subroutine, public section_vals_val_get(section_vals, keyword_name, i_rep_section, i_rep_val, n_rep_val, val, l_val, i_val, r_val, c_val, l_vals, i_vals, r_vals, c_vals, explicit)
returns the requested value
Defines the basic variable types.
Definition kinds.F:23
integer, parameter, public dp
Definition kinds.F:34
Collection of simple mathematical functions and subroutines.
Definition mathlib.F:15
subroutine, public jacobi(a, d, v)
Jacobi matrix diagonalization. The eigenvalues are returned in vector d and the eigenvectors are retu...
Definition mathlib.F:1475
pure real(kind=dp) function, dimension(3, 3), public inv_3x3(a)
Returns the inverse of the 3 x 3 matrix a.
Definition mathlib.F:523
represent a simple array based list of the given type
Definition of physical constants:
Definition physcon.F:68
real(kind=dp), parameter, public pascal
Definition physcon.F:174
Space Group Symmetry Type Module (version 1.0, Ferbruary 12, 2021)
subroutine, public cleanup_spgr_type(spgr)
Cleanup all buffers the SPGR type.
Space Group Symmetry Module (version 1.0, January 16, 2020)
subroutine, public spgr_create(scoor, types, cell, gopt_env, eps_symmetry, pol, ranges, nparticle, n_atom, n_core, n_shell, iunit, print_atoms)
routine creates the space group structure
subroutine, public spgr_find_equivalent_atoms(spgr, scoord)
routine indentifies the equivalent atoms for each rotation matrix.
subroutine, public print_spgr(spgr)
routine prints Space Group Information.
subroutine, public spgr_apply_rotations_stress(spgr, cell, stress)
routine applies the rotation matrices to the stress tensor.
subroutine, public spgr_apply_rotations_coord(spgr, coord)
routine applies the rotation matrices to the coordinates.
subroutine, public identify_space_group(subsys, geo_section, gopt_env, iunit)
routine indentifies the space group and finds rotation matrices.
subroutine, public spgr_apply_rotations_force(spgr, force)
routine applies the rotation matrices to the forces.
subroutine, public spgr_write_stress_tensor(stress, spgr)
Variable precision output of the symmetrized stress tensor.
Interface for SPGLIB symmetry routines.
Definition spglib_f08.F:119
integer function, public spg_get_international(symbol, lattice, position, types, num_atom, symprec)
...
Definition spglib_f08.F:202
integer function, public spg_get_multiplicity(lattice, position, types, num_atom, symprec)
...
Definition spglib_f08.F:177
integer function, public spg_get_pointgroup(symbol, trans_mat, rotations, num_rotations)
...
Definition spglib_f08.F:256
integer function, public spg_get_symmetry(rotation, translation, max_size, lattice, position, types, num_atom, symprec)
...
Definition spglib_f08.F:147
integer function, public spg_get_schoenflies(symbol, lattice, position, types, num_atom, symprec)
...
Definition spglib_f08.F:230
Utilities for string manipulations.
integer function, public strlcpy_c2f(fstring, cstring)
Copy the content of a \0-terminated C-string to a finite-length Fortran string.
Type defining parameters related to the simulation cell.
Definition cell_types.F:60
represents a system: atoms, molecules, their pos,vel,...
calculates the potential energy of a system, and its derivatives