Octopus
species_pot.F90
Go to the documentation of this file.
1!! Copyright (C) 2002-2006 M. Marques, A. Castro, A. Rubio, G. Bertsch
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
24 use debug_oct_m
25 use global_oct_m
27 use index_oct_m
28 use, intrinsic :: iso_fortran_env
33 use logrid_oct_m
35 use mesh_oct_m
37 use mpi_oct_m
39 use parser_oct_m
41 use ps_oct_m
44 use space_oct_m
49 use unit_oct_m
51 use volume_oct_m
52
53 implicit none
54
55 private
56 public :: &
64
65 type(mesh_t), pointer :: mesh_p
66 real(real64), allocatable :: rho_p(:)
67 real(real64), allocatable :: grho_p(:, :)
68 real(real64) :: alpha2_p
69 real(real64), pointer :: pos_p(:)
70
71contains
72
73
74 ! ---------------------------------------------------------
75 subroutine species_atom_density(species, namespace, space, latt, pos, mesh, spin_channels, rho)
76 class(species_t), target, intent(in) :: species
77 type(namespace_t), intent(in) :: namespace
78 class(space_t), intent(in) :: space
79 type(lattice_vectors_t), intent(in) :: latt
80 real(real64), intent(in) :: pos(1:space%dim)
81 type(mesh_t), intent(in) :: mesh
82 integer, intent(in) :: spin_channels
83 real(real64), intent(inout) :: rho(:, :)
84
85 integer :: isp, ip, in_points, icell
86 real(real64) :: rr, x, pos_pc(space%dim), nrm, rmax
87 real(real64) :: xx(space%dim), yy(space%dim), rerho, imrho
88 real(real64), allocatable :: dorbital(:)
89 type(ps_t), pointer :: ps
90 type(volume_t) :: volume
91 integer :: in_points_red
92 type(lattice_iterator_t) :: latt_iter
93 integer :: iorb, ii, nn, ll, mm
94 real(real64) :: radius, density
95 type(submesh_t) :: sphere
96
97 push_sub(species_atom_density)
98
99 assert(spin_channels == 1 .or. spin_channels == 2)
100
101 rho = m_zero
102
103 ! build density ...
104 select type (species)
105 type is(species_from_file_t)
107
110
111 type is(soft_coulomb_t)
113
114 class is(allelectron_t)
115
116 do isp = 1, spin_channels
117 do iorb = 1, species%get_niwfs()
118 call species%get_iwf_ilm(iorb, isp, ii, ll, mm)
119 ! For all-electron species, we want to use the principal quantum number
120 call species%get_iwf_n(iorb, isp, nn)
121
122 radius = species%get_iwf_radius(nn, isp)
123 ! make sure that if the spacing is too large, the orbitals fit in a few points at least
124 radius = max(radius, m_two*maxval(mesh%spacing))
125
126 call submesh_init(sphere, space, mesh, latt, pos, radius)
127 safe_allocate(dorbital(1:sphere%np))
128
129 call datomic_orbital_get_submesh(species, sphere, nn, ll, mm, isp, dorbital)
130 ! The occupations are for one type of orbitals, e.g. 2p gets 6 electrons
131 ! So we normalize them by (2*l+1) such that they get distributed evenly
132 ! for each value of m
133 do ip = 1, sphere%np
134 dorbital(ip) = species%conf%occ(ii, isp)/real(2*ll+1, real64) *dorbital(ip)*dorbital(ip)
135 end do
136 call submesh_add_to_mesh(sphere, dorbital, rho(:, isp))
137 safe_deallocate_a(dorbital)
138
139 call submesh_end(sphere)
140 end do
141 end do
142
143 type is (jellium_charge_t)
144 ! We put, for the electron density, the same as the positive density that
145 ! creates the external potential.
146 ! This code is repeated in get_density, and should therefore be cleaned!!!!!
147
148 call volume_init(volume)
149 call volume_read_from_block(volume, namespace, trim(species%rho_string()))
150
151 rmax = latt%max_length()
152 latt_iter = lattice_iterator_t(latt, rmax)
153 rho = m_zero
154 do icell = 1, latt_iter%n_cells
155 yy = latt_iter%get(icell)
156 do ip = 1, mesh%np
157 call mesh_r(mesh, ip, rr, origin = pos, coords = xx)
158 xx = xx + yy
159 rr = norm2(xx)
161 rerho = m_zero
162 if (volume_in_volume(space, volume, xx)) rerho = m_one
163 rho(ip, 1) = rho(ip, 1) + rerho
164 end do
165 end do
166
167 call volume_end(volume)
168
169 if (spin_channels > 1) then
170 rho(:, 1) = m_half*rho(:, 1)
171 rho(:, 2) = rho(:, 1)
172 end if
173
174 ! rescale to match the valence charge
175 do isp = 1, spin_channels
176 x = species%get_zval() / dmf_integrate(mesh, rho(:, isp))
177 !$omp parallel do
178 do ip = 1, mesh%np
179 rho(ip, isp) = x * rho(ip, isp)
180 end do
181 !$omp end parallel do
182 end do
183
185 ! We put, for the electron density, the same as the positive density that
186 ! creates the external potential.
187 ! This code is repeated in get_density, and should therefore be cleaned!!!!!
188
189 rmax = latt%max_length()
190 latt_iter = lattice_iterator_t(latt, rmax)
191 rho = m_zero
192 do icell = 1, latt_iter%n_cells
193 yy = latt_iter%get(icell)
194 do ip = 1, mesh%np
195 call mesh_r(mesh, ip, rr, origin = pos, coords = xx)
196 xx = xx + yy
197 rr = norm2(xx)
198
199 rerho = m_zero
200 call parse_expression(rerho, imrho, space%dim, xx, rr, m_zero, trim(species%rho_string()))
201 rho(ip, 1) = rho(ip, 1) + rerho
202 end do
203 end do
204
205 if (spin_channels > 1) then
206 rho(:, 1) = m_half*rho(:, 1)
207 rho(:, 2) = rho(:, 1)
208 end if
209
210 ! rescale to match the valence charge
211 do isp = 1, spin_channels
212 x = species%get_zval() / dmf_integrate(mesh, rho(:, isp))
213 !$omp parallel do
214 do ip = 1, mesh%np
215 rho(ip, isp) = x * rho(ip, isp)
216 end do
217 !$omp end parallel do
218 end do
219
220
221 type is (jellium_sphere_t) ! ... from jellium
222 in_points = 0
223 do ip = 1, mesh%np
224 call mesh_r(mesh, ip, rr, origin = pos)
225 if (rr <= species%radius()) then
226 in_points = in_points + 1
227 end if
228 end do
229
230 if (mesh%parallel_in_domains) then
231 call mesh%mpi_grp%allreduce(in_points, in_points_red, 1, mpi_integer, mpi_sum)
232 in_points = in_points_red
233 end if
234
235 if (in_points > 0) then
236 ! This probably should be done inside the mesh_function_oct_m module.
237
238 if (mesh%use_curvilinear) then
239 do ip = 1, mesh%np
240 call mesh_r(mesh, ip, rr, origin = pos)
241 if (rr <= species%radius()) then
242 rho(ip, 1:spin_channels) = species%get_zval() / &
243 (mesh%vol_pp(ip) * real(in_points*spin_channels, real64) )
244 end if
245 end do
246 else
247 do ip = 1, mesh%np
248 call mesh_r(mesh, ip, rr, origin = pos)
249 if (rr <= species%radius()) then
250 rho(ip, 1:spin_channels) = species%get_zval() / &
251 (mesh%vol_pp(1) * real(in_points * spin_channels, real64) )
252 end if
253 end do
254 end if
255 end if
256
257 type is (jellium_slab_t) ! ... from jellium slab
258 density = species%get_density(mesh%box%bounding_box_l) / spin_channels
259
260 do ip = 1, mesh%np
261 rr = abs(mesh%x(3, ip) - pos(3))
262 if (rr <= species%thickness() / m_two) then
263 rho(ip, 1:spin_channels) = density
264 end if
265 end do
266
267 class is (pseudopotential_t)
268 ! ...from pseudopotentials
269
270 ps => species%ps
271
272 if (ps_has_density(ps)) then
273
274 assert(allocated(ps%density))
275
276 rmax = m_zero
277 do isp = 1, spin_channels
278 rmax = max(rmax, ps%density(isp)%x_threshold)
279 end do
280
281 latt_iter = lattice_iterator_t(latt, rmax)
282 do icell = 1, latt_iter%n_cells
283 pos_pc = pos + latt_iter%get(icell)
284 do ip = 1, mesh%np
285 call mesh_r(mesh, ip, rr, origin = pos_pc)
286 rr = max(rr, r_small)
287
288 do isp = 1, spin_channels
289 if (rr >= spline_range_max(ps%density(isp))) cycle
290 rho(ip, isp) = rho(ip, isp) + spline_eval(ps%density(isp), rr)
291 end do
292
293 end do
294 end do
295
296 else
297
298 !we use the square root of the short-range local potential, just to put something that looks like a density
299
300 latt_iter = lattice_iterator_t(latt, ps%vl%x_threshold)
301 do icell = 1, latt_iter%n_cells
302 pos_pc = pos + latt_iter%get(icell)
303 do ip = 1, mesh%np
304 call mesh_r(mesh, ip, rr, origin = pos_pc)
305 rr = max(rr, r_small)
306
307 if (rr >= spline_range_max(ps%vl)) cycle
308
309 do isp = 1, spin_channels
310 rho(ip, isp) = rho(ip, isp) + sqrt(abs(spline_eval(ps%vl, rr)))
311 end do
312
313 end do
314 end do
315
316 ! normalize
317 nrm = m_zero
318 do isp = 1, spin_channels
319 nrm = nrm + dmf_integrate(mesh, rho(:, isp))
320 end do
321
322 do isp = 1, spin_channels
323 call lalg_scal(mesh%np, species%get_zval()/nrm, rho(:, isp))
324 end do
325
326 end if
327 class default
328 assert(.false.)
329 end select
330
331 pop_sub(species_atom_density)
332 contains
333 subroutine generate_uniform_density()
334 do isp = 1, spin_channels
335 rho(1:mesh%np, isp) = m_one
336 x = (species%get_zval()/real(spin_channels, real64) ) / dmf_integrate(mesh, rho(:, isp))
337 rho(1:mesh%np, isp) = x
338 end do
339 end subroutine generate_uniform_density
340 end subroutine species_atom_density
341
342 ! ---------------------------------------------------------
343 ! A non periodized version of the routine species_atom_density
344 ! This is used for the Hirshfeld routines
345 ! TODO: implement it for other approaches than pseudo potentials.
346 subroutine species_atom_density_np(species, namespace, pos, mesh, spin_channels, rho)
347 class(species_t), target, intent(in) :: species
348 type(namespace_t), intent(in) :: namespace
349 real(real64), intent(in) :: pos(:)
350 type(mesh_t), intent(in) :: mesh
351 integer, intent(in) :: spin_channels
352 real(real64), intent(inout) :: rho(:, :)
353
354 integer :: isp, ip
355 real(real64) :: rr, nrm
356 type(ps_t), pointer :: ps
357
359
360 call profiling_in("SPECIES_ATOM_DEN_NP")
361
362 rho = m_zero
363 select type(species)
364 class is(pseudopotential_t)
365 ! ...from pseudopotentials
366
367 ps => species%ps
368 if (ps_has_density(ps)) then
369
370 assert(allocated(ps%density))
371
372 !$omp parallel private(ip, rr, isp)
373 do isp = 1, spin_channels
374 !$omp do
375 do ip = 1, mesh%np
376 call mesh_r(mesh, ip, rr, origin = pos)
377 if (rr >= spline_range_max(ps%density(isp))) cycle
378 rr = max(rr, r_small)
379 rho(ip, isp) = rho(ip, isp) + spline_eval(ps%density(isp), rr)
380 end do
381 !$omp end do nowait
382 end do
383 !$omp end parallel
384
385 else
386
387 !we use the square root of the short-range local potential, just to put something that looks like a density
388
389 do ip = 1, mesh%np
390 call mesh_r(mesh, ip, rr, origin = pos)
391 rr = max(rr, r_small)
392
393 if (rr >= spline_range_max(ps%vl)) cycle
394
395 do isp = 1, spin_channels
396 rho(ip, isp) = rho(ip, isp) + sqrt(abs(spline_eval(ps%vl, rr)))
397 end do
398
399 end do
400
401 ! normalize
402 nrm = m_zero
403 do isp = 1, spin_channels
404 nrm = nrm + dmf_integrate(mesh, rho(:, isp))
405 end do
406
407 do isp = 1, spin_channels
408 call lalg_scal(mesh%np, species%get_zval()/nrm, rho(:, isp))
409 end do
410
411 end if
412 class default
413 call messages_not_implemented('species_atom_density_np for non-pseudopotential species', namespace=namespace)
414
415 end select
416
417 call profiling_out("SPECIES_ATOM_DEN_NP")
418
420 end subroutine species_atom_density_np
421
422 ! ---------------------------------------------------------
423 !! Non-periodic version of the above routine
424 subroutine species_atom_density_derivative_np(species, namespace, pos, mesh, spin_channels, drho)
425 class(species_t), target, intent(in) :: species
426 type(namespace_t), intent(in) :: namespace
427 real(real64), intent(in) :: pos(:)
428 type(mesh_t), intent(in) :: mesh
429 integer, intent(in) :: spin_channels
430 real(real64), intent(inout) :: drho(:, :)
431
432 integer :: isp, ip
433 real(real64) :: rr
434 type(ps_t), pointer :: ps
435
437
438 call profiling_in("SPECIES_ATOM_DEN_DER_NP")
439
440 select type(species)
442 ps => species%ps
443
444 if (ps_has_density(ps)) then
445 !$omp parallel private(ip, rr, isp)
446 do isp = 1, spin_channels
447 !$omp do
448 do ip = 1, mesh%np
449 call mesh_r(mesh, ip, rr, origin = pos)
450 if (rr >= spline_range_max(ps%density_der(isp))) cycle
451 rr = max(rr, r_small)
452 drho(ip, isp) = drho(ip, isp) + spline_eval(ps%density_der(isp), rr)
453 end do
454 !$omp end do nowait
455 end do
456 !$omp end parallel
457
458 else
459 call messages_write('The pseudopotential for')
460 call messages_write(species%get_label())
461 call messages_write(' does not contain the density.')
462 call messages_fatal(namespace=namespace)
463 end if
464 class default
465 assert(.false.)
466 end select
467
468 call profiling_out("SPECIES_ATOM_DEN_DER_NP")
469
472
473
474 ! ---------------------------------------------------------
475 !! Gradient of the atomic density, if available
476 subroutine species_atom_density_grad(species, namespace, space, latt, pos, mesh, spin_channels, drho)
477 class(species_t), target, intent(in) :: species
478 type(namespace_t), intent(in) :: namespace
479 class(space_t), intent(in) :: space
480 type(lattice_vectors_t), intent(in) :: latt
481 real(real64), intent(in) :: pos(1:space%dim)
482 type(mesh_t), intent(in) :: mesh
483 integer, intent(in) :: spin_channels
484 real(real64), intent(inout) :: drho(:, :, :)
485
486 integer :: isp, ip, icell, idir
487 real(real64) :: rr, pos_pc(space%dim), range, spline
488 type(ps_t), pointer :: ps
489 type(lattice_iterator_t) :: latt_iter
490
492
493 assert(spin_channels == 1 .or. spin_channels == 2)
494
495 drho = m_zero
496
497 ! build density ...
498 select type(species)
499 class is(pseudopotential_t)
500 ps => species%ps
501 ! ...from pseudopotentials
502
503 if (ps_has_density(ps)) then
504
505 range = ps%density_der(1)%x_threshold
506 if (spin_channels == 2) range = max(range, ps%density_der(2)%x_threshold)
507 latt_iter = lattice_iterator_t(latt, range)
508
509 do icell = 1, latt_iter%n_cells
510 pos_pc = pos + latt_iter%get(icell)
511
512 do ip = 1, mesh%np
513 call mesh_r(mesh, ip, rr, origin = pos_pc)
514 rr = max(rr, r_small)
515
516 do isp = 1, spin_channels
517 if (rr >= spline_range_max(ps%density_der(isp))) cycle
518 spline = spline_eval(ps%density_der(isp), rr)
520 if(abs(spline) < 1e-150_real64) cycle
521
522 do idir = 1, space%dim
523 drho(ip, isp, idir) = drho(ip, isp, idir) - spline*(mesh%x(idir, ip) - pos_pc(idir))/rr
524 end do
525 end do
526 end do
527 end do
528
529 else
530 call messages_write('The pseudopotential for')
531 call messages_write(species%get_label())
532 call messages_write(' does not contain the density.')
533 call messages_fatal(namespace=namespace)
534 end if
535
536 class default
537 call messages_not_implemented('species_atom_density_grad for non-pseudopotential species', namespace=namespace)
538
539 end select
540
542 end subroutine species_atom_density_grad
543
544 ! ---------------------------------------------------------
545
546 subroutine species_get_long_range_density(species, namespace, space, latt, pos, mesh, rho, sphere_inout, nlr_x)
547 class(species_t), target, intent(in) :: species
548 type(namespace_t), intent(in) :: namespace
549 class(space_t), intent(in) :: space
550 type(lattice_vectors_t), intent(in) :: latt
551 real(real64), target, intent(in) :: pos(1:space%dim)
552 class(mesh_t), target, intent(in) :: mesh
553 real(real64), intent(out) :: rho(:)
554 type(submesh_t), optional, target, intent(inout) :: sphere_inout
555 real(real64), optional, intent(inout) :: nlr_x(:,:)
556
557 type(root_solver_t) :: rs
558 logical :: conv
559 real(real64) :: startval(space%dim)
560 real(real64) :: delta, alpha, xx(space%dim), yy(space%dim), rr, imrho1, rerho
561 real(real64) :: dist2_min
562 integer :: icell, ipos, ip, idir, rankmin
563 type(lattice_iterator_t) :: latt_iter
564 type(ps_t), pointer :: ps
565 type(volume_t) :: volume
566 type(submesh_t), target :: sphere_local
567 type(submesh_t), pointer :: sphere
568 logical :: have_point
569 real(real64), allocatable :: rho_sphere(:)
570 real(real64), parameter :: threshold = 1e-6_real64
571 real(real64) :: norm_factor, range, radius, radius_nlr, radius_vl
572
574
575 call profiling_in("SPECIES_LR_DENSITY")
576
577 if(present(nlr_x)) then
578 assert(species%is_ps())
579 end if
580
581 select type (species)
582 type is(pseudopotential_t)
583 ps => species%ps
584 radius_nlr = spline_x_threshold(ps%nlr, threshold)
585 if (present(sphere_inout)) then
586 radius_vl = ps%vl%x_threshold*1.05_real64
587 radius = max(radius_nlr, radius_vl)
588 call submesh_init(sphere_inout, space, mesh, latt, pos, radius)
589 sphere => sphere_inout
590 else
591 radius = radius_nlr
592 call submesh_init(sphere_local, space, mesh, latt, pos, radius)
593 sphere => sphere_local
594 endif
595
596 safe_allocate(rho_sphere(1:sphere%np))
597 if (.not. present(sphere_inout) .and. sphere%np > 0) then
598 call lalg_copy(sphere%np, sphere%r, rho_sphere)
599 call spline_eval_vec(ps%nlr, sphere%np, rho_sphere)
600 else
601 do ip = 1, sphere%np
602 if(sphere%r(ip) <= radius_nlr) then
603 rho_sphere(ip) = spline_eval(ps%nlr, sphere%r(ip))
604 else
605 rho_sphere(ip) = m_zero
606 endif
607 end do
608 end if
609
610 rho(1:mesh%np) = m_zero
611
612 ! A small amount of charge is missing with the cutoff, we
613 ! renormalize so that the long range potential is exact
614 norm_factor = abs(species%get_zval()/dsm_integrate(mesh, sphere, rho_sphere))
615 do ip = 1, sphere%np
616 rho(sphere%map(ip)) = rho(sphere%map(ip)) + norm_factor*rho_sphere(ip)
617 end do
618
619 if (present(nlr_x)) then
620 do idir = 1, space%dim
621 do ip = 1, sphere%np
622 nlr_x(sphere%map(ip), idir) = nlr_x(sphere%map(ip), idir) + norm_factor*rho_sphere(ip)*sphere%rel_x(idir, ip)
623 end do
624 end do
625 end if
626
627 safe_deallocate_a(rho_sphere)
628 nullify(ps)
629 if ( .not. present(sphere_inout) ) then
630 call submesh_end(sphere)
631 end if
632 nullify(sphere)
633
634 type is (full_delta_t)
635
636 rho(1:mesh%np) = m_zero
637
638 ipos = mesh_nearest_point(mesh, pos, dist2_min, rankmin)
639 have_point = .true.
640 if (mesh%mpi_grp%rank /= rankmin) have_point = .false.
642 if (have_point) then
643 if (mesh%use_curvilinear) then
644 rho(ipos) = -species%get_z()/mesh%vol_pp(ipos)
645 else
646 rho(ipos) = -species%get_z()/mesh%vol_pp(1)
647 end if
648 end if
649
650 write(message(1), '(3a,f5.2,3a)') &
651 "Info: species_full_delta species ", trim(species%get_label()), &
652 " atom displaced ", units_from_atomic(units_out%length, sqrt(dist2_min)), &
653 " [ ", trim(units_abbrev(units_out%length)), " ]"
654 call messages_info(1, namespace=namespace)
655
656 type is (full_gaussian_t)
657
658 ! periodic copies are not considered in this routine
659 if (space%is_periodic()) then
660 call messages_not_implemented("species_full_gaussian for periodic systems", namespace=namespace)
661 end if
662
663 ! We need to work with \xi and \xi_0, not x(\xi) and x(\xi_0) as we do now
664 ! for the argument of the Gaussian
665 if (mesh%use_curvilinear) then
666 call messages_not_implemented("species_full_gaussian with curvilinear coordinates", namespace=namespace)
667 end if
668
669 ! --------------------------------------------------------------
670 ! Constructs density for an all-electron atom with the procedure
671 ! sketched in Modine et al. [Phys. Rev. B 55, 10289 (1997)],
672 ! section II.B
673 ! --------------------------------------------------------------
674
675 safe_allocate(rho_p(1:mesh%np))
676 safe_allocate(grho_p(1:mesh%np, 1:space%dim))
677
678 mesh_p => mesh
679 pos_p => pos
680
681 ! Initial guess.
682 delta = mesh%spacing(1)
683 alpha = sqrt(m_two)*species%get_sigma()*delta
684 alpha2_p = alpha**2 ! global copy of alpha
685
686 ! the dim variables are the position of the delta function
687 startval(1:space%dim) = pos
688
689 ! solve equation
690 ! Setting a tolerance such that the distance to the first moment is smaller than 1e-5 Bohr
691 call root_solver_init(rs, namespace, space%dim, solver_type=root_newton, maxiter=500, abs_tolerance=1.0e-10_real64)
692 call droot_solver_run(rs, func, xx, conv, startval=startval)
693
694 if (.not. conv) then
695 write(message(1),'(a)') 'Root finding in species_get_density did not converge.'
696 call messages_fatal(1, namespace=namespace)
697 end if
698
699 if(debug%info .and. space%dim == 3) then
700 write(message(1),'(a,3(f6.3,a))') 'Debug: Gaussian charge position (', xx(1), ', ', xx(2), ', ', xx(3), ')'
701 call messages_info(1, namespace=namespace)
702 end if
703
704 ! we want a charge of -Z
705 rho = -species%get_z()*rho_p
706
707 nullify(mesh_p)
708 nullify(pos_p)
709 safe_deallocate_a(grho_p)
710 safe_deallocate_a(rho_p)
711
712 type is (full_anc_t)
713
714 rho = m_zero
715
716 type is(jellium_charge_t)
717
718 call volume_init(volume)
719 call volume_read_from_block(volume, namespace, trim(species%rho_string()))
720
721 range = latt%max_length()
722 latt_iter = lattice_iterator_t(latt, range)
723
724 rho = m_zero
725 do icell = 1, latt_iter%n_cells
726 yy = latt_iter%get(icell)
727 do ip = 1, mesh%np
728 call mesh_r(mesh, ip, rr, origin = pos, coords = xx)
729 xx = xx + yy
730 rr = norm2(xx)
731
732 rerho = m_zero
733 if (volume_in_volume(space, volume, xx)) rerho = m_one
734 rho(ip) = rho(ip) - rerho
735 end do
736 end do
737
738 call volume_end(volume)
739
741
742 range = latt%max_length()
743 latt_iter = lattice_iterator_t(latt, range)
744
745 rho = m_zero
746 do icell = 1, latt_iter%n_cells
747 yy = latt_iter%get(icell)
748 do ip = 1, mesh%np
749 call mesh_r(mesh, ip, rr, origin = pos, coords = xx)
750 xx = xx + yy
751 rr = norm2(xx)
752
753 rerho = m_zero
754 call parse_expression(rerho, imrho1, space%dim, xx, rr, m_zero, trim(species%rho_string()))
755 rho(ip) = rho(ip) - rerho
756 end do
757 end do
758
759 rr = species%get_zval() / abs(dmf_integrate(mesh, rho(:)))
760 call lalg_scal(mesh%np, rr, rho)
761
762 class default
763 assert(.false.)
764 end select
765
766 call profiling_out("SPECIES_LR_DENSITY")
768 end subroutine species_get_long_range_density
769
770
771 ! ---------------------------------------------------------
772 subroutine func(xin, ff, jacobian)
773 real(real64), intent(in) :: xin(:)
774 real(real64), intent(out) :: ff(:), jacobian(:,:)
775
776 real(real64), allocatable :: xrho(:)
777 integer :: idir, jdir, dim, ip
778
779 push_sub(func)
780
781 dim = mesh_p%box%dim
782
783 call getrho(dim, xin)
784 safe_allocate(xrho(1:mesh_p%np))
785
786 ! First, we calculate the function ff.
787 do idir = 1, dim
788 !$omp parallel do simd
789 do ip = 1, mesh_p%np
790 xrho(ip) = rho_p(ip) * mesh_p%x_t(ip, idir)
791 end do
792 ff(idir) = dmf_integrate(mesh_p, xrho) - pos_p(idir)
793 end do
794
795 ! Now the jacobian.
796 do idir = 1, dim
797 do jdir = 1, dim
798 !$omp parallel do simd
799 do ip = 1, mesh_p%np
800 xrho(ip) = grho_p(ip, jdir) * mesh_p%x_t(ip, idir)
801 end do
802 jacobian(idir, jdir) = dmf_integrate(mesh_p, xrho)
803 end do
804 end do
805
806 safe_deallocate_a(xrho)
807 pop_sub(func)
808 end subroutine func
809
810 ! ---------------------------------------------------------
811 subroutine species_get_nlcc(species, space, latt, pos, mesh, rho_core, accumulate)
812 class(species_t), target, intent(in) :: species
813 class(space_t), intent(in) :: space
814 type(lattice_vectors_t), intent(in) :: latt
815 real(real64), intent(in) :: pos(1:space%dim)
816 class(mesh_t), intent(in) :: mesh
817 real(real64), intent(inout) :: rho_core(:)
818 logical, optional, intent(in) :: accumulate
819
820 real(real64) :: center(space%dim), rr
821 integer :: icell, ip
822 type(lattice_iterator_t) :: latt_iter
823 type(ps_t), pointer :: ps
824
825 push_sub(species_get_nlcc)
826
827 ! only for 3D pseudopotentials, please
828 select type(species)
829 class is(pseudopotential_t)
830 ps => species%ps
831 if (.not. optional_default(accumulate, .false.)) rho_core = m_zero
832
833 latt_iter = lattice_iterator_t(latt, ps%core%x_threshold)
834 do icell = 1, latt_iter%n_cells
835 center = pos + latt_iter%get(icell)
836 do ip = 1, mesh%np
837 rr = norm2(mesh%x(1:space%dim, ip) - center)
838 if (rr < spline_range_max(ps%core)) then
839 rho_core(ip) = rho_core(ip) + spline_eval(ps%core, rr)
840 end if
841 end do
842 end do
843 class default
844 if (.not. optional_default(accumulate, .false.)) rho_core = m_zero
845 end select
846
847 pop_sub(species_get_nlcc)
848 end subroutine species_get_nlcc
849
850 ! ---------------------------------------------------------
851 ! Return the density of a normalized Gaussian centered on xin
852 ! as well as its gradient with respect to the central position
853 subroutine getrho(dim, xin)
854 integer, intent(in) :: dim
855 real(real64), intent(in) :: xin(1:dim)
856
857 integer :: ip, idir
858 real(real64) :: r2, chi(dim), norm, threshold
859
860 push_sub(getrho)
861
862 ! We set here a threshold of 0.0001 for the tail of the Gaussian, similar to what we do for the
863 ! pseudopotentials.
864 ! Note that this needs to be small enough such that the norm is close to 1. Else, we would need to get
865 ! the derivative of the normalization with respect to the grid to have the correct Jacobian.
866 threshold = -log(0.0001_real64)*alpha2_p
868 do ip = 1, mesh_p%np
869 ! This is not correct for curvilinear meshes
870 chi(1:dim) = mesh_p%x(1:dim, ip)
871 r2 = sum((chi - xin(1:dim))**2)
872
873 if (r2 < threshold) then
874 rho_p(ip) = exp(-r2/alpha2_p)
875 else
876 rho_p(ip) = m_zero
877 end if
878
879 do idir = 1, dim
880 grho_p(ip, idir) = (chi(idir) - xin(idir)) * rho_p(ip)
881 end do
882 end do
883
884 norm = dmf_integrate(mesh_p, rho_p)
885 call lalg_scal(mesh_p%np, m_one/norm, rho_p)
886 call lalg_scal(mesh_p%np, dim, m_two/alpha2_p/norm, grho_p)
887
888 pop_sub(getrho)
889 end subroutine getrho
890
891
892 ! ---------------------------------------------------------
894 subroutine species_get_local(species, namespace, space, latt, pos, mesh, vl)
895 class(species_t), target, intent(in) :: species
896 type(namespace_t), intent(in) :: namespace
897 class(space_t), intent(in) :: space
898 type(lattice_vectors_t), intent(in) :: latt
899 real(real64), intent(in) :: pos(1:space%dim)
900 type(mesh_t), intent(in) :: mesh
901 real(real64), intent(out) :: vl(:)
902
903 real(real64) :: a1, a2, Rb2, range, density ! for jellium
904 real(real64) :: xx(space%dim), pos_pc(space%dim), r, r2, threshold
905 integer :: ip, err, icell
906 complex(real64) :: zpot
907 type(lattice_iterator_t) :: latt_iter
908 real(real64) :: aa, bb
909
910 push_sub_with_profile(species_get_local)
911
912 select type(species)
913
914 type is (soft_coulomb_t)
915
916 call parse_variable(namespace, 'SpeciesProjectorSphereThreshold', 0.001_real64, threshold)
917
918 !Assuming that we want to take the contribution from all replica that contributes up to 0.001
919 ! to the center of the cell, we arrive to a range of 1000 a.u..
920 latt_iter = lattice_iterator_t(latt, species%get_zval() / threshold)
921 vl = m_zero
922 do icell = 1, latt_iter%n_cells
923 pos_pc = pos + latt_iter%get(icell)
924 do ip = 1, mesh%np
925 call mesh_r(mesh, ip, r, origin = pos_pc)
926 r2 = r*r
927 vl(ip) = vl(ip) -species%get_zval()/sqrt(r2+species%get_softening2())
928 end do
929 end do
930
931 type is (species_user_defined_t)
932 !TODO: we should control the value of 5 by a variable.
933 range = 5.0_real64 * latt%max_length()
934 latt_iter = lattice_iterator_t(latt, range)
935 vl = m_zero
936 do icell = 1, latt_iter%n_cells
937 pos_pc = pos + latt_iter%get(icell)
938 do ip = 1, mesh%np
939 call mesh_r(mesh, ip, r, origin = pos_pc, coords = xx)
940
941 zpot = species%user_pot(space%dim, xx, r)
942 vl(ip) = vl(ip) + real(zpot, real64)
943 end do
944 end do
945
946 type is(species_from_file_t)
947
948 call dio_function_input(trim(species%get_filename()), namespace, space, mesh, vl, err)
949 if (err /= 0) then
950 write(message(1), '(a)') 'Error loading file '//trim(species%get_filename())//'.'
951 write(message(2), '(a,i4)') 'Error code returned = ', err
952 call messages_fatal(2, namespace=namespace)
953 end if
954
955 type is(jellium_sphere_t)
956
957 assert(.not. space%is_periodic())
958
959 a1 = species%get_z()/(m_two*species%radius()**3)
960 a2 = species%get_z()/species%radius()
961 rb2= species%radius()**2
962
963 do ip = 1, mesh%np
964
965 xx = mesh%x(:, ip) - pos(1:space%dim)
966 r = norm2(xx)
967
968 if (r <= species%radius()) then
969 vl(ip) = (a1*(r*r - rb2) - a2)
970 else
971 vl(ip) = -species%get_z()/r
972 end if
973
974 end do
975
976 type is (jellium_slab_t)
977
978 ! Electrostatic potential from an infinite slab of thickness species%thickness
979 ! Potential and electric fields are continuous at +/- L/2
980 density = species%get_density(mesh%box%bounding_box_l)
981 a1 = m_four * m_pi * density * species%thickness() / m_two
982
983 do ip = 1, mesh%np
984
985 r = abs(mesh%x(3, ip) - pos(3))
986
987 if (r <= species%thickness()/m_two) then
988 vl(ip) = a1 * (r * r / species%thickness() + species%thickness() / m_four)
989 else
990 vl(ip) = a1 * r
991 end if
992
993 end do
994
995 class is (pseudopotential_t)
996
997 assert(.not. space%is_periodic())
998
999 !$omp parallel do private(r)
1000 do ip = 1, mesh%np
1001 r = norm2(mesh%x(:, ip) - pos)
1002 vl(ip) = long_range_potential(r, species%ps%sigma_erf, species%ps%z_val)
1003 end do
1004
1005 type is (full_anc_t)
1006 ! periodic copies are not considered in this routine
1007 if (space%is_periodic()) then
1008 call messages_experimental("species_full_anc for periodic systems", namespace=namespace)
1009 end if
1010
1011 aa = species%a()
1012 bb = species%b()
1013 assert(bb < m_zero) ! To be sure it was computed
1014
1015 ! Evaluation of the scaled potential, see Eq. 19
1016 do ip = 1, mesh%np
1017 r2 = sum((mesh%x(:, ip) - pos)**2)*(species%get_z()*aa)**2
1018 if(r2 > r_small**2) then
1019 r = sqrt(r2)
1020 vl(ip) = -m_half &
1021 - (erf(r) + m_two*(aa*bb + m_one/sqrt(m_pi))*r*exp(-r2))/r*aa &
1022 + (erf(r) + m_two*(aa*bb + m_one/sqrt(m_pi))*r*exp(-r2))**2*m_half &
1023 + (-m_two*aa**2*bb - m_four*aa/sqrt(m_pi) &
1024 + m_four*aa*(aa*bb + m_one/sqrt(m_pi))*r2)*exp(-r2)*m_half
1025 else ! Eq. 10
1026 vl(ip) = -m_half - m_three * aa**2*bb - 6.0_real64*aa/sqrt(m_pi)
1027 end if
1028 vl(ip) = vl(ip) * (species%get_z())**2
1029 end do
1030
1031 class default
1032 vl(1:mesh%np) = m_zero
1033 end select
1034
1035 pop_sub_with_profile(species_get_local)
1036 end subroutine species_get_local
1037
1038end module species_pot_oct_m
1039
1040!! Local Variables:
1041!! mode: f90
1042!! coding: utf-8
1043!! End:
Copies a vector x, to a vector y.
Definition: lalg_basic.F90:188
scales a vector by a constant
Definition: lalg_basic.F90:159
Both the filling of the function, and the retrieval of the values may be done using single- or double...
Definition: splines.F90:166
double log(double __x) __attribute__((__nothrow__
double exp(double __x) __attribute__((__nothrow__
subroutine, public datomic_orbital_get_submesh(species, submesh, ii, ll, mm, ispin, phi, derivative)
type(debug_t), save, public debug
Definition: debug.F90:158
real(real64), parameter, public m_two
Definition: global.F90:202
real(real64), parameter, public r_small
Definition: global.F90:192
real(real64), parameter, public m_zero
Definition: global.F90:200
real(real64), parameter, public m_four
Definition: global.F90:204
real(real64), parameter, public m_pi
some mathematical constants
Definition: global.F90:198
real(real64), parameter, public m_half
Definition: global.F90:206
real(real64), parameter, public m_one
Definition: global.F90:201
real(real64), parameter, public m_three
Definition: global.F90:203
This module implements the index, used for the mesh points.
Definition: index.F90:124
subroutine, public dio_function_input(filename, namespace, space, mesh, ff, ierr, map)
Reads a mesh function from file filename, and puts it into ff. If the map argument is passed,...
This module defines various routines, operating on mesh functions.
This module defines the meshes, which are used in Octopus.
Definition: mesh.F90:120
integer function, public mesh_nearest_point(mesh, pos, dmin, rankmin)
Returns the index of the point which is nearest to a given vector position pos.
Definition: mesh.F90:386
pure subroutine, public mesh_r(mesh, ip, rr, origin, coords)
return the distance to the origin for a given grid point
Definition: mesh.F90:342
subroutine, public messages_not_implemented(feature, namespace)
Definition: messages.F90:1068
character(len=256), dimension(max_lines), public message
to be output by fatal, warning
Definition: messages.F90:162
subroutine, public messages_fatal(no_lines, only_root_writes, namespace)
Definition: messages.F90:410
subroutine, public messages_experimental(name, namespace)
Definition: messages.F90:1040
subroutine, public messages_info(no_lines, iunit, debug_only, stress, all_nodes, namespace)
Definition: messages.F90:594
subroutine, public profiling_out(label)
Increment out counter and sum up difference between entry and exit time.
Definition: profiling.F90:631
subroutine, public profiling_in(label, exclude)
Increment in counter and save entry time.
Definition: profiling.F90:554
Definition: ps.F90:116
pure logical function, public ps_has_density(ps)
Definition: ps.F90:1616
real(real64) pure function, public long_range_potential(r, sigma, z_val)
Evaluate the long-range potential at a given distance.
Definition: ps.F90:750
integer, parameter, public root_newton
subroutine, public root_solver_init(rs, namespace, dimensionality, solver_type, maxiter, rel_tolerance, abs_tolerance)
subroutine, public droot_solver_run(rs, func, root, success, startval)
subroutine, public species_get_local(species, namespace, space, latt, pos, mesh, vl)
used when the density is not available, or otherwise the Poisson eqn would be used instead
subroutine func(xin, ff, jacobian)
subroutine, public species_atom_density_np(species, namespace, pos, mesh, spin_channels, rho)
subroutine, public species_get_long_range_density(species, namespace, space, latt, pos, mesh, rho, sphere_inout, nlr_x)
subroutine, public species_atom_density_derivative_np(species, namespace, pos, mesh, spin_channels, drho)
subroutine, public species_atom_density_grad(species, namespace, space, latt, pos, mesh, spin_channels, drho)
subroutine getrho(dim, xin)
subroutine, public species_get_nlcc(species, space, latt, pos, mesh, rho_core, accumulate)
subroutine, public species_atom_density(species, namespace, space, latt, pos, mesh, spin_channels, rho)
real(real64) function, public spline_x_threshold(spl, threshold)
Determines the largest value of x for which the spline values are above the threshold.
Definition: splines.F90:1070
real(real64) function, public spline_eval(spl, x)
Definition: splines.F90:441
real(real64) pure function, public spline_range_max(this)
Definition: splines.F90:1109
real(real64) function, public dsm_integrate(mesh, sm, ff, reduce)
Definition: submesh.F90:1091
subroutine, public submesh_end(this)
Definition: submesh.F90:677
subroutine, public submesh_init(this, space, mesh, latt, center, rc)
Definition: submesh.F90:226
brief This module defines the class unit_t which is used by the unit_systems_oct_m module.
Definition: unit.F90:134
character(len=20) pure function, public units_abbrev(this)
Definition: unit.F90:225
This module defines the unit system, used for input and output.
type(unit_system_t), public units_out
subroutine, public volume_read_from_block(vol, namespace, block_name)
Definition: volume.F90:159
logical function, public volume_in_volume(space, vol, xx)
Definition: volume.F90:229
subroutine, public volume_end(vol)
Definition: volume.F90:151
subroutine, public volume_init(vol)
Definition: volume.F90:145
subroutine generate_uniform_density()
An abstract type for all electron species.
The following class implements a lattice iterator. It allows one to loop over all cells that are with...
Describes mesh distribution to nodes.
Definition: mesh.F90:187
A type storing the information and data about a pseudopotential.
Definition: ps.F90:188
An abstract class for species. Derived classes include jellium, all electron, and pseudopotential spe...
Definition: species.F90:147
A submesh is a type of mesh, used for the projectors in the pseudopotentials It contains points on a ...
Definition: submesh.F90:174
int true(void)