2008-08-22 23:53:34 +08:00
|
|
|
!
|
2010-01-10 21:22:09 +08:00
|
|
|
! Copyright (C) 2008-2010 Quantum ESPRESSO group
|
2008-08-22 23:53:34 +08:00
|
|
|
! This file is distributed under the terms of the
|
|
|
|
! GNU General Public License. See the file `License'
|
|
|
|
! in the root directory of the present distribution,
|
|
|
|
! or http://www.gnu.org/copyleft/gpl.txt .
|
|
|
|
!
|
|
|
|
!--------------------------------------------------------------------------
|
|
|
|
!
|
|
|
|
MODULE symme
|
2010-01-15 04:17:37 +08:00
|
|
|
|
2008-08-22 23:53:34 +08:00
|
|
|
USE kinds, ONLY : DP
|
2010-01-15 23:33:11 +08:00
|
|
|
USE cell_base, ONLY : at, bg
|
2010-02-13 04:57:55 +08:00
|
|
|
USE symm_base, ONLY : s, sname, ftau, nrot, nsym, t_rev, time_reversal,&
|
|
|
|
irt, invs, invsym
|
2008-08-22 23:53:34 +08:00
|
|
|
!
|
2010-02-13 04:57:55 +08:00
|
|
|
! ... Routines used for symmetrization
|
|
|
|
!
|
2008-08-22 23:53:34 +08:00
|
|
|
SAVE
|
2009-12-23 01:01:28 +08:00
|
|
|
PRIVATE
|
|
|
|
!
|
2010-01-15 15:36:54 +08:00
|
|
|
! General-purpose symmetrizaton routines
|
2010-01-10 21:22:09 +08:00
|
|
|
!
|
2010-02-13 04:57:55 +08:00
|
|
|
PUBLIC :: symscalar, symvector, symtensor, symmatrix, symv, &
|
2010-01-15 15:36:54 +08:00
|
|
|
symtensor3, symmatrix3, crys_to_cart, cart_to_crys
|
2010-01-10 21:22:09 +08:00
|
|
|
!
|
2010-01-07 00:54:57 +08:00
|
|
|
! For symmetrization in reciprocal space (all variables are private)
|
|
|
|
!
|
2010-01-10 21:22:09 +08:00
|
|
|
PUBLIC :: sym_rho_init, sym_rho, sym_rho_deallocate
|
2009-12-23 01:01:28 +08:00
|
|
|
!
|
2010-01-07 00:54:57 +08:00
|
|
|
LOGICAL :: &
|
2010-01-09 23:21:34 +08:00
|
|
|
no_rho_sym=.true. ! do not perform symetrization of charge density
|
2010-01-07 00:54:57 +08:00
|
|
|
INTEGER :: ngs ! number of symmetry-related G-vector shells
|
|
|
|
TYPE shell_type
|
|
|
|
INTEGER, POINTER :: vect(:)
|
|
|
|
END TYPE shell_type
|
|
|
|
! shell contains a list of symmetry-related G-vectors for each shell
|
|
|
|
TYPE(shell_type), ALLOCATABLE :: shell(:)
|
|
|
|
! Arrays used for parallel symmetrization
|
2009-12-23 01:01:28 +08:00
|
|
|
INTEGER, ALLOCATABLE :: sendcnt(:), recvcnt(:), sdispls(:), rdispls(:)
|
|
|
|
!
|
|
|
|
CONTAINS
|
2010-01-09 23:21:34 +08:00
|
|
|
!
|
|
|
|
LOGICAL FUNCTION rho_sym_needed ( )
|
2010-01-10 21:22:09 +08:00
|
|
|
!-----------------------------------------------------------------------
|
2010-01-09 23:21:34 +08:00
|
|
|
rho_sym_needed = .NOT. no_rho_sym
|
|
|
|
END FUNCTION rho_sym_needed
|
|
|
|
!
|
2010-01-10 21:22:09 +08:00
|
|
|
SUBROUTINE symscalar (nat, scalar)
|
|
|
|
!-----------------------------------------------------------------------
|
|
|
|
! Symmetrize a function f(na), na=atom index
|
|
|
|
!
|
|
|
|
IMPLICIT NONE
|
|
|
|
!
|
|
|
|
INTEGER, INTENT(IN) :: nat
|
|
|
|
REAL(DP), intent(INOUT) :: scalar(nat)
|
|
|
|
!
|
|
|
|
INTEGER :: isym
|
|
|
|
REAL(DP), ALLOCATABLE :: work (:)
|
|
|
|
|
|
|
|
IF (nsym == 1) RETURN
|
|
|
|
|
|
|
|
ALLOCATE (work(nat))
|
|
|
|
work(:) = 0.0_dp
|
|
|
|
DO isym = 1, nsym
|
|
|
|
work (:) = work (:) + scalar(irt(isym,:))
|
|
|
|
END DO
|
|
|
|
scalar(:) = work(:) / DBLE(nsym)
|
|
|
|
DEALLOCATE (work)
|
|
|
|
|
|
|
|
END SUBROUTINE symscalar
|
|
|
|
!
|
|
|
|
SUBROUTINE symvector (nat, vect)
|
|
|
|
!-----------------------------------------------------------------------
|
|
|
|
! Symmetrize a function f(i,na), i=cartesian component, na=atom index
|
|
|
|
! e.g. : forces (in cartesian axis)
|
|
|
|
!
|
|
|
|
IMPLICIT NONE
|
|
|
|
!
|
|
|
|
INTEGER, INTENT(IN) :: nat
|
|
|
|
REAL(DP), intent(INOUT) :: vect(3,nat)
|
|
|
|
!
|
|
|
|
INTEGER :: na, isym, nar
|
|
|
|
REAL(DP), ALLOCATABLE :: work (:,:)
|
|
|
|
!
|
|
|
|
IF (nsym == 1) RETURN
|
|
|
|
!
|
|
|
|
ALLOCATE (work(3,nat))
|
|
|
|
!
|
|
|
|
! bring vector to crystal axis
|
|
|
|
!
|
|
|
|
DO na = 1, nat
|
|
|
|
work(:,na) = vect(1,na)*at(1,:) + &
|
|
|
|
vect(2,na)*at(2,:) + &
|
|
|
|
vect(3,na)*at(3,:)
|
|
|
|
END DO
|
|
|
|
!
|
|
|
|
! symmetrize in crystal axis
|
|
|
|
!
|
|
|
|
vect (:,:) = 0.0_dp
|
|
|
|
DO na = 1, nat
|
|
|
|
DO isym = 1, nsym
|
|
|
|
nar = irt (isym, na)
|
|
|
|
vect (:, na) = vect (:, na) + &
|
|
|
|
s (:, 1, isym) * work (1, nar) + &
|
|
|
|
s (:, 2, isym) * work (2, nar) + &
|
|
|
|
s (:, 3, isym) * work (3, nar)
|
|
|
|
END DO
|
|
|
|
END DO
|
|
|
|
work (:,:) = vect (:,:) / DBLE(nsym)
|
|
|
|
!
|
|
|
|
! bring vector back to cartesian axis
|
|
|
|
!
|
|
|
|
DO na = 1, nat
|
|
|
|
vect(:,na) = work(1,na)*bg(:,1) + &
|
|
|
|
work(2,na)*bg(:,2) + &
|
|
|
|
work(3,na)*bg(:,3)
|
|
|
|
END DO
|
|
|
|
!
|
|
|
|
DEALLOCATE (work)
|
|
|
|
!
|
|
|
|
END SUBROUTINE symvector
|
2010-01-07 00:54:57 +08:00
|
|
|
!
|
2010-01-11 03:51:53 +08:00
|
|
|
SUBROUTINE symtensor (nat, tens)
|
|
|
|
!-----------------------------------------------------------------------
|
|
|
|
! Symmetrize a function f(i,j,na), i,j=cartesian components, na=atom index
|
|
|
|
! e.g. : effective charges (in cartesian axis)
|
|
|
|
!
|
|
|
|
IMPLICIT NONE
|
|
|
|
!
|
|
|
|
INTEGER, INTENT(IN) :: nat
|
|
|
|
REAL(DP), intent(INOUT) :: tens(3,3,nat)
|
|
|
|
!
|
|
|
|
INTEGER :: na, isym, nar, i,j,k,l
|
|
|
|
REAL(DP), ALLOCATABLE :: work (:,:,:)
|
|
|
|
!
|
|
|
|
IF (nsym == 1) RETURN
|
|
|
|
!
|
|
|
|
! bring tensor to crystal axis
|
|
|
|
!
|
2010-01-15 04:17:37 +08:00
|
|
|
DO na=1,nat
|
|
|
|
CALL cart_to_crys ( tens (:,:,na) )
|
2010-01-11 03:51:53 +08:00
|
|
|
END DO
|
|
|
|
!
|
|
|
|
! symmetrize in crystal axis
|
|
|
|
!
|
2010-01-15 04:17:37 +08:00
|
|
|
ALLOCATE (work(3,3,nat))
|
|
|
|
work (:,:,:) = 0.0_dp
|
2010-01-11 03:51:53 +08:00
|
|
|
DO na = 1, nat
|
|
|
|
DO isym = 1, nsym
|
|
|
|
nar = irt (isym, na)
|
|
|
|
DO i = 1, 3
|
|
|
|
DO j = 1, 3
|
|
|
|
DO k = 1, 3
|
|
|
|
DO l = 1, 3
|
2010-01-15 04:17:37 +08:00
|
|
|
work (i,j,na) = work (i,j,na) + &
|
|
|
|
s (i,k,isym) * s (j,l,isym) * tens (k,l,nar)
|
2010-01-11 03:51:53 +08:00
|
|
|
END DO
|
|
|
|
END DO
|
|
|
|
END DO
|
|
|
|
END DO
|
|
|
|
END DO
|
|
|
|
END DO
|
2010-01-15 04:17:37 +08:00
|
|
|
tens (:,:,:) = work (:,:,:) / DBLE(nsym)
|
|
|
|
DEALLOCATE (work)
|
2010-01-11 03:51:53 +08:00
|
|
|
!
|
|
|
|
! bring tensor back to cartesian axis
|
|
|
|
!
|
2010-01-15 04:17:37 +08:00
|
|
|
DO na=1,nat
|
|
|
|
CALL crys_to_cart ( tens (:,:,na) )
|
2010-01-11 03:51:53 +08:00
|
|
|
END DO
|
|
|
|
!
|
|
|
|
!
|
|
|
|
END SUBROUTINE symtensor
|
|
|
|
!
|
2010-02-13 04:57:55 +08:00
|
|
|
!-----------------------------------------------------------------------
|
|
|
|
SUBROUTINE symv ( vect)
|
|
|
|
!--------------------------------------------------------------------
|
|
|
|
!
|
|
|
|
! Symmetrize a vector f(i), i=cartesian components
|
|
|
|
! The vector is supposed to be axial: inversion does not change it.
|
|
|
|
! Time reversal changes its sign. Note that only groups compatible with
|
|
|
|
! a finite magnetization give a nonzero output vector.
|
|
|
|
!
|
|
|
|
IMPLICIT NONE
|
|
|
|
!
|
|
|
|
REAL (DP), INTENT(inout) :: vect(3) ! the vector to rotate
|
|
|
|
!
|
|
|
|
integer :: isym
|
|
|
|
real(DP) :: work (3), segno
|
|
|
|
!
|
|
|
|
IF (nsym == 1) RETURN
|
|
|
|
!
|
|
|
|
! bring vector to crystal axis
|
|
|
|
!
|
|
|
|
work(:) = vect(1)*at(1,:) + vect(2)*at(2,:) + vect(3)*at(3,:)
|
|
|
|
vect = work
|
2010-05-07 22:42:00 +08:00
|
|
|
work=0.0_DP
|
2010-02-13 04:57:55 +08:00
|
|
|
do isym = 1, nsym
|
|
|
|
segno=1.0_DP
|
|
|
|
IF (sname(isym)(1:3)=='inv') segno=-1.0_DP
|
|
|
|
IF (t_rev(isym)==1) segno=-1.0_DP*segno
|
|
|
|
work (:) = work (:) + segno * &
|
|
|
|
s (:, 1, isym) * vect (1) + &
|
|
|
|
s (:, 2, isym) * vect (2) + &
|
|
|
|
s (:, 3, isym) * vect (3)
|
|
|
|
enddo
|
|
|
|
work=work/nsym
|
|
|
|
!
|
|
|
|
! And back in cartesian coordinates.
|
|
|
|
!
|
|
|
|
vect(:) = work(1) * bg(:,1) + work(2) * bg(:,2) + work(3) * bg(:,3)
|
|
|
|
!
|
|
|
|
end subroutine symv
|
|
|
|
!
|
2010-01-12 06:48:10 +08:00
|
|
|
SUBROUTINE symmatrix ( matr )
|
|
|
|
!-----------------------------------------------------------------------
|
|
|
|
! Symmetrize a function f(i,j), i,j=cartesian components
|
|
|
|
! e.g. : stress, dielectric tensor (in cartesian axis)
|
|
|
|
!
|
|
|
|
IMPLICIT NONE
|
|
|
|
!
|
|
|
|
REAL(DP), intent(INOUT) :: matr(3,3)
|
|
|
|
!
|
|
|
|
INTEGER :: isym, i,j,k,l
|
|
|
|
REAL(DP) :: work (3,3)
|
|
|
|
!
|
|
|
|
IF (nsym == 1) RETURN
|
|
|
|
!
|
|
|
|
! bring matrix to crystal axis
|
|
|
|
!
|
2010-01-15 15:36:54 +08:00
|
|
|
CALL cart_to_crys ( matr )
|
2010-01-15 04:17:37 +08:00
|
|
|
!
|
|
|
|
! symmetrize in crystal axis
|
|
|
|
!
|
2010-01-12 06:48:10 +08:00
|
|
|
work (:,:) = 0.0_dp
|
2010-01-15 04:17:37 +08:00
|
|
|
DO isym = 1, nsym
|
|
|
|
DO i = 1, 3
|
|
|
|
DO j = 1, 3
|
|
|
|
DO k = 1, 3
|
|
|
|
DO l = 1, 3
|
|
|
|
work (i,j) = work (i,j) + &
|
|
|
|
s (i,k,isym) * s (j,l,isym) * matr (k,l)
|
|
|
|
END DO
|
2010-01-12 06:48:10 +08:00
|
|
|
END DO
|
|
|
|
END DO
|
|
|
|
END DO
|
|
|
|
END DO
|
2010-01-15 04:17:37 +08:00
|
|
|
matr (:,:) = work (:,:) / DBLE(nsym)
|
2010-01-12 06:48:10 +08:00
|
|
|
!
|
2010-01-15 04:17:37 +08:00
|
|
|
! bring matrix back to cartesian axis
|
2010-01-12 06:48:10 +08:00
|
|
|
!
|
2010-01-15 15:36:54 +08:00
|
|
|
CALL crys_to_cart ( matr )
|
2010-01-15 04:17:37 +08:00
|
|
|
!
|
|
|
|
END SUBROUTINE symmatrix
|
|
|
|
!
|
|
|
|
SUBROUTINE symmatrix3 ( mat3 )
|
|
|
|
!-----------------------------------------------------------------------
|
|
|
|
!
|
|
|
|
! Symmetrize a function f(i,j,k), i,j,k=cartesian components
|
|
|
|
! e.g. : nonlinear susceptibility
|
2010-01-15 23:33:11 +08:00
|
|
|
! BEWARE: input in crystal axis, output in cartesian axis
|
2010-01-15 04:17:37 +08:00
|
|
|
!
|
|
|
|
IMPLICIT NONE
|
|
|
|
!
|
|
|
|
REAL(DP), intent(INOUT) :: mat3(3,3,3)
|
|
|
|
!
|
|
|
|
INTEGER :: isym, i,j,k,l,m,n
|
|
|
|
REAL(DP) :: work (3,3,3)
|
|
|
|
!
|
|
|
|
IF (nsym == 1) RETURN
|
|
|
|
!
|
|
|
|
work (:,:,:) = 0.0_dp
|
2010-01-12 06:48:10 +08:00
|
|
|
DO isym = 1, nsym
|
|
|
|
DO i = 1, 3
|
|
|
|
DO j = 1, 3
|
|
|
|
DO k = 1, 3
|
|
|
|
DO l = 1, 3
|
2010-01-15 04:17:37 +08:00
|
|
|
DO m = 1, 3
|
|
|
|
DO n = 1, 3
|
|
|
|
work (i, j, k) = work (i, j, k) + &
|
|
|
|
s (i, l, isym) * s (j, m, isym) * &
|
|
|
|
s (k, n, isym) * mat3 (l, m, n)
|
|
|
|
END DO
|
|
|
|
END DO
|
2010-01-12 06:48:10 +08:00
|
|
|
END DO
|
|
|
|
END DO
|
|
|
|
END DO
|
|
|
|
END DO
|
|
|
|
END DO
|
2010-01-15 04:17:37 +08:00
|
|
|
mat3 = work/ DBLE(nsym)
|
2010-01-12 06:48:10 +08:00
|
|
|
!
|
2010-01-15 23:33:11 +08:00
|
|
|
! Bring to cartesian axis
|
|
|
|
!
|
|
|
|
CALL crys_to_cart_mat3 ( mat3 )
|
|
|
|
!
|
2010-01-15 04:17:37 +08:00
|
|
|
END SUBROUTINE symmatrix3
|
|
|
|
!
|
|
|
|
!
|
|
|
|
SUBROUTINE symtensor3 (nat, tens3 )
|
|
|
|
!-----------------------------------------------------------------------
|
|
|
|
! Symmetrize a function f(i,j,k, na), i,j,k=cartesian, na=atom index
|
|
|
|
! e.g. : raman tensor
|
2010-01-15 23:33:11 +08:00
|
|
|
! BEWARE: input in crystal axis, output in cartesian axis
|
2010-01-15 04:17:37 +08:00
|
|
|
!
|
|
|
|
IMPLICIT NONE
|
|
|
|
!
|
|
|
|
INTEGER, INTENT(IN) :: nat
|
|
|
|
REAL(DP), intent(INOUT) :: tens3(3,3,3,nat)
|
|
|
|
!
|
|
|
|
INTEGER :: na, isym, nar, i,j,k,l,n,m
|
|
|
|
REAL(DP), ALLOCATABLE :: work (:,:,:,:)
|
|
|
|
!
|
|
|
|
IF (nsym == 1) RETURN
|
|
|
|
!
|
|
|
|
! symmetrize in crystal axis
|
|
|
|
!
|
|
|
|
ALLOCATE (work(3,3,3,nat))
|
|
|
|
work (:,:,:,:) = 0.0_dp
|
|
|
|
DO na = 1, nat
|
|
|
|
DO isym = 1, nsym
|
|
|
|
nar = irt (isym, na)
|
|
|
|
DO i = 1, 3
|
|
|
|
DO j = 1, 3
|
|
|
|
DO k = 1, 3
|
|
|
|
DO l = 1, 3
|
|
|
|
DO m =1, 3
|
|
|
|
DO n =1, 3
|
|
|
|
work (i, j, k, na) = work (i, j, k, na) + &
|
|
|
|
s (i, l, isym) * s (j, m, isym) * &
|
|
|
|
s (k, n, isym) * tens3 (l, m, n, nar)
|
|
|
|
END DO
|
|
|
|
END DO
|
|
|
|
END DO
|
|
|
|
END DO
|
|
|
|
END DO
|
|
|
|
END DO
|
|
|
|
END DO
|
|
|
|
END DO
|
|
|
|
tens3 (:,:,:,:) = work(:,:,:,:) / DBLE (nsym)
|
|
|
|
DEALLOCATE (work)
|
2010-01-12 06:48:10 +08:00
|
|
|
!
|
2010-01-15 23:33:11 +08:00
|
|
|
! Bring to cartesian axis
|
|
|
|
!
|
|
|
|
DO na = 1, nat
|
|
|
|
CALL crys_to_cart_mat3 ( tens3(:,:,:,na) )
|
|
|
|
END DO
|
2010-01-15 04:17:37 +08:00
|
|
|
!
|
2010-01-15 23:33:11 +08:00
|
|
|
END SUBROUTINE symtensor3
|
|
|
|
!
|
|
|
|
! Routines for crystal to cartesian axis conversion
|
|
|
|
!
|
|
|
|
!INTERFACE cart_to_crys
|
|
|
|
! MODULE PROCEDURE cart_to_crys_mat, cart_to_crys_mat3
|
|
|
|
!END INTERFACE
|
|
|
|
!INTERFACE crys_to_cart
|
|
|
|
! MODULE PROCEDURE crys_to_cart
|
|
|
|
!END INTERFACE
|
|
|
|
!
|
2010-01-15 04:17:37 +08:00
|
|
|
SUBROUTINE cart_to_crys ( matr )
|
2010-01-15 23:33:11 +08:00
|
|
|
!-----------------------------------------------------------------------
|
2010-01-15 04:17:37 +08:00
|
|
|
!
|
|
|
|
IMPLICIT NONE
|
|
|
|
!
|
|
|
|
REAL(DP), intent(INOUT) :: matr(3,3)
|
|
|
|
!
|
|
|
|
REAL(DP) :: work(3,3)
|
|
|
|
INTEGER :: i,j,k,l
|
|
|
|
!
|
|
|
|
work(:,:) = 0.0_dp
|
2010-01-12 06:48:10 +08:00
|
|
|
DO i = 1, 3
|
|
|
|
DO j = 1, 3
|
|
|
|
DO k = 1, 3
|
|
|
|
DO l = 1, 3
|
2010-01-15 04:17:37 +08:00
|
|
|
work(i,j) = work(i,j) + matr(k,l) * at(k,i) * at(l,j)
|
2010-01-12 06:48:10 +08:00
|
|
|
END DO
|
|
|
|
END DO
|
|
|
|
END DO
|
|
|
|
END DO
|
|
|
|
!
|
2010-01-15 04:17:37 +08:00
|
|
|
matr(:,:) = work(:,:)
|
|
|
|
!
|
|
|
|
END SUBROUTINE cart_to_crys
|
2010-01-12 06:48:10 +08:00
|
|
|
!
|
2010-01-15 04:17:37 +08:00
|
|
|
SUBROUTINE crys_to_cart ( matr )
|
2010-01-15 23:33:11 +08:00
|
|
|
!-----------------------------------------------------------------------
|
2010-01-15 04:17:37 +08:00
|
|
|
!
|
|
|
|
IMPLICIT NONE
|
|
|
|
!
|
|
|
|
REAL(DP), intent(INOUT) :: matr(3,3)
|
|
|
|
!
|
|
|
|
REAL(DP) :: work(3,3)
|
|
|
|
INTEGER :: i,j,k,l
|
|
|
|
!
|
|
|
|
work(:,:) = 0.0_dp
|
|
|
|
DO i = 1, 3
|
|
|
|
DO j = 1, 3
|
|
|
|
DO k = 1, 3
|
|
|
|
DO l = 1, 3
|
|
|
|
work(i,j) = work(i,j) + &
|
|
|
|
matr(k,l) * bg(i,k) * bg(j,l)
|
|
|
|
END DO
|
|
|
|
END DO
|
|
|
|
END DO
|
|
|
|
END DO
|
|
|
|
matr(:,:) = work(:,:)
|
|
|
|
!
|
|
|
|
END SUBROUTINE crys_to_cart
|
2010-01-15 23:33:11 +08:00
|
|
|
!
|
|
|
|
SUBROUTINE crys_to_cart_mat3 ( mat3 )
|
|
|
|
!-----------------------------------------------------------------------
|
|
|
|
!
|
|
|
|
IMPLICIT NONE
|
|
|
|
!
|
|
|
|
REAL(DP), intent(INOUT) :: mat3(3,3,3)
|
|
|
|
!
|
|
|
|
REAL(DP) :: work(3,3,3)
|
|
|
|
INTEGER :: i,j,k,l,m,n
|
|
|
|
!
|
|
|
|
work(:,:,:) = 0.0_dp
|
|
|
|
DO i = 1, 3
|
|
|
|
DO j = 1, 3
|
|
|
|
DO k = 1, 3
|
|
|
|
DO l = 1, 3
|
|
|
|
DO m = 1, 3
|
|
|
|
DO n = 1, 3
|
|
|
|
work (i, j, k) = work (i, j, k) + &
|
|
|
|
mat3 (l, m, n) * bg (i, l) * bg (j, m) * bg (k, n)
|
|
|
|
END DO
|
|
|
|
END DO
|
|
|
|
END DO
|
|
|
|
END DO
|
|
|
|
END DO
|
|
|
|
END DO
|
|
|
|
mat3(:,:,:) = work (:,:,:)
|
|
|
|
!
|
|
|
|
END SUBROUTINE crys_to_cart_mat3
|
|
|
|
!
|
|
|
|
! G-space symmetrization
|
|
|
|
!
|
2010-01-07 00:54:57 +08:00
|
|
|
SUBROUTINE sym_rho_init ( gamma_only )
|
2009-12-23 01:01:28 +08:00
|
|
|
!-----------------------------------------------------------------------
|
|
|
|
!
|
2010-01-07 00:54:57 +08:00
|
|
|
! Initialize arrays needed for symmetrization in reciprocal space
|
2009-12-23 01:01:28 +08:00
|
|
|
!
|
2010-01-07 00:54:57 +08:00
|
|
|
USE gvect, ONLY : ngm, g
|
|
|
|
!
|
|
|
|
LOGICAL, INTENT(IN) :: gamma_only
|
|
|
|
!
|
|
|
|
no_rho_sym = gamma_only .OR. (nsym==1)
|
|
|
|
IF (no_rho_sym) RETURN
|
|
|
|
#ifdef __PARA
|
|
|
|
CALL sym_rho_init_para ( )
|
|
|
|
#else
|
|
|
|
CALL sym_rho_init_shells( ngm, g )
|
|
|
|
#endif
|
|
|
|
!
|
|
|
|
END SUBROUTINE sym_rho_init
|
|
|
|
!
|
2009-12-23 01:01:28 +08:00
|
|
|
#ifdef __PARA
|
2010-01-07 00:54:57 +08:00
|
|
|
!
|
|
|
|
SUBROUTINE sym_rho_init_para ( )
|
|
|
|
!-----------------------------------------------------------------------
|
|
|
|
!
|
|
|
|
! Initialize arrays needed for parallel symmetrization
|
|
|
|
!
|
2009-12-23 01:01:28 +08:00
|
|
|
USE mp_global, ONLY : nproc_pool, me_pool, intra_pool_comm
|
|
|
|
USE parallel_include
|
2010-01-07 00:54:57 +08:00
|
|
|
USE gvect, ONLY : ngm, gcutm, g, gg
|
2009-12-23 01:01:28 +08:00
|
|
|
!
|
2010-01-07 00:54:57 +08:00
|
|
|
IMPLICIT NONE
|
2009-12-23 01:01:28 +08:00
|
|
|
!
|
2010-01-07 00:54:57 +08:00
|
|
|
REAL(DP), PARAMETER :: twothirds = 0.6666666666666666_dp
|
|
|
|
REAL(DP), ALLOCATABLE :: gcut_(:), g_(:,:)
|
|
|
|
INTEGER :: np, ig, ngloc, ngpos, ierr, ngm_
|
2009-12-23 01:01:28 +08:00
|
|
|
!
|
|
|
|
ALLOCATE ( sendcnt(nproc_pool), recvcnt(nproc_pool), &
|
|
|
|
sdispls(nproc_pool), rdispls(nproc_pool) )
|
|
|
|
ALLOCATE ( gcut_(nproc_pool) )
|
|
|
|
!
|
|
|
|
! the gcut_ cutoffs are estimated in such a way that there is an similar
|
|
|
|
! number of G-vectors in each shell gcut_(i) < G^2 < gcut_(i+1)
|
|
|
|
!
|
|
|
|
DO np = 1, nproc_pool
|
|
|
|
gcut_(np) = gcutm * np**twothirds/nproc_pool**twothirds
|
|
|
|
END DO
|
|
|
|
!
|
|
|
|
! find the number of G-vectors in each shell (defined as above)
|
|
|
|
! beware: will work only if G-vectors are in order of increasing |G|
|
|
|
|
!
|
|
|
|
ngpos=0
|
|
|
|
DO np = 1, nproc_pool
|
|
|
|
sdispls(np) = ngpos
|
|
|
|
ngloc=0
|
|
|
|
DO ig=ngpos+1,ngm
|
|
|
|
IF ( gg(ig) > gcut_(np) ) EXIT
|
|
|
|
ngloc = ngloc+1
|
|
|
|
END DO
|
|
|
|
IF ( ngloc < 1 ) CALL infomsg('sym_rho_init', &
|
|
|
|
'likely internal error: no G-vectors found')
|
|
|
|
sendcnt(np) = ngloc
|
|
|
|
ngpos = ngpos + ngloc
|
|
|
|
IF ( ngpos > ngm ) &
|
|
|
|
CALL errore('sym_rho','internal error: too many G-vectors', ngpos)
|
|
|
|
END DO
|
|
|
|
IF ( ngpos /= ngm .OR. ngpos /= SUM (sendcnt)) &
|
|
|
|
CALL errore('sym_rho_init', &
|
|
|
|
'internal error: inconsistent number of G-vectors', ngpos)
|
|
|
|
DEALLOCATE ( gcut_ )
|
|
|
|
!
|
|
|
|
! sendcnt(i) = n_j(i) = number of G-vectors in shell i for processor j (this)
|
|
|
|
! sdispls(i) = \sum_{k=1}^i n_j(k) = starting position of shell i for proc j
|
|
|
|
! we need the number and positions of G-vector shells for other processors
|
|
|
|
!
|
|
|
|
CALL mpi_alltoall( sendcnt, 1, MPI_INTEGER, recvcnt, 1, MPI_INTEGER, &
|
|
|
|
intra_pool_comm, ierr)
|
|
|
|
!
|
|
|
|
rdispls(1) = 0
|
|
|
|
DO np = 2, nproc_pool
|
|
|
|
rdispls(np) = rdispls(np-1)+ recvcnt(np-1)
|
|
|
|
END DO
|
|
|
|
!
|
|
|
|
! recvcnt(i) = n_i(j) = number of G-vectors in shell j for processor i
|
|
|
|
! rdispls(i) = \sum_{k=1}^i n_k(j) = start.pos. of shell j for proc i
|
|
|
|
!
|
2010-01-07 00:54:57 +08:00
|
|
|
! now collect G-vector shells on each processor
|
|
|
|
!
|
|
|
|
ngm_ = SUM(recvcnt)
|
|
|
|
ALLOCATE (g_(3,ngm_))
|
|
|
|
! remember that G-vectors have 3 components
|
|
|
|
sendcnt(:) = 3*sendcnt(:)
|
|
|
|
recvcnt(:) = 3*recvcnt(:)
|
|
|
|
sdispls(:) = 3*sdispls(:)
|
|
|
|
rdispls(:) = 3*rdispls(:)
|
|
|
|
CALL mpi_alltoallv ( g , sendcnt, sdispls, MPI_DOUBLE_PRECISION, &
|
|
|
|
g_, recvcnt, rdispls, MPI_DOUBLE_PRECISION, &
|
|
|
|
intra_pool_comm, ierr)
|
|
|
|
sendcnt(:) = sendcnt(:)/3
|
|
|
|
recvcnt(:) = recvcnt(:)/3
|
|
|
|
sdispls(:) = sdispls(:)/3
|
|
|
|
rdispls(:) = rdispls(:)/3
|
|
|
|
!
|
|
|
|
! find shells of symetry-related G-vectors
|
|
|
|
!
|
|
|
|
CALL sym_rho_init_shells( ngm_, g_ )
|
|
|
|
!
|
|
|
|
DEALLOCATE (g_)
|
|
|
|
!
|
|
|
|
END SUBROUTINE sym_rho_init_para
|
|
|
|
!
|
2009-12-23 01:01:28 +08:00
|
|
|
#endif
|
2010-01-07 00:54:57 +08:00
|
|
|
!
|
|
|
|
SUBROUTINE sym_rho_init_shells ( ngm_, g_ )
|
|
|
|
!-----------------------------------------------------------------------
|
|
|
|
!
|
|
|
|
! Initialize G-vector shells needed for symmetrization
|
|
|
|
!
|
|
|
|
IMPLICIT NONE
|
|
|
|
!
|
|
|
|
INTEGER, INTENT(IN) :: ngm_
|
|
|
|
REAL(DP), INTENT(IN) :: g_(3,ngm_)
|
|
|
|
!
|
|
|
|
LOGICAL, ALLOCATABLE :: done(:)
|
|
|
|
INTEGER, ALLOCATABLE :: n(:,:)
|
|
|
|
INTEGER :: i,j,is,ig, ng, sn(3), gshell(3,48)
|
|
|
|
LOGICAL :: found
|
|
|
|
!
|
|
|
|
ngs = 0
|
|
|
|
! shell should be allocated to the number of symmetry shells
|
|
|
|
! since this is unknown, we use the number of all G-vectors
|
|
|
|
ALLOCATE ( shell(ngm_) )
|
|
|
|
ALLOCATE ( done(ngm_), n(3,ngm_) )
|
|
|
|
DO ig=1,ngm_
|
|
|
|
!
|
|
|
|
done(ig) = .false.
|
|
|
|
! G-vectors are stored as integer indices in crystallographic axis:
|
|
|
|
! G = n(1)*at(1) + n(2)*at(2) + n(3)*at(3)
|
|
|
|
n(:,ig) = nint ( at(1,:)*g_(1,ig) + at(2,:)*g_(2,ig) + at(3,:)*g_(3,ig) )
|
|
|
|
!
|
2010-01-10 16:29:36 +08:00
|
|
|
NULLIFY(shell(ig)%vect)
|
|
|
|
!
|
2010-01-07 00:54:57 +08:00
|
|
|
END DO
|
|
|
|
!
|
|
|
|
DO ig=1,ngm_
|
|
|
|
!
|
|
|
|
IF ( done(ig) ) CYCLE
|
|
|
|
!
|
|
|
|
! we start a new shell of symmetry-equivalent G-vectors
|
|
|
|
ngs = ngs+1
|
|
|
|
! ng: counter on G-vectors in this shell
|
|
|
|
ng = 0
|
|
|
|
DO is=1,nsym
|
|
|
|
! integer indices for rotated G-vector
|
|
|
|
sn(:)=s(:,1,is)*n(1,ig)+s(:,2,is)*n(2,ig)+s(:,3,is)*n(3,ig)
|
|
|
|
found = .false.
|
|
|
|
! check if this rotated G-vector is equivalent to any other
|
|
|
|
! vector already present in this shell
|
|
|
|
shelloop: DO i=1,ng
|
|
|
|
found = ( sn(1)==gshell(1,i) .and. &
|
|
|
|
sn(2)==gshell(2,i) .and. &
|
|
|
|
sn(3)==gshell(3,i) )
|
|
|
|
if (found) exit shelloop
|
|
|
|
END DO shelloop
|
|
|
|
IF ( .not. found ) THEN
|
|
|
|
! add rotated G-vector to this shell
|
|
|
|
ng = ng + 1
|
|
|
|
IF (ng > 48) CALL errore('sym_rho_init_shell','internal error',48)
|
|
|
|
gshell(:,ng) = sn(:)
|
|
|
|
END IF
|
|
|
|
END DO
|
|
|
|
! there are ng vectors gshell in shell ngs
|
|
|
|
! now we have to locate them in the list of G-vectors
|
|
|
|
ALLOCATE ( shell(ngs)%vect(ng))
|
|
|
|
DO i=1,ng
|
|
|
|
gloop: DO j=ig,ngm_
|
|
|
|
IF (done(j)) CYCLE gloop
|
|
|
|
found = ( gshell(1,i)==n(1,j) .and. &
|
|
|
|
gshell(2,i)==n(2,j) .and. &
|
|
|
|
gshell(3,i)==n(3,j) )
|
|
|
|
IF ( found ) THEN
|
|
|
|
done(j)=.true.
|
|
|
|
shell(ngs)%vect(i) = j
|
|
|
|
EXIT gloop
|
|
|
|
END IF
|
|
|
|
END DO gloop
|
|
|
|
IF (.not. found) CALL errore('sym_rho_init_shell','lone vector',i)
|
|
|
|
END DO
|
|
|
|
!
|
|
|
|
END DO
|
|
|
|
DEALLOCATE ( n, done )
|
|
|
|
|
|
|
|
END SUBROUTINE sym_rho_init_shells
|
2009-12-23 01:01:28 +08:00
|
|
|
!
|
|
|
|
!-----------------------------------------------------------------------
|
2010-01-07 00:54:57 +08:00
|
|
|
SUBROUTINE sym_rho (nspin, rhog)
|
2009-12-23 01:01:28 +08:00
|
|
|
!-----------------------------------------------------------------------
|
|
|
|
!
|
|
|
|
! Symmetrize the charge density rho in reciprocal space
|
|
|
|
! Distributed parallel algorithm: collects entire shells of G-vectors
|
|
|
|
! and corresponding rho(G), calls sym_rho_serial to perform the
|
|
|
|
! symmetrization, re-distributed rho(G) into original ordering
|
|
|
|
! rhog(ngm,nspin) components of rho: rhog(ig) = rho(G(:,ig))
|
|
|
|
! unsymmetrized on input, symmetrized on output
|
|
|
|
! nspin=1,2,4 unpolarized, LSDA, non-colinear magnetism
|
|
|
|
!
|
|
|
|
USE constants, ONLY : eps8, eps6
|
2010-01-07 00:54:57 +08:00
|
|
|
USE gvect, ONLY : ngm, g
|
2009-12-23 01:01:28 +08:00
|
|
|
#ifdef __PARA
|
|
|
|
USE parallel_include
|
|
|
|
USE mp_global, ONLY : nproc_pool, me_pool, intra_pool_comm
|
|
|
|
#endif
|
|
|
|
!
|
2010-01-07 00:54:57 +08:00
|
|
|
IMPLICIT NONE
|
2009-12-23 01:01:28 +08:00
|
|
|
!
|
|
|
|
INTEGER, INTENT(IN) :: nspin
|
2010-01-07 00:54:57 +08:00
|
|
|
COMPLEX(DP), INTENT(INOUT) :: rhog(ngm,nspin)
|
2009-12-23 01:01:28 +08:00
|
|
|
!
|
2010-01-07 00:54:57 +08:00
|
|
|
REAL(DP), allocatable :: g0(:,:), g_(:,:), gg_(:)
|
|
|
|
REAL(DP) :: gg0_, gg1_
|
|
|
|
COMPLEX(DP), allocatable :: rhog_(:,:)
|
|
|
|
INTEGER :: is, ig, igl, np, ierr, ngm_
|
2009-12-23 01:01:28 +08:00
|
|
|
!
|
2010-01-07 00:54:57 +08:00
|
|
|
IF ( no_rho_sym) RETURN
|
2009-12-23 01:01:28 +08:00
|
|
|
#ifndef __PARA
|
|
|
|
!
|
2010-01-07 00:54:57 +08:00
|
|
|
CALL sym_rho_serial ( ngm, g, nspin, rhog )
|
2009-12-23 01:01:28 +08:00
|
|
|
!
|
|
|
|
#else
|
|
|
|
!
|
|
|
|
! we transpose the matrix of G-vectors and their coefficients
|
|
|
|
!
|
|
|
|
ngm_ = SUM(recvcnt)
|
|
|
|
ALLOCATE (rhog_(ngm_,nspin),g_(3,ngm_))
|
|
|
|
DO is=1,nspin
|
|
|
|
CALL mpi_alltoallv (rhog (1,is) , sendcnt, sdispls, MPI_DOUBLE_COMPLEX,&
|
|
|
|
rhog_(1,is), recvcnt, rdispls, MPI_DOUBLE_COMPLEX, &
|
|
|
|
intra_pool_comm, ierr)
|
|
|
|
END DO
|
|
|
|
! remember that G-vectors have 3 components
|
|
|
|
sendcnt(:) = 3*sendcnt(:)
|
|
|
|
recvcnt(:) = 3*recvcnt(:)
|
|
|
|
sdispls(:) = 3*sdispls(:)
|
|
|
|
rdispls(:) = 3*rdispls(:)
|
|
|
|
CALL mpi_alltoallv ( g , sendcnt, sdispls, MPI_DOUBLE_PRECISION, &
|
|
|
|
g_, recvcnt, rdispls, MPI_DOUBLE_PRECISION, &
|
|
|
|
intra_pool_comm, ierr)
|
|
|
|
!
|
|
|
|
! Now symmetrize
|
|
|
|
!
|
2010-01-07 00:54:57 +08:00
|
|
|
CALL sym_rho_serial ( ngm_, g_, nspin, rhog_ )
|
2009-12-23 01:01:28 +08:00
|
|
|
!
|
2010-01-07 00:54:57 +08:00
|
|
|
DEALLOCATE ( g_ )
|
2009-12-23 01:01:28 +08:00
|
|
|
!
|
2010-01-07 00:54:57 +08:00
|
|
|
! bring symmetrized rho(G) back to original distributed form
|
2009-12-23 01:01:28 +08:00
|
|
|
!
|
|
|
|
sendcnt(:) = sendcnt(:)/3
|
|
|
|
recvcnt(:) = recvcnt(:)/3
|
|
|
|
sdispls(:) = sdispls(:)/3
|
|
|
|
rdispls(:) = rdispls(:)/3
|
|
|
|
DO is = 1, nspin
|
|
|
|
CALL mpi_alltoallv (rhog_(1,is), recvcnt, rdispls, MPI_DOUBLE_COMPLEX, &
|
|
|
|
rhog (1,is), sendcnt, sdispls, MPI_DOUBLE_COMPLEX, &
|
|
|
|
intra_pool_comm, ierr)
|
|
|
|
END DO
|
|
|
|
DEALLOCATE ( rhog_ )
|
2010-01-07 00:54:57 +08:00
|
|
|
#endif
|
2009-12-23 01:01:28 +08:00
|
|
|
!
|
|
|
|
RETURN
|
|
|
|
END SUBROUTINE sym_rho
|
|
|
|
!
|
|
|
|
!-----------------------------------------------------------------------
|
2010-01-07 00:54:57 +08:00
|
|
|
SUBROUTINE sym_rho_serial ( ngm_, g_, nspin_, rhog_ )
|
2009-12-23 01:01:28 +08:00
|
|
|
!-----------------------------------------------------------------------
|
|
|
|
!
|
|
|
|
! symmetrize the charge density rho in reciprocal space
|
|
|
|
! Serial algorithm - requires in input:
|
2010-01-07 00:54:57 +08:00
|
|
|
! g_(3,ngm_) list of G-vectors
|
2009-12-23 01:01:28 +08:00
|
|
|
! nspin_ number of spin components to be symmetrized
|
|
|
|
! rhog_(ngm_,nspin_) rho in reciprocal space: rhog_(ig) = rho(G(:,ig))
|
|
|
|
! unsymmetrized on input, symmetrized on output
|
|
|
|
!
|
|
|
|
USE kinds
|
|
|
|
USE constants, ONLY : tpi
|
|
|
|
USE gvect, ONLY : nr1,nr2,nr3
|
|
|
|
!
|
|
|
|
IMPLICIT NONE
|
|
|
|
!
|
2010-01-07 00:54:57 +08:00
|
|
|
INTEGER, INTENT (IN) :: ngm_, nspin_
|
2009-12-23 01:01:28 +08:00
|
|
|
REAL(DP) , INTENT (IN) :: g_( 3, ngm_ )
|
|
|
|
COMPLEX(DP) , INTENT (INOUT) :: rhog_( ngm_, nspin_ )
|
|
|
|
!
|
2010-01-07 00:54:57 +08:00
|
|
|
REAL(DP), ALLOCATABLE :: g0(:,:)
|
|
|
|
REAL(DP) :: sg(3), ft(3,48), arg
|
|
|
|
COMPLEX(DP) :: fact, rhosum(2), mag(3), magrot(3), magsum(3)
|
|
|
|
INTEGER :: irot(48), ig, isg, igl, ng, ns, nspin_lsda, is
|
|
|
|
LOGICAL, ALLOCATABLE :: done(:)
|
|
|
|
LOGICAL :: non_symmorphic(48)
|
2009-12-23 01:01:28 +08:00
|
|
|
!
|
|
|
|
! convert fractional translations to a.u.
|
|
|
|
!
|
|
|
|
DO ns=1,nsym
|
|
|
|
non_symmorphic(ns) = (ftau(1,ns)/=0 .OR. ftau(2,ns)/=0 .OR. ftau(3,ns)/=0)
|
|
|
|
IF ( non_symmorphic(ns) ) ft(:,ns) = at(:,1)*ftau(1,ns)/nr1 + &
|
|
|
|
at(:,2)*ftau(2,ns)/nr2 + &
|
|
|
|
at(:,3)*ftau(3,ns)/nr3
|
|
|
|
END DO
|
|
|
|
!
|
|
|
|
IF ( nspin_ == 4 ) THEN
|
2010-01-07 00:54:57 +08:00
|
|
|
nspin_lsda = 1
|
2009-12-23 01:01:28 +08:00
|
|
|
!
|
|
|
|
ELSE IF ( nspin_ == 1 .OR. nspin_ == 2 ) THEN
|
2010-01-07 00:54:57 +08:00
|
|
|
nspin_lsda = nspin_
|
2009-12-23 01:01:28 +08:00
|
|
|
ELSE
|
|
|
|
CALL errore('sym_rho_serial','incorrect value of nspin',nspin_)
|
|
|
|
END IF
|
|
|
|
!
|
|
|
|
! scan shells of G-vectors
|
|
|
|
!
|
2010-01-07 00:54:57 +08:00
|
|
|
DO igl=1, ngs
|
2009-12-23 01:01:28 +08:00
|
|
|
!
|
|
|
|
! symmetrize: \rho_sym(G) = \sum_S rho(SG) for all G-vectors in the star
|
|
|
|
!
|
2010-01-07 00:54:57 +08:00
|
|
|
ng = SIZE ( shell(igl)%vect )
|
2009-12-23 01:01:28 +08:00
|
|
|
allocate ( g0(3,ng), done(ng) )
|
|
|
|
IF ( ng < 1 ) CALL errore('sym_rho_serial','internal error',1)
|
|
|
|
!
|
|
|
|
! bring G-vectors to crystal axis
|
|
|
|
!
|
2010-01-07 00:54:57 +08:00
|
|
|
DO ig=1,ng
|
|
|
|
g0(:,ig) = g_(:,shell(igl)%vect(ig) )
|
|
|
|
END DO
|
2009-12-23 01:01:28 +08:00
|
|
|
CALL cryst_to_cart (ng, g0, at,-1)
|
|
|
|
!
|
|
|
|
! rotate G-vectors
|
|
|
|
!
|
|
|
|
done(1:ng) = .false.
|
|
|
|
DO ig=1,ng
|
|
|
|
IF ( .NOT. done(ig)) THEN
|
|
|
|
rhosum(:) = (0.0_dp, 0.0_dp)
|
|
|
|
magsum(:) = (0.0_dp, 0.0_dp)
|
2010-02-13 04:57:55 +08:00
|
|
|
! S^{-1} are needed here
|
2009-12-23 01:01:28 +08:00
|
|
|
DO ns=1,nsym
|
2010-05-23 19:45:13 +08:00
|
|
|
|
2010-02-09 00:41:35 +08:00
|
|
|
sg(:) = s(:,1,invs(ns)) * g0(1,ig) + &
|
|
|
|
s(:,2,invs(ns)) * g0(2,ig) + &
|
|
|
|
s(:,3,invs(ns)) * g0(3,ig)
|
2009-12-23 01:01:28 +08:00
|
|
|
irot(ns) = 0
|
|
|
|
DO isg=1,ng
|
|
|
|
IF ( ABS ( sg(1)-g0(1,isg) ) < 1.0D-5 .AND. &
|
|
|
|
ABS ( sg(2)-g0(2,isg) ) < 1.0D-5 .AND. &
|
|
|
|
ABS ( sg(3)-g0(3,isg) ) < 1.0D-5 ) THEN
|
|
|
|
irot(ns) = isg
|
|
|
|
EXIT
|
|
|
|
END IF
|
|
|
|
END DO
|
|
|
|
IF ( irot(ns) < 1 .OR. irot(ns) > ng ) &
|
|
|
|
CALL errore('sym_rho_serial','internal error',2)
|
|
|
|
! isg is the index of rotated G-vector
|
2010-01-07 00:54:57 +08:00
|
|
|
isg = shell(igl)%vect(irot(ns))
|
2009-12-23 01:01:28 +08:00
|
|
|
!
|
|
|
|
! non-spin-polarized case: component 1 is the charge
|
|
|
|
! LSDA case: components 1,2 are spin-up and spin-down charge
|
|
|
|
! non colinear case: component 1 is the charge density,
|
|
|
|
! components 2,3,4 are the magnetization
|
|
|
|
! non colinear case: components 2,3,4 are the magnetization
|
|
|
|
!
|
|
|
|
IF ( nspin_ == 4 ) THEN
|
|
|
|
! bring magnetization to crystal axis
|
|
|
|
mag(:) = rhog_(isg, 2) * bg(1,:) + &
|
|
|
|
rhog_(isg, 3) * bg(2,:) + &
|
|
|
|
rhog_(isg, 4) * bg(3,:)
|
|
|
|
! rotate and add magnetization
|
2010-05-23 19:45:13 +08:00
|
|
|
magrot(:) = s(1,:,invs(ns)) * mag(1) + &
|
|
|
|
s(2,:,invs(ns)) * mag(2) + &
|
|
|
|
s(3,:,invs(ns)) * mag(3)
|
|
|
|
IF (sname(invs(ns))(1:3)=='inv') magrot(:)=-magrot(:)
|
|
|
|
IF (t_rev(invs(ns)) == 1) magrot(:)=-magrot(:)
|
2009-12-23 01:01:28 +08:00
|
|
|
END IF
|
|
|
|
IF ( non_symmorphic (ns) ) THEN
|
|
|
|
arg = tpi * ( g_(1,isg) * ft(1,ns) + &
|
|
|
|
g_(2,isg) * ft(2,ns) + &
|
|
|
|
g_(3,isg) * ft(3,ns) )
|
|
|
|
fact = CMPLX ( COS(arg), -SIN(arg), KIND=dp )
|
2010-01-07 00:54:57 +08:00
|
|
|
DO is=1,nspin_lsda
|
2009-12-23 01:01:28 +08:00
|
|
|
rhosum(is) = rhosum(is) + rhog_(isg, is) * fact
|
|
|
|
END DO
|
|
|
|
IF ( nspin_ == 4 ) &
|
|
|
|
magsum(:) = magsum(:) + magrot(:) * fact
|
|
|
|
ELSE
|
2010-01-07 00:54:57 +08:00
|
|
|
DO is=1,nspin_lsda
|
2009-12-23 01:01:28 +08:00
|
|
|
rhosum(is) = rhosum(is) + rhog_(isg, is)
|
|
|
|
END DO
|
|
|
|
IF ( nspin_ == 4 ) &
|
|
|
|
magsum(:) = magsum(:) + magrot(:)
|
|
|
|
END IF
|
|
|
|
END DO
|
|
|
|
!
|
2010-01-07 00:54:57 +08:00
|
|
|
DO is=1,nspin_lsda
|
2009-12-23 01:01:28 +08:00
|
|
|
rhosum(is) = rhosum(is) / nsym
|
|
|
|
END DO
|
|
|
|
IF ( nspin_ == 4 ) magsum(:) = magsum(:) / nsym
|
|
|
|
!
|
2010-01-07 00:54:57 +08:00
|
|
|
! now fill the shell of G-vectors with the symmetrized value
|
|
|
|
!
|
2009-12-23 01:01:28 +08:00
|
|
|
DO ns=1,nsym
|
2010-01-07 00:54:57 +08:00
|
|
|
isg = shell(igl)%vect(irot(ns))
|
2009-12-23 01:01:28 +08:00
|
|
|
IF ( nspin_ == 4 ) THEN
|
|
|
|
! rotate magnetization
|
2010-05-23 19:45:13 +08:00
|
|
|
magrot(:) = s(1,:,ns) * magsum(1) + &
|
|
|
|
s(2,:,ns) * magsum(2) + &
|
|
|
|
s(3,:,ns) * magsum(3)
|
2009-12-23 01:01:28 +08:00
|
|
|
IF (sname(ns)(1:3)=='inv') magrot(:)=-magrot(:)
|
|
|
|
IF (t_rev(ns) == 1) magrot(:)=-magrot(:)
|
|
|
|
! back to cartesian coordinates
|
|
|
|
mag(:) = magrot(1) * at(:,1) + &
|
|
|
|
magrot(2) * at(:,2) + &
|
|
|
|
magrot(3) * at(:,3)
|
|
|
|
END IF
|
|
|
|
IF ( non_symmorphic (ns) ) THEN
|
|
|
|
arg = tpi * ( g_(1,isg) * ft(1,ns) + &
|
|
|
|
g_(2,isg) * ft(2,ns) + &
|
|
|
|
g_(3,isg) * ft(3,ns) )
|
|
|
|
fact = CMPLX ( COS(arg), SIN(arg), KIND=dp )
|
2010-01-07 00:54:57 +08:00
|
|
|
DO is=1,nspin_lsda
|
2009-12-23 01:01:28 +08:00
|
|
|
rhog_(isg,is) = rhosum(is) * fact
|
|
|
|
END DO
|
|
|
|
IF ( nspin_ == 4 ) THEN
|
|
|
|
DO is=2,nspin_
|
|
|
|
rhog_(isg, is) = mag(is-1)*fact
|
|
|
|
END DO
|
|
|
|
END IF
|
|
|
|
ELSE
|
2010-01-07 00:54:57 +08:00
|
|
|
DO is=1,nspin_lsda
|
2009-12-23 01:01:28 +08:00
|
|
|
rhog_(isg,is) = rhosum(is)
|
|
|
|
END DO
|
|
|
|
IF ( nspin_ == 4 ) THEN
|
|
|
|
DO is=2,nspin_
|
|
|
|
rhog_(isg, is) = mag(is-1)
|
|
|
|
END DO
|
|
|
|
END IF
|
|
|
|
END IF
|
|
|
|
done(irot(ns)) =.true.
|
|
|
|
END DO
|
|
|
|
END IF
|
|
|
|
END DO
|
|
|
|
DEALLOCATE ( done, g0 )
|
|
|
|
END DO
|
|
|
|
!
|
|
|
|
RETURN
|
|
|
|
END SUBROUTINE sym_rho_serial
|
|
|
|
|
|
|
|
SUBROUTINE sym_rho_deallocate ( )
|
2010-01-07 00:54:57 +08:00
|
|
|
!
|
2009-12-23 01:01:28 +08:00
|
|
|
IF ( ALLOCATED (rdispls) ) DEALLOCATE (rdispls)
|
|
|
|
IF ( ALLOCATED (recvcnt) ) DEALLOCATE (recvcnt)
|
|
|
|
IF ( ALLOCATED (sdispls) ) DEALLOCATE (sdispls)
|
|
|
|
IF ( ALLOCATED (sendcnt) ) DEALLOCATE (sendcnt)
|
2010-01-07 00:54:57 +08:00
|
|
|
IF ( ALLOCATED (shell) ) THEN
|
|
|
|
DO i=1,SIZE(shell)
|
|
|
|
IF ( ASSOCIATED(shell(i)%vect) ) DEALLOCATE (shell(i)%vect)
|
|
|
|
END DO
|
|
|
|
DEALLOCATE (shell)
|
|
|
|
END IF
|
|
|
|
!
|
2009-12-23 01:01:28 +08:00
|
|
|
END SUBROUTINE sym_rho_deallocate
|
|
|
|
!
|
2008-08-22 23:53:34 +08:00
|
|
|
END MODULE symme
|