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