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
31 use loct_oct_m
32 use math_oct_m
33 use mesh_oct_m
35 use mpi_oct_m
40 use space_oct_m
43 use unit_oct_m
44
45 implicit none
46
47 private
48
49 public :: &
56
57 integer, public, parameter :: &
58 SM_POISSON_DIRECT = 0, &
59 sm_poisson_isf = 1, &
62
63
64contains
65
66
71 integer function orbitalset_utils_count(species, iselect) result(norb)
72 class(species_t), intent(in) :: species
73 integer, optional, intent(in) :: iselect
74
75 integer :: iorb, ii, ll, mm
76
77 norb = 0
78 do iorb = 1, species%get_niwfs()
79 call species%get_iwf_ilm(iorb, 1, ii, ll, mm)
80 if (present(iselect)) then
81 if (ii == iselect) norb = norb + 1
82 else
83 norb = max(norb, ii)
84 end if
85 end do
86 end function orbitalset_utils_count
87
88 subroutine orbitalset_init_intersite(this, namespace, space, ind, ions, der, psolver, os, nos, maxnorbs, &
89 rcut, kpt, has_phase, sm_poisson, basis_from_states, combine_j_orbitals)
90 type(orbitalset_t), intent(inout) :: this
91 type(namespace_t), intent(in) :: namespace
92 class(space_t), intent(in) :: space
93 integer, intent(in) :: ind
94 type(ions_t), intent(in) :: ions
95 type(derivatives_t), intent(in) :: der
96 type(poisson_t), intent(in) :: psolver
97 type(orbitalset_t), intent(inout) :: os(:)
98 integer, intent(in) :: nos, maxnorbs
99 real(real64), intent(in) :: rcut
100 type(distributed_t), intent(in) :: kpt
101 logical, intent(in) :: has_phase
102 integer, intent(in) :: sm_poisson
103 logical, intent(in) :: basis_from_states
104 logical, intent(in) :: combine_j_orbitals
105
106
107 type(lattice_iterator_t) :: latt_iter
108 real(real64) :: xat(space%dim), xi(space%dim)
109 real(real64) :: rr
110 integer :: inn, ist, jst, nneighbors, norbs, ndim
111 integer :: ip, ios, ip2, is1, is2
112 type(submesh_t) :: sm
113 real(real64), allocatable :: tmp(:), vv(:), nn(:)
114 complex(real64), allocatable :: ztmp(:), zvv(:,:), znn(:)
115 real(real64), allocatable :: dorb(:,:,:,:)
116 complex(real64), allocatable :: zorb(:,:,:,:)
117 real(real64), parameter :: TOL_INTERSITE = 1.e-5_real64
118 type(distributed_t) :: dist
119 integer :: sm_poisson_
120
122
123 call messages_print_with_emphasis(msg="Intersite Coulomb integrals", namespace=namespace)
124
125 sm_poisson_ = sm_poisson
126 ndim = this%ndim
127
128 this%nneighbors = 0
129 if (this%iatom /= -1) then
130 xat = ions%pos(:, this%iatom)
131 else
132 xat = this%sphere%center
133 end if
134
135 latt_iter = lattice_iterator_t(ions%latt, rcut)
136
137 !We first count first the number of neighboring atoms at a distance max rcut
138 do ios = 1, nos
139 do inn = 1, latt_iter%n_cells
140
141 xi = os(ios)%sphere%center(1:space%dim) + latt_iter%get(inn)
142 rr = norm2(xi - xat)
143
144 !This atom is too far
145 if( rr >rcut + tol_intersite ) cycle
146 !Intra atomic interaction
147 if( ios == ind .and. rr < tol_intersite) cycle
148
149 this%nneighbors = this%nneighbors +1
150 end do
151 end do
152
153 !The first three values are the position of the periodic copies
154 !and the zero value one is used to store the actual value of V_ij
155 safe_allocate(this%V_ij(1:this%nneighbors, 0:space%dim+1))
156 this%V_ij(1:this%nneighbors, 0:space%dim+1) = m_zero
157 safe_allocate(this%map_os(1:this%nneighbors))
158 this%map_os(1:this%nneighbors) = 0
159 if(has_phase) then
160 safe_allocate(this%phase_shift(1:this%nneighbors, kpt%start:kpt%end))
161 end if
162
163 this%nneighbors = 0
164 do ios = 1, nos
165 do inn = 1, latt_iter%n_cells
166 xi = os(ios)%sphere%center(1:space%dim) + latt_iter%get(inn)
167 rr = norm2(xi - xat)
168
169 if( rr > rcut + tol_intersite ) cycle
170 if( ios == ind .and. rr < tol_intersite) cycle
171
172 this%nneighbors = this%nneighbors +1
173
174 this%V_ij(this%nneighbors, 1:space%dim) = xi(1:space%dim) -os(ios)%sphere%center(1:space%dim)
175 this%V_ij(this%nneighbors, space%dim+1) = rr
176
177 this%map_os(this%nneighbors) = ios
178 end do
179 end do
180
181 write(message(1),'(a, i3, a)') 'Intersite interaction will be computed for ', this%nneighbors, ' neighboring atoms.'
182 call messages_info(1, namespace=namespace)
183
184 ! Local definitions to reduce the macro line length
185 norbs = this%norbs
186 nneighbors = this%nneighbors
187
188 if (ndim == 1) then
189 safe_allocate(this%coulomb_IIJJ(1:norbs,1:norbs,1:maxnorbs,1:maxnorbs,1:nneighbors))
190 this%coulomb_IIJJ = m_zero
191 else
192 safe_allocate(this%zcoulomb_IIJJ(1:norbs,1:norbs,1:maxnorbs,1:maxnorbs, 1:ndim, 1:ndim, 1:nneighbors))
193 this%zcoulomb_IIJJ = m_zero
194 end if
195
196 if(this%nneighbors == 0) then
197 call messages_print_with_emphasis(namespace=namespace)
199 return
200 end if
201
202 call distributed_nullify(dist, this%nneighbors)
203#ifdef HAVE_MPI
204 if(.not. der%mesh%parallel_in_domains) then
205 call distributed_init(dist, this%nneighbors, mpi_comm_world, 'orbs')
206 end if
207#endif
208
209 do inn = dist%start, dist%end
210
211 ios = this%map_os(inn)
212
213 if(.not. basis_from_states) then
214 !Init a submesh from the union of two submeshes
215 call submesh_merge(sm, space, der%mesh, this%sphere, os(ios)%sphere, &
216 shift = this%V_ij(inn, 1:space%dim))
217
218 write(message(1),'(a, i3, a, f6.3, a, i7, a)') 'Neighbor ', inn, ' is located at ', &
219 this%V_ij(inn, space%dim+1), ' Bohr and has ', sm%np, ' grid points.'
220 call messages_info(1, namespace=namespace)
221
222 if (ndim == 1) then
223 safe_allocate(dorb(1:sm%np, 1:1, 1:max(this%norbs, os(ios)%norbs), 1:2))
224 else
225 safe_allocate(zorb(1:sm%np, 1:2, 1:max(this%norbs, os(ios)%norbs), 1:2))
226 end if
227
228 ! Get the orbitals from the first set of orbitals
229 if (ndim == 1) then
230 do ist = 1, this%norbs
231 call dget_orbital(this%spec, sm, this%ii, this%ll, this%jj, ist, 1, dorb(:, :, ist, 1), combine_j_orbitals)
232 end do
233 else
234 do ist = 1, this%norbs
235 call zget_orbital(this%spec, sm, this%ii, this%ll, this%jj, ist, 2, zorb(:, :, ist, 1), combine_j_orbitals)
236 end do
237 end if
238
239 call submesh_shift_center(sm, space, this%V_ij(inn, 1:space%dim)+os(ios)%sphere%center(1:space%dim))
240
241 ! Get the orbitals from the second set of orbitals
242 if (ndim == 1) then
243 do ist = 1, os(ios)%norbs
244 call dget_orbital(os(ios)%spec, sm, os(ios)%ii, os(ios)%ll, os(ios)%jj, ist, 1, dorb(:, :, ist, 2), combine_j_orbitals)
245 end do
246 else
247 do ist = 1, os(ios)%norbs
248 call zget_orbital(os(ios)%spec, sm, os(ios)%ii, os(ios)%ll, os(ios)%jj, ist, 2, zorb(:, :, ist, 2), combine_j_orbitals)
249 end do
250 end if
251
252 else
253 ! TODO: Replace datomic_orbital_get_submesh_safe by the logic above
254 assert(ndim == 1)
255 !Init a submesh from the union of two submeshes
256 call submesh_merge(sm, ions%space, der%mesh, this%sphere, os(ios)%sphere, &
257 shift = this%V_ij(inn, 1:ions%space%dim))
258
259 write(message(1),'(a, i3, a, f6.3, a, i5, a)') 'Neighbor ', inn, ' is located at ', &
260 this%V_ij(inn, ions%space%dim+1), ' Bohr and has ', sm%np, ' grid points.'
261 call messages_info(1, namespace=namespace)
262
263 safe_allocate(dorb(1:sm%np, 1:1, 1:max(this%norbs,os(ios)%norbs), 1:2))
264 dorb = m_zero
265
266 ! All the points of the first submesh are included in the union of the submeshes
267 do ist = 1, this%norbs
268 if(allocated(this%dorb)) then
269 dorb(1:this%sphere%np, 1, ist, 1) = this%dorb(:,1,ist)
270 else
271 dorb(1:this%sphere%np, 1, ist, 1) = real(this%zorb(:,1,ist), real64)
272 end if
273 end do
274
275 call submesh_shift_center(sm, ions%space, this%V_ij(inn, 1:ions%space%dim)+os(ios)%sphere%center(1:ions%space%dim))
276
277 ! TODO: This probably needs some optimization
278 ! However, this is only done at initialization time
279 do ist = 1, os(ios)%norbs
280 if(allocated(this%dorb)) then
281 !$omp parallel do private(ip)
282 do ip2 = 1, sm%np
283 do ip = 1, os(ios)%sphere%np
284 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
285 dorb(ip2, 1, ist, 2) = os(ios)%dorb(ip, 1, ist)
286 end if
287 end do
288 end do
289 else
290 !$omp parallel do private(ip)
291 do ip2 = 1, sm%np
292 do ip = 1, os(ios)%sphere%np
293 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
294 dorb(ip2, 1, ist, 2) = real(os(ios)%zorb(ip, 1, ist), real64)
295 end if
296 end do
297 end do
298 end if
299 end do
300
301 end if
302
303 select case (sm_poisson_)
304 case(sm_poisson_direct)
305 !Build information needed for the direct Poisson solver on the submesh
306 call submesh_build_global(sm, space)
307 call poisson_init_sm(this%poisson, namespace, space, psolver, der, sm, method = poisson_direct_sum)
308 case(sm_poisson_isf)
309 call poisson_init_sm(this%poisson, namespace, space, psolver, der, sm, method = poisson_isf)
311 call poisson_init_sm(this%poisson, namespace, space, psolver, der, sm, method = poisson_psolver)
312 case(sm_poisson_fft)
313 call poisson_init_sm(this%poisson, namespace, space, psolver, der, sm, method = poisson_fft, &
314 force_cmplx=(ndim==2))
315 end select
316
317 if (ndim == 1) then ! Real orbitals
318 safe_allocate(tmp(1:sm%np))
319 safe_allocate(nn(1:sm%np))
320 safe_allocate(vv(1:sm%np))
321
322 do ist = 1, this%norbs
323 !$omp parallel do
324 do ip = 1, sm%np
325 nn(ip) = dorb(ip, 1, ist, 1)*dorb(ip, 1, ist, 1)
326 end do
327 !$omp end parallel do
328
329 ! Here it is important to use a non-periodic poisson solver, e.g. the direct solver,
330 ! to not include contribution from periodic copies.
331 call dpoisson_solve_sm(this%poisson, namespace, sm, vv, nn)
332
333 do jst = 1, os(ios)%norbs
334
335 !$omp parallel do
336 do ip = 1, sm%np
337 tmp(ip) = vv(ip)*dorb(ip, 1, jst, 2)*dorb(ip, 1, jst, 2)
338 end do
339 !$omp end parallel do
340
341 this%coulomb_IIJJ(ist, ist, jst, jst, inn) = dsm_integrate(der%mesh, sm, tmp, reduce = .false.)
342 end do !jst
343 end do !ist
344
345 safe_deallocate_a(nn)
346 safe_deallocate_a(vv)
347 safe_deallocate_a(tmp)
348
349 else ! Complex orbitals
350 safe_allocate(ztmp(1:sm%np))
351 safe_allocate(znn(1:sm%np))
352 safe_allocate(zvv(1:sm%np, 1:ndim))
353
354 do ist = 1, this%norbs
355 do is1 = 1, ndim
356 !$omp parallel do
357 do ip = 1, sm%np
358 znn(ip) = conjg(zorb(ip, is1, ist, 1))*zorb(ip, is1, ist, 1)
359 end do
360 !$omp end parallel do
361
362 ! Here it is important to use a non-periodic poisson solver, e.g. the direct solver,
363 ! to not include contribution from periodic copies.
364 call zpoisson_solve_sm(this%poisson, namespace, sm, zvv(:,is1), znn)
365 end do !is1
366
367 do jst = 1, os(ios)%norbs
368
369 do is1 = 1, ndim
370 do is2 = 1, ndim
371 !$omp parallel do
372 do ip = 1, sm%np
373 ztmp(ip) = zvv(ip, is1)*conjg(zorb(ip, is2, jst, 2))*zorb(ip, is2, jst, 2)
374 end do
375 !$omp end parallel do
376
377 this%zcoulomb_IIJJ(ist, ist, jst, jst, is1, is2, inn) = zsm_integrate(der%mesh, sm, ztmp)
378 end do
379 end do
380 end do !jst
381 end do !ist
382
383 safe_deallocate_a(znn)
384 safe_deallocate_a(zvv)
385 safe_deallocate_a(ztmp)
386 end if
387
388 call poisson_end(this%poisson)
389
390
391 if (sm_poisson_ == sm_poisson_direct) call submesh_end_global(sm)
392 call submesh_end_cube_map(sm)
393 call submesh_end(sm)
394 safe_deallocate_a(dorb)
395 safe_deallocate_a(zorb)
396 end do !inn
397
398 if(this%ndim == 1) then
399 call der%mesh%allreduce(this%coulomb_IIJJ)
400 end if
401
402 if(dist%parallel) then
403 if (ndim == 1) then
404 call comm_allreduce(dist%mpi_grp, this%coulomb_IIJJ)
405 else
406 do inn = 1, this%nneighbors
407 do is2 = 1, ndim
408 do is1 = 1, ndim
409 call comm_allreduce(dist%mpi_grp, this%zcoulomb_IIJJ(:,:,:,:, is1, is2, inn))
410 end do
411 end do
412 end do
413 end if
414 end if
415
416 call distributed_end(dist)
417
418 call messages_print_with_emphasis(namespace=namespace)
419
421 end subroutine orbitalset_init_intersite
422
423#include "undef.F90"
424#include "real.F90"
425#include "orbitalset_utils_inc.F90"
426
427#include "undef.F90"
428#include "complex.F90"
429#include "orbitalset_utils_inc.F90"
430
431end module orbitalset_utils_oct_m
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:188
This module is intended to contain "only mathematical" functions and procedures.
Definition: math.F90:115
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:920
character(len=512), private msg
Definition: messages.F90:165
character(len=256), dimension(max_lines), public message
to be output by fatal, warning
Definition: messages.F90:160
subroutine, public messages_info(no_lines, iunit, debug_only, stress, all_nodes, namespace)
Definition: messages.F90:616
integer, parameter, public sm_poisson_psolver
subroutine zget_orbital(species, sm, i, l, j_in, iorb, ndim, orb, combine_j_orbitals)
Returns an orbital on the intersite submesh.
subroutine, public dorbitalset_utils_getorbitals(namespace, os, ions, mesh, use_mesh, normalize, index_shift)
integer, parameter, public sm_poisson_isf
subroutine, public zorbitalset_get_center_of_mass(os, space, mesh, latt)
subroutine, public zorbitalset_utils_getorbitals(namespace, os, ions, mesh, use_mesh, normalize, index_shift)
subroutine, public orbitalset_init_intersite(this, namespace, space, ind, ions, der, psolver, os, nos, maxnorbs, rcut, kpt, has_phase, sm_poisson, basis_from_states, combine_j_orbitals)
subroutine dget_orbital(species, sm, i, l, j_in, iorb, ndim, orb, combine_j_orbitals)
Returns an orbital on the intersite submesh.
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)
Count the number of orbital sets we have for a given atom.
subroutine, public zpoisson_solve_sm(this, namespace, sm, pot, rho, all_nodes)
Calculates the Poisson equation. Given the density returns the corresponding potential.
Definition: poisson.F90:2346
integer, parameter, public poisson_psolver
Definition: poisson.F90:189
integer, parameter, public poisson_fft
Definition: poisson.F90:189
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:2161
integer, parameter, public poisson_direct_sum
Definition: poisson.F90:189
subroutine, public poisson_init_sm(this, namespace, space, main, der, sm, method, force_cmplx)
Definition: poisson.F90:999
integer, parameter, public poisson_isf
Definition: poisson.F90:189
subroutine, public poisson_end(this)
Definition: poisson.F90:709
subroutine, public submesh_end_global(this)
Definition: submesh.F90:871
complex(real64) function, public zsm_integrate(mesh, sm, ff, reduce)
Definition: submesh.F90:1703
subroutine, public submesh_shift_center(this, space, newcenter)
Definition: submesh.F90:631
real(real64) function, public dsm_integrate(mesh, sm, ff, reduce)
Definition: submesh.F90:1166
subroutine, public submesh_merge(this, space, mesh, sm1, sm2, shift)
Definition: submesh.F90:565
subroutine, public submesh_end_cube_map(sm)
Definition: submesh.F90:1046
subroutine, public submesh_end(this)
Definition: submesh.F90:736
subroutine, public submesh_build_global(this, space)
Definition: submesh.F90:820
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...