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 call lalg_copy(sphere%np, sphere%r, rho_sphere)
639 call spline_eval_vec(ps%nlr, sphere%np, rho_sphere)
640 else
641 do ip = 1, sphere%np
642 if(sphere%r(ip) <= radius_nlr) then
643 rho_sphere(ip) = spline_eval(ps%nlr, sphere%r(ip))
644 else
645 rho_sphere(ip) = m_zero
646 endif
647 end do
648 end if
649
650 rho(1:mesh%np) = m_zero
651
652 ! A small amount of charge is missing with the cutoff, we
653 ! renormalize so that the long range potential is exact
654 norm_factor = abs(species%get_zval()/dsm_integrate(mesh, sphere, rho_sphere))
655 do ip = 1, sphere%np
656 rho(sphere%map(ip)) = rho(sphere%map(ip)) + norm_factor*rho_sphere(ip)
657 end do
658
659 if (present(nlr_x)) then
660 do idir = 1, space%dim
661 do ip = 1, sphere%np
662 nlr_x(sphere%map(ip), idir) = nlr_x(sphere%map(ip), idir) + norm_factor*rho_sphere(ip)*sphere%rel_x(idir, ip)
663 end do
664 end do
665 end if
666
667 safe_deallocate_a(rho_sphere)
668 nullify(ps)
669 if ( .not. present(sphere_inout) ) then
670 call submesh_end(sphere)
671 end if
672 nullify(sphere)
673
674 type is (full_delta_t)
675
676 rho(1:mesh%np) = m_zero
677
678 ipos = mesh_nearest_point(mesh, pos, dist2_min, rankmin)
679 have_point = .true.
680 if (mesh%mpi_grp%rank /= rankmin) have_point = .false.
681
682 if (have_point) then
683 if (mesh%use_curvilinear) then
684 rho(ipos) = -species%get_z()/mesh%vol_pp(ipos)
685 else
686 rho(ipos) = -species%get_z()/mesh%vol_pp(1)
687 end if
688 end if
689
690 write(message(1), '(3a,f5.2,3a)') &
691 "Info: species_full_delta species ", trim(species%get_label()), &
692 " atom displaced ", units_from_atomic(units_out%length, sqrt(dist2_min)), &
693 " [ ", trim(units_abbrev(units_out%length)), " ]"
694 call messages_info(1, namespace=namespace)
695
696 type is (full_gaussian_t)
697
698 ! periodic copies are not considered in this routine
699 if (space%is_periodic()) then
700 call messages_not_implemented("species_full_gaussian for periodic systems", namespace=namespace)
701 end if
702
703 ! We need to work with \xi and \xi_0, not x(\xi) and x(\xi_0) as we do now
704 ! for the argument of the Gaussian
705 if (mesh%use_curvilinear) then
706 call messages_not_implemented("species_full_gaussian with curvilinear coordinates", namespace=namespace)
707 end if
708
709 ! --------------------------------------------------------------
710 ! Constructs density for an all-electron atom with the procedure
711 ! sketched in Modine et al. [Phys. Rev. B 55, 10289 (1997)],
712 ! section II.B
713 ! --------------------------------------------------------------
714
715 safe_allocate(rho_p(1:mesh%np))
716 safe_allocate(grho_p(1:mesh%np, 1:space%dim))
717
718 mesh_p => mesh
719 pos_p => pos
720
721 ! Initial guess.
722 delta = mesh%spacing(1)
723 alpha = sqrt(m_two)*species%get_sigma()*delta
724 alpha2_p = alpha**2 ! global copy of alpha
725
726 ! the dim variables are the position of the delta function
727 startval(1:space%dim) = pos
728
729 ! solve equation
730 ! Setting a tolerance such that the distance to the first moment is smaller than 1e-5 Bohr
731 call root_solver_init(rs, namespace, space%dim, solver_type=root_newton, maxiter=500, abs_tolerance=1.0e-10_real64)
732 call droot_solver_run(rs, func, xx, conv, startval=startval)
733
734 if (.not. conv) then
735 write(message(1),'(a)') 'Root finding in species_get_density did not converge.'
736 call messages_fatal(1, namespace=namespace)
737 end if
738
739 if(debug%info .and. space%dim == 3) then
740 write(message(1),'(a,3(f6.3,a))') 'Debug: Gaussian charge position (', xx(1), ', ', xx(2), ', ', xx(3), ')'
741 call messages_info(1, namespace=namespace)
742 end if
743
744 ! we want a charge of -Z
745 rho = -species%get_z()*rho_p
746
747 nullify(mesh_p)
748 nullify(pos_p)
749 safe_deallocate_a(grho_p)
750 safe_deallocate_a(rho_p)
751
752 type is (full_anc_t)
753
754 rho = m_zero
755
756 type is(jellium_charge_t)
757
758 call volume_init(volume)
759 call volume_read_from_block(volume, namespace, trim(species%rho_string()))
760
761 range = latt%max_length()
762 latt_iter = lattice_iterator_t(latt, range)
763
764 rho = m_zero
765 do icell = 1, latt_iter%n_cells
766 yy = latt_iter%get(icell)
767 do ip = 1, mesh%np
768 call mesh_r(mesh, ip, rr, origin = pos, coords = xx)
769 xx = xx + yy
770 rr = norm2(xx)
771
772 rerho = m_zero
773 if (volume_in_volume(space, volume, xx)) rerho = m_one
774 rho(ip) = rho(ip) - rerho
775 end do
776 end do
777
778 call volume_end(volume)
779
781
782 range = latt%max_length()
783 latt_iter = lattice_iterator_t(latt, range)
784
785 rho = m_zero
786 do icell = 1, latt_iter%n_cells
787 yy = latt_iter%get(icell)
788 do ip = 1, mesh%np
789 call mesh_r(mesh, ip, rr, origin = pos, coords = xx)
790 xx = xx + yy
791 rr = norm2(xx)
792
793 rerho = m_zero
794 call parse_expression(rerho, imrho1, space%dim, xx, rr, m_zero, trim(species%rho_string()))
795 rho(ip) = rho(ip) - rerho
796 end do
797 end do
798
799 rr = species%get_zval() / abs(dmf_integrate(mesh, rho(:)))
800 rho(1:mesh%np) = rr * rho(1:mesh%np)
801
802 class default
803 assert(.false.)
804 end select
805
806 call profiling_out("SPECIES_LR_DENSITY")
808 end subroutine species_get_long_range_density
809
810
811 ! ---------------------------------------------------------
812 subroutine func(xin, ff, jacobian)
813 real(real64), intent(in) :: xin(:)
814 real(real64), intent(out) :: ff(:), jacobian(:,:)
815
816 real(real64), allocatable :: xrho(:)
817 integer :: idir, jdir, dim, ip
818
819 push_sub(func)
820
821 dim = mesh_p%box%dim
822
823 call getrho(dim, xin)
824 safe_allocate(xrho(1:mesh_p%np))
825
826 ! First, we calculate the function ff.
827 do idir = 1, dim
828 !$omp parallel do simd
829 do ip = 1, mesh_p%np
830 xrho(ip) = rho_p(ip) * mesh_p%x(ip, idir)
831 end do
832 ff(idir) = dmf_integrate(mesh_p, xrho) - pos_p(idir)
833 end do
834
835 ! Now the jacobian.
836 do idir = 1, dim
837 do jdir = 1, dim
838 !$omp parallel do simd
839 do ip = 1, mesh_p%np
840 xrho(ip) = grho_p(ip, jdir) * mesh_p%x(ip, idir)
841 end do
842 jacobian(idir, jdir) = dmf_integrate(mesh_p, xrho)
843 end do
844 end do
845
846 safe_deallocate_a(xrho)
847 pop_sub(func)
848 end subroutine func
849
850 ! ---------------------------------------------------------
851 subroutine species_get_nlcc(species, space, latt, pos, mesh, rho_core, accumulate)
852 class(species_t), target, intent(in) :: species
853 class(space_t), intent(in) :: space
854 type(lattice_vectors_t), intent(in) :: latt
855 real(real64), intent(in) :: pos(1:space%dim)
856 type(mesh_t), intent(in) :: mesh
857 real(real64), intent(inout) :: rho_core(:)
858 logical, optional, intent(in) :: accumulate
859
860 real(real64) :: center(space%dim), rr
861 integer :: icell, ip
862 type(lattice_iterator_t) :: latt_iter
863 type(ps_t), pointer :: ps
864
865 push_sub(species_get_nlcc)
866
867 ! only for 3D pseudopotentials, please
868 select type(species)
869 class is(pseudopotential_t)
870 ps => species%ps
871 if (.not. optional_default(accumulate, .false.)) rho_core = m_zero
872
873 latt_iter = lattice_iterator_t(latt, ps%core%x_threshold)
874 do icell = 1, latt_iter%n_cells
875 center = pos + latt_iter%get(icell)
876 do ip = 1, mesh%np
877 rr = norm2(mesh%x(ip, 1:space%dim) - center)
878 if (rr < spline_range_max(ps%core)) then
879 rho_core(ip) = rho_core(ip) + spline_eval(ps%core, rr)
880 end if
881 end do
882 end do
883 class default
884 if (.not. optional_default(accumulate, .false.)) rho_core = m_zero
885 end select
886
887 pop_sub(species_get_nlcc)
888 end subroutine species_get_nlcc
889
890 ! ---------------------------------------------------------
891 subroutine species_get_nlcc_grad(species, space, latt, pos, mesh, rho_core_grad, gnlcc_x)
892 class(species_t), target, intent(in) :: species
893 class(space_t), intent(in) :: space
894 type(lattice_vectors_t), intent(in) :: latt
895 real(real64), intent(in) :: pos(1:space%dim)
896 class(mesh_t), intent(in) :: mesh
897 real(real64), intent(out) :: rho_core_grad(:,:)
898 real(real64), optional, intent(inout) :: gnlcc_x(:,:,:)
899
900 real(real64) :: center(space%dim), rr, spline
901 integer :: icell, ip, idir, jdir
902 type(lattice_iterator_t) :: latt_iter
903 type(ps_t), pointer :: ps
904
906
907 rho_core_grad = m_zero
908
909 ! only for 3D pseudopotentials, please
910 if (.not. species%is_ps()) then
911 pop_sub(species_get_nlcc_grad)
912 return
913 endif
914
915 select type(species)
916 class is(pseudopotential_t)
917 ps => species%ps
918 if (.not. ps_has_nlcc(ps)) then
919 pop_sub(species_get_nlcc_grad)
920 return
921 endif
922
923 latt_iter = lattice_iterator_t(latt, ps%core_der%x_threshold)
924 ! TODO: (#706) These loops should be reformulated as the code here is most likely very slow and inefficient
925 do icell = 1, latt_iter%n_cells
926 center = pos + latt_iter%get(icell)
927 do ip = 1, mesh%np
928 call mesh_r(mesh, ip, rr, origin = center)
929 rr = max(rr, r_small)
930 if (rr >= spline_range_max(ps%core_der)) cycle
931 spline = spline_eval(ps%core_der, rr)
932 if(abs(spline) < 1e-150_real64) cycle
933
934 do idir = 1, space%dim
935 rho_core_grad(ip, idir) = rho_core_grad(ip, idir) - spline*(mesh%x(ip, idir)-center(idir))/rr
936 if (present(gnlcc_x)) then
937 do jdir = 1, space%dim
938 gnlcc_x(ip, idir, jdir) = gnlcc_x(ip, idir, jdir) &
939 - spline*(mesh%x(ip, idir)-center(idir))/rr*(mesh%x(ip, jdir)-center(jdir))
940 end do
941 end if
942
943 end do
944 end do
945 end do
946 class default
947 assert(.false.)
948 end select
949
950 pop_sub(species_get_nlcc_grad)
951 end subroutine species_get_nlcc_grad
952
953 ! ---------------------------------------------------------
954 ! Return the density of a normalized Gaussian centered on xin
955 ! as well as its gradient with respect to the central position
956 subroutine getrho(dim, xin)
957 integer, intent(in) :: dim
958 real(real64), intent(in) :: xin(1:dim)
959
960 integer :: ip, idir
961 real(real64) :: r2, chi(dim), norm, threshold
962
963 push_sub(getrho)
964
965 ! We set here a threshold of 0.001 for the tail of the Gaussian, similar to what we do for the
966 ! pseudopotentials. The value of the threshold corresponds to the default for pseudopotentials
967 threshold = -log(0.001_real64)*alpha2_p
968
969 do ip = 1, mesh_p%np
970 ! This is not correct for curvilinear meshes
971 chi(1:dim) = mesh_p%x(ip,1:dim)
972 r2 = sum((chi - xin(1:dim))**2)
973
974 if (r2 < threshold) then
975 rho_p(ip) = exp(-r2/alpha2_p)
976 else
977 rho_p(ip) = m_zero
978 end if
979
980 do idir = 1, dim
981 grho_p(ip, idir) = (chi(idir) - xin(idir)) * rho_p(ip)
982 end do
983 end do
985 norm = dmf_integrate(mesh_p, rho_p)
986 call lalg_scal(mesh_p%np, m_one/norm, rho_p)
987 call lalg_scal(mesh_p%np, dim, m_two/alpha2_p/norm, grho_p)
988
989 pop_sub(getrho)
990 end subroutine getrho
991
992
993 ! ---------------------------------------------------------
995 subroutine species_get_local(species, namespace, space, latt, pos, mesh, vl)
996 class(species_t), target, intent(in) :: species
997 type(namespace_t), intent(in) :: namespace
998 class(space_t), intent(in) :: space
999 type(lattice_vectors_t), intent(in) :: latt
1000 real(real64), intent(in) :: pos(1:space%dim)
1001 type(mesh_t), intent(in) :: mesh
1002 real(real64), intent(out) :: vl(:)
1003
1004 real(real64) :: a1, a2, rb2, range, density ! for jellium
1005 real(real64) :: xx(space%dim), pos_pc(space%dim), r, r2, threshold
1006 integer :: ip, err, icell
1007 type(ps_t), pointer :: ps
1008 complex(real64) :: zpot
1009 type(lattice_iterator_t) :: latt_iter
1010 real(real64) :: aa, bb
1011
1012
1013 push_sub(species_get_local)
1014
1015 call profiling_in("SPECIES_GET_LOCAL")
1016
1017 select type(species)
1018
1019 type is (soft_coulomb_t)
1020
1021 call parse_variable(namespace, 'SpeciesProjectorSphereThreshold', 0.001_real64, threshold)
1022
1023 !Assuming that we want to take the contribution from all replica that contributes up to 0.001
1024 ! to the center of the cell, we arrive to a range of 1000 a.u..
1025 latt_iter = lattice_iterator_t(latt, species%get_zval() / threshold)
1026 vl = m_zero
1027 do icell = 1, latt_iter%n_cells
1028 pos_pc = pos + latt_iter%get(icell)
1029 do ip = 1, mesh%np
1030 call mesh_r(mesh, ip, r, origin = pos_pc)
1031 r2 = r*r
1032 vl(ip) = vl(ip) -species%get_zval()/sqrt(r2+species%get_softening())
1033 end do
1034 end do
1035
1036 type is (species_user_defined_t)
1037 !TODO: we should control the value of 5 by a variable.
1038 range = 5.0_real64 * latt%max_length()
1039 latt_iter = lattice_iterator_t(latt, range)
1040 vl = m_zero
1041 do icell = 1, latt_iter%n_cells
1042 pos_pc = pos + latt_iter%get(icell)
1043 do ip = 1, mesh%np
1044 call mesh_r(mesh, ip, r, origin = pos_pc, coords = xx)
1045
1046 zpot = species%user_pot(space%dim, xx, r)
1047 vl(ip) = vl(ip) + real(zpot, real64)
1048 end do
1049 end do
1050
1051 type is(species_from_file_t)
1052
1053 assert(.not. space%is_periodic())
1054
1055 call dio_function_input(trim(species%get_filename()), namespace, space, mesh, vl, err)
1056 if (err /= 0) then
1057 write(message(1), '(a)') 'Error loading file '//trim(species%get_filename())//'.'
1058 write(message(2), '(a,i4)') 'Error code returned = ', err
1059 call messages_fatal(2, namespace=namespace)
1060 end if
1061
1062 type is(jellium_sphere_t)
1063
1064 assert(.not. space%is_periodic())
1065
1066 a1 = species%get_z()/(m_two*species%radius()**3)
1067 a2 = species%get_z()/species%radius()
1068 rb2= species%radius()**2
1069
1070 do ip = 1, mesh%np
1071
1072 xx = mesh%x(ip, :) - pos(1:space%dim)
1073 r = norm2(xx)
1074
1075 if (r <= species%radius()) then
1076 vl(ip) = (a1*(r*r - rb2) - a2)
1077 else
1078 vl(ip) = -species%get_z()/r
1079 end if
1080
1081 end do
1082
1083 type is (jellium_slab_t)
1084
1085 ! Electrostatic potential from an infinite slab of thickness species%thickness
1086 ! Potential and electric fields are continuous at +/- L/2
1087 density = species%get_density(mesh%box%bounding_box_l)
1088 a1 = m_four * m_pi * density * species%thickness() / m_two
1089
1090 do ip = 1, mesh%np
1091
1092 r = abs(mesh%x(ip, 3) - pos(3))
1093
1094 if (r <= species%thickness()/m_two) then
1095 vl(ip) = a1 * (r * r / species%thickness() + species%thickness() / m_four)
1096 else
1097 vl(ip) = a1 * r
1098 end if
1099
1100 end do
1101
1102 class is (pseudopotential_t)
1103
1104 assert(.not. space%is_periodic())
1105
1106 ps => species%ps
1107
1108 do ip = 1, mesh%np
1109 r2 = sum((mesh%x(ip, :) - pos)**2)
1110 if (r2 < spline_range_max(ps%vlr_sq)) then
1111 vl(ip) = spline_eval(ps%vlr_sq, r2)
1112 else
1113 vl(ip) = p_proton_charge*species%get_zval()/sqrt(r2)
1114 end if
1115 end do
1116
1117 nullify(ps)
1118
1119 type is (full_anc_t)
1120 ! periodic copies are not considered in this routine
1121 if (space%is_periodic()) then
1122 call messages_experimental("species_full_anc for periodic systems", namespace=namespace)
1123 end if
1124
1125 aa = species%a()
1126 bb = species%b()
1127 assert(bb < m_zero) ! To be sure it was computed
1128
1129 ! Evaluation of the scaled potential, see Eq. 19
1130 do ip = 1, mesh%np
1131 r2 = sum((mesh%x(ip, :) - pos)**2)*(species%get_z()*aa)**2
1132 if(r2 > r_small**2) then
1133 r = sqrt(r2)
1134 vl(ip) = -m_half &
1135 - (loct_erf(r) + m_two*(aa*bb + m_one/sqrt(m_pi))*r*exp(-r2))/r*aa &
1136 + (loct_erf(r) + m_two*(aa*bb + m_one/sqrt(m_pi))*r*exp(-r2))**2*m_half &
1137 + (-m_two*aa**2*bb - m_four*aa/sqrt(m_pi) &
1138 + m_four*aa*(aa*bb + m_one/sqrt(m_pi))*r2)*exp(-r2)*m_half
1139 else ! Eq. 10
1140 vl(ip) = -m_half - m_three * aa**2*bb - 6.0_real64*aa/sqrt(m_pi)
1141 end if
1142 vl(ip) = vl(ip) * (species%get_z())**2
1143 end do
1144
1145 class default
1146 vl(1:mesh%np) = m_zero
1147 end select
1148
1149 call profiling_out("SPECIES_GET_LOCAL")
1150 pop_sub(species_get_local)
1151 end subroutine species_get_local
1152
1153end module species_pot_oct_m
1154
1155!! Local Variables:
1156!! mode: f90
1157!! coding: utf-8
1158!! End:
Copies a vector x, to a vector y.
Definition: lalg_basic.F90:186
scales a vector by a constant
Definition: lalg_basic.F90:157
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:156
real(real64), parameter, public m_two
Definition: global.F90:190
real(real64), parameter, public p_proton_charge
Definition: global.F90:227
real(real64), parameter, public r_small
Definition: global.F90:180
real(real64), parameter, public m_zero
Definition: global.F90:188
real(real64), parameter, public m_four
Definition: global.F90:192
real(real64), parameter, public m_pi
some mathematical constants
Definition: global.F90:186
real(real64), parameter, public m_half
Definition: global.F90:194
real(real64), parameter, public m_one
Definition: global.F90:189
real(real64), parameter, public m_three
Definition: global.F90:191
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:1113
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:414
subroutine, public messages_experimental(name, namespace)
Definition: messages.F90:1085
subroutine, public messages_info(no_lines, iunit, debug_only, stress, all_nodes, namespace)
Definition: messages.F90:616
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:1645
pure logical function, public ps_has_nlcc(ps)
Definition: ps.F90:1654
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:1165
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
A type storing the information and data about a pseudopotential.
Definition: ps.F90:184
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)