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_softening2())
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.
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:1166
subroutine, public submesh_end(this)
Definition: submesh.F90:736
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)