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, grp, 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 type(mpi_grp_t), intent(in) :: grp
94 integer, intent(in) :: ind
95 type(ions_t), intent(in) :: ions
96 type(derivatives_t), intent(in) :: der
97 type(poisson_t), intent(in) :: psolver
98 type(orbitalset_t), intent(inout) :: os(:)
99 integer, intent(in) :: nos, maxnorbs
100 real(real64), intent(in) :: rcut
101 type(distributed_t), intent(in) :: kpt
102 logical, intent(in) :: has_phase
103 integer, intent(in) :: sm_poisson
104 logical, intent(in) :: basis_from_states
105 logical, intent(in) :: combine_j_orbitals
106
107
108 type(lattice_iterator_t) :: latt_iter
109 real(real64) :: xat(space%dim), xi(space%dim)
110 real(real64) :: rr
111 integer :: inn, ist, jst, nneighbors, norbs, ndim
112 integer :: ip, ios, ip2, is1, is2
113 type(submesh_t) :: sm
114 real(real64), allocatable :: tmp(:), vv(:), nn(:)
115 complex(real64), allocatable :: ztmp(:), zvv(:,:), znn(:)
116 real(real64), allocatable :: dorb(:,:,:,:)
117 complex(real64), allocatable :: zorb(:,:,:,:)
118 real(real64), parameter :: TOL_INTERSITE = 1.e-5_real64
119 type(distributed_t) :: dist
120 integer :: sm_poisson_
121
123
124 call messages_print_with_emphasis(msg="Intersite Coulomb integrals", namespace=namespace)
125
126 sm_poisson_ = sm_poisson
127 ndim = this%ndim
128
129 this%nneighbors = 0
130 if (this%iatom /= -1) then
131 xat = ions%pos(:, this%iatom)
132 else
133 xat = this%sphere%center
134 end if
135
136 latt_iter = lattice_iterator_t(ions%latt, rcut)
137
138 !We first count first the number of neighboring atoms at a distance max rcut
139 do ios = 1, nos
140 do inn = 1, latt_iter%n_cells
141
142 xi = os(ios)%sphere%center(1:space%dim) + latt_iter%get(inn)
143 rr = norm2(xi - xat)
144
145 !This atom is too far
146 if( rr >rcut + tol_intersite ) cycle
147 !Intra atomic interaction
148 if( ios == ind .and. rr < tol_intersite) cycle
149
150 this%nneighbors = this%nneighbors +1
151 end do
152 end do
153
154 !The first three values are the position of the periodic copies
155 !and the zero value one is used to store the actual value of V_ij
156 safe_allocate(this%V_ij(1:this%nneighbors, 0:space%dim+1))
157 this%V_ij(1:this%nneighbors, 0:space%dim+1) = m_zero
158 safe_allocate(this%map_os(1:this%nneighbors))
159 this%map_os(1:this%nneighbors) = 0
160 if(has_phase) then
161 safe_allocate(this%phase_shift(1:this%nneighbors, kpt%start:kpt%end))
162 end if
163
164 this%nneighbors = 0
165 do ios = 1, nos
166 do inn = 1, latt_iter%n_cells
167 xi = os(ios)%sphere%center(1:space%dim) + latt_iter%get(inn)
168 rr = norm2(xi - xat)
169
170 if( rr > rcut + tol_intersite ) cycle
171 if( ios == ind .and. rr < tol_intersite) cycle
172
173 this%nneighbors = this%nneighbors +1
174
175 this%V_ij(this%nneighbors, 1:space%dim) = xi(1:space%dim) -os(ios)%sphere%center(1:space%dim)
176 this%V_ij(this%nneighbors, space%dim+1) = rr
177
178 this%map_os(this%nneighbors) = ios
179 end do
180 end do
181
182 write(message(1),'(a, i3, a)') 'Intersite interaction will be computed for ', this%nneighbors, ' neighboring atoms.'
183 call messages_info(1, namespace=namespace)
184
185 ! Local definitions to reduce the macro line length
186 norbs = this%norbs
187 nneighbors = this%nneighbors
188
189 if (ndim == 1) then
190 safe_allocate(this%coulomb_IIJJ(1:norbs,1:norbs,1:maxnorbs,1:maxnorbs,1:nneighbors))
191 this%coulomb_IIJJ = m_zero
192 else
193 safe_allocate(this%zcoulomb_IIJJ(1:norbs,1:norbs,1:maxnorbs,1:maxnorbs, 1:ndim, 1:ndim, 1:nneighbors))
194 this%zcoulomb_IIJJ = m_zero
195 end if
196
197 if(this%nneighbors == 0) then
198 call messages_print_with_emphasis(namespace=namespace)
200 return
201 end if
202
203 if (der%mesh%parallel_in_domains) then
204 call distributed_init_serial(dist, this%nneighbors)
205 else
206 call distributed_init(dist, this%nneighbors, mpi_world%comm, 'orbs')
207 end if
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, space, der%mesh, this%sphere, os(ios)%sphere, &
257 shift = this%V_ij(inn, 1: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, 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, space, this%V_ij(inn, 1:space%dim)+os(ios)%sphere%center(1: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:space%dim, ip2)-os(ios)%sphere%rel_x(1:space%dim, ip)) < r_small)) 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:space%dim, ip2)-os(ios)%sphere%rel_x(1:space%dim, ip)) < r_small)) 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, grp, method = poisson_direct_sum)
308 case(sm_poisson_isf)
309 call poisson_init_sm(this%poisson, namespace, space, psolver, der, sm, grp, method = poisson_isf)
311 call poisson_init_sm(this%poisson, namespace, space, psolver, der, sm, grp, method = poisson_psolver)
312 case(sm_poisson_fft)
313 call poisson_init_sm(this%poisson, namespace, space, psolver, der, sm, grp, 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_init(this, total, comm, tag, scalapack_compat)
Distribute N instances across M processes of communicator comm
subroutine, public distributed_init_serial(this, total)
Serial initialization of a distributed instance. The calling process is assigned all total instances,...
real(real64), parameter, public r_small
Definition: global.F90:192
real(real64), parameter, public m_zero
Definition: global.F90:200
System information (time, memory, sysname)
Definition: loct.F90:117
This module is intended to contain "only mathematical" functions and procedures.
Definition: math.F90:117
This module defines the meshes, which are used in Octopus.
Definition: mesh.F90:120
subroutine, public messages_print_with_emphasis(msg, iunit, namespace)
Definition: messages.F90:898
character(len=512), private msg
Definition: messages.F90:167
character(len=256), dimension(max_lines), public message
to be output by fatal, warning
Definition: messages.F90:162
subroutine, public messages_info(no_lines, iunit, debug_only, stress, all_nodes, namespace)
Definition: messages.F90:594
type(mpi_grp_t), public mpi_world
Definition: mpi.F90:276
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 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)
subroutine, public orbitalset_init_intersite(this, namespace, space, grp, ind, ions, der, psolver, os, nos, maxnorbs, rcut, kpt, has_phase, sm_poisson, basis_from_states, combine_j_orbitals)
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:2428
integer, parameter, public poisson_psolver
Definition: poisson.F90:191
integer, parameter, public poisson_fft
Definition: poisson.F90:191
subroutine, public poisson_init_sm(this, namespace, space, main, der, sm, grp, method, force_cmplx)
Definition: poisson.F90:1125
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:2172
integer, parameter, public poisson_direct_sum
Definition: poisson.F90:191
integer, parameter, public poisson_isf
Definition: poisson.F90:191
subroutine, public poisson_end(this)
Definition: poisson.F90:692
subroutine, public submesh_end_global(this)
Definition: submesh.F90:799
complex(real64) function, public zsm_integrate(mesh, sm, ff, reduce)
Definition: submesh.F90:1648
subroutine, public submesh_shift_center(this, space, newcenter)
Definition: submesh.F90:575
real(real64) function, public dsm_integrate(mesh, sm, ff, reduce)
Definition: submesh.F90:1094
subroutine, public submesh_merge(this, space, mesh, sm1, sm2, shift)
Definition: submesh.F90:509
subroutine, public submesh_end_cube_map(sm)
Definition: submesh.F90:974
subroutine, public submesh_end(this)
Definition: submesh.F90:680
subroutine, public submesh_build_global(this, space)
Definition: submesh.F90:748
brief This module defines the class unit_t which is used by the unit_systems_oct_m module.
Definition: unit.F90:134
The following class implements a lattice iterator. It allows one to loop over all cells that are with...