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