Octopus
hirshfeld.F90
Go to the documentation of this file.
1!! Copyright (C) 2015 X. Andrade
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!!
18
19#include "global.h"
20
21module hirshfeld_oct_m
22 use atom_oct_m
23 use comm_oct_m
24 use debug_oct_m
26 use global_oct_m
27 use, intrinsic :: iso_fortran_env
29 use mesh_oct_m
33 use parser_oct_m
35 use ps_oct_m
37 use space_oct_m
41
42 implicit none
43
44 private
45 public :: &
53
54 type hirshfeld_t
55 private
56 class(mesh_t), pointer :: mesh
57 type(atom_t), pointer :: atom(:)
58 real(real64), pointer :: pos(:,:)
59 integer :: natoms
60 type(lattice_vectors_t), pointer :: latt
61 real(real64), allocatable :: total_density(:)
62 real(real64), allocatable :: free_volume(:)
63 real(real64), allocatable :: free_vol_r3(:,:)
64 integer :: nspin
65 type(namespace_t) :: namespace
66 end type hirshfeld_t
67
68 real(real64), parameter, public :: TOL_HIRSHFELD = 1e-9_real64
69
70contains
71
72 subroutine hirshfeld_init(this, mesh, namespace, space, latt, atom, natoms, pos, nspin)
73 type(hirshfeld_t), intent(out) :: this
74 class(mesh_t), target, intent(in) :: mesh
75 type(namespace_t), intent(in) :: namespace
76 class(space_t), intent(in) :: space
77 type(lattice_vectors_t), target, intent(in):: latt
78 type(atom_t), target, intent(in) :: atom(:)
79 integer, intent(in) :: natoms
80 real(real64), target, intent(in) :: pos(1:space%dim,1:natoms)
81 integer, intent(in) :: nspin
82
83 integer :: iatom, ip, isp
84 real(real64) :: rr, atom_pos(space%dim), rmax, den
85 real(real64), allocatable :: atom_density(:, :)
86 type(ps_t), pointer :: ps
87 type(lattice_iterator_t) :: latt_iter
88 integer :: icell
89 push_sub(hirshfeld_init)
90
91 call profiling_in("HIRSHFELD_INIT")
92
93 this%mesh => mesh
94 this%atom => atom
95 this%natoms = natoms
96 this%nspin = nspin
97 this%pos => pos
98 this%latt => latt
99 this%namespace = namespace
100
101 safe_allocate(this%total_density(1:mesh%np))
102 safe_allocate(this%free_volume(1:natoms))
103 safe_allocate(this%free_vol_r3(1:mesh%np, 1:natoms))
104 safe_allocate(atom_density(1:mesh%np, 1:nspin))
105
106 !$omp parallel
107 !$omp do simd
108 do ip = 1, mesh%np
109 this%total_density(ip) = m_zero
110 end do
111 !$omp end do simd nowait
112 do iatom = 1, natoms
113 !$omp do simd
114 do ip = 1, mesh%np
115 this%free_vol_r3(ip, iatom) = m_zero
116 end do
117 !$omp end do simd nowait
118 end do
119 !$omp end parallel
120
121 do iatom = 1, natoms
122 select type(spec=>atom(iatom)%species)
123 type is(pseudopotential_t)
124 ps => spec%ps
125 class default
126 assert(.false.)
127 end select
128
129 rmax = m_zero
130 do isp = 1, nspin
131 rmax = max(rmax, ps%density(isp)%x_threshold)
132 end do
133
134 latt_iter = lattice_iterator_t(latt, rmax)
135 do icell = 1, latt_iter%n_cells
136 atom_pos = pos(:, iatom) + latt_iter%get(icell)
137 !We get the non periodized density
138 !We need to do it to have the r^3 correctly computed for periodic systems
139 call species_atom_density_np(atom(iatom)%species, namespace, atom_pos, mesh, nspin, atom_density)
140
141 !$omp parallel do simd private(rr, den)
142 do ip = 1, mesh%np
143 rr = norm2(mesh%x(ip, :) - atom_pos)
144 den = sum(atom_density(ip, 1:nspin))
145
146 this%total_density(ip) = this%total_density(ip) + den
147 this%free_vol_r3(ip, iatom) = this%free_vol_r3(ip, iatom) + den*rr**3
148 end do
149 end do
150 this%free_volume(iatom) = dmf_integrate(this%mesh, this%free_vol_r3(:, iatom), reduce = .false.)
151 end do
153 if (this%mesh%parallel_in_domains) then
154 call this%mesh%allreduce(this%free_volume)
155 end if
157 safe_deallocate_a(atom_density)
159 call profiling_out("HIRSHFELD_INIT")
160
162 end subroutine hirshfeld_init
163
164 ! ------------------------------------------------
166 subroutine hirshfeld_end(this)
167 type(hirshfeld_t), intent(inout) :: this
168
169 push_sub(hirshfeld_end)
170
171 safe_deallocate_a(this%total_density)
172 safe_deallocate_a(this%free_volume)
173 safe_deallocate_a(this%free_vol_r3)
174
175 nullify(this%mesh)
176 nullify(this%pos)
177 nullify(this%atom)
178 nullify(this%latt)
179
180 pop_sub(hirshfeld_end)
181 end subroutine hirshfeld_end
182
183 ! -----------------------------------------------
184
185 subroutine hirshfeld_charge(this, space, iatom, density, charge)
186 type(hirshfeld_t), intent(in) :: this
187 class(space_t), intent(in) :: space
188 integer, intent(in) :: iatom
189 real(real64), intent(in) :: density(:, :)
190 real(real64), intent(out) :: charge
191
192 integer :: ip
193 real(real64) :: dens_ip
194 real(real64), allocatable :: atom_density(:, :), hirshfeld_density(:)
195
196 push_sub(hirshfeld_charge)
197
198 call profiling_in("HIRSHFELD_CHARGE")
199
200 assert(allocated(this%total_density))
201
202 safe_allocate(atom_density(1:this%mesh%np, 1:this%nspin))
203 safe_allocate(hirshfeld_density(1:this%mesh%np))
204
205 call species_atom_density(this%atom(iatom)%species, this%namespace, space, this%latt, &
206 this%pos(:, iatom), this%mesh, this%nspin, atom_density)
207
208 !$omp parallel do simd private(dens_ip)
209 do ip = 1, this%mesh%np
210 dens_ip = sum(atom_density(ip, 1:this%nspin))
211 if (abs(dens_ip) > tol_hirshfeld) then
212 hirshfeld_density(ip) = sum(density(ip, 1:this%nspin))*dens_ip/this%total_density(ip)
213 else
214 hirshfeld_density(ip) = 0.0_real64
215 end if
216 end do
217
218 charge = dmf_integrate(this%mesh, hirshfeld_density)
219
220 safe_deallocate_a(atom_density)
221 safe_deallocate_a(hirshfeld_density)
222
223 call profiling_out("HIRSHFELD_CHARGE")
224
225 pop_sub(hirshfeld_charge)
226 end subroutine hirshfeld_charge
227
228 ! -----------------------------------------------
229
230 subroutine hirshfeld_volume_ratio(this, iatom, density, volume_ratio)
231 type(hirshfeld_t), intent(in) :: this
232 integer, intent(in) :: iatom
233 real(real64), intent(in) :: density(:, :)
234 real(real64), intent(out) :: volume_ratio
235
236 integer :: ip
237 real(real64), allocatable :: hirshfeld_density(:)
238
239
240 push_sub(hirshfeld_volume_ratio)
241
242 call profiling_in("HIRSHFELD_VOLUME_RATIO")
243
244 assert(allocated(this%total_density))
245
246 safe_allocate(hirshfeld_density(1:this%mesh%np))
247
248 !$omp parallel do simd
249 do ip = 1, this%mesh%np
250 if (this%total_density(ip) > tol_hirshfeld) then
251 hirshfeld_density(ip) = this%free_vol_r3(ip, iatom)*sum(density(ip, 1:this%nspin))/this%total_density(ip)
252 else
253 hirshfeld_density(ip) = 0.0_real64
254 end if
255 end do
256
257 volume_ratio = dmf_integrate(this%mesh, hirshfeld_density)/this%free_volume(iatom)
258
259 safe_deallocate_a(hirshfeld_density)
260
261 call profiling_out("HIRSHFELD_VOLUME_RATIO")
262
264 end subroutine hirshfeld_volume_ratio
265
266 ! -----------------------------------------------
267
268 subroutine hirshfeld_density_derivative(this, iatom, ddensity)
269 type(hirshfeld_t), intent(in) :: this
270 integer, intent(in) :: iatom
271 real(real64), intent(out) :: ddensity(:)
272
273 integer :: ip
274 real(real64), allocatable :: atom_density(:, :)
275
277
278 call profiling_in("HIRSHFELD_DENSITY_DER")
279
280 safe_allocate(atom_density(1:this%mesh%np, 1:this%nspin))
281
282 !$omp parallel do simd
283 do ip = 1, this%mesh%np
284 if (abs(this%total_density(ip)) > tol_hirshfeld) then
285 ddensity(ip) = this%free_vol_r3(ip, iatom)/(this%total_density(ip)*this%free_volume(iatom))
286 else
287 ddensity(ip) = m_zero
288 end if
289 end do
290
291 safe_deallocate_a(atom_density)
292
293 call profiling_out("HIRSHFELD_DENSITY_DER")
294
296 end subroutine hirshfeld_density_derivative
297
298 ! -----------------------------------------------
299 !dvadrr_ij = \frac{\delta V_i}{\delta \vec{x_j}}
300 subroutine hirshfeld_position_derivative(this, space, iatom, jatom, density, dposition)
301 type(hirshfeld_t), intent(in) :: this
302 class(space_t), intent(in) :: space
303 integer, intent(in) :: iatom
304 integer, intent(in) :: jatom
305 real(real64), intent(in) :: density(:, :)
306 real(real64), contiguous, intent(out) :: dposition(:)
307
308 integer :: ip, idir, icell, jcell, isp
309 real(real64) :: atom_dens, atom_der,rri, rri2, rrj, tdensity, rij, rmax_isqu, rmax_jsqu
310 real(real64) :: pos_i(space%dim), pos_j(space%dim), rmax_i, rmax_j
311 real(real64), allocatable :: grad(:, :), atom_density(:, :), atom_derivative(:, :)
312 type(lattice_iterator_t) :: latt_iter_i, latt_iter_j
313 type(ps_t), pointer :: ps_i, ps_j
314 real(real64) :: tmp, xxi(space%dim), xxj(space%dim)
315
316 real(real64) :: tol_spacing
317
319
320 tol_spacing = maxval(this%mesh%spacing(1:space%dim))
321
322 call profiling_in("HIRSHFELD_POSITION_DER")
324 dposition(1:space%dim) = m_zero
325
326 select type(spec=> this%atom(iatom)%species)
327 type is(pseudopotential_t)
328 ps_i => spec%ps
329 class default
330 assert(.false.)
331 end select
332 select type(spec=> this%atom(jatom)%species)
333 type is(pseudopotential_t)
334 ps_j => spec%ps
335 class default
336 assert(.false.)
337 end select
338
339 rmax_i = m_zero
340 rmax_j = m_zero
341 do isp = 1, this%nspin
342 rmax_i = max(rmax_i, ps_i%density(isp)%x_threshold)
343 rmax_j = max(rmax_j, ps_j%density_der(isp)%x_threshold)
344 end do
345
346 rmax_isqu = rmax_i**2
347 rmax_jsqu = rmax_j**2
348
349 safe_allocate(grad(1:this%mesh%np, 1:space%dim))
350 grad(1:this%mesh%np, 1:space%dim) = m_zero
351 safe_allocate(atom_derivative(1:this%mesh%np, 1:this%nspin))
352 safe_allocate(atom_density(1:this%mesh%np, 1:this%nspin))
353
354 latt_iter_j = lattice_iterator_t(this%latt, rmax_j)
355 do jcell = 1, latt_iter_j%n_cells
356
357 pos_j = this%pos(:, jatom) + latt_iter_j%get(jcell)
358 atom_derivative(1:this%mesh%np, 1:this%nspin) = m_zero
359 call species_atom_density_derivative_np(this%atom(jatom)%species, this%namespace, pos_j, this%mesh, &
360 min(this%nspin, 2), atom_derivative(1:this%mesh%np, 1:this%nspin))
362 latt_iter_i = lattice_iterator_t(this%latt, (rmax_j+rmax_i)) ! jcells further away from this distance cannot respect the following 'if' condition with respect to the i atom in this icell
363 do icell = 1, latt_iter_i%n_cells
364
365 pos_i = pos_j + latt_iter_i%get(icell) + (this%pos(:, iatom) - this%pos(:, jatom))
366 rij = norm2(pos_i - pos_j)
367
368 if (rij - (rmax_j+rmax_i) < tol_spacing) then
369
370 !We get the non periodized density
371 !We need to do it to have the r^3 correctly computed for periodic systems
372 call species_atom_density_np(this%atom(iatom)%species, this%namespace, pos_i, this%mesh, this%nspin, &
373 atom_density(1:this%mesh%np, 1:this%nspin))
374
375 !$omp parallel do private(xxi, rri, rri2, xxj, rrj, tdensity, atom_dens, atom_der, tmp, idir)
376 do ip = 1, this%mesh%np
377 if (this%total_density(ip)< tol_hirshfeld) cycle
378
379 xxi = this%mesh%x(ip, :) - pos_i
380 rri2 = sum(xxi**2)
381 if (rri2 - rmax_isqu > tol_spacing) cycle ! In this case atom_dens = 0
382
383 xxj = this%mesh%x(ip, :) - pos_j
384 rrj = sum(xxj**2)
385 if (rrj - rmax_jsqu > tol_spacing) cycle ! In this case atom_der = 0
386
387 rri = sqrt(rri2)
388 rrj = sqrt(rrj)
389
390 tdensity = sum(density(ip, 1:this%nspin))
391 atom_dens = sum(atom_density(ip, 1:this%nspin))
392 atom_der = sum(atom_derivative(ip, 1:this%nspin))
394 if (rrj > tol_hirshfeld) then
395 tmp = rri*rri2*atom_dens*tdensity/this%total_density(ip)**2
396 do idir = 1, space%dim
397 grad(ip, idir) = grad(ip, idir) - tmp*atom_der*xxj(idir)/rrj
398 end do
399 end if
400
401 !Only if we really have the same atoms
402 if (iatom == jatom .and. rij < tol_hirshfeld) then
403 grad(ip, :) = grad(ip, :) + (m_three*rri*atom_dens + rri2*atom_der)*tdensity/this%total_density(ip)*xxi
404 end if
405
406 end do
407
408 end if
409 end do
410 end do
411
412 do idir = 1, space%dim
413 dposition(idir) = dmf_integrate(this%mesh, grad(1:this%mesh%np, idir), reduce = .false.) &
414 /this%free_volume(iatom)
415 end do
416
417 if (this%mesh%parallel_in_domains) then
418 call this%mesh%allreduce(dposition, dim = space%dim)
419 end if
420
421 safe_deallocate_a(atom_density)
422 safe_deallocate_a(atom_derivative)
423 safe_deallocate_a(grad)
424
425 call profiling_out("HIRSHFELD_POSITION_DER")
426
428 end subroutine hirshfeld_position_derivative
429
430end module hirshfeld_oct_m
431
432!! Local Variables:
433!! mode: f90
434!! coding: utf-8
435!! End:
double sqrt(double __x) __attribute__((__nothrow__
This module calculates the derivatives (gradients, Laplacians, etc.) of a function.
real(real64), parameter, public m_zero
Definition: global.F90:187
real(real64), parameter, public m_three
Definition: global.F90:190
subroutine, public hirshfeld_init(this, mesh, namespace, space, latt, atom, natoms, pos, nspin)
Definition: hirshfeld.F90:166
subroutine, public hirshfeld_charge(this, space, iatom, density, charge)
Definition: hirshfeld.F90:279
subroutine, public hirshfeld_end(this)
Definition: hirshfeld.F90:260
subroutine, public hirshfeld_density_derivative(this, iatom, ddensity)
Definition: hirshfeld.F90:362
subroutine, public hirshfeld_position_derivative(this, space, iatom, jatom, density, dposition)
Definition: hirshfeld.F90:394
subroutine, public hirshfeld_volume_ratio(this, iatom, density, volume_ratio)
Definition: hirshfeld.F90:324
This module defines various routines, operating on mesh functions.
real(real64) function, public dmf_integrate(mesh, ff, mask, reduce)
Integrate a function on the mesh.
This module defines the meshes, which are used in Octopus.
Definition: mesh.F90:118
subroutine, public profiling_out(label)
Increment out counter and sum up difference between entry and exit time.
Definition: profiling.F90:623
subroutine, public profiling_in(label, exclude)
Increment in counter and save entry time.
Definition: profiling.F90:552
Definition: ps.F90:114
subroutine, public species_atom_density_np(species, namespace, pos, mesh, spin_channels, rho)
subroutine, public species_atom_density_derivative_np(species, namespace, pos, mesh, spin_channels, drho)
subroutine, public species_atom_density(species, namespace, space, latt, pos, mesh, spin_channels, rho)
The following class implements a lattice iterator. It allows one to loop over all cells that are with...