LCOV - code coverage report
Current view: top level - src/motion - space_groups.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:7641cd9) Lines: 90.9 % 361 328
Test Date: 2026-05-25 07:16:39 Functions: 100.0 % 11 11

            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              :    USE cell_types,                      ONLY: cell_copy,&
      21              :                                               cell_type,&
      22              :                                               real_to_scaled,&
      23              :                                               scaled_to_real
      24              :    USE cp_subsys_types,                 ONLY: cp_subsys_get,&
      25              :                                               cp_subsys_type
      26              :    USE gopt_f_types,                    ONLY: gopt_f_type
      27              :    USE input_constants,                 ONLY: default_cell_method_id,&
      28              :                                               default_minimization_method_id,&
      29              :                                               default_ts_method_id
      30              :    USE input_section_types,             ONLY: section_vals_type,&
      31              :                                               section_vals_val_get
      32              :    USE kinds,                           ONLY: dp
      33              :    USE mathlib,                         ONLY: det_3x3,&
      34              :                                               inv_3x3,&
      35              :                                               jacobi
      36              :    USE particle_list_types,             ONLY: particle_list_type
      37              :    USE physcon,                         ONLY: pascal
      38              :    USE space_groups_types,              ONLY: cleanup_spgr_type,&
      39              :                                               spgr_type
      40              :    USE spglib_f08,                      ONLY: spg_get_international,&
      41              :                                               spg_get_multiplicity,&
      42              :                                               spg_get_pointgroup,&
      43              :                                               spg_get_schoenflies,&
      44              :                                               spg_get_symmetry
      45              :    USE string_utilities,                ONLY: strlcpy_c2f
      46              : #include "../base/base_uses.f90"
      47              : 
      48              :    IMPLICIT NONE
      49              : 
      50              :    PRIVATE
      51              : 
      52              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'space_groups'
      53              : 
      54              :    PUBLIC :: spgr_create, identify_space_group, spgr_find_equivalent_atoms
      55              :    PUBLIC :: spgr_apply_rotations_coord, spgr_apply_rotations_force, print_spgr
      56              :    PUBLIC :: spgr_apply_rotations_stress, spgr_write_stress_tensor
      57              : 
      58              : CONTAINS
      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           20 :    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           20 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: tmp_types
     100              :       LOGICAL                                            :: spglib
     101           20 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: tmp_coor
     102              :       TYPE(spgr_type), POINTER                           :: spgr
     103              : 
     104           20 :       CALL timeset(routineN, handle)
     105              : 
     106           20 :       spgr => gopt_env%spgr
     107           20 :       CPASSERT(ASSOCIATED(spgr))
     108              : 
     109           20 :       CALL cleanup_spgr_type(spgr)
     110              : 
     111              :       !..total number of particles (atoms plus shells)
     112           20 :       IF (PRESENT(nparticle)) THEN
     113           20 :          CPASSERT(nparticle == SIZE(scoor, 2))
     114           20 :          spgr%nparticle = nparticle
     115              :       ELSE
     116            0 :          spgr%nparticle = SIZE(scoor, 2)
     117              :       END IF
     118              : 
     119           20 :       IF (PRESENT(n_atom)) THEN
     120           20 :          spgr%n_atom = n_atom
     121            0 :       ELSE IF (PRESENT(n_core)) THEN
     122            0 :          spgr%n_atom = spgr%nparticle - n_core
     123            0 :       ELSE IF (PRESENT(n_shell)) THEN
     124            0 :          spgr%n_atom = spgr%nparticle - n_shell
     125              :       ELSE
     126            0 :          spgr%n_atom = spgr%nparticle
     127              :       END IF
     128              : 
     129           20 :       IF (PRESENT(n_core)) THEN
     130           20 :          spgr%n_core = n_core
     131            0 :       ELSE IF (PRESENT(n_shell)) THEN
     132            0 :          spgr%n_core = n_shell
     133              :       END IF
     134              : 
     135           20 :       IF (PRESENT(n_shell)) THEN
     136           20 :          spgr%n_shell = n_shell
     137            0 :       ELSE IF (PRESENT(n_core)) THEN
     138            0 :          spgr%n_shell = n_core
     139              :       END IF
     140              : 
     141           20 :       IF (.NOT. (spgr%nparticle == (spgr%n_atom + spgr%n_shell))) THEN
     142            0 :          CPABORT("spgr_create: nparticle not equal to natom + nshell.")
     143              :       END IF
     144              : 
     145           20 :       spgr%nparticle_sym = spgr%nparticle
     146           20 :       spgr%n_atom_sym = spgr%n_atom
     147           20 :       spgr%n_core_sym = spgr%n_core
     148           20 :       spgr%n_shell_sym = spgr%n_shell
     149              : 
     150           20 :       spgr%iunit = iunit
     151           20 :       spgr%print_atoms = print_atoms
     152              : 
     153              :       ! accuracy for symmetry
     154           20 :       IF (PRESENT(eps_symmetry)) THEN
     155           20 :          spgr%eps_symmetry = eps_symmetry
     156              :       END IF
     157              : 
     158              :       ! vector to test reduced symmetry
     159           20 :       IF (PRESENT(pol)) THEN
     160           20 :          spgr%pol(1) = pol(1)
     161           20 :          spgr%pol(2) = pol(2)
     162           20 :          spgr%pol(3) = pol(3)
     163              :       END IF
     164              : 
     165           60 :       ALLOCATE (spgr%lat(spgr%nparticle))
     166          256 :       spgr%lat = .TRUE.
     167              : 
     168           20 :       IF (PRESENT(ranges)) THEN
     169            0 :          n_sr_rep = SIZE(ranges, 2)
     170            0 :          DO i = 1, n_sr_rep
     171            0 :             DO j = ranges(1, i), ranges(2, i)
     172            0 :                spgr%lat(j) = .FALSE.
     173            0 :                spgr%nparticle_sym = spgr%nparticle_sym - 1
     174            0 :                IF (j <= spgr%n_atom) THEN
     175            0 :                   spgr%n_atom_sym = spgr%n_atom_sym - 1
     176            0 :                ELSE IF (j > spgr%n_atom .AND. j <= spgr%nparticle) THEN
     177            0 :                   spgr%n_core_sym = spgr%n_core_sym - 1
     178            0 :                   spgr%n_shell_sym = spgr%n_shell_sym - 1
     179              :                ELSE
     180            0 :                   CPABORT("Symmetry exclusion range larger than actual number of particles.")
     181              :                END IF
     182              :             END DO
     183              :          END DO
     184              :       END IF
     185              : 
     186          100 :       ALLOCATE (tmp_coor(3, spgr%n_atom_sym), tmp_types(spgr%n_atom_sym))
     187              : 
     188           20 :       j = 0
     189          184 :       DO i = 1, spgr%n_atom
     190          184 :          IF (spgr%lat(i)) THEN
     191          164 :             j = j + 1
     192          656 :             tmp_coor(:, j) = scoor(:, i)
     193          164 :             tmp_types(j) = types(i)
     194              :          END IF
     195              :       END DO
     196              : 
     197              :       !..set cell values
     198           20 :       NULLIFY (spgr%cell_ref)
     199           20 :       CALL cell_create(spgr%cell_ref)
     200           20 :       CALL cell_copy(cell, spgr%cell_ref, tag="CELL_OPT_REF")
     201           24 :       SELECT CASE (gopt_env%type_id)
     202              :       CASE (default_minimization_method_id, default_ts_method_id)
     203            4 :          CALL init_cell(spgr%cell_ref, hmat=cell%hmat)
     204              :       CASE (default_cell_method_id)
     205           16 :          CALL init_cell(spgr%cell_ref, hmat=gopt_env%h_ref)
     206              :       CASE DEFAULT
     207           20 :          CPABORT("SPACE_GROUP_SYMMETRY is not compatible with md.")
     208              :       END SELECT
     209              : 
     210              :       ! atom types
     211           60 :       ALLOCATE (spgr%atype(spgr%nparticle))
     212          256 :       spgr%atype(1:spgr%nparticle) = types(1:spgr%nparticle)
     213              : 
     214           20 :       spgr%n_operations = 0
     215              : 
     216              : #ifdef __SPGLIB
     217           20 :       spglib = .TRUE.
     218           20 :       CALL cite_reference(Togo2018)
     219              :       spgr%space_group_number = spg_get_international(spgr%international_symbol, TRANSPOSE(cell%hmat), tmp_coor, tmp_types, &
     220           20 :                                                       spgr%n_atom_sym, eps_symmetry)
     221           20 :       buffer = ''
     222           20 :       nchars = strlcpy_c2f(buffer, spgr%international_symbol)
     223           20 :       spgr%international_symbol = buffer(1:nchars)
     224           20 :       IF (spgr%space_group_number == 0) THEN
     225            0 :          CPABORT("Symmetry Library SPGLIB failed, most likely due a problem with the coordinates.")
     226            0 :          spglib = .FALSE.
     227              :       ELSE
     228              :          nop = spg_get_multiplicity(TRANSPOSE(cell%hmat), tmp_coor, tmp_types, &
     229           20 :                                     spgr%n_atom_sym, eps_symmetry)
     230          100 :          ALLOCATE (spgr%rotations(3, 3, nop), spgr%translations(3, nop))
     231           80 :          ALLOCATE (spgr%eqatom(nop, spgr%nparticle))
     232           60 :          ALLOCATE (spgr%lop(nop))
     233           20 :          spgr%n_operations = nop
     234         1620 :          spgr%lop = .TRUE.
     235              :          ierr = spg_get_symmetry(spgr%rotations, spgr%translations, nop, TRANSPOSE(cell%hmat), &
     236           20 :                                  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           20 :                                     spgr%n_atom_sym, eps_symmetry)
     240           20 :          buffer = ''
     241           20 :          nchars = strlcpy_c2f(buffer, spgr%schoenflies)
     242           20 :          spgr%schoenflies = buffer(1:nchars)
     243              : 
     244              :          ! Point Group
     245           20 :          tra_mat = 0
     246              :          ierr = spg_get_pointgroup(spgr%pointgroup_symbol, tra_mat, &
     247           20 :                                    spgr%rotations, spgr%n_operations)
     248           20 :          buffer = ''
     249           20 :          nchars = strlcpy_c2f(buffer, spgr%pointgroup_symbol)
     250           20 :          spgr%pointgroup_symbol = buffer(1:nchars)
     251              :       END IF
     252              : #else
     253              :       CPABORT("Symmetry library SPGLIB not available")
     254              :       spglib = .FALSE.
     255              : #endif
     256           20 :       spgr%symlib = spglib
     257              : 
     258           20 :       DEALLOCATE (tmp_coor, tmp_types)
     259              : 
     260           20 :       CALL timestop(handle)
     261              : 
     262           20 :    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           20 :    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           20 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: atype
     288           20 :       INTEGER, ALLOCATABLE, DIMENSION(:, :)              :: ranges
     289           20 :       INTEGER, DIMENSION(:), POINTER                     :: tmp
     290              :       LOGICAL                                            :: print_atoms
     291              :       REAL(KIND=dp)                                      :: eps_symmetry
     292           20 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: scoord
     293           20 :       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           20 :       CALL timeset(routineN, handle)
     300              : 
     301              :       n_sr_rep = 0
     302              :       nparticle = 0
     303              :       n_atom = 0
     304           20 :       n_core = 0
     305           20 :       n_shell = 0
     306              : 
     307           20 :       NULLIFY (particles)
     308           20 :       NULLIFY (core_particles)
     309           20 :       NULLIFY (shell_particles)
     310              : 
     311              :       NULLIFY (cell)
     312           20 :       cell => subsys%cell
     313           20 :       CPASSERT(ASSOCIATED(cell))
     314              : 
     315           20 :       CALL cp_subsys_get(subsys, particles=particles, shell_particles=shell_particles, core_particles=core_particles)
     316              : 
     317           20 :       CPASSERT(ASSOCIATED(particles))
     318           20 :       n_atom = particles%n_els
     319              :       ! Check if we have other kinds of particles in this subsystem
     320           20 :       IF (ASSOCIATED(shell_particles)) THEN
     321            6 :          n_shell = shell_particles%n_els
     322            6 :          CPASSERT(ASSOCIATED(core_particles))
     323            6 :          n_core = subsys%core_particles%n_els
     324              :          ! The same number of shell and core particles is assumed
     325            6 :          CPASSERT(n_core == n_shell)
     326           14 :       ELSE IF (ASSOCIATED(core_particles)) THEN
     327              :          ! This case should not occur at the moment
     328            0 :          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           20 :       nparticle = n_atom + n_shell
     335          100 :       ALLOCATE (scoord(3, nparticle), atype(nparticle))
     336          184 :       DO i = 1, n_atom
     337          164 :          shell_index = particles%els(i)%shell_index
     338          184 :          IF (shell_index == 0) THEN
     339           92 :             CALL real_to_scaled(scoord(1:3, i), particles%els(i)%r(1:3), cell)
     340           92 :             CALL get_atomic_kind(atomic_kind=particles%els(i)%atomic_kind, kind_number=atype(i))
     341              :          ELSE
     342           72 :             CALL real_to_scaled(scoord(1:3, i), core_particles%els(shell_index)%r(1:3), cell)
     343           72 :             CALL get_atomic_kind(atomic_kind=core_particles%els(shell_index)%atomic_kind, kind_number=atype(i))
     344           72 :             k = n_atom + shell_index
     345           72 :             CALL real_to_scaled(scoord(1:3, k), shell_particles%els(shell_index)%r(1:3), cell)
     346           72 :             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           20 :       CALL section_vals_val_get(geo_section, "SPGR_PRINT_ATOMS", l_val=print_atoms)
     351           20 :       CALL section_vals_val_get(geo_section, "EPS_SYMMETRY", r_val=eps_symmetry)
     352           20 :       CALL section_vals_val_get(geo_section, "SYMM_REDUCTION", r_vals=pol)
     353           20 :       CALL section_vals_val_get(geo_section, "SYMM_EXCLUDE_RANGE", n_rep_val=n_sr_rep)
     354           20 :       IF (n_sr_rep > 0) THEN
     355            0 :          ALLOCATE (ranges(2, n_sr_rep))
     356            0 :          DO i = 1, n_sr_rep
     357            0 :             CALL section_vals_val_get(geo_section, "SYMM_EXCLUDE_RANGE", i_rep_val=i, i_vals=tmp)
     358            0 :             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            0 :                           n_core=n_core, n_shell=n_shell, iunit=iunit, print_atoms=print_atoms)
     363            0 :          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           20 :                           n_core=n_core, n_shell=n_shell, iunit=iunit, print_atoms=print_atoms)
     368              :       END IF
     369              : 
     370              :       NULLIFY (spgr)
     371           20 :       spgr => gopt_env%spgr
     372              : 
     373           20 :       CALL spgr_find_equivalent_atoms(spgr, scoord)
     374           20 :       CALL spgr_reduce_symm(spgr)
     375           20 :       CALL spgr_rotations_subset(spgr)
     376              : 
     377           20 :       DEALLOCATE (scoord, atype)
     378              : 
     379           20 :       CALL timestop(handle)
     380              : 
     381           80 :    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           20 :    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           20 :       CALL timeset(routineN, handle)
     406              : 
     407           20 :       nop = spgr%n_operations
     408           20 :       natom = spgr%n_atom
     409           20 :       nshell = spgr%n_shell
     410              : 
     411           20 :       IF (.NOT. (spgr%nparticle == (natom + nshell))) THEN
     412            0 :          CPABORT("spgr_find_equivalent_atoms: nparticle not equal to natom + nshell.")
     413              :       END IF
     414              : 
     415          256 :       DO ia = 1, spgr%nparticle
     416        10328 :          spgr%eqatom(:, ia) = ia
     417              :       END DO
     418              : 
     419           20 :       !$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           20 :       !$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           20 :       CALL timestop(handle)
     474              : 
     475           20 :    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           20 :    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           20 :       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           20 :       CALL timeset(routineN, handle)
     497              : 
     498           20 :       nop = spgr%n_operations
     499           20 :       nparticle = spgr%nparticle
     500           80 :       ALLOCATE (x(3*nparticle), xold(3*nparticle))
     501           20 :       x = 0.0_dp
     502          256 :       DO ia = 1, nparticle
     503          236 :          ja = 3*(ia - 1)
     504          236 :          x(ja + 1) = x(ja + 1) + spgr%pol(1)
     505          236 :          x(ja + 2) = x(ja + 2) + spgr%pol(2)
     506          256 :          x(ja + 3) = x(ja + 3) + spgr%pol(3)
     507              :       END DO
     508          728 :       xold(:) = x(:)
     509              : 
     510              :       nops = 0
     511         1620 :       DO ir = 1, nop
     512         1600 :          x = 0.d0
     513         1600 :          spgr%lop(ir) = .TRUE.
     514        20800 :          rot(1:3, 1:3) = spgr%rotations(1:3, 1:3, ir)
     515        11672 :          DO ia = 1, nparticle
     516        10072 :             IF (.NOT. spgr%lat(ia)) CYCLE
     517        10072 :             ja = 3*(ia - 1)
     518        40288 :             ri(1:3) = xold(ja + 1:ja + 3)
     519        10072 :             ro(1) = REAL(rot(1, 1), dp)*ri(1) + REAL(rot(2, 1), dp)*ri(2) + REAL(rot(3, 1), dp)*ri(3)
     520        10072 :             ro(2) = REAL(rot(1, 2), dp)*ri(1) + REAL(rot(2, 2), dp)*ri(2) + REAL(rot(3, 2), dp)*ri(3)
     521        10072 :             ro(3) = REAL(rot(1, 3), dp)*ri(1) + REAL(rot(2, 3), dp)*ri(2) + REAL(rot(3, 3), dp)*ri(3)
     522        41888 :             x(ja + 1:ja + 3) = ro(1:3)
     523              :          END DO
     524        11672 :          DO ia = 1, nparticle
     525        10072 :             IF (.NOT. spgr%lat(ia)) CYCLE
     526        10072 :             ib = spgr%eqatom(ir, ia)
     527        10072 :             ja = 3*(ia - 1)
     528        10072 :             jb = 3*(ib - 1)
     529        40288 :             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        11672 :                             .AND. (ABS(ro(3)) < spgr%eps_symmetry))
     533              :          END DO
     534         1620 :          IF (spgr%lop(ir)) nops = nops + 1
     535              :       END DO
     536              : 
     537           20 :       spgr%n_reduced_operations = nops
     538              : 
     539           20 :       DEALLOCATE (x, xold)
     540           20 :       CALL timestop(handle)
     541              : 
     542           20 :    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           20 :    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           20 :       LOGICAL, ALLOCATABLE, DIMENSION(:)                 :: mask
     561              : 
     562           20 :       CALL timeset(routineN, handle)
     563              : 
     564           60 :       ALLOCATE (mask(spgr%n_operations))
     565         1620 :       mask = .TRUE.
     566              : 
     567         1620 :       DO i = 1, spgr%n_operations
     568         1620 :          IF (.NOT. spgr%lop(i)) mask(i) = .FALSE.
     569              :       END DO
     570              : 
     571         1600 :       DO i = 1, spgr%n_operations - 1
     572         1580 :          IF (.NOT. mask(i)) CYCLE
     573        64928 :          DO j = i + 1, spgr%n_operations
     574        64472 :             IF (.NOT. mask(j)) CYCLE
     575       486200 :             d(:, :) = spgr%rotations(:, :, j) - spgr%rotations(:, :, i)
     576       487780 :             IF (SUM(ABS(d)) == 0) mask(j) = .FALSE.
     577              :          END DO
     578              :       END DO
     579              : 
     580           20 :       spgr%n_operations_subset = 0
     581         1620 :       DO i = 1, spgr%n_operations
     582         1620 :          IF (mask(i)) spgr%n_operations_subset = spgr%n_operations_subset + 1
     583              :       END DO
     584              : 
     585           60 :       ALLOCATE (spgr%rotations_subset(3, 3, spgr%n_operations_subset))
     586              : 
     587           20 :       j = 0
     588         1620 :       DO i = 1, spgr%n_operations
     589         1620 :          IF (mask(i)) THEN
     590          448 :             j = j + 1
     591         5824 :             spgr%rotations_subset(:, :, j) = spgr%rotations(:, :, i)
     592              :          END IF
     593              :       END DO
     594              : 
     595           20 :       DEALLOCATE (mask)
     596           20 :       CALL timestop(handle)
     597              : 
     598           20 :    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          196 :    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          196 :       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          196 :       CALL timeset(routineN, handle)
     622              : 
     623          588 :       ALLOCATE (cold(SIZE(coord)))
     624        13060 :       cold(:) = coord(:)
     625              : 
     626          196 :       nop = spgr%n_operations
     627          196 :       nparticle = spgr%nparticle
     628          196 :       nops = spgr%n_reduced_operations
     629              : 
     630          196 :       !$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          196 :       DEALLOCATE (cold)
     657          196 :       CALL timestop(handle)
     658              : 
     659          196 :    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          921 :    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          921 :       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          921 :       CALL timeset(routineN, handle)
     683              : 
     684         2763 :       ALLOCATE (fold(SIZE(force)))
     685        69903 :       fold(:) = force(:)
     686              : 
     687          921 :       nop = spgr%n_operations
     688          921 :       nparticle = spgr%nparticle
     689          921 :       nops = spgr%n_reduced_operations
     690              : 
     691          921 :       !$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          921 :       DEALLOCATE (fold)
     713          921 :       CALL timestop(handle)
     714              : 
     715          921 :    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          544 :    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          544 :       CALL timeset(routineN, handle)
     738              : 
     739          544 :       ih1 = inv_3x3(h1)
     740          544 :       ih2 = inv_3x3(h2)
     741        21760 :       h2ih1 = MATMUL(h2, ih1)
     742        21760 :       h1ih2 = MATMUL(h1, ih2)
     743              : 
     744         2816 :       DO ir = 1, nop
     745        29536 :          r(:, :) = roti(:, :, ir)
     746        90880 :          s = MATMUL(h2ih1, r)
     747        90880 :          r = MATMUL(s, h1ih2)
     748        30080 :          roto(:, :, ir) = r(:, :)
     749              :       END DO
     750              : 
     751          544 :       CALL timestop(handle)
     752              : 
     753          544 :    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          544 :    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          544 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :)     :: roto
     774              :       REAL(KIND=dp), DIMENSION(3, 3)                     :: hmat1, hmat2, r, stin
     775              : 
     776          544 :       CALL timeset(routineN, handle)
     777              : 
     778         7072 :       hmat1 = TRANSPOSE(cell%hmat)
     779              : 
     780          544 :       hmat2 = 0d0
     781          544 :       hmat2(1, 1) = 1.d0
     782          544 :       hmat2(2, 2) = 1.d0
     783          544 :       hmat2(3, 3) = 1.d0
     784              : 
     785          544 :       nop = spgr%n_operations_subset
     786              : 
     787         1632 :       ALLOCATE (roto(3, 3, nop))
     788              : 
     789          544 :       CALL spgr_change_basis(spgr%rotations_subset, roto, spgr%n_operations_subset, hmat1, hmat2)
     790              : 
     791          544 :       stin = stress
     792          544 :       stress = 0.d0
     793         2816 :       DO ir = 1, nop
     794        29536 :          r(:, :) = roto(:, :, ir)
     795         9632 :          DO i = 1, 3
     796        29536 :             DO j = 1, 3
     797        88608 :                DO k = 1, 3
     798       265824 :                   DO l = 1, 3
     799       245376 :                      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         7072 :       stress = stress/REAL(nop, dp)
     806              : 
     807          544 :       DEALLOCATE (roto)
     808              : 
     809          544 :       CALL timestop(handle)
     810              : 
     811          544 :    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           20 :    SUBROUTINE print_spgr(spgr)
     821              : 
     822              :       TYPE(spgr_type), INTENT(IN), POINTER               :: spgr
     823              : 
     824              :       INTEGER                                            :: i, j
     825              : 
     826           20 :       IF (spgr%iunit > 0) THEN
     827           10 :          WRITE (spgr%iunit, '(/,T2,A,A)') "----------------------------------------", &
     828           20 :             "---------------------------------------"
     829           10 :          WRITE (spgr%iunit, "(T2,A,T25,A,T77,A)") "----", "SPACE GROUP SYMMETRY INFORMATION", "----"
     830           10 :          WRITE (spgr%iunit, '(T2,A,A)') "----------------------------------------", &
     831           20 :             "---------------------------------------"
     832           10 :          IF (spgr%symlib) THEN
     833           10 :             WRITE (spgr%iunit, '(T2,A,T73,I8)') "SPGR| SPACE GROUP NUMBER:", &
     834           20 :                spgr%space_group_number
     835           10 :             WRITE (spgr%iunit, '(T2,A,T70,A11)') "SPGR| INTERNATIONAL SYMBOL:", &
     836           20 :                TRIM(ADJUSTR(spgr%international_symbol))
     837           10 :             WRITE (spgr%iunit, '(T2,A,T75,A6)') "SPGR| POINT GROUP SYMBOL:", &
     838           20 :                TRIM(ADJUSTR(spgr%pointgroup_symbol))
     839           10 :             WRITE (spgr%iunit, '(T2,A,T74,A7)') "SPGR| SCHOENFLIES SYMBOL:", &
     840           20 :                TRIM(ADJUSTR(spgr%schoenflies))
     841           10 :             WRITE (spgr%iunit, '(T2,A,T73,I8)') "SPGR| NUMBER OF SYMMETRY OPERATIONS:", &
     842           20 :                spgr%n_operations
     843           10 :             WRITE (spgr%iunit, '(T2,A,T73,I8)') "SPGR| NUMBER OF UNIQUE ROTATIONS:", &
     844           20 :                spgr%n_operations_subset
     845           10 :             WRITE (spgr%iunit, '(T2,A,T73,I8)') "SPGR| NUMBER OF REDUCED SYMMETRY OPERATIONS:", &
     846           20 :                spgr%n_reduced_operations
     847           10 :             WRITE (spgr%iunit, '(T2,A,T65,I8,I8)') "SPGR| NUMBER OF PARTICLES AND SYMMETRIZED PARTICLES:", &
     848           20 :                spgr%nparticle, spgr%nparticle_sym
     849           10 :             WRITE (spgr%iunit, '(T2,A,T65,I8,I8)') "SPGR| NUMBER OF ATOMS AND SYMMETRIZED ATOMS:", &
     850           20 :                spgr%n_atom, spgr%n_atom_sym
     851           10 :             WRITE (spgr%iunit, '(T2,A,T65,I8,I8)') "SPGR| NUMBER OF CORES AND SYMMETRIZED CORES:", &
     852           20 :                spgr%n_core, spgr%n_core_sym
     853           10 :             WRITE (spgr%iunit, '(T2,A,T65,I8,I8)') "SPGR| NUMBER OF SHELLS AND SYMMETRIZED SHELLS:", &
     854           20 :                spgr%n_shell, spgr%n_shell_sym
     855           10 :             IF (spgr%print_atoms) THEN
     856            5 :                WRITE (spgr%iunit, *) "SPGR| ACTIVE REDUCED SYMMETRY OPERATIONS:", spgr%lop
     857            1 :                WRITE (spgr%iunit, '(/,T2,A,A)') "----------------------------------------", &
     858            2 :                   "---------------------------------------"
     859            1 :                WRITE (spgr%iunit, '(T2,A,T34,A,T77,A)') "----", "EQUIVALENT ATOMS", "----"
     860            1 :                WRITE (spgr%iunit, '(T2,A,A)') "----------------------------------------", &
     861            2 :                   "---------------------------------------"
     862           25 :                DO i = 1, spgr%nparticle
     863          121 :                   DO j = 1, spgr%n_operations
     864           96 :                      WRITE (spgr%iunit, '(T2,A,T52,I8,I8,I8)') "SPGR| ATOM | SYMMETRY OPERATION | EQUIVALENT ATOM", &
     865          216 :                         i, j, spgr%eqatom(j, i)
     866              :                   END DO
     867              :                END DO
     868            1 :                WRITE (spgr%iunit, '(T2,A,A)') "----------------------------------------", &
     869            2 :                   "---------------------------------------"
     870            5 :                DO i = 1, spgr%n_operations
     871              :                   WRITE (spgr%iunit, '(T2,A,T46,i4,T51,3I10,/,T51,3I10,/,T51,3I10)') &
     872           52 :                      "SPGR| SYMMETRY OPERATION #:", i, (spgr%rotations(j, :, i), j=1, 3)
     873           17 :                   WRITE (spgr%iunit, '(T51,3F10.5)') spgr%translations(:, i)
     874              :                END DO
     875              :             END IF
     876              :          ELSE
     877            0 :             WRITE (spgr%iunit, "(T2,A)") "SPGLIB for Crystal Symmetry Information determination is not availale"
     878              :          END IF
     879              :       END IF
     880              : 
     881           20 :    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          544 :    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         7072 :       stress_tensor(:, :) = stress(:, :)*pascal*1.0E-9_dp
     901              : 
     902          544 :       IF (spgr%iunit > 0) THEN
     903              :          WRITE (UNIT=spgr%iunit, FMT='(/,T2,A)') &
     904          273 :             'SPGR STRESS| Symmetrized stress tensor [GPa]'
     905              :          WRITE (UNIT=spgr%iunit, FMT='(T2,A,T19,3(19X,A1))') &
     906          273 :             'SPGR STRESS|', 'x', 'y', 'z'
     907              :          WRITE (UNIT=spgr%iunit, FMT='(T2,A,T26,3(1X,ES19.11))') &
     908          273 :             'SPGR STRESS|      x', stress_tensor(1, 1:3)
     909              :          WRITE (UNIT=spgr%iunit, FMT='(T2,A,T26,3(1X,ES19.11))') &
     910          273 :             'SPGR STRESS|      y', stress_tensor(2, 1:3)
     911              :          WRITE (UNIT=spgr%iunit, FMT='(T2,A,T26,3(1X,ES19.11))') &
     912          273 :             'SPGR STRESS|      z', stress_tensor(3, 1:3)
     913              :          WRITE (UNIT=spgr%iunit, FMT='(T2,A,T66,ES20.11)') &
     914          273 :             'SPGR STRESS| 1/3 Trace', (stress_tensor(1, 1) + &
     915              :                                        stress_tensor(2, 2) + &
     916          546 :                                        stress_tensor(3, 3))/3.0_dp
     917              :          WRITE (UNIT=spgr%iunit, FMT='(T2,A,T66,ES20.11)') &
     918          273 :             'SPGR STRESS| Determinant', det_3x3(stress_tensor(1:3, 1), &
     919              :                                                 stress_tensor(1:3, 2), &
     920          546 :                                                 stress_tensor(1:3, 3))
     921          273 :          eigval(:) = 0.0_dp
     922          273 :          eigvec(:, :) = 0.0_dp
     923          273 :          CALL jacobi(stress_tensor, eigval, eigvec)
     924              :          WRITE (UNIT=spgr%iunit, FMT='(/,T2,A)') &
     925          273 :             'SPGR STRESS| Eigenvectors and eigenvalues of the symmetrized stress tensor [GPa]'
     926              :          WRITE (UNIT=spgr%iunit, FMT='(T2,A,T19,3(1X,I19))') &
     927          273 :             'SPGR STRESS|', 1, 2, 3
     928              :          WRITE (UNIT=spgr%iunit, FMT='(T2,A,T26,3(1X,ES19.11))') &
     929          273 :             'SPGR STRESS| Eigenvalues', eigval(1:3)
     930              :          WRITE (UNIT=spgr%iunit, FMT='(T2,A,T26,3(1X,F19.12))') &
     931          273 :             'SPGR STRESS|      x', eigvec(1, 1:3)
     932              :          WRITE (UNIT=spgr%iunit, FMT='(T2,A,T26,3(1X,F19.12))') &
     933          273 :             'SPGR STRESS|      y', eigvec(2, 1:3)
     934              :          WRITE (UNIT=spgr%iunit, FMT='(T2,A,T26,3(1X,F19.12))') &
     935          273 :             'SPGR STRESS|      z', eigvec(3, 1:3)
     936              :       END IF
     937              : 
     938          544 :    END SUBROUTINE spgr_write_stress_tensor
     939              : 
     940              : END MODULE space_groups
        

Generated by: LCOV version 2.0-1