TABLE OF CONTENTS
ABINIT/multipoles_fftr [ Functions ]
NAME
multipoles_fftr
FUNCTION
Compute spatial multipole moments of input array on FFT grid Namely, the electrical dipole, quadrupole, etc... of the electron density
COPYRIGHT
Copyright (C) 2003-2018 ABINIT group (MJV, MT) This file is distributed under the terms of the GNU General Public License, see ~abinit/COPYING or http://www.gnu.org/copyleft/gpl.txt .
INPUTS
arraysp(nfft,nspden)=the array whose average has to be computed [distribfft<type(distribfft_type)>]= -optional- infos related to FFT parallelism [mpi_comm_grid]= -optional- MPI communicator over the grid origin(3)=vector defining the origin of the dipole (point of observation, in reduced coordinates) nfft=number of FFT points stored by one proc nfftot=total number of FFT points ngfft =number of subdivisions along each lattice vector nspden=number of spin-density components rprimd = dimensionful lattice vectors
OUTPUT
dipole(nspden)=mean value of the dipole of input array, for each nspden component
PARENTS
multipoles_out
CHILDREN
destroy_distribfft,init_distribfft_seq,xmpi_sum
SOURCE
38 #if defined HAVE_CONFIG_H 39 #include "config.h" 40 #endif 41 42 #include "abi_common.h" 43 44 subroutine multipoles_fftr(arraysp,dipole,nfft,ngfft,nspden,rprimd,origin,& 45 & distribfft,mpi_comm_grid) 46 47 use m_profiling_abi 48 use defs_basis 49 use m_errors 50 use defs_abitypes 51 use m_distribfft 52 use m_xmpi 53 54 !This section has been created automatically by the script Abilint (TD). 55 !Do not modify the following lines by hand. 56 #undef ABI_FUNC 57 #define ABI_FUNC 'multipoles_fftr' 58 !End of the abilint section 59 60 implicit none 61 62 !Arguments ------------------------------------ 63 !scalars 64 integer,intent(in) :: nfft,nspden 65 integer,intent(in),optional :: mpi_comm_grid 66 type(distribfft_type),intent(in),optional,target :: distribfft 67 !arrays 68 integer,intent(in) :: ngfft(18) 69 real(dp),intent(in) :: arraysp(nfft,nspden),origin(3),rprimd(3,3) 70 real(dp),intent(out) :: dipole(3,nspden) 71 !Local variables------------------------------- 72 !scalars 73 integer,parameter :: ishift=5 74 integer :: ierr,ifft1,ifft2,ifft3,ifft0,ifft,ispden,i1,i2,i3,n1,n2,n3 75 integer :: me_fft,my_mpi_comm,nfftot 76 logical :: fftgrid_found 77 real(dp) :: invn1,invn2,invn3,invnfftot,wrapfft1,wrapfft2,wrapfft3 78 character(len=500) :: msg 79 type(distribfft_type),pointer :: my_distribfft 80 !arrays 81 integer, ABI_CONTIGUOUS pointer :: fftn3_distrib(:),ffti3_local(:) 82 real(dp) :: dipole_tmp(3,nspden) 83 84 ! ************************************************************************* 85 86 87 !Several initializations 88 my_mpi_comm=xmpi_comm_self;if (present(mpi_comm_grid)) my_mpi_comm=mpi_comm_grid 89 n1=ngfft(1);n2=ngfft(2);n3=ngfft(3) 90 nfftot=n1*n2*n3;invnfftot=one/(dble(nfftot)) 91 invn1=one/real(n1,kind=dp);invn2=one/real(n2,kind=dp);invn3=one/real(n3,kind=dp) 92 me_fft=xmpi_comm_rank(my_mpi_comm) 93 94 dipole(:,:)=zero 95 96 !Get the distrib associated with the FFT grid 97 if (present(distribfft)) then 98 my_distribfft => distribfft 99 else 100 ABI_DATATYPE_ALLOCATE(my_distribfft,) 101 call init_distribfft_seq(my_distribfft,'f',n2,n3,'fourdp') 102 end if 103 fftgrid_found=.false. 104 if (n2 == my_distribfft%n2_coarse ) then 105 if (n3 == size(my_distribfft%tab_fftdp3_distrib)) then 106 fftn3_distrib => my_distribfft%tab_fftdp3_distrib 107 ffti3_local => my_distribfft%tab_fftdp3_local 108 fftgrid_found=.true. 109 end if 110 end if 111 if (n2 == my_distribfft%n2_fine ) then 112 if (n3 == size(my_distribfft%tab_fftdp3dg_distrib)) then 113 fftn3_distrib => my_distribfft%tab_fftdp3dg_distrib 114 ffti3_local => my_distribfft%tab_fftdp3dg_local 115 fftgrid_found = .true. 116 end if 117 end if 118 if (.not.(fftgrid_found)) then 119 msg='Unable to find an allocated distrib for the FFT grid!' 120 MSG_BUG(msg) 121 end if 122 123 !Loop over FFT grid points 124 !$OMP PARALLEL PRIVATE(ifft,i1,i2,ifft1,ifft2,ispden,wrapfft1,wrapfft2) 125 do ifft3=1,n3 126 i3=mod(ifft3-1+ishift*n3,n3) 127 if(fftn3_distrib(1+i3)==me_fft) then 128 wrapfft3=mod(real(ifft3-1,kind=dp)*invn3-origin(3)+1.5_dp,one)-half 129 ifft0=1+n1*n2*(ffti3_local(1+i3)-1) 130 !$OMP SINGLE 131 dipole_tmp=zero 132 !$OMP END SINGLE 133 !$OMP DO COLLAPSE(2) REDUCTION(+:dipole_tmp) 134 do ifft2=1,n2 135 do ifft1=1,n1 136 i2=mod(ifft2-1+ishift*n2,n2) 137 i1=mod(ifft1-1+ishift*n1,n1) 138 wrapfft2=mod(real(ifft2-1,kind=dp)*invn2-origin(2)+1.5_dp,one)-half 139 wrapfft1=mod(real(ifft1-1,kind=dp)*invn1-origin(1)+1.5_dp,one)-half 140 ifft=ifft0+n1*i2+i1 141 142 ! Computation of integral(s) 143 do ispden=1,nspden 144 dipole_tmp(1,ispden)=dipole_tmp(1,ispden)+wrapfft1*arraysp(ifft,ispden) 145 dipole_tmp(2,ispden)=dipole_tmp(2,ispden)+wrapfft2*arraysp(ifft,ispden) 146 dipole_tmp(3,ispden)=dipole_tmp(3,ispden)+wrapfft3*arraysp(ifft,ispden) 147 end do 148 149 end do 150 end do 151 !$OMP END DO 152 !$OMP SINGLE 153 dipole=dipole+dipole_tmp 154 !$OMP END SINGLE 155 end if 156 end do 157 !$OMP END PARALLEL 158 159 !MPI parallelization 160 if (xmpi_comm_size(my_mpi_comm)>1) then 161 call xmpi_sum(dipole,my_mpi_comm,ierr) 162 end if 163 164 !From reduced to cartesian coordinates 165 do ispden=1,nspden 166 dipole(:,ispden)=matmul(rprimd,dipole(:,ispden))*invnfftot 167 end do 168 169 if (.not.present(distribfft)) then 170 call destroy_distribfft(my_distribfft) 171 ABI_DATATYPE_DEALLOCATE(my_distribfft) 172 end if 173 174 end subroutine multipoles_fftr