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