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 call distributed_nullify(dist, this%nneighbors)
204#ifdef HAVE_MPI
205 if(.not. der%mesh%parallel_in_domains) then
206 call distributed_init(dist, this%nneighbors, mpi_comm_world, 'orbs')
207 end if
208#endif
209
210 do inn = dist%start, dist%end
211
212 ios = this%map_os(inn)
213
214 if(.not. basis_from_states) then
215 !Init a submesh from the union of two submeshes
216 call submesh_merge(sm, space, der%mesh, this%sphere, os(ios)%sphere, &
217 shift = this%V_ij(inn, 1:space%dim))
218
219 write(message(1),'(a, i3, a, f6.3, a, i7, a)') 'Neighbor ', inn, ' is located at ', &
220 this%V_ij(inn, space%dim+1), ' Bohr and has ', sm%np, ' grid points.'
221 call messages_info(1, namespace=namespace)
222
223 if (ndim == 1) then
224 safe_allocate(dorb(1:sm%np, 1:1, 1:max(this%norbs, os(ios)%norbs), 1:2))
225 else
226 safe_allocate(zorb(1:sm%np, 1:2, 1:max(this%norbs, os(ios)%norbs), 1:2))
227 end if
228
229 ! Get the orbitals from the first set of orbitals
230 if (ndim == 1) then
231 do ist = 1, this%norbs
232 call dget_orbital(this%spec, sm, this%ii, this%ll, this%jj, ist, 1, dorb(:, :, ist, 1), combine_j_orbitals)
233 end do
234 else
235 do ist = 1, this%norbs
236 call zget_orbital(this%spec, sm, this%ii, this%ll, this%jj, ist, 2, zorb(:, :, ist, 1), combine_j_orbitals)
237 end do
238 end if
239
240 call submesh_shift_center(sm, space, this%V_ij(inn, 1:space%dim)+os(ios)%sphere%center(1:space%dim))
241
242 ! Get the orbitals from the second set of orbitals
243 if (ndim == 1) then
244 do ist = 1, os(ios)%norbs
245 call dget_orbital(os(ios)%spec, sm, os(ios)%ii, os(ios)%ll, os(ios)%jj, ist, 1, dorb(:, :, ist, 2), combine_j_orbitals)
246 end do
247 else
248 do ist = 1, os(ios)%norbs
249 call zget_orbital(os(ios)%spec, sm, os(ios)%ii, os(ios)%ll, os(ios)%jj, ist, 2, zorb(:, :, ist, 2), combine_j_orbitals)
250 end do
251 end if
252
253 else
254 ! TODO: Replace datomic_orbital_get_submesh_safe by the logic above
255 assert(ndim == 1)
256 !Init a submesh from the union of two submeshes
257 call submesh_merge(sm, space, der%mesh, this%sphere, os(ios)%sphere, &
258 shift = this%V_ij(inn, 1:space%dim))
259
260 write(message(1),'(a, i3, a, f6.3, a, i5, a)') 'Neighbor ', inn, ' is located at ', &
261 this%V_ij(inn, space%dim+1), ' Bohr and has ', sm%np, ' grid points.'
262 call messages_info(1, namespace=namespace)
263
264 safe_allocate(dorb(1:sm%np, 1:1, 1:max(this%norbs,os(ios)%norbs), 1:2))
265 dorb = m_zero
266
267 ! All the points of the first submesh are included in the union of the submeshes
268 do ist = 1, this%norbs
269 if(allocated(this%dorb)) then
270 dorb(1:this%sphere%np, 1, ist, 1) = this%dorb(:,1,ist)
271 else
272 dorb(1:this%sphere%np, 1, ist, 1) = real(this%zorb(:,1,ist), real64)
273 end if
274 end do
275
276 call submesh_shift_center(sm, space, this%V_ij(inn, 1:space%dim)+os(ios)%sphere%center(1:space%dim))
277
278 ! TODO: This probably needs some optimization
279 ! However, this is only done at initialization time
280 do ist = 1, os(ios)%norbs
281 if(allocated(this%dorb)) then
282 !$omp parallel do private(ip)
283 do ip2 = 1, sm%np
284 do ip = 1, os(ios)%sphere%np
285 if(all(abs(sm%rel_x(1:space%dim, ip2)-os(ios)%sphere%rel_x(1:space%dim, ip)) < r_small)) then
286 dorb(ip2, 1, ist, 2) = os(ios)%dorb(ip, 1, ist)
287 end if
288 end do
289 end do
290 else
291 !$omp parallel do private(ip)
292 do ip2 = 1, sm%np
293 do ip = 1, os(ios)%sphere%np
294 if(all(abs(sm%rel_x(1:space%dim, ip2)-os(ios)%sphere%rel_x(1:space%dim, ip)) < r_small)) then
295 dorb(ip2, 1, ist, 2) = real(os(ios)%zorb(ip, 1, ist), real64)
296 end if
297 end do
298 end do
299 end if
300 end do
301
302 end if
303
304 select case (sm_poisson_)
305 case(sm_poisson_direct)
306 !Build information needed for the direct Poisson solver on the submesh
307 call submesh_build_global(sm, space)
308 call poisson_init_sm(this%poisson, namespace, space, psolver, der, sm, grp, method = poisson_direct_sum)
309 case(sm_poisson_isf)
310 call poisson_init_sm(this%poisson, namespace, space, psolver, der, sm, grp, method = poisson_isf)
312 call poisson_init_sm(this%poisson, namespace, space, psolver, der, sm, grp, method = poisson_psolver)
313 case(sm_poisson_fft)
314 call poisson_init_sm(this%poisson, namespace, space, psolver, der, sm, grp, method = poisson_fft, &
315 force_cmplx=(ndim==2))
316 end select
317
318 if (ndim == 1) then ! Real orbitals
319 safe_allocate(tmp(1:sm%np))
320 safe_allocate(nn(1:sm%np))
321 safe_allocate(vv(1:sm%np))
322
323 do ist = 1, this%norbs
324 !$omp parallel do
325 do ip = 1, sm%np
326 nn(ip) = dorb(ip, 1, ist, 1)*dorb(ip, 1, ist, 1)
327 end do
328 !$omp end parallel do
329
330 ! Here it is important to use a non-periodic poisson solver, e.g. the direct solver,
331 ! to not include contribution from periodic copies.
332 call dpoisson_solve_sm(this%poisson, namespace, sm, vv, nn)
333
334 do jst = 1, os(ios)%norbs
335
336 !$omp parallel do
337 do ip = 1, sm%np
338 tmp(ip) = vv(ip)*dorb(ip, 1, jst, 2)*dorb(ip, 1, jst, 2)
339 end do
340 !$omp end parallel do
341
342 this%coulomb_IIJJ(ist, ist, jst, jst, inn) = dsm_integrate(der%mesh, sm, tmp, reduce = .false.)
343 end do !jst
344 end do !ist
345
346 safe_deallocate_a(nn)
347 safe_deallocate_a(vv)
348 safe_deallocate_a(tmp)
349
350 else ! Complex orbitals
351 safe_allocate(ztmp(1:sm%np))
352 safe_allocate(znn(1:sm%np))
353 safe_allocate(zvv(1:sm%np, 1:ndim))
354
355 do ist = 1, this%norbs
356 do is1 = 1, ndim
357 !$omp parallel do
358 do ip = 1, sm%np
359 znn(ip) = conjg(zorb(ip, is1, ist, 1))*zorb(ip, is1, ist, 1)
360 end do
361 !$omp end parallel do
362
363 ! Here it is important to use a non-periodic poisson solver, e.g. the direct solver,
364 ! to not include contribution from periodic copies.
365 call zpoisson_solve_sm(this%poisson, namespace, sm, zvv(:,is1), znn)
366 end do !is1
367
368 do jst = 1, os(ios)%norbs
369
370 do is1 = 1, ndim
371 do is2 = 1, ndim
372 !$omp parallel do
373 do ip = 1, sm%np
374 ztmp(ip) = zvv(ip, is1)*conjg(zorb(ip, is2, jst, 2))*zorb(ip, is2, jst, 2)
375 end do
376 !$omp end parallel do
377
378 this%zcoulomb_IIJJ(ist, ist, jst, jst, is1, is2, inn) = zsm_integrate(der%mesh, sm, ztmp)
379 end do
380 end do
381 end do !jst
382 end do !ist
383
384 safe_deallocate_a(znn)
385 safe_deallocate_a(zvv)
386 safe_deallocate_a(ztmp)
387 end if
388
389 call poisson_end(this%poisson)
390
391
392 if (sm_poisson_ == sm_poisson_direct) call submesh_end_global(sm)
393 call submesh_end_cube_map(sm)
394 call submesh_end(sm)
395 safe_deallocate_a(dorb)
396 safe_deallocate_a(zorb)
397 end do !inn
398
399 if(this%ndim == 1) then
400 call der%mesh%allreduce(this%coulomb_IIJJ)
401 end if
402
403 if(dist%parallel) then
404 if (ndim == 1) then
405 call comm_allreduce(dist%mpi_grp, this%coulomb_IIJJ)
406 else
407 do inn = 1, this%nneighbors
408 do is2 = 1, ndim
409 do is1 = 1, ndim
410 call comm_allreduce(dist%mpi_grp, this%zcoulomb_IIJJ(:,:,:,:, is1, is2, inn))
411 end do
412 end do
413 end do
414 end if
415 end if
416
417 call distributed_end(dist)
418
419 call messages_print_with_emphasis(namespace=namespace)
420
422 end subroutine orbitalset_init_intersite
423
424#include "undef.F90"
425#include "real.F90"
426#include "orbitalset_utils_inc.F90"
427
428#include "undef.F90"
429#include "complex.F90"
430#include "orbitalset_utils_inc.F90"
431
432end 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 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
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:2181
integer, parameter, public poisson_psolver
Definition: poisson.F90:188
integer, parameter, public poisson_fft
Definition: poisson.F90:188
subroutine, public poisson_init_sm(this, namespace, space, main, der, sm, grp, method, force_cmplx)
Definition: poisson.F90:969
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:2022
integer, parameter, public poisson_direct_sum
Definition: poisson.F90:188
integer, parameter, public poisson_isf
Definition: poisson.F90:188
subroutine, public poisson_end(this)
Definition: poisson.F90:679
subroutine, public submesh_end_global(this)
Definition: submesh.F90:796
complex(real64) function, public zsm_integrate(mesh, sm, ff, reduce)
Definition: submesh.F90:1628
subroutine, public submesh_shift_center(this, space, newcenter)
Definition: submesh.F90:572
real(real64) function, public dsm_integrate(mesh, sm, ff, reduce)
Definition: submesh.F90:1091
subroutine, public submesh_merge(this, space, mesh, sm1, sm2, shift)
Definition: submesh.F90:506
subroutine, public submesh_end_cube_map(sm)
Definition: submesh.F90:971
subroutine, public submesh_end(this)
Definition: submesh.F90:677
subroutine, public submesh_build_global(this, space)
Definition: submesh.F90:745
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...