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