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 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 : ! **************************************************************************************************
14 : MODULE space_groups
15 : USE atomic_kind_types, ONLY: get_atomic_kind
16 : USE bibliography, ONLY: Togo2018,&
17 : cite_reference
18 : USE cell_methods, ONLY: cell_create,&
19 : init_cell,&
20 : set_cell_param
21 : USE cell_types, ONLY: cell_copy,&
22 : cell_type,&
23 : real_to_scaled,&
24 : scaled_to_real
25 : USE cp_subsys_types, ONLY: cp_subsys_get,&
26 : cp_subsys_type
27 : USE gopt_f_types, ONLY: gopt_f_type
28 : USE input_constants, ONLY: default_cell_method_id,&
29 : default_minimization_method_id,&
30 : default_ts_method_id
31 : USE input_section_types, ONLY: section_vals_type,&
32 : section_vals_val_get
33 : USE kinds, ONLY: dp
34 : USE mathlib, ONLY: det_3x3,&
35 : inv_3x3,&
36 : jacobi
37 : USE particle_list_types, ONLY: particle_list_type
38 : USE physcon, ONLY: pascal
39 : USE space_groups_types, ONLY: cleanup_spgr_type,&
40 : spgr_type
41 : USE spglib_f08, ONLY: spg_get_international,&
42 : spg_get_multiplicity,&
43 : spg_get_pointgroup,&
44 : spg_get_schoenflies,&
45 : spg_get_symmetry
46 : USE string_utilities, ONLY: strlcpy_c2f
47 : #include "../base/base_uses.f90"
48 :
49 : IMPLICIT NONE
50 :
51 : PRIVATE
52 :
53 : CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'space_groups'
54 :
55 : PUBLIC :: spgr_create, identify_space_group, spgr_find_equivalent_atoms
56 : PUBLIC :: spgr_apply_rotations_coord, spgr_apply_rotations_force, print_spgr
57 : PUBLIC :: spgr_apply_rotations_stress, spgr_project_cell_metric, spgr_write_stress_tensor
58 :
59 : CONTAINS
60 :
61 : ! **************************************************************************************************
62 : !> \brief routine creates the space group structure
63 : !> \param scoor ...
64 : !> \param types ...
65 : !> \param cell ...
66 : !> \param gopt_env ...
67 : !> \param eps_symmetry ...
68 : !> \param pol ...
69 : !> \param ranges ...
70 : !> \param nparticle ...
71 : !> \param n_atom ...
72 : !> \param n_core ...
73 : !> \param n_shell ...
74 : !> \param iunit ...
75 : !> \param print_atoms ...
76 : !> \par History
77 : !> 01.2020 created [pcazade]
78 : !> \author Pierre-André Cazade (first version)
79 : ! **************************************************************************************************
80 24 : SUBROUTINE spgr_create(scoor, types, cell, gopt_env, eps_symmetry, pol, ranges, &
81 : nparticle, n_atom, n_core, n_shell, iunit, print_atoms)
82 :
83 : REAL(KIND=dp), DIMENSION(:, :), INTENT(IN) :: scoor
84 : INTEGER, DIMENSION(:), INTENT(IN) :: types
85 : TYPE(cell_type), INTENT(IN), POINTER :: cell
86 : TYPE(gopt_f_type), INTENT(IN), POINTER :: gopt_env
87 : REAL(KIND=dp), INTENT(IN), OPTIONAL :: eps_symmetry
88 : REAL(KIND=dp), DIMENSION(3), INTENT(IN), OPTIONAL :: pol
89 : INTEGER, DIMENSION(:, :), INTENT(IN), OPTIONAL :: ranges
90 : INTEGER, INTENT(IN), OPTIONAL :: nparticle, n_atom, n_core, n_shell
91 : INTEGER, INTENT(IN) :: iunit
92 : LOGICAL, INTENT(IN) :: print_atoms
93 :
94 : CHARACTER(LEN=*), PARAMETER :: routineN = 'spgr_create'
95 : #ifdef __SPGLIB
96 : CHARACTER(LEN=1000) :: buffer
97 : INTEGER :: ierr, nchars, nop, tra_mat(3, 3)
98 : #endif
99 : INTEGER :: handle, i, j, n_sr_rep
100 24 : INTEGER, ALLOCATABLE, DIMENSION(:) :: tmp_types
101 : LOGICAL :: spglib
102 24 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :) :: tmp_coor
103 : TYPE(spgr_type), POINTER :: spgr
104 :
105 24 : CALL timeset(routineN, handle)
106 :
107 24 : spgr => gopt_env%spgr
108 24 : CPASSERT(ASSOCIATED(spgr))
109 :
110 24 : CALL cleanup_spgr_type(spgr)
111 :
112 : !..total number of particles (atoms plus shells)
113 24 : IF (PRESENT(nparticle)) THEN
114 24 : CPASSERT(nparticle == SIZE(scoor, 2))
115 24 : spgr%nparticle = nparticle
116 : ELSE
117 0 : spgr%nparticle = SIZE(scoor, 2)
118 : END IF
119 :
120 24 : IF (PRESENT(n_atom)) THEN
121 24 : spgr%n_atom = n_atom
122 0 : ELSE IF (PRESENT(n_core)) THEN
123 0 : spgr%n_atom = spgr%nparticle - n_core
124 0 : ELSE IF (PRESENT(n_shell)) THEN
125 0 : spgr%n_atom = spgr%nparticle - n_shell
126 : ELSE
127 0 : spgr%n_atom = spgr%nparticle
128 : END IF
129 :
130 24 : IF (PRESENT(n_core)) THEN
131 24 : spgr%n_core = n_core
132 0 : ELSE IF (PRESENT(n_shell)) THEN
133 0 : spgr%n_core = n_shell
134 : END IF
135 :
136 24 : IF (PRESENT(n_shell)) THEN
137 24 : spgr%n_shell = n_shell
138 0 : ELSE IF (PRESENT(n_core)) THEN
139 0 : spgr%n_shell = n_core
140 : END IF
141 :
142 24 : IF (.NOT. (spgr%nparticle == (spgr%n_atom + spgr%n_shell))) THEN
143 0 : CPABORT("spgr_create: nparticle not equal to natom + nshell.")
144 : END IF
145 :
146 24 : spgr%nparticle_sym = spgr%nparticle
147 24 : spgr%n_atom_sym = spgr%n_atom
148 24 : spgr%n_core_sym = spgr%n_core
149 24 : spgr%n_shell_sym = spgr%n_shell
150 :
151 24 : spgr%iunit = iunit
152 24 : spgr%print_atoms = print_atoms
153 :
154 : ! accuracy for symmetry
155 24 : IF (PRESENT(eps_symmetry)) THEN
156 24 : spgr%eps_symmetry = eps_symmetry
157 : END IF
158 :
159 : ! vector to test reduced symmetry
160 24 : IF (PRESENT(pol)) THEN
161 24 : spgr%pol(1) = pol(1)
162 24 : spgr%pol(2) = pol(2)
163 24 : spgr%pol(3) = pol(3)
164 : END IF
165 :
166 72 : ALLOCATE (spgr%lat(spgr%nparticle))
167 268 : spgr%lat = .TRUE.
168 :
169 24 : IF (PRESENT(ranges)) THEN
170 0 : n_sr_rep = SIZE(ranges, 2)
171 0 : DO i = 1, n_sr_rep
172 0 : DO j = ranges(1, i), ranges(2, i)
173 0 : spgr%lat(j) = .FALSE.
174 0 : spgr%nparticle_sym = spgr%nparticle_sym - 1
175 0 : IF (j <= spgr%n_atom) THEN
176 0 : spgr%n_atom_sym = spgr%n_atom_sym - 1
177 0 : ELSE IF (j > spgr%n_atom .AND. j <= spgr%nparticle) THEN
178 0 : spgr%n_core_sym = spgr%n_core_sym - 1
179 0 : spgr%n_shell_sym = spgr%n_shell_sym - 1
180 : ELSE
181 0 : CPABORT("Symmetry exclusion range larger than actual number of particles.")
182 : END IF
183 : END DO
184 : END DO
185 : END IF
186 :
187 120 : ALLOCATE (tmp_coor(3, spgr%n_atom_sym), tmp_types(spgr%n_atom_sym))
188 :
189 24 : j = 0
190 196 : DO i = 1, spgr%n_atom
191 196 : IF (spgr%lat(i)) THEN
192 172 : j = j + 1
193 688 : tmp_coor(:, j) = scoor(:, i)
194 172 : tmp_types(j) = types(i)
195 : END IF
196 : END DO
197 :
198 : !..set cell values
199 24 : NULLIFY (spgr%cell_ref)
200 24 : CALL cell_create(spgr%cell_ref)
201 24 : CALL cell_copy(cell, spgr%cell_ref, tag="CELL_OPT_REF")
202 28 : SELECT CASE (gopt_env%type_id)
203 : CASE (default_minimization_method_id, default_ts_method_id)
204 4 : CALL init_cell(spgr%cell_ref, hmat=cell%hmat)
205 : CASE (default_cell_method_id)
206 20 : CALL init_cell(spgr%cell_ref, hmat=gopt_env%h_ref)
207 : CASE DEFAULT
208 24 : CPABORT("SPACE_GROUP_SYMMETRY is not compatible with md.")
209 : END SELECT
210 :
211 : ! atom types
212 72 : ALLOCATE (spgr%atype(spgr%nparticle))
213 268 : spgr%atype(1:spgr%nparticle) = types(1:spgr%nparticle)
214 :
215 24 : spgr%n_operations = 0
216 :
217 : #ifdef __SPGLIB
218 24 : spglib = .TRUE.
219 24 : CALL cite_reference(Togo2018)
220 : spgr%space_group_number = spg_get_international(spgr%international_symbol, TRANSPOSE(cell%hmat), tmp_coor, tmp_types, &
221 24 : spgr%n_atom_sym, eps_symmetry)
222 24 : buffer = ''
223 24 : nchars = strlcpy_c2f(buffer, spgr%international_symbol)
224 24 : spgr%international_symbol = buffer(1:nchars)
225 24 : IF (spgr%space_group_number == 0) THEN
226 0 : CPABORT("Symmetry Library SPGLIB failed, most likely due a problem with the coordinates.")
227 0 : spglib = .FALSE.
228 : ELSE
229 : nop = spg_get_multiplicity(TRANSPOSE(cell%hmat), tmp_coor, tmp_types, &
230 24 : spgr%n_atom_sym, eps_symmetry)
231 120 : ALLOCATE (spgr%rotations(3, 3, nop), spgr%translations(3, nop))
232 96 : ALLOCATE (spgr%eqatom(nop, spgr%nparticle))
233 72 : ALLOCATE (spgr%lop(nop))
234 24 : spgr%n_operations = nop
235 1816 : spgr%lop = .TRUE.
236 : ierr = spg_get_symmetry(spgr%rotations, spgr%translations, nop, TRANSPOSE(cell%hmat), &
237 24 : tmp_coor, tmp_types, spgr%n_atom_sym, eps_symmetry)
238 : ! Schoenflies Symbol
239 : ierr = spg_get_schoenflies(spgr%schoenflies, TRANSPOSE(cell%hmat), tmp_coor, tmp_types, &
240 24 : spgr%n_atom_sym, eps_symmetry)
241 24 : buffer = ''
242 24 : nchars = strlcpy_c2f(buffer, spgr%schoenflies)
243 24 : spgr%schoenflies = buffer(1:nchars)
244 :
245 : ! Point Group
246 24 : tra_mat = 0
247 : ierr = spg_get_pointgroup(spgr%pointgroup_symbol, tra_mat, &
248 24 : spgr%rotations, spgr%n_operations)
249 24 : buffer = ''
250 24 : nchars = strlcpy_c2f(buffer, spgr%pointgroup_symbol)
251 24 : spgr%pointgroup_symbol = buffer(1:nchars)
252 : END IF
253 : #else
254 : CPABORT("Symmetry library SPGLIB not available")
255 : spglib = .FALSE.
256 : #endif
257 24 : spgr%symlib = spglib
258 :
259 24 : DEALLOCATE (tmp_coor, tmp_types)
260 :
261 24 : CALL timestop(handle)
262 :
263 24 : END SUBROUTINE spgr_create
264 :
265 : ! **************************************************************************************************
266 : !> \brief routine indentifies the space group and finds rotation matrices.
267 : !> \param subsys ...
268 : !> \param geo_section ...
269 : !> \param gopt_env ...
270 : !> \param iunit ...
271 : !> \par History
272 : !> 01.2020 created [pcazade]
273 : !> \author Pierre-André Cazade (first version)
274 : !> \note rotation matrices innclude translations and translation symmetry:
275 : !> it works with supercells as well.
276 : ! **************************************************************************************************
277 24 : SUBROUTINE identify_space_group(subsys, geo_section, gopt_env, iunit)
278 :
279 : TYPE(cp_subsys_type), INTENT(IN), POINTER :: subsys
280 : TYPE(section_vals_type), INTENT(IN), POINTER :: geo_section
281 : TYPE(gopt_f_type), INTENT(IN), POINTER :: gopt_env
282 : INTEGER, INTENT(IN) :: iunit
283 :
284 : CHARACTER(LEN=*), PARAMETER :: routineN = 'identify_space_group'
285 :
286 : INTEGER :: handle, i, k, n_atom, n_core, n_shell, &
287 : n_sr_rep, nparticle, shell_index
288 24 : INTEGER, ALLOCATABLE, DIMENSION(:) :: atype
289 24 : INTEGER, ALLOCATABLE, DIMENSION(:, :) :: ranges
290 24 : INTEGER, DIMENSION(:), POINTER :: tmp
291 : LOGICAL :: print_atoms
292 : REAL(KIND=dp) :: eps_symmetry
293 24 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :) :: scoord
294 24 : REAL(KIND=dp), DIMENSION(:), POINTER :: pol
295 : TYPE(cell_type), POINTER :: cell
296 : TYPE(particle_list_type), POINTER :: core_particles, particles, &
297 : shell_particles
298 : TYPE(spgr_type), POINTER :: spgr
299 :
300 24 : CALL timeset(routineN, handle)
301 :
302 : n_sr_rep = 0
303 : nparticle = 0
304 : n_atom = 0
305 24 : n_core = 0
306 24 : n_shell = 0
307 :
308 24 : NULLIFY (particles)
309 24 : NULLIFY (core_particles)
310 24 : NULLIFY (shell_particles)
311 :
312 : NULLIFY (cell)
313 24 : cell => subsys%cell
314 24 : CPASSERT(ASSOCIATED(cell))
315 :
316 24 : CALL cp_subsys_get(subsys, particles=particles, shell_particles=shell_particles, core_particles=core_particles)
317 :
318 24 : CPASSERT(ASSOCIATED(particles))
319 24 : n_atom = particles%n_els
320 : ! Check if we have other kinds of particles in this subsystem
321 24 : IF (ASSOCIATED(shell_particles)) THEN
322 6 : n_shell = shell_particles%n_els
323 6 : CPASSERT(ASSOCIATED(core_particles))
324 6 : n_core = subsys%core_particles%n_els
325 : ! The same number of shell and core particles is assumed
326 6 : CPASSERT(n_core == n_shell)
327 18 : ELSE IF (ASSOCIATED(core_particles)) THEN
328 : ! This case should not occur at the moment
329 0 : CPABORT("Core particles should not be defined without corresponding shell particles.")
330 : ELSE
331 : n_core = 0
332 : n_shell = 0
333 : END IF
334 :
335 24 : nparticle = n_atom + n_shell
336 120 : ALLOCATE (scoord(3, nparticle), atype(nparticle))
337 196 : DO i = 1, n_atom
338 172 : shell_index = particles%els(i)%shell_index
339 196 : IF (shell_index == 0) THEN
340 100 : CALL real_to_scaled(scoord(1:3, i), particles%els(i)%r(1:3), cell)
341 100 : CALL get_atomic_kind(atomic_kind=particles%els(i)%atomic_kind, kind_number=atype(i))
342 : ELSE
343 72 : CALL real_to_scaled(scoord(1:3, i), core_particles%els(shell_index)%r(1:3), cell)
344 72 : CALL get_atomic_kind(atomic_kind=core_particles%els(shell_index)%atomic_kind, kind_number=atype(i))
345 72 : k = n_atom + shell_index
346 72 : CALL real_to_scaled(scoord(1:3, k), shell_particles%els(shell_index)%r(1:3), cell)
347 72 : CALL get_atomic_kind(atomic_kind=shell_particles%els(shell_index)%atomic_kind, kind_number=atype(k))
348 : END IF
349 : END DO
350 :
351 24 : CALL section_vals_val_get(geo_section, "SPGR_PRINT_ATOMS", l_val=print_atoms)
352 24 : CALL section_vals_val_get(geo_section, "EPS_SYMMETRY", r_val=eps_symmetry)
353 24 : CALL section_vals_val_get(geo_section, "SYMM_REDUCTION", r_vals=pol)
354 24 : CALL section_vals_val_get(geo_section, "SYMM_EXCLUDE_RANGE", n_rep_val=n_sr_rep)
355 24 : IF (n_sr_rep > 0) THEN
356 0 : ALLOCATE (ranges(2, n_sr_rep))
357 0 : DO i = 1, n_sr_rep
358 0 : CALL section_vals_val_get(geo_section, "SYMM_EXCLUDE_RANGE", i_rep_val=i, i_vals=tmp)
359 0 : ranges(:, i) = tmp(:)
360 : END DO
361 : CALL spgr_create(scoord, atype, cell, gopt_env, eps_symmetry=eps_symmetry, pol=pol(1:3), &
362 : ranges=ranges, nparticle=nparticle, n_atom=n_atom, &
363 0 : n_core=n_core, n_shell=n_shell, iunit=iunit, print_atoms=print_atoms)
364 0 : DEALLOCATE (ranges)
365 : ELSE
366 : CALL spgr_create(scoord, atype, cell, gopt_env, eps_symmetry=eps_symmetry, pol=pol(1:3), &
367 : nparticle=nparticle, n_atom=n_atom, &
368 24 : n_core=n_core, n_shell=n_shell, iunit=iunit, print_atoms=print_atoms)
369 : END IF
370 :
371 : NULLIFY (spgr)
372 24 : spgr => gopt_env%spgr
373 :
374 24 : CALL spgr_find_equivalent_atoms(spgr, scoord)
375 24 : CALL spgr_reduce_symm(spgr)
376 24 : CALL spgr_rotations_subset(spgr)
377 :
378 24 : DEALLOCATE (scoord, atype)
379 :
380 24 : CALL timestop(handle)
381 :
382 96 : END SUBROUTINE identify_space_group
383 :
384 : ! **************************************************************************************************
385 : !> \brief routine indentifies the equivalent atoms for each rotation matrix.
386 : !> \param spgr ...
387 : !> \param scoord ...
388 : !> \par History
389 : !> 01.2020 created [pcazade]
390 : !> \author Pierre-André Cazade (first version)
391 : ! **************************************************************************************************
392 24 : SUBROUTINE spgr_find_equivalent_atoms(spgr, scoord)
393 :
394 : TYPE(spgr_type), INTENT(INOUT), POINTER :: spgr
395 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :), &
396 : INTENT(IN) :: scoord
397 :
398 : CHARACTER(LEN=*), PARAMETER :: routineN = 'spgr_find_equivalent_atoms'
399 :
400 : INTEGER :: handle, i, ia, ib, ir, j, natom, nop, &
401 : nshell
402 : REAL(KIND=dp) :: diff
403 : REAL(KIND=dp), DIMENSION(3) :: rb, ri, ro, tr
404 : REAL(KIND=dp), DIMENSION(3, 3) :: rot
405 :
406 24 : CALL timeset(routineN, handle)
407 :
408 24 : nop = spgr%n_operations
409 24 : natom = spgr%n_atom
410 24 : nshell = spgr%n_shell
411 :
412 24 : IF (.NOT. (spgr%nparticle == (natom + nshell))) THEN
413 0 : CPABORT("spgr_find_equivalent_atoms: nparticle not equal to natom + nshell.")
414 : END IF
415 :
416 268 : DO ia = 1, spgr%nparticle
417 10724 : spgr%eqatom(:, ia) = ia
418 : END DO
419 :
420 24 : !$OMP PARALLEL DO PRIVATE (ia,ib,ir,ri,rb,ro,rot,tr,diff) SHARED (spgr,scoord,natom,nop) DEFAULT(NONE)
421 : DO ia = 1, natom
422 : IF (.NOT. spgr%lat(ia)) CYCLE
423 : ri(1:3) = scoord(1:3, ia)
424 : DO ir = 1, nop
425 : rot(1:3, 1:3) = spgr%rotations(1:3, 1:3, ir)
426 : tr(1:3) = spgr%translations(1:3, ir)
427 : DO ib = 1, natom
428 : IF (.NOT. spgr%lat(ib)) CYCLE
429 : rb(1:3) = scoord(1:3, ib)
430 : 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)
431 : 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)
432 : 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)
433 : ro(1) = ro(1) - REAL(NINT(ro(1) - ri(1)), dp)
434 : ro(2) = ro(2) - REAL(NINT(ro(2) - ri(2)), dp)
435 : ro(3) = ro(3) - REAL(NINT(ro(3) - ri(3)), dp)
436 : diff = NORM2(ri(:) - ro(:))
437 : IF ((diff < spgr%eps_symmetry) .AND. (spgr%atype(ia) == spgr%atype(ib))) THEN
438 : spgr%eqatom(ir, ia) = ib
439 : EXIT
440 : END IF
441 : END DO
442 : END DO
443 : END DO
444 : !$OMP END PARALLEL DO
445 :
446 24 : !$OMP PARALLEL DO PRIVATE (i,j,ia,ib,ir,ri,rb,ro,rot,tr,diff) SHARED (spgr,scoord,natom,nshell,nop) DEFAULT(NONE)
447 : DO i = 1, nshell
448 : ia = natom + i
449 : IF (.NOT. spgr%lat(ia)) CYCLE
450 : ri(1:3) = scoord(1:3, ia)
451 : DO ir = 1, nop
452 : rot(1:3, 1:3) = spgr%rotations(1:3, 1:3, ir)
453 : tr(1:3) = spgr%translations(1:3, ir)
454 : DO j = 1, nshell
455 : ib = natom + j
456 : IF (.NOT. spgr%lat(ib)) CYCLE
457 : rb(1:3) = scoord(1:3, ib)
458 : 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)
459 : 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)
460 : 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)
461 : ro(1) = ro(1) - REAL(NINT(ro(1) - ri(1)), dp)
462 : ro(2) = ro(2) - REAL(NINT(ro(2) - ri(2)), dp)
463 : ro(3) = ro(3) - REAL(NINT(ro(3) - ri(3)), dp)
464 : diff = NORM2(ri(:) - ro(:))
465 : IF ((diff < spgr%eps_symmetry) .AND. (spgr%atype(ia) == spgr%atype(ib))) THEN
466 : spgr%eqatom(ir, ia) = ib
467 : EXIT
468 : END IF
469 : END DO
470 : END DO
471 : END DO
472 : !$OMP END PARALLEL DO
473 :
474 24 : CALL timestop(handle)
475 :
476 24 : END SUBROUTINE spgr_find_equivalent_atoms
477 :
478 : ! **************************************************************************************************
479 : !> \brief routine looks for operations compatible with efield
480 : !> \param spgr ...
481 : !> \par History
482 : !> 01.2020 created [pcazade]
483 : !> \author Pierre-André Cazade (first version)
484 : ! **************************************************************************************************
485 24 : SUBROUTINE spgr_reduce_symm(spgr)
486 :
487 : TYPE(spgr_type), INTENT(INOUT), POINTER :: spgr
488 :
489 : CHARACTER(LEN=*), PARAMETER :: routineN = 'spgr_reduce_symm'
490 :
491 : INTEGER :: handle, ia, ib, ir, ja, jb, nop, nops, &
492 : nparticle
493 24 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: x, xold
494 : REAL(KIND=dp), DIMENSION(3) :: ri, ro
495 : REAL(KIND=dp), DIMENSION(3, 3) :: rot
496 :
497 24 : CALL timeset(routineN, handle)
498 :
499 24 : nop = spgr%n_operations
500 24 : nparticle = spgr%nparticle
501 96 : ALLOCATE (x(3*nparticle), xold(3*nparticle))
502 24 : x = 0.0_dp
503 268 : DO ia = 1, nparticle
504 244 : ja = 3*(ia - 1)
505 244 : x(ja + 1) = x(ja + 1) + spgr%pol(1)
506 244 : x(ja + 2) = x(ja + 2) + spgr%pol(2)
507 268 : x(ja + 3) = x(ja + 3) + spgr%pol(3)
508 : END DO
509 756 : xold(:) = x(:)
510 :
511 : nops = 0
512 1816 : DO ir = 1, nop
513 1792 : x = 0.d0
514 1792 : spgr%lop(ir) = .TRUE.
515 23296 : rot(1:3, 1:3) = spgr%rotations(1:3, 1:3, ir)
516 12248 : DO ia = 1, nparticle
517 10456 : IF (.NOT. spgr%lat(ia)) CYCLE
518 10456 : ja = 3*(ia - 1)
519 41824 : ri(1:3) = xold(ja + 1:ja + 3)
520 10456 : ro(1) = REAL(rot(1, 1), dp)*ri(1) + REAL(rot(2, 1), dp)*ri(2) + REAL(rot(3, 1), dp)*ri(3)
521 10456 : ro(2) = REAL(rot(1, 2), dp)*ri(1) + REAL(rot(2, 2), dp)*ri(2) + REAL(rot(3, 2), dp)*ri(3)
522 10456 : ro(3) = REAL(rot(1, 3), dp)*ri(1) + REAL(rot(2, 3), dp)*ri(2) + REAL(rot(3, 3), dp)*ri(3)
523 43616 : x(ja + 1:ja + 3) = ro(1:3)
524 : END DO
525 12248 : DO ia = 1, nparticle
526 10456 : IF (.NOT. spgr%lat(ia)) CYCLE
527 10456 : ib = spgr%eqatom(ir, ia)
528 10456 : ja = 3*(ia - 1)
529 10456 : jb = 3*(ib - 1)
530 41824 : ro = x(jb + 1:jb + 3) - xold(ja + 1:ja + 3)
531 : spgr%lop(ir) = (spgr%lop(ir) .AND. (ABS(ro(1)) < spgr%eps_symmetry) &
532 : .AND. (ABS(ro(2)) < spgr%eps_symmetry) &
533 12248 : .AND. (ABS(ro(3)) < spgr%eps_symmetry))
534 : END DO
535 1816 : IF (spgr%lop(ir)) nops = nops + 1
536 : END DO
537 :
538 24 : spgr%n_reduced_operations = nops
539 :
540 24 : DEALLOCATE (x, xold)
541 24 : CALL timestop(handle)
542 :
543 24 : END SUBROUTINE spgr_reduce_symm
544 :
545 : ! **************************************************************************************************
546 : !> \brief routine looks for unique rotations
547 : !> \param spgr ...
548 : !> \par History
549 : !> 01.2020 created [pcazade]
550 : !> \author Pierre-André Cazade (first version)
551 : ! **************************************************************************************************
552 :
553 24 : SUBROUTINE spgr_rotations_subset(spgr)
554 :
555 : TYPE(spgr_type), INTENT(INOUT), POINTER :: spgr
556 :
557 : CHARACTER(LEN=*), PARAMETER :: routineN = 'spgr_rotations_subset'
558 :
559 : INTEGER :: handle, i, j
560 : INTEGER, DIMENSION(3, 3) :: d
561 24 : LOGICAL, ALLOCATABLE, DIMENSION(:) :: mask
562 :
563 24 : CALL timeset(routineN, handle)
564 :
565 72 : ALLOCATE (mask(spgr%n_operations))
566 1816 : mask = .TRUE.
567 :
568 1816 : DO i = 1, spgr%n_operations
569 1816 : IF (.NOT. spgr%lop(i)) mask(i) = .FALSE.
570 : END DO
571 :
572 1792 : DO i = 1, spgr%n_operations - 1
573 1768 : IF (.NOT. mask(i)) CYCLE
574 69632 : DO j = i + 1, spgr%n_operations
575 68984 : IF (.NOT. mask(j)) CYCLE
576 544856 : d(:, :) = spgr%rotations(:, :, j) - spgr%rotations(:, :, i)
577 546624 : IF (SUM(ABS(d)) == 0) mask(j) = .FALSE.
578 : END DO
579 : END DO
580 :
581 24 : spgr%n_operations_subset = 0
582 1816 : DO i = 1, spgr%n_operations
583 1816 : IF (mask(i)) spgr%n_operations_subset = spgr%n_operations_subset + 1
584 : END DO
585 :
586 72 : ALLOCATE (spgr%rotations_subset(3, 3, spgr%n_operations_subset))
587 :
588 24 : j = 0
589 1816 : DO i = 1, spgr%n_operations
590 1816 : IF (mask(i)) THEN
591 640 : j = j + 1
592 8320 : spgr%rotations_subset(:, :, j) = spgr%rotations(:, :, i)
593 : END IF
594 : END DO
595 :
596 24 : DEALLOCATE (mask)
597 24 : CALL timestop(handle)
598 :
599 24 : END SUBROUTINE spgr_rotations_subset
600 :
601 : ! **************************************************************************************************
602 : !> \brief routine applies the rotation matrices to the coordinates.
603 : !> \param spgr ...
604 : !> \param coord ...
605 : !> \par History
606 : !> 01.2020 created [pcazade]
607 : !> \author Pierre-André Cazade (first version)
608 : ! **************************************************************************************************
609 212 : SUBROUTINE spgr_apply_rotations_coord(spgr, coord)
610 :
611 : TYPE(spgr_type), INTENT(IN), POINTER :: spgr
612 : REAL(KIND=dp), DIMENSION(:), INTENT(INOUT) :: coord
613 :
614 : CHARACTER(LEN=*), PARAMETER :: routineN = 'spgr_apply_rotations_coord'
615 :
616 : INTEGER :: handle, ia, ib, ir, ja, jb, nop, nops, &
617 : nparticle
618 212 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: cold
619 : REAL(KIND=dp), DIMENSION(3) :: rf, ri, rn, ro, tr
620 : REAL(KIND=dp), DIMENSION(3, 3) :: rot
621 :
622 212 : CALL timeset(routineN, handle)
623 :
624 636 : ALLOCATE (cold(SIZE(coord)))
625 13268 : cold(:) = coord(:)
626 :
627 212 : nop = spgr%n_operations
628 212 : nparticle = spgr%nparticle
629 212 : nops = spgr%n_reduced_operations
630 :
631 212 : !$OMP PARALLEL DO PRIVATE (ia,ib,ja,jb,ir,ri,ro,rf,rn,rot,tr) SHARED (spgr,coord,nparticle,nop,nops) DEFAULT(NONE)
632 : DO ia = 1, nparticle
633 : IF (.NOT. spgr%lat(ia)) CYCLE
634 : ja = 3*(ia - 1)
635 : CALL real_to_scaled(rf(1:3), coord(ja + 1:ja + 3), spgr%cell_ref)
636 : rn(1:3) = 0.d0
637 : DO ir = 1, nop
638 : IF (.NOT. spgr%lop(ir)) CYCLE
639 : ib = spgr%eqatom(ir, ia)
640 : rot(1:3, 1:3) = spgr%rotations(1:3, 1:3, ir)
641 : tr(1:3) = spgr%translations(1:3, ir)
642 : jb = 3*(ib - 1)
643 : CALL real_to_scaled(ri(1:3), coord(jb + 1:jb + 3), spgr%cell_ref)
644 : 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)
645 : 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)
646 : 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)
647 : ro(1) = ro(1) - REAL(NINT(ro(1) - rf(1)), dp)
648 : ro(2) = ro(2) - REAL(NINT(ro(2) - rf(2)), dp)
649 : ro(3) = ro(3) - REAL(NINT(ro(3) - rf(3)), dp)
650 : rn(1:3) = rn(1:3) + ro(1:3)
651 : END DO
652 : rn = rn/REAL(nops, dp)
653 : CALL scaled_to_real(coord(ja + 1:ja + 3), rn(1:3), spgr%cell_ref)
654 : END DO
655 : !$OMP END PARALLEL DO
656 :
657 212 : DEALLOCATE (cold)
658 212 : CALL timestop(handle)
659 :
660 212 : END SUBROUTINE spgr_apply_rotations_coord
661 :
662 : ! **************************************************************************************************
663 : !> \brief routine applies the rotation matrices to the forces.
664 : !> \param spgr ...
665 : !> \param force ...
666 : !> \par History
667 : !> 01.2020 created [pcazade]
668 : !> \author Pierre-André Cazade (first version)
669 : ! **************************************************************************************************
670 945 : SUBROUTINE spgr_apply_rotations_force(spgr, force)
671 :
672 : TYPE(spgr_type), INTENT(IN), POINTER :: spgr
673 : REAL(KIND=dp), DIMENSION(:), INTENT(INOUT) :: force
674 :
675 : CHARACTER(LEN=*), PARAMETER :: routineN = 'spgr_apply_rotations_force'
676 :
677 : INTEGER :: handle, ia, ib, ir, ja, jb, nop, nops, &
678 : nparticle
679 945 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: fold
680 : REAL(KIND=dp), DIMENSION(3) :: ri, rn, ro
681 : REAL(KIND=dp), DIMENSION(3, 3) :: rot
682 :
683 945 : CALL timeset(routineN, handle)
684 :
685 2835 : ALLOCATE (fold(SIZE(force)))
686 70215 : fold(:) = force(:)
687 :
688 945 : nop = spgr%n_operations
689 945 : nparticle = spgr%nparticle
690 945 : nops = spgr%n_reduced_operations
691 :
692 945 : !$OMP PARALLEL DO PRIVATE (ia,ib,ja,jb,ir,ri,ro,rn,rot) SHARED (spgr,force,nparticle,nop,nops) DEFAULT(NONE)
693 : DO ia = 1, nparticle
694 : IF (.NOT. spgr%lat(ia)) CYCLE
695 : ja = 3*(ia - 1)
696 : rn(1:3) = 0.d0
697 : DO ir = 1, nop
698 : IF (.NOT. spgr%lop(ir)) CYCLE
699 : ib = spgr%eqatom(ir, ia)
700 : rot(1:3, 1:3) = spgr%rotations(1:3, 1:3, ir)
701 : jb = 3*(ib - 1)
702 : CALL real_to_scaled(ri(1:3), force(jb + 1:jb + 3), spgr%cell_ref)
703 : ro(1) = REAL(rot(1, 1), dp)*ri(1) + REAL(rot(2, 1), dp)*ri(2) + REAL(rot(3, 1), dp)*ri(3)
704 : ro(2) = REAL(rot(1, 2), dp)*ri(1) + REAL(rot(2, 2), dp)*ri(2) + REAL(rot(3, 2), dp)*ri(3)
705 : ro(3) = REAL(rot(1, 3), dp)*ri(1) + REAL(rot(2, 3), dp)*ri(2) + REAL(rot(3, 3), dp)*ri(3)
706 : rn(1:3) = rn(1:3) + ro(1:3)
707 : END DO
708 : rn = rn/REAL(nops, dp)
709 : CALL scaled_to_real(force(ja + 1:ja + 3), rn(1:3), spgr%cell_ref)
710 : END DO
711 : !$OMP END PARALLEL DO
712 :
713 945 : DEALLOCATE (fold)
714 945 : CALL timestop(handle)
715 :
716 945 : END SUBROUTINE spgr_apply_rotations_force
717 :
718 : ! **************************************************************************************************
719 : !> \brief ...
720 : !> \param roti ...
721 : !> \param roto ...
722 : !> \param nop ...
723 : !> \param h1 ...
724 : !> \param h2 ...
725 : ! **************************************************************************************************
726 552 : SUBROUTINE spgr_change_basis(roti, roto, nop, h1, h2)
727 :
728 : INTEGER, DIMENSION(:, :, :) :: roti
729 : REAL(KIND=dp), DIMENSION(:, :, :) :: roto
730 : INTEGER :: nop
731 : REAL(KIND=dp), DIMENSION(3, 3) :: h1, h2
732 :
733 : CHARACTER(LEN=*), PARAMETER :: routineN = 'spgr_change_basis'
734 :
735 : INTEGER :: handle, ir
736 : REAL(KIND=dp), DIMENSION(3, 3) :: h1ih2, h2ih1, ih1, ih2, r, s
737 :
738 552 : CALL timeset(routineN, handle)
739 :
740 552 : ih1 = inv_3x3(h1)
741 552 : ih2 = inv_3x3(h2)
742 22080 : h2ih1 = MATMUL(h2, ih1)
743 22080 : h1ih2 = MATMUL(h1, ih2)
744 :
745 3208 : DO ir = 1, nop
746 34528 : r(:, :) = roti(:, :, ir)
747 106240 : s = MATMUL(h2ih1, r)
748 106240 : r = MATMUL(s, h1ih2)
749 35080 : roto(:, :, ir) = r(:, :)
750 : END DO
751 :
752 552 : CALL timestop(handle)
753 :
754 552 : END SUBROUTINE spgr_change_basis
755 :
756 : ! **************************************************************************************************
757 : !> \brief routine applies the rotation matrices to the stress tensor.
758 : !> \param spgr ...
759 : !> \param cell ...
760 : !> \param stress ...
761 : !> \par History
762 : !> 01.2020 created [pcazade]
763 : !> \author Pierre-André Cazade (first version)
764 : ! **************************************************************************************************
765 552 : SUBROUTINE spgr_apply_rotations_stress(spgr, cell, stress)
766 :
767 : TYPE(spgr_type), INTENT(IN), POINTER :: spgr
768 : TYPE(cell_type), INTENT(IN), POINTER :: cell
769 : REAL(KIND=dp), DIMENSION(3, 3), INTENT(INOUT) :: stress
770 :
771 : CHARACTER(LEN=*), PARAMETER :: routineN = 'spgr_apply_rotations_stress'
772 :
773 : INTEGER :: handle, i, ir, j, k, l, nop
774 552 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :) :: roto
775 : REAL(KIND=dp), DIMENSION(3, 3) :: hmat1, hmat2, r, stin
776 :
777 552 : CALL timeset(routineN, handle)
778 :
779 7176 : hmat1 = TRANSPOSE(cell%hmat)
780 :
781 552 : hmat2 = 0d0
782 552 : hmat2(1, 1) = 1.d0
783 552 : hmat2(2, 2) = 1.d0
784 552 : hmat2(3, 3) = 1.d0
785 :
786 552 : nop = spgr%n_operations_subset
787 :
788 1656 : ALLOCATE (roto(3, 3, nop))
789 :
790 552 : CALL spgr_change_basis(spgr%rotations_subset, roto, spgr%n_operations_subset, hmat1, hmat2)
791 :
792 552 : stin = stress
793 552 : stress = 0.d0
794 3208 : DO ir = 1, nop
795 34528 : r(:, :) = roto(:, :, ir)
796 11176 : DO i = 1, 3
797 34528 : DO j = 1, 3
798 103584 : DO k = 1, 3
799 310752 : DO l = 1, 3
800 286848 : stress(i, j) = stress(i, j) + (r(k, i)*r(l, j)*stin(k, l))
801 : END DO
802 : END DO
803 : END DO
804 : END DO
805 : END DO
806 7176 : stress = stress/REAL(nop, dp)
807 :
808 552 : DEALLOCATE (roto)
809 :
810 552 : CALL timestop(handle)
811 :
812 552 : END SUBROUTINE spgr_apply_rotations_stress
813 :
814 : ! **************************************************************************************************
815 : !> \brief Project a cell onto the metric preserved by the selected space-group rotations.
816 : !> \param spgr ...
817 : !> \param cell ...
818 : ! **************************************************************************************************
819 794 : SUBROUTINE spgr_project_cell_metric(spgr, cell)
820 :
821 : TYPE(spgr_type), INTENT(IN), POINTER :: spgr
822 : TYPE(cell_type), INTENT(INOUT), POINTER :: cell
823 :
824 : INTEGER :: i, ir, nop
825 : REAL(KIND=dp) :: scale
826 : REAL(KIND=dp), DIMENSION(3) :: abc, cell_angle
827 : REAL(KIND=dp), DIMENSION(3, 3) :: metric, metric_sym, rot
828 :
829 794 : CPASSERT(ALLOCATED(spgr%rotations_subset))
830 794 : nop = spgr%n_operations_subset
831 794 : CPASSERT(nop > 0)
832 :
833 31760 : metric = MATMUL(TRANSPOSE(cell%hmat), cell%hmat)
834 794 : metric_sym = 0.0_dp
835 4506 : DO ir = 1, nop
836 48256 : rot = REAL(spgr%rotations_subset(:, :, ir), dp)
837 338586 : metric_sym = metric_sym + MATMUL(rot, MATMUL(metric, TRANSPOSE(rot)))
838 : END DO
839 10322 : metric_sym = metric_sym/REAL(nop, dp)
840 :
841 : ! The group average can change the determinant. Retain the volume of the
842 : ! optimizer proposal so KEEP_VOLUME and hydrostatic changes remain intact.
843 794 : scale = (cell%deth**2/det_3x3(metric_sym))**(1.0_dp/3.0_dp)
844 10322 : metric_sym = scale*metric_sym
845 :
846 3176 : DO i = 1, 3
847 3176 : abc(i) = SQRT(metric_sym(i, i))
848 : END DO
849 794 : cell_angle(1) = ACOS(MAX(-1.0_dp, MIN(1.0_dp, metric_sym(2, 3)/(abc(2)*abc(3)))))
850 794 : cell_angle(2) = ACOS(MAX(-1.0_dp, MIN(1.0_dp, metric_sym(1, 3)/(abc(1)*abc(3)))))
851 794 : cell_angle(3) = ACOS(MAX(-1.0_dp, MIN(1.0_dp, metric_sym(1, 2)/(abc(1)*abc(2)))))
852 : CALL set_cell_param(cell, cell_length=abc, cell_angle=cell_angle, &
853 794 : periodic=cell%perd, do_init_cell=.TRUE.)
854 :
855 794 : END SUBROUTINE spgr_project_cell_metric
856 :
857 : ! **************************************************************************************************
858 : !> \brief routine prints Space Group Information.
859 : !> \param spgr ...
860 : !> \par History
861 : !> 01.2020 created [pcazade]
862 : !> \author Pierre-André Cazade (first version)
863 : ! **************************************************************************************************
864 24 : SUBROUTINE print_spgr(spgr)
865 :
866 : TYPE(spgr_type), INTENT(IN), POINTER :: spgr
867 :
868 : INTEGER :: i, j
869 :
870 24 : IF (spgr%iunit > 0) THEN
871 12 : WRITE (spgr%iunit, '(/,T2,A,A)') "----------------------------------------", &
872 24 : "---------------------------------------"
873 12 : WRITE (spgr%iunit, "(T2,A,T25,A,T77,A)") "----", "SPACE GROUP SYMMETRY INFORMATION", "----"
874 12 : WRITE (spgr%iunit, '(T2,A,A)') "----------------------------------------", &
875 24 : "---------------------------------------"
876 12 : IF (spgr%symlib) THEN
877 12 : WRITE (spgr%iunit, '(T2,A,T73,I8)') "SPGR| SPACE GROUP NUMBER:", &
878 24 : spgr%space_group_number
879 12 : WRITE (spgr%iunit, '(T2,A,T70,A11)') "SPGR| INTERNATIONAL SYMBOL:", &
880 24 : TRIM(ADJUSTR(spgr%international_symbol))
881 12 : WRITE (spgr%iunit, '(T2,A,T75,A6)') "SPGR| POINT GROUP SYMBOL:", &
882 24 : TRIM(ADJUSTR(spgr%pointgroup_symbol))
883 12 : WRITE (spgr%iunit, '(T2,A,T74,A7)') "SPGR| SCHOENFLIES SYMBOL:", &
884 24 : TRIM(ADJUSTR(spgr%schoenflies))
885 12 : WRITE (spgr%iunit, '(T2,A,T73,I8)') "SPGR| NUMBER OF SYMMETRY OPERATIONS:", &
886 24 : spgr%n_operations
887 12 : WRITE (spgr%iunit, '(T2,A,T73,I8)') "SPGR| NUMBER OF UNIQUE ROTATIONS:", &
888 24 : spgr%n_operations_subset
889 12 : WRITE (spgr%iunit, '(T2,A,T73,I8)') "SPGR| NUMBER OF REDUCED SYMMETRY OPERATIONS:", &
890 24 : spgr%n_reduced_operations
891 12 : WRITE (spgr%iunit, '(T2,A,T65,I8,I8)') "SPGR| NUMBER OF PARTICLES AND SYMMETRIZED PARTICLES:", &
892 24 : spgr%nparticle, spgr%nparticle_sym
893 12 : WRITE (spgr%iunit, '(T2,A,T65,I8,I8)') "SPGR| NUMBER OF ATOMS AND SYMMETRIZED ATOMS:", &
894 24 : spgr%n_atom, spgr%n_atom_sym
895 12 : WRITE (spgr%iunit, '(T2,A,T65,I8,I8)') "SPGR| NUMBER OF CORES AND SYMMETRIZED CORES:", &
896 24 : spgr%n_core, spgr%n_core_sym
897 12 : WRITE (spgr%iunit, '(T2,A,T65,I8,I8)') "SPGR| NUMBER OF SHELLS AND SYMMETRIZED SHELLS:", &
898 24 : spgr%n_shell, spgr%n_shell_sym
899 12 : IF (spgr%print_atoms) THEN
900 5 : WRITE (spgr%iunit, *) "SPGR| ACTIVE REDUCED SYMMETRY OPERATIONS:", spgr%lop
901 1 : WRITE (spgr%iunit, '(/,T2,A,A)') "----------------------------------------", &
902 2 : "---------------------------------------"
903 1 : WRITE (spgr%iunit, '(T2,A,T34,A,T77,A)') "----", "EQUIVALENT ATOMS", "----"
904 1 : WRITE (spgr%iunit, '(T2,A,A)') "----------------------------------------", &
905 2 : "---------------------------------------"
906 25 : DO i = 1, spgr%nparticle
907 121 : DO j = 1, spgr%n_operations
908 96 : WRITE (spgr%iunit, '(T2,A,T52,I8,I8,I8)') "SPGR| ATOM | SYMMETRY OPERATION | EQUIVALENT ATOM", &
909 216 : i, j, spgr%eqatom(j, i)
910 : END DO
911 : END DO
912 1 : WRITE (spgr%iunit, '(T2,A,A)') "----------------------------------------", &
913 2 : "---------------------------------------"
914 5 : DO i = 1, spgr%n_operations
915 : WRITE (spgr%iunit, '(T2,A,T46,i4,T51,3I10,/,T51,3I10,/,T51,3I10)') &
916 52 : "SPGR| SYMMETRY OPERATION #:", i, (spgr%rotations(j, :, i), j=1, 3)
917 17 : WRITE (spgr%iunit, '(T51,3F10.5)') spgr%translations(:, i)
918 : END DO
919 : END IF
920 : ELSE
921 0 : WRITE (spgr%iunit, "(T2,A)") "SPGLIB for Crystal Symmetry Information determination is not availale"
922 : END IF
923 : END IF
924 :
925 24 : END SUBROUTINE print_spgr
926 :
927 : ! **************************************************************************************************
928 : !> \brief Variable precision output of the symmetrized stress tensor
929 : !>
930 : !> \param stress tensor ...
931 : !> \param spgr ...
932 : !> \par History
933 : !> 07.2020 adapted to spgr [pcazade]
934 : !> \author MK (26.08.2010).
935 : ! **************************************************************************************************
936 552 : SUBROUTINE spgr_write_stress_tensor(stress, spgr)
937 :
938 : REAL(KIND=dp), DIMENSION(3, 3), INTENT(IN) :: stress
939 : TYPE(spgr_type), INTENT(IN), POINTER :: spgr
940 :
941 : REAL(KIND=dp), DIMENSION(3) :: eigval
942 : REAL(KIND=dp), DIMENSION(3, 3) :: eigvec, stress_tensor
943 :
944 7176 : stress_tensor(:, :) = stress(:, :)*pascal*1.0E-9_dp
945 :
946 552 : IF (spgr%iunit > 0) THEN
947 : WRITE (UNIT=spgr%iunit, FMT='(/,T2,A)') &
948 277 : 'SPGR STRESS| Symmetrized stress tensor [GPa]'
949 : WRITE (UNIT=spgr%iunit, FMT='(T2,A,T19,3(19X,A1))') &
950 277 : 'SPGR STRESS|', 'x', 'y', 'z'
951 : WRITE (UNIT=spgr%iunit, FMT='(T2,A,T26,3(1X,ES19.11))') &
952 277 : 'SPGR STRESS| x', stress_tensor(1, 1:3)
953 : WRITE (UNIT=spgr%iunit, FMT='(T2,A,T26,3(1X,ES19.11))') &
954 277 : 'SPGR STRESS| y', stress_tensor(2, 1:3)
955 : WRITE (UNIT=spgr%iunit, FMT='(T2,A,T26,3(1X,ES19.11))') &
956 277 : 'SPGR STRESS| z', stress_tensor(3, 1:3)
957 : WRITE (UNIT=spgr%iunit, FMT='(T2,A,T66,ES20.11)') &
958 277 : 'SPGR STRESS| 1/3 Trace', (stress_tensor(1, 1) + &
959 : stress_tensor(2, 2) + &
960 554 : stress_tensor(3, 3))/3.0_dp
961 : WRITE (UNIT=spgr%iunit, FMT='(T2,A,T66,ES20.11)') &
962 277 : 'SPGR STRESS| Determinant', det_3x3(stress_tensor(1:3, 1), &
963 : stress_tensor(1:3, 2), &
964 554 : stress_tensor(1:3, 3))
965 277 : eigval(:) = 0.0_dp
966 277 : eigvec(:, :) = 0.0_dp
967 277 : CALL jacobi(stress_tensor, eigval, eigvec)
968 : WRITE (UNIT=spgr%iunit, FMT='(/,T2,A)') &
969 277 : 'SPGR STRESS| Eigenvectors and eigenvalues of the symmetrized stress tensor [GPa]'
970 : WRITE (UNIT=spgr%iunit, FMT='(T2,A,T19,3(1X,I19))') &
971 277 : 'SPGR STRESS|', 1, 2, 3
972 : WRITE (UNIT=spgr%iunit, FMT='(T2,A,T26,3(1X,ES19.11))') &
973 277 : 'SPGR STRESS| Eigenvalues', eigval(1:3)
974 : WRITE (UNIT=spgr%iunit, FMT='(T2,A,T26,3(1X,F19.12))') &
975 277 : 'SPGR STRESS| x', eigvec(1, 1:3)
976 : WRITE (UNIT=spgr%iunit, FMT='(T2,A,T26,3(1X,F19.12))') &
977 277 : 'SPGR STRESS| y', eigvec(2, 1:3)
978 : WRITE (UNIT=spgr%iunit, FMT='(T2,A,T26,3(1X,F19.12))') &
979 277 : 'SPGR STRESS| z', eigvec(3, 1:3)
980 : END IF
981 :
982 552 : END SUBROUTINE spgr_write_stress_tensor
983 :
984 : END MODULE space_groups
|