Octopus
orbitalset_utils.F90
Go to the documentation of this file.
1!! Copyright (C) 2016 N. Tancogne-Dejean
2!!
3!! This program is free software; you can redistribute it and/or modify
4!! it under the terms of the GNU General Public License as published by
5!! the Free Software Foundation; either version 2, or (at your option)
6!! any later version.
7!!
8!! This program is distributed in the hope that it will be useful,
9!! but WITHOUT ANY WARRANTY; without even the implied warranty of
10!! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11!! GNU General Public License for more details.
12!!
13!! You should have received a copy of the GNU General Public License
14!! along with this program; if not, write to the Free Software
15!! Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16!! 02110-1301, USA.
17#include "global.h"
18
21 use comm_oct_m
22 use debug_oct_m
25 use global_oct_m
27 use ions_oct_m
28 use, intrinsic :: iso_fortran_env
30 use loct_oct_m
31 use mesh_oct_m
33 use mpi_oct_m
38 use space_oct_m
41 use unit_oct_m
42
43 implicit none
44
45 private
46
47 public :: &
54
55 integer, public, parameter :: &
56 SM_POISSON_DIRECT = 0, &
57 sm_poisson_isf = 1, &
60
61
62contains
63
64 integer function orbitalset_utils_count(species, iselect) result(norb)
65 class(species_t), intent(in) :: species
66 integer, optional, intent(in) :: iselect
67
68 integer :: iorb, ii, ll, mm
69
70 !We count the number of orbital sets we have for a given atom
71 !If iselect is present, this routine return instead the number of orbital for a given
72 !value of i
73 norb = 0
74 do iorb = 1, species%get_niwfs()
75 call species%get_iwf_ilm(iorb, 1, ii, ll, mm)
76 if (present(iselect)) then
77 if (ii == iselect) norb = norb + 1
78 else
79 norb = max(norb, ii)
80 end if
81 end do
82 end function orbitalset_utils_count
83
84 subroutine orbitalset_init_intersite(this, namespace, space, ind, ions, der, psolver, os, nos, maxnorbs, &
85 rcut, kpt, has_phase, sm_poisson, basis_from_states)
86 type(orbitalset_t), intent(inout) :: this
87 type(namespace_t), intent(in) :: namespace
88 class(space_t), intent(in) :: space
89 integer, intent(in) :: ind
90 type(ions_t), intent(in) :: ions
91 type(derivatives_t), intent(in) :: der
92 type(poisson_t), intent(in) :: psolver
93 type(orbitalset_t), intent(inout) :: os(:)
94 integer, intent(in) :: nos, maxnorbs
95 real(real64), intent(in) :: rcut
96 type(distributed_t), intent(in) :: kpt
97 logical, intent(in) :: has_phase
98 integer, intent(in) :: sm_poisson
99 logical, intent(in) :: basis_from_states
100
101
102 type(lattice_iterator_t) :: latt_iter
103 real(real64) :: xat(space%dim), xi(space%dim)
104 real(real64) :: rr
105 integer :: inn, ist, jst
106 integer :: ip, ios, ip2
107 type(submesh_t) :: sm
108 real(real64), allocatable :: tmp(:), vv(:), nn(:)
109 real(real64), allocatable :: orb(:,:,:)
110 real(real64), parameter :: TOL_INTERSITE = 1.e-5_real64
111 type(distributed_t) :: dist
112 integer :: sm_poisson_
113
115
116 call messages_print_with_emphasis(msg="Intersite Coulomb integrals", namespace=namespace)
117
118 sm_poisson_ = sm_poisson
119
120 this%nneighbors = 0
121 if (this%iatom /= -1) then
122 xat = ions%pos(:, this%iatom)
123 else
124 xat = this%sphere%center
125 end if
126
127 latt_iter = lattice_iterator_t(ions%latt, rcut)
128
129 !We first count first the number of neighboring atoms at a distance max rcut
130 do ios = 1, nos
131 do inn = 1, latt_iter%n_cells
132
133 xi = os(ios)%sphere%center(1:space%dim) + latt_iter%get(inn)
134 rr = norm2(xi - xat)
135
136 !This atom is too far
137 if( rr >rcut + tol_intersite ) cycle
138 !Intra atomic interaction
139 if( ios == ind .and. rr < tol_intersite) cycle
140
141 this%nneighbors = this%nneighbors +1
142 end do
143 end do
144
145 !The first three values are the position of the periodic copies
146 !and the zero value one is used to store the actual value of V_ij
147 safe_allocate(this%V_ij(1:this%nneighbors, 0:space%dim+1))
148 this%V_ij(1:this%nneighbors, 0:space%dim+1) = m_zero
149 safe_allocate(this%map_os(1:this%nneighbors))
150 this%map_os(1:this%nneighbors) = 0
151 if(has_phase) then
152 safe_allocate(this%phase_shift(1:this%nneighbors, kpt%start:kpt%end))
153 end if
154
155 this%nneighbors = 0
156 do ios = 1, nos
157 do inn = 1, latt_iter%n_cells
158 xi = os(ios)%sphere%center(1:space%dim) + latt_iter%get(inn)
159 rr = norm2(xi - xat)
160
161 if( rr > rcut + tol_intersite ) cycle
162 if( ios == ind .and. rr < tol_intersite) cycle
163
164 this%nneighbors = this%nneighbors +1
165
166 this%V_ij(this%nneighbors, 1:space%dim) = xi(1:space%dim) -os(ios)%sphere%center(1:space%dim)
167 this%V_ij(this%nneighbors, space%dim+1) = rr
168
169 this%map_os(this%nneighbors) = ios
170 end do
171 end do
172
173 write(message(1),'(a, i3, a)') 'Intersite interaction will be computed for ', this%nneighbors, ' neighboring atoms.'
174 call messages_info(1, namespace=namespace)
175
176
177 safe_allocate(this%coulomb_IIJJ(1:this%norbs,1:this%norbs,1:maxnorbs,1:maxnorbs,1:this%nneighbors))
178 this%coulomb_IIJJ = m_zero
179
180 if(this%nneighbors == 0) then
181 call messages_print_with_emphasis(namespace=namespace)
183 return
184 end if
185
186 call distributed_nullify(dist, this%nneighbors)
187#ifdef HAVE_MPI
188 if(.not. der%mesh%parallel_in_domains) then
189 call distributed_init(dist, this%nneighbors, mpi_comm_world, 'orbs')
190 end if
191#endif
192
193 do inn = dist%start, dist%end
194
195 ios = this%map_os(inn)
196
197 if(.not. basis_from_states) then
198 !Init a submesh from the union of two submeshes
199 call submesh_merge(sm, space, der%mesh, this%sphere, os(ios)%sphere, &
200 shift = this%V_ij(inn, 1:space%dim))
201
202 write(message(1),'(a, i3, a, f6.3, a, i7, a)') 'Neighbor ', inn, ' is located at ', &
203 this%V_ij(inn, space%dim+1), ' Bohr and has ', sm%np, ' grid points.'
204 call messages_info(1, namespace=namespace)
205
206 safe_allocate(orb(1:sm%np, 1:max(this%norbs,os(ios)%norbs),1:2))
207
208 do ist = 1, this%norbs
209 call datomic_orbital_get_submesh_safe(this%spec, sm, this%ii, this%ll, ist-1-this%ll, &
210 1, orb(1:sm%np, ist,1))
211 end do
212
213 call submesh_shift_center(sm, space, this%V_ij(inn, 1:space%dim)+os(ios)%sphere%center(1:space%dim))
214
215 do ist = 1, os(ios)%norbs
216 call datomic_orbital_get_submesh_safe(os(ios)%spec, sm, os(ios)%ii, os(ios)%ll, ist-1-os(ios)%ll, &
217 1, orb(1:sm%np, ist, 2))
218 end do
219
220 else
221 !Init a submesh from the union of two submeshes
222 call submesh_merge(sm, ions%space, der%mesh, this%sphere, os(ios)%sphere, &
223 shift = this%V_ij(inn, 1:ions%space%dim))
224
225 write(message(1),'(a, i3, a, f6.3, a, i5, a)') 'Neighbor ', inn, ' is located at ', &
226 this%V_ij(inn, ions%space%dim+1), ' Bohr and has ', sm%np, ' grid points.'
227 call messages_info(1, namespace=namespace)
228
229 safe_allocate(orb(1:sm%np, 1:max(this%norbs,os(ios)%norbs),1:2))
230 orb = m_zero
231
232 ! All the points of the first submesh are included in the union of the submeshes
233 do ist = 1, this%norbs
234 if(allocated(this%dorb)) then
235 orb(1:this%sphere%np, ist, 1) = this%dorb(:,1,ist)
236 else
237 orb(1:this%sphere%np, ist, 1) = real(this%zorb(:,1,ist), real64)
238 end if
239 end do
240
241 call submesh_shift_center(sm, ions%space, this%V_ij(inn, 1:ions%space%dim)+os(ios)%sphere%center(1:ions%space%dim))
242
243 ! TODO: This probably needs some optimization
244 ! However, this is only done at initialization time
245 do ist = 1, os(ios)%norbs
246 if(allocated(this%dorb)) then
247 !$omp parallel do private(ip)
248 do ip2 = 1, sm%np
249 do ip = 1, os(ios)%sphere%np
250 if(all(abs(sm%rel_x(1:ions%space%dim, ip2)-os(ios)%sphere%rel_x(1:ions%space%dim, ip)) < 1e-6_real64)) then
251 orb(ip2, ist, 2) = os(ios)%dorb(ip, 1, ist)
252 end if
253 end do
254 end do
255 else
256 !$omp parallel do private(ip)
257 do ip2 = 1, sm%np
258 do ip = 1, os(ios)%sphere%np
259 if(all(abs(sm%rel_x(1:ions%space%dim, ip2)-os(ios)%sphere%rel_x(1:ions%space%dim, ip)) < 1e-6_real64)) then
260 orb(ip2, ist, 2) = real(os(ios)%zorb(ip, 1, ist), real64)
261 end if
262 end do
263 end do
264 end if
265 end do
266
267 end if
268
269 safe_allocate(tmp(1:sm%np))
270 safe_allocate(nn(1:sm%np))
271 safe_allocate(vv(1:sm%np))
272
273 select case (sm_poisson_)
274 case(sm_poisson_direct)
275 !Build information needed for the direct Poisson solver on the submesh
276 call submesh_build_global(sm, space)
277 call poisson_init_sm(this%poisson, namespace, space, psolver, der, sm, method = poisson_direct_sum)
278 case(sm_poisson_isf)
279 call poisson_init_sm(this%poisson, namespace, space, psolver, der, sm, method = poisson_isf)
281 call poisson_init_sm(this%poisson, namespace, space, psolver, der, sm, method = poisson_psolver)
282 case(sm_poisson_fft)
283 call poisson_init_sm(this%poisson, namespace, space, psolver, der, sm, method = poisson_fft)
284 end select
285
286 do ist = 1, this%norbs
287 !$omp parallel do
288 do ip = 1, sm%np
289 nn(ip) = orb(ip, ist, 1)*orb(ip, ist, 1)
290 end do
291 !$omp end parallel do
292
293 !Here it is important to use a non-periodic poisson solver, e.g. the direct solver
294 call dpoisson_solve_sm(this%poisson, namespace, sm, vv, nn)
295
296 do jst = 1, os(ios)%norbs
297
298 !$omp parallel do
299 do ip = 1, sm%np
300 tmp(ip) = vv(ip)*orb(ip, jst, 2)*orb(ip, jst, 2)
301 end do
302 !$omp end parallel do
303
304 this%coulomb_IIJJ(ist, ist, jst, jst, inn) = dsm_integrate(der%mesh, sm, tmp, reduce = .false.)
305 end do !jst
306 end do !ist
307
308 call poisson_end(this%poisson)
309
310 safe_deallocate_a(nn)
311 safe_deallocate_a(vv)
312 safe_deallocate_a(tmp)
313
314 if (sm_poisson_ == sm_poisson_direct) call submesh_end_global(sm)
315 call submesh_end_cube_map(sm)
316 call submesh_end(sm)
317 safe_deallocate_a(orb)
318 end do !inn
319
320 if(der%mesh%parallel_in_domains) then
321 call der%mesh%allreduce(this%coulomb_IIJJ)
322 end if
323
324 if(dist%parallel) then
325 call comm_allreduce(dist%mpi_grp, this%coulomb_IIJJ)
326 end if
327
328 call distributed_end(dist)
329
330 call messages_print_with_emphasis(namespace=namespace)
331
333 end subroutine orbitalset_init_intersite
334
335#include "undef.F90"
336#include "real.F90"
337#include "orbitalset_utils_inc.F90"
338
339#include "undef.F90"
340#include "complex.F90"
341#include "orbitalset_utils_inc.F90"
342
343end module orbitalset_utils_oct_m
subroutine, public datomic_orbital_get_submesh_safe(species, submesh, ii, ll, mm, ispin, phi)
This module calculates the derivatives (gradients, Laplacians, etc.) of a function.
subroutine, public distributed_end(this)
subroutine, public distributed_nullify(this, total)
subroutine, public distributed_init(this, total, comm, tag, scalapack_compat)
Distribute N instances across M processes of communicator comm
real(real64), parameter, public m_zero
Definition: global.F90:187
This module defines the meshes, which are used in Octopus.
Definition: mesh.F90:118
subroutine, public messages_print_with_emphasis(msg, iunit, namespace)
Definition: messages.F90:930
character(len=512), private msg
Definition: messages.F90:165
subroutine, public messages_info(no_lines, iunit, verbose_limit, stress, all_nodes, namespace)
Definition: messages.F90:624
character(len=256), dimension(max_lines), public message
to be output by fatal, warning
Definition: messages.F90:160
subroutine, public zorbitalset_utils_getorbitals(namespace, os, ions, mesh, use_mesh, normalize)
integer, parameter, public sm_poisson_psolver
integer, parameter, public sm_poisson_isf
subroutine, public dorbitalset_utils_getorbitals(namespace, os, ions, mesh, use_mesh, normalize)
subroutine, public zorbitalset_get_center_of_mass(os, space, mesh, latt)
subroutine, public orbitalset_init_intersite(this, namespace, space, ind, ions, der, psolver, os, nos, maxnorbs, rcut, kpt, has_phase, sm_poisson, basis_from_states)
subroutine, public dorbitalset_get_center_of_mass(os, space, mesh, latt)
integer, parameter, public sm_poisson_fft
integer function, public orbitalset_utils_count(species, iselect)
integer, parameter, public poisson_psolver
Definition: poisson.F90:196
integer, parameter, public poisson_fft
Definition: poisson.F90:196
subroutine, public dpoisson_solve_sm(this, namespace, sm, pot, rho, all_nodes)
Calculates the Poisson equation. Given the density returns the corresponding potential.
Definition: poisson.F90:2384
integer, parameter, public poisson_direct_sum
Definition: poisson.F90:196
subroutine, public poisson_init_sm(this, namespace, space, main, der, sm, method, force_cmplx)
Definition: poisson.F90:1018
integer, parameter, public poisson_isf
Definition: poisson.F90:196
subroutine, public poisson_end(this)
Definition: poisson.F90:732
subroutine, public submesh_end_global(this)
Definition: submesh.F90:872
subroutine, public submesh_shift_center(this, space, newcenter)
Definition: submesh.F90:633
real(real64) function, public dsm_integrate(mesh, sm, ff, reduce)
Definition: submesh.F90:1163
subroutine, public submesh_merge(this, space, mesh, sm1, sm2, shift)
Definition: submesh.F90:567
subroutine, public submesh_end_cube_map(sm)
Definition: submesh.F90:1043
subroutine, public submesh_end(this)
Definition: submesh.F90:737
subroutine, public submesh_build_global(this, space)
Definition: submesh.F90:821
brief This module defines the class unit_t which is used by the unit_systems_oct_m module.
Definition: unit.F90:132
The following class implements a lattice iterator. It allows one to loop over all cells that are with...