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

Generated by: LCOV version 2.0-1