Octopus
ion_interaction.F90
Go to the documentation of this file.
1!! Copyright (C) 2002-2006 M. Marques, A. Castro, A. Rubio, G. Bertsch
2!! Copyright (C) 2021 N. Tancogne-Dejean
3!!
4!! This program is free software; you can redistribute it and/or modify
5!! it under the terms of the GNU General Public License as published by
6!! the Free Software Foundation; either version 2, or (at your option)
7!! any later version.
8!!
9!! This program is distributed in the hope that it will be useful,
10!! but WITHOUT ANY WARRANTY; without even the implied warranty of
11!! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12!! GNU General Public License for more details.
13!!
14!! You should have received a copy of the GNU General Public License
15!! along with this program; if not, write to the Free Software
16!! Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17!! 02110-1301, USA.
18!!
19
20#include "global.h"
21
23 use atom_oct_m
24 use comm_oct_m
25 use debug_oct_m
26 use global_oct_m
33 use mpi_oct_m
36 use parser_oct_m
38 use ps_oct_m
40 use space_oct_m
43
44 implicit none
45
46 private
47 public :: &
55
57 real(real64) :: alpha
58 type(distributed_t) :: dist
59 end type ion_interaction_t
60
61 integer, parameter :: &
62 ION_COMPONENT_REAL = 1, &
66
67contains
68
69 subroutine ion_interaction_init(this, namespace, space, natoms)
70 type(ion_interaction_t), intent(out) :: this
71 type(namespace_t), intent(in) :: namespace
72 class(space_t), intent(in) :: space
73 integer, intent(in) :: natoms
74
75 push_sub(ion_interaction_init)
76
77 !%Variable EwaldAlpha
78 !%Type float
79 !%Default 0.21
80 !%Section Hamiltonian
81 !%Description
82 !% The value 'Alpha' that controls the splitting of the Coulomb
83 !% interaction in the Ewald sum used to calculation the ion-ion
84 !% interaction for periodic systems. This value affects the speed
85 !% of the calculation, normally users do not need to modify it.
86 !%End
87 call parse_variable(namespace, 'EwaldAlpha', 0.21_real64, this%alpha)
88
89 call distributed_nullify(this%dist, natoms)
90
91 if (space%periodic_dim == 1) then
92 call messages_write('For systems that are periodic in 1D, the interaction between', new_line = .true.)
93 call messages_write('ions is not implemented. This affects the calculation', new_line = .true.)
94 call messages_write('of total energy and forces, so both are zeroed.')
95 call messages_warning(namespace=namespace)
96 end if
97
99 end subroutine ion_interaction_init
100
101 subroutine ion_interaction_init_parallelization(this, natoms, mc)
102 type(ion_interaction_t), intent(inout) :: this
103 integer, intent(in) :: natoms
104 type(multicomm_t), intent(in) :: mc
105
107
108 !As the code below is not parallelized with any of k-point, states nor domain
109 !we can safely parallelize it over atoms
110 call distributed_init(this%dist, natoms, mc%master_comm, "Ions")
111
114
115 subroutine ion_interaction_end(this)
116 type(ion_interaction_t), intent(inout) :: this
117
118 push_sub(ion_interaction_end)
119
120 this%alpha = -m_one
121
122 call distributed_end(this%dist)
123
124 pop_sub(ion_interaction_end)
125 end subroutine ion_interaction_end
126
131 subroutine ion_interaction_calculate(this, space, latt, atom, natoms, pos, lsize, energy, force, &
132 energy_components, force_components)
133 type(ion_interaction_t), intent(inout) :: this
134 class(space_t), intent(in) :: space
135 type(lattice_vectors_t), intent(in) :: latt
136 type(atom_t), intent(in) :: atom(:)
137 integer, intent(in) :: natoms
138 real(real64), intent(in) :: pos(1:space%dim,1:natoms)
139 real(real64), intent(in) :: lsize(:)
140 real(real64), intent(out) :: energy
141 real(real64), intent(out) :: force(:, :)
142 real(real64), optional, intent(out) :: energy_components(:)
143 real(real64), optional, intent(out) :: force_components(:, :, :)
144
145
147 call profiling_in("ION_ION_INTERACTION")
148
149 if (present(energy_components)) then
150 assert(ubound(energy_components, dim = 1) == ion_num_components)
151 energy_components = m_zero
152 end if
153
154 if (present(force_components)) then
155 assert(all(ubound(force_components) == (/space%dim, natoms, ion_num_components/)))
156 force_components = m_zero
157 end if
158
159 if (space%is_periodic() .and. any_species_is_jellium_sphere(atom)) then
160 call messages_not_implemented('No periodic implementation of ion-ion energy for the jellium sphere')
161 end if
163 if (space%is_periodic()) then
164 if (all_species_are_jellium_slab(atom)) then
165 energy = jellium_slab_energy_periodic(space, latt, atom, lsize)
166 force = 0._real64
167 else
168 call ion_interaction_periodic(this, space, latt, atom, natoms, pos, energy, force, energy_components, force_components)
169 end if
170 else
171 call ion_interaction_finite(this%dist, space, atom, pos, lsize, energy, force)
172 energy = energy + jellium_self_energy_finite(this%dist, latt, atom, lsize)
173 end if
174
175 call profiling_out("ION_ION_INTERACTION")
177
178 end subroutine ion_interaction_calculate
179
184 function jellium_slab_energy_periodic(space, latt, atom, lsize) result(energy)
185 class(space_t), intent(in) :: space
186 type(lattice_vectors_t), intent(in) :: latt
187 type(atom_t), intent(in) :: atom(:)
188 real(real64), intent(in) :: lsize(:)
189 real(real64) :: energy
190
191 ! Implementation assumes a single atom
192 assert(size(atom) == 1)
193 ! This is only allowed if periodic dim = 2. In that case the lattice volume is in fact an area.
194 assert(space%periodic_dim == 2)
195
196 select type(spec => atom(1)%species)
197 type is (jellium_slab_t)
198 energy = m_pi * spec%get_zval()**2 /latt%rcell_volume * (lsize(3) - spec%thickness() / m_three)
199 class default
200 assert(.false.)
201 end select
202
204
218 function jellium_self_energy_finite(dist, latt, atom, lsize) result(energy)
219 type(distributed_t), intent(in) :: dist
220 type(lattice_vectors_t), intent(in) :: latt
221 type(atom_t), intent(in) :: atom(:)
222 real(real64), intent(in) :: lsize(:)
223 real(real64) :: energy
225 real(real64) :: zi
226 integer :: iatom
227 logical :: lattice_is_orthogonal
228 class(species_t), pointer :: spec
229
231
232 energy = 0._real64
233 lattice_is_orthogonal = .not. latt%nonorthogonal
234
235 do iatom = dist%start, dist%end
236 spec => atom(iatom)%species
237 zi = spec%get_zval()
238
239 select type(spec)
240 type is (jellium_sphere_t)
241 energy = energy + (m_three / m_five) * zi**2 / spec%radius()
242 ! The part depending on the simulation sphere is neglected
243
244 type is (jellium_slab_t)
245 ! Jellium slab energy only implemented for orthogonal cells.
246 ! One would need to replace (lsize(1) * lsize(2)) * species_jthick(spci)) with the triple product
247 assert(lattice_is_orthogonal)
248 energy = energy - m_pi * zi**2 / (m_four * lsize(1)*lsize(2)) * spec%thickness() / m_three
249 ! The part depending on the simulation box transverse dimension is neglected
250 end select
251 nullify(spec)
252 enddo
253
254 call comm_allreduce(dist%mpi_grp, energy)
255
257
258 end function jellium_self_energy_finite
259
261 subroutine ion_interaction_finite(dist, space, atom, pos, lsize, energy, force)
262 type(distributed_t), intent(in) :: dist
263 class(space_t), intent(in) :: space
264 type(atom_t), intent(in) :: atom(:)
265 real(real64), intent(in) :: pos(:,:)
266 real(real64), intent(in) :: lsize(:)
267 real(real64), intent(out) :: energy
268 real(real64), intent(out) :: force(:, :)
269
270 class(species_t), pointer :: species_i, species_j
271 real(real64) :: r(space%dim), f(space%dim)
272 real(real64) :: r_mag
273 real(real64) :: u_e
274 real(real64) :: zi, zj
275 integer :: iatom, jatom, natoms
276
278
279 natoms = size(atom)
280 energy = m_zero
281 force(1:space%dim, 1:natoms) = m_zero
282
283 do iatom = dist%start, dist%end
284 species_i => atom(iatom)%species
285 zi = species_i%get_zval()
286
287 do jatom = iatom + 1, natoms
288 species_j => atom(jatom)%species
289 zj = species_j%get_zval()
290
291 r = pos(:, iatom) - pos(:, jatom)
292 r_mag = norm2(r)
293 u_e = zi * zj / r_mag
294
295 energy = energy + u_e
296 f(1:space%dim) = (u_e / r_mag**2) * r(1:space%dim)
297 force(1:space%dim, iatom) = force(1:space%dim, iatom) + f(1:space%dim)
298 force(1:space%dim, jatom) = force(1:space%dim, jatom) - f(1:space%dim)
299 end do
300 end do
301
302 call comm_allreduce(dist%mpi_grp, energy)
303 call comm_allreduce(dist%mpi_grp, force)
304
305 nullify(species_i, species_j)
306
308
309 end subroutine ion_interaction_finite
310
312 subroutine ion_interaction_periodic(this, space, latt, atom, natoms, pos, energy, force, &
313 energy_components, force_components)
314 type(ion_interaction_t), intent(in) :: this
315 class(space_t), intent(in) :: space
316 type(lattice_vectors_t), intent(in) :: latt
317 type(atom_t), intent(in) :: atom(:)
318 integer, intent(in) :: natoms
319 real(real64), intent(in) :: pos(1:space%dim,1:natoms)
320 real(real64), intent(out) :: energy
321 real(real64), intent(out) :: force(:, :)
322 real(real64), optional, intent(out) :: energy_components(:)
323 real(real64), optional, intent(out) :: force_components(:, :, :)
324
325 real(real64) :: ereal, efourier, epseudo, eself
326 real(real64) :: charge
327
329
330 energy = m_zero
331 force(1:space%dim, 1:natoms) = m_zero
332
333 call ewald_short(this%dist, space, latt, atom, pos, this%alpha, ereal, force)
334 if (present(force_components)) then
335 force_components(1:space%dim, 1:natoms, ion_component_real) = force(1:space%dim, 1:natoms)
336 end if
337
338 call ewald_self_interaction(this%dist, atom, this%alpha, eself, charge)
339
340 call profiling_in("EWALD_LONG")
341 select case (space%periodic_dim)
342 case (1)
343 ! Warning added in init routine, such that it is not displayed per SCF step
344 efourier = m_zero
345 ! Do not confuse the user and set to zero all the other components
346 ereal = m_zero
347 eself = m_zero
348 force = m_zero
349 epseudo = m_zero
350 case (2)
351 ! The energy contribution of the long range part of the pseudo is
352 ! not correctly accounted for in systems periodic in 1D or 2D, however
353 ! this term should not appear here anyway. See Issue #950.
354 epseudo = m_zero
355 call ewald_long_2d(this, space, latt, atom, natoms, pos, efourier, force)
356 case (3)
357 call ewald_long_3d(this, space, latt, atom, natoms, pos, efourier, force, charge)
358 !TODO(Alex/Nicolas) Issue #950. Refactor: Move G=0 correction from ion-ion energy to pseudopotential energy
359 call pseudopotential_correction_3d(this%dist, latt, atom, charge, epseudo)
360 end select
361 call profiling_out("EWALD_LONG")
362
363 if (present(energy_components)) then
364 energy_components(ion_component_real) = ereal
365 energy_components(ion_component_self) = eself
366 energy_components(ion_component_fourier) = efourier
367 end if
368
369 if (present(force_components)) then
370 ! This is dependent on the order in which the force terms are computed
371 force_components(1:space%dim, 1:natoms, ion_component_fourier) = &
372 force(1:space%dim, 1:natoms) - force_components(1:space%dim, 1:natoms, ion_component_real)
373 end if
374
375 energy = ereal + efourier + eself + epseudo
376
378 end subroutine ion_interaction_periodic
379
400 subroutine ewald_short(dist, space, latt, atom, pos, alpha, ereal, force)
401 type(distributed_t), intent(in) :: dist
402 class(space_t), intent(in) :: space
403 type(lattice_vectors_t), intent(in) :: latt
404 type(atom_t), intent(in) :: atom(:)
405 real(real64), intent(in) :: pos(:, :)
406
407 real(real64), intent(in) :: alpha
408 real(real64), intent(out) :: ereal
409 real(real64), intent(inout) :: force(:, :)
410 ! Intent(inout) allows force contributions to be summed
411 integer :: iatom, jatom, icopy, natoms
412 real(real64) :: rnorm, xi(space%dim)
413 real(real64) :: force_real(space%dim)
414 real(real64) :: zi, zj
415 real(real64) :: erfc
416 real(real64) :: rcut
417 type(lattice_iterator_t) :: latt_iter
418
419 push_sub_with_profile(ewald_short)
420
421 ereal = m_zero
422 ! Origin of this value is not documented
423 rcut = 6.0_real64 / alpha
424 latt_iter = lattice_iterator_t(latt, rcut)
425 natoms = size(atom)
426
427 !$omp parallel default(shared) private(iatom, jatom, zi, zj, icopy, xi, rnorm, erfc, force_real) reduction(+:ereal, force)
428 do iatom = dist%start, dist%end
429 if (.not. atom(iatom)%species%represents_real_atom()) cycle
430 zi = atom(iatom)%species%get_zval()
431
432 ! Diagonal terms iatom == jatom for all cells, except T=(0,0,0)
433 !$omp do
434 do icopy = 1, latt_iter%n_cells
435 rnorm = norm2(latt_iter%get(icopy))
436 if (rnorm < r_min_atom_dist) cycle
437 if (rnorm > rcut) cycle
438 erfc = m_one - loct_erf(alpha * rnorm)
439 ereal = ereal + m_half * zi * zi * erfc /rnorm
440 enddo
441 !$omp end do
442
443 ! Upper triangle, for all replica cells
444 do jatom = iatom + 1, natoms
445 zj = atom(jatom)%species%get_zval()
446
447 !$omp do
448 do icopy = 1, latt_iter%n_cells
449 xi = pos(:, iatom) + latt_iter%get(icopy)
450 rnorm = norm2(xi - pos(:, jatom))
451 if (rnorm > rcut) cycle
452
453 erfc = m_one - loct_erf(alpha * rnorm)
454 force_real(:) = zj * zi * (xi - pos(:, jatom)) * &
455 (erfc / rnorm + m_two * alpha / sqrt(m_pi) *exp(-(alpha*rnorm)**2)) / rnorm**2
456
457 ! Factor 1/2 omitted as one is only summing over upper triangle
458 ereal = ereal + zj*zi*erfc/rnorm
459
460 ! Upper trianglar contribution
461 force(1:space%dim, jatom) = force(1:space%dim, jatom) - force_real
462
463 ! Lower triangular contribution
464 force(1:space%dim, iatom) = force(1:space%dim, iatom) + force_real
465 end do
466 !$omp end do
467
468 end do
469 end do
470 !$omp end parallel
471
472 call comm_allreduce(dist%mpi_grp, ereal)
473 call comm_allreduce(dist%mpi_grp, force)
474
475 pop_sub_with_profile(ewald_short)
476 end subroutine ewald_short
477
482 subroutine ewald_self_interaction(dist, atom, alpha, eself, charge)
483 type(distributed_t), intent(in) :: dist
484 type(atom_t), intent(in) :: atom(:)
485 real(real64), intent(in) :: alpha
486 real(real64), intent(out) :: eself
487 real(real64), intent(out) :: charge
488
489 integer :: iatom
490 real(real64) :: zi
491
492 push_sub(ewald_self_interaction)
494 eself = m_zero
495 charge = m_zero
496
497 do iatom = dist%start, dist%end
498 zi = atom(iatom)%species%get_zval()
499 charge = charge + zi
500 eself = eself - alpha / sqrt(m_pi) * zi**2
501 end do
502
503 call comm_allreduce(dist%mpi_grp, eself)
504 call comm_allreduce(dist%mpi_grp, charge)
505
507 end subroutine ewald_self_interaction
508
510 subroutine ewald_long_3d(this, space, latt, atom, natoms, pos, efourier, force, charge)
511 type(ion_interaction_t), intent(in) :: this
512 class(space_t), intent(in) :: space
513 type(lattice_vectors_t), intent(in) :: latt
514 type(atom_t), intent(in) :: atom(:)
515 integer, intent(in) :: natoms
516 real(real64), intent(in) :: pos(:,:)
517 real(real64), intent(inout) :: efourier
518 real(real64), intent(inout) :: force(:, :)
519 real(real64), intent(in) :: charge
520
521 real(real64) :: rcut, gmax_squared
522 integer :: iatom
523 integer :: ix, iy, iz, isph
524 real(real64) :: gvec(3), gred(3), gg2, gx
525 real(real64) :: factor
526 complex(real64) :: sumatoms, tmp(3), aa
527
528 complex(real64), allocatable :: phase(:)
529
530 push_sub(ewald_long_3d)
531
532 assert(space%dim == 3)
533 assert(space%periodic_dim == 3)
534
535 ! And the long-range part, using an Ewald sum
536 safe_allocate(phase(1:natoms))
537
538 ! get a converged value for the cutoff in g
539 rcut = sqrt(minval(sum(latt%klattice**2, dim=1)))
540
541 ! 9.5 is a constant that controls the range separation
542 isph = ceiling(9.5_real64*this%alpha/rcut)
543
544 ! First the G = 0 term (charge was calculated previously)
545 efourier = -m_pi*charge**2/(m_two*this%alpha**2*latt%rcell_volume)
546
547 ! Getting the G-shell cutoff
548 gmax_squared = isph**2 * minval(sum(latt%klattice**2, dim=1))
549
550 do ix = -isph, isph
551 do iy = -isph, isph
552 do iz = -isph, isph
553
554 gred = [ix, iy, iz]
555 call kpoints_to_absolute(latt, gred, gvec)
556 gg2 = dot_product(gvec, gvec)
557
558 ! g=0 must be removed from the sum
559 if (gg2 < m_epsilon .or. gg2 > gmax_squared*1.001_real64) cycle
560
561 gx = -0.25_real64*gg2/this%alpha**2
562
563 if (gx < -36.0_real64) cycle
564
565 factor = m_two*m_pi/latt%rcell_volume*exp(gx)/gg2
566
567 if (factor < epsilon(factor)) cycle
568
569 sumatoms = m_z0
570 !$omp parallel do private(iatom, gx, aa) reduction(+:sumatoms)
571 do iatom = 1, natoms
572 gx = sum(gvec*pos(:,iatom))
573 aa = atom(iatom)%species%get_zval()*cmplx(cos(gx), sin(gx), real64)
574 phase(iatom) = aa
575 sumatoms = sumatoms + aa
576 end do
577
578 efourier = efourier + real(factor*sumatoms*conjg(sumatoms), real64)
579
580 do iatom = 1, natoms
581 tmp = m_zi*gvec*phase(iatom)
582 force(1:space%dim, iatom) = force(1:space%dim, iatom) - factor*real(conjg(tmp)*sumatoms + tmp*conjg(sumatoms), real64)
583 end do
584
585 end do
586 end do
587 end do
588
589 safe_deallocate_a(phase)
590
591 pop_sub(ewald_long_3d)
592
593 end subroutine ewald_long_3d
594
596 subroutine ewald_long_2d(this, space, latt, atom, natoms, pos, efourier, force)
597 type(ion_interaction_t), intent(in) :: this
598 class(space_t), intent(in) :: space
599 type(lattice_vectors_t), intent(in) :: latt
600 type(atom_t), intent(in) :: atom(:)
601 integer, intent(in) :: natoms
602 real(real64), intent(in) :: pos(1:space%dim,1:natoms)
603 real(real64), intent(inout) :: efourier
604 real(real64), intent(inout) :: force(:, :)
605
606 real(real64) :: rcut, gmax_squared
607 integer :: iatom, jatom
608 integer :: ix, iy, ix_max, iy_max
609 real(real64) :: gvec(space%dim), gg2, gx, gg_abs
610 real(real64) :: factor,factor1,factor2, coeff
611 real(real64) :: dz_max, dz_ij, erfc1, erfc2, tmp_erf
612 real(real64), allocatable :: force_tmp(:,:)
613 real(real64), parameter :: tol = 1e-10_real64
614
615 push_sub(ewald_long_2d)
616
617 assert(space%periodic_dim == 2)
618 assert(space%dim == 2 .or. space%dim == 3)
619
620 ! And the long-range part, using an Ewald sum
621
622 ! Searching maximum distance
623 if (space%dim == 3) then
624 dz_max = m_zero
625 do iatom = 1, natoms
626 do jatom = iatom + 1, natoms
627 dz_max = max(dz_max, abs(pos(3, iatom) - pos(3, jatom)))
628 end do
629 end do
630 else
631 ! For a 2D system, all atoms are on the plane, so the distance is zero
632 dz_max = m_zero
633 end if
634
635 !get a converged value for the cutoff in g
636 rcut = m_two*this%alpha*4.6_real64 + m_two*this%alpha**2*dz_max
637 if (dz_max > tol) then
638 do
639 if (rcut * dz_max >= m_max_exp_arg) exit !Maximum double precision number
640 erfc1 = m_one - loct_erf(this%alpha*dz_max + m_half*rcut/this%alpha)
641 if (erfc1 * exp(rcut*dz_max) < 1.e-10_real64) exit
642 rcut = rcut * 1.414_real64
643 end do
644 end if
645
646 ix_max = ceiling(rcut/norm2(latt%klattice(:, 1)))
647 iy_max = ceiling(rcut/norm2(latt%klattice(:, 2)))
648
649 safe_allocate(force_tmp(1:space%dim, 1:natoms))
650 force_tmp = m_zero
651
652 ! First the G = 0 term
653 efourier = m_zero
654 factor = m_pi/latt%rcell_volume
655 !$omp parallel do private(jatom, dz_ij, tmp_erf, factor1, factor2) reduction(+:efourier,force_tmp) &
656 !$omp& collapse(2)
657 do iatom = this%dist%start, this%dist%end
658 do jatom = 1, natoms
659 ! efourier
660 if (space%dim == 3) then
661 dz_ij = pos(3, iatom) - pos(3, jatom)
662 else
663 dz_ij = m_zero
664 end if
665
666 tmp_erf = loct_erf(this%alpha*dz_ij)
667 factor1 = dz_ij*tmp_erf
668 factor2 = exp(-(this%alpha*dz_ij)**2)/(this%alpha*sqrt(m_pi))
669
670 efourier = efourier - factor &
671 * atom(iatom)%species%get_zval()*atom(jatom)%species%get_zval() * (factor1 + factor2)
672
673 ! force
674 if (iatom == jatom)cycle
675 if (abs(tmp_erf) < m_epsilon) cycle
676
677 if (space%dim == 3) then
678 force_tmp(3, iatom) = force_tmp(3, iatom) - (- m_two*factor) &
679 * atom(iatom)%species%get_zval()*atom(jatom)%species%get_zval() * tmp_erf
680 end if
681
682 end do
683 end do
684
685 ! Getting the G-shell cutoff
686 gmax_squared = sum(ix_max*latt%klattice(:, 1)**2)
687 gmax_squared = min(gmax_squared, sum(iy_max*latt%klattice(:, 2)**2))
688
689 !$omp parallel do private(iy, gvec, gg2, gg_abs, factor, iatom, jatom, gx, dz_ij, erfc1, factor1, erfc2, factor2, coeff) &
690 !$omp& collapse(2) reduction(+:efourier, force_tmp)
691 do ix = -ix_max, ix_max
692 do iy = -iy_max, iy_max
693
694 gvec = ix*latt%klattice(:, 1) + iy*latt%klattice(:, 2)
695 gg2 = sum(gvec**2)
696
697 ! g=0 must be removed from the sum
698 if (gg2 < m_epsilon .or. gg2 > gmax_squared*1.001_real64) cycle
699 gg_abs = sqrt(gg2)
700 factor = m_half*m_pi/(latt%rcell_volume*gg_abs)
701
702 do iatom = this%dist%start, this%dist%end
703 do jatom = iatom, natoms
704 ! efourier
705 gx = sum(gvec(1:2) * (pos(1:2, iatom) - pos(1:2, jatom)))
706 gx = gvec(1)*(pos(1, iatom) - pos(1, jatom)) + gvec(2)*(pos(2, iatom) - pos(2, jatom))
707 if (space%dim == 3) then
708 dz_ij = pos(3, iatom) - pos(3, jatom)
709 else
710 dz_ij = m_zero
711 end if
712
713 erfc1 = m_one - loct_erf(this%alpha*dz_ij + m_half*gg_abs/this%alpha)
714 if (abs(erfc1) > m_epsilon) then
715 factor1 = exp(gg_abs*dz_ij)*erfc1
716 else
717 factor1 = m_zero
718 end if
719 erfc2 = m_one - loct_erf(-this%alpha*dz_ij + m_half*gg_abs/this%alpha)
720 if (abs(erfc2) > m_epsilon) then
721 factor2 = exp(-gg_abs*dz_ij)*erfc2
722 else
723 factor2 = m_zero
724 end if
725
726 if (iatom == jatom) then
727 coeff = m_one
728 else
729 coeff = m_two
730 end if
731
732 efourier = efourier &
733 + factor * coeff &
734 * atom(iatom)%species%get_zval()*atom(jatom)%species%get_zval() &
735 * cos(gx)* ( factor1 + factor2)
736
737 ! force
738 if (iatom == jatom) cycle
739
740 force_tmp(1:2, iatom) = force_tmp(1:2, iatom) &
741 + m_two * factor * gvec(1:2) &
742 * atom(iatom)%species%get_zval()*atom(jatom)%species%get_zval() &
743 *sin(gx)*(factor1 + factor2)
744
745 force_tmp(1:2, jatom) = force_tmp(1:2, jatom) &
746 - m_two * factor * gvec(1:2) &
747 * atom(iatom)%species%get_zval()*atom(jatom)%species%get_zval() &
748 *sin(gx)*(factor1 + factor2)
749
750 factor1 = gg_abs*erfc1 &
751 - m_two*this%alpha/sqrt(m_pi)*exp(-(this%alpha*dz_ij + m_half*gg_abs/this%alpha)**2)
752 if (abs(factor1) > m_epsilon) then
753 factor1 = factor1*exp(gg_abs*dz_ij)
754 else
755 factor1 = m_zero
756 end if
757
758 factor2 = gg_abs*erfc2 &
759 - m_two*this%alpha/sqrt(m_pi)*exp(-(-this%alpha*dz_ij + m_half*gg_abs/this%alpha)**2)
760 if (abs(factor2) > m_epsilon) then
761 factor2 = factor2*exp(-gg_abs*dz_ij)
762 else
763 factor2 = m_zero
764 end if
765
766 if (space%dim == 3) then
767 force_tmp(3, iatom) = force_tmp(3, iatom) &
768 - m_two*factor &
769 * atom(iatom)%species%get_zval()*atom(jatom)%species%get_zval() &
770 * cos(gx)* ( factor1 - factor2)
771 force_tmp(3, jatom) = force_tmp(3, jatom) &
772 + m_two*factor &
773 * atom(iatom)%species%get_zval()*atom(jatom)%species%get_zval() &
774 * cos(gx)* ( factor1 - factor2)
775 end if
776
777 end do
778 end do
779
780
781 end do
782 end do
783
784 call comm_allreduce(this%dist%mpi_grp, efourier)
785 call comm_allreduce(this%dist%mpi_grp, force_tmp)
786
787 force = force + force_tmp
788
789 safe_deallocate_a(force_tmp)
790
791 pop_sub(ewald_long_2d)
792 end subroutine ewald_long_2d
793
794 !TODO(Alex/Nicolas) Issue #950. Refactor: Move G=0 correction from ion-ion energy to pseudopotential energy
801 subroutine pseudopotential_correction_3d(dist, latt, atom, charge, epseudo)
802 type(distributed_t), intent(in) :: dist
803 type(lattice_vectors_t), intent(in) :: latt
804 type(atom_t), intent(in) :: atom(:)
805 real(real64), intent(out) :: epseudo
806
807 real(real64) :: zi
808 real(real64) :: charge
809 integer :: iatom
810
812
813 epseudo = m_zero
814 do iatom = dist%start, dist%end
815 select type(spec => atom(iatom)%species)
816 class is(pseudopotential_t)
817 zi = spec%get_zval()
818 epseudo = epseudo + m_pi *zi * &
819 (spec%ps%sigma_erf * sqrt(m_two))**2 / latt%rcell_volume * charge
820 end select
821 end do
822 call comm_allreduce(dist%mpi_grp, epseudo)
823
825
826 end subroutine pseudopotential_correction_3d
827
829 subroutine ion_interaction_stress(this, space, latt, atom, natoms, pos, stress_ii)
830 type(ion_interaction_t), intent(inout) :: this
831 class(space_t), intent(in) :: space
832 type(lattice_vectors_t), intent(in) :: latt
833 type(atom_t), intent(in) :: atom(:)
834 integer, intent(in) :: natoms
835 real(real64), intent(in) :: pos(:,:)
836 real(real64), intent(out) :: stress_ii(space%dim, space%dim)
837
838 real(real64) :: stress_short(1:space%dim, 1:space%dim), stress_Ewald(1:space%dim, 1:space%dim)
839
840 push_sub(ion_interaction_stress)
841
842 stress_ii = m_zero
843
844 ! Only implemented in the periodic case
845 assert(space%is_periodic())
846
847 ! Short range part in real space
848 call ion_interaction_stress_short(this, space, latt, atom, natoms, pos, stress_short)
849
850 ! Long range part in Fourier space
851 select case(space%periodic_dim)
852 case(3)
853 call ewald_3d_stress(this, space, latt, atom, natoms, pos, stress_ewald)
854 case(2)
855 call ewald_2d_stress(this, space, latt, atom, natoms, pos, stress_ewald)
856 case default
857 assert(.false.)
858 end select
859
860 stress_ii = stress_short + stress_ewald
861
863 end subroutine ion_interaction_stress
864
865 ! ---------------------------------------------------------
881
882 subroutine ion_interaction_stress_short(this, space, latt, atom, natoms, pos, stress_short)
883 type(ion_interaction_t), intent(inout) :: this
884 class(space_t), intent(in) :: space
885 type(lattice_vectors_t), intent(in) :: latt
886 type(atom_t), intent(in) :: atom(:)
887 integer, intent(in) :: natoms
888 real(real64), intent(in) :: pos(1:space%dim,1:natoms)
889 real(real64), intent(out) :: stress_short(1:space%dim, 1:space%dim)
890
891 real(real64) :: xi(space%dim)
892 real(real64) :: r_ij, zi, zj, erfc, Hp, factor
893 integer :: iatom, jatom, icopy, idir, jdir
894 real(real64) :: alpha, rcut
895 type(lattice_iterator_t) :: latt_iter
896
898 call profiling_in("ION_ION_STRESS_SHORT")
899
900 ! Only implemented in the periodic case
901 assert(space%is_periodic())
902
903 alpha = this%alpha
904
905 ! See the code for the energy above to understand this parameter
906 rcut = 6.0_real64/alpha
907
908 ! the short-range part is calculated directly
909 stress_short = m_zero
910 latt_iter = lattice_iterator_t(latt, rcut)
911
912 do iatom = this%dist%start, this%dist%end
913 select type(spec => atom(iatom)%species)
914 class is(jellium_t)
915 cycle
916 end select
917 zi = atom(iatom)%species%get_zval()
918
919 do icopy = 1, latt_iter%n_cells
920 xi = pos(:, iatom) + latt_iter%get(icopy)
921
922 do jatom = 1, natoms
923 zj = atom(jatom)%species%get_zval()
924 r_ij = norm2(xi - pos(:, jatom))
925
926 if (r_ij < r_min_atom_dist) cycle
927
928 erfc = m_one - loct_erf(alpha*r_ij)
929 hp = -m_two/sqrt(m_pi)*exp(-(alpha*r_ij)**2) - erfc/(alpha*r_ij)
930 factor = m_half*zj*zi*alpha*hp
931 do idir = 1, space%periodic_dim
932 do jdir = 1, space%periodic_dim
933 stress_short(idir, jdir) = stress_short(idir, jdir) &
934 - factor*(xi(idir) - pos(idir, jatom))*(xi(jdir) - pos(jdir, jatom))/(r_ij**2)
935 end do
936 end do
937
938 end do
939 end do
940 end do
941
942 if (this%dist%parallel) then
943 call comm_allreduce(this%dist%mpi_grp, stress_short)
944 end if
945
946 stress_short = stress_short/latt%rcell_volume
947
948 call profiling_out("ION_ION_STRESS_SHORT")
949
951 end subroutine ion_interaction_stress_short
952
953
954
955 ! ---------------------------------------------------------
967 subroutine ewald_3d_stress(this, space, latt, atom, natoms, pos, stress_Ewald)
968 type(ion_interaction_t), intent(inout) :: this
969 class(space_t), intent(in) :: space
970 type(lattice_vectors_t), intent(in) :: latt
971 type(atom_t), intent(in) :: atom(:)
972 integer, intent(in) :: natoms
973 real(real64), intent(in) :: pos(1:space%dim,1:natoms)
974 real(real64), intent(out) :: stress_ewald(3, 3)
976 real(real64) :: zi, rcut, gmax_squared
977 integer :: iatom
978 integer :: ix, iy, iz, isph, idim, idir, jdir
979 real(real64) :: gred(3), gvec(3), gg2, gx
980 real(real64) :: factor, charge, charge_sq
981 complex(real64) :: sumatoms, aa
982
983 call profiling_in("STRESS_3D_EWALD")
984 push_sub(ewald_3d_stress)
985
986 ! Currently this is only implemented for 3D
987 assert(space%dim == 3)
988 assert(space%periodic_dim == 3) ! Not working for mixed periodicity
989 ! (klattice along the non-periodic directions is wrong)
990 ! Anyway gg/gg2 is not correct for mixed periodicity
991
992 stress_ewald = m_zero
993
994 ! And the long-range part, using an Ewald sum
995 charge = m_zero
996 charge_sq = m_zero
997 do iatom = 1, natoms
998 zi = atom(iatom)%species%get_zval()
999 charge = charge + zi
1000 charge_sq = charge_sq + zi**2
1001 end do
1002
1003 ! get a converged value for the cutoff in g
1004 rcut = huge(rcut)
1005 do idim = 1, space%periodic_dim
1006 rcut = min(rcut, sum(latt%klattice(1:space%periodic_dim, idim)**2))
1007 end do
1008
1009 rcut = sqrt(rcut)
1010
1011 isph = ceiling(9.5_real64*this%alpha/rcut)
1012
1013 ! Getting the G-shell cutoff
1014 gmax_squared = isph**2 * minval(sum(latt%klattice**2, dim=1))
1015
1016 do ix = -isph, isph
1017 do iy = -isph, isph
1018 do iz = -isph, isph
1019
1020 gred = [ix, iy, iz]
1021 call kpoints_to_absolute(latt, gred, gvec)
1022 gg2 = sum(gvec**2)
1023
1024 ! g=0 must be removed from the sum
1025 if (gg2 < m_epsilon .or. gg2 > gmax_squared*1.001_real64) cycle
1026
1027 gx = -0.25_real64*gg2/this%alpha**2
1028
1029 if (gx < -36.0_real64) cycle
1030
1031 factor = m_two*m_pi*exp(gx)/(latt%rcell_volume*gg2)
1032
1033 if (factor < epsilon(factor)) cycle
1034
1035 sumatoms = m_z0
1036
1037 do iatom = 1, natoms
1038 gx = sum(gvec*pos(:, iatom))
1039 aa = atom(iatom)%species%get_zval()*cmplx(cos(gx), sin(gx), real64)
1040 sumatoms = sumatoms + aa
1041 end do
1042
1043 factor = factor*abs(sumatoms)**2
1044
1045 do idir = 1, 3
1046 do jdir = 1, 3
1047 stress_ewald(idir, jdir) = stress_ewald(idir, jdir) &
1048 - m_two*factor*gvec(idir)*gvec(jdir)/gg2*(0.25_real64*gg2/this%alpha**2+m_one)
1049 end do
1050 stress_ewald(idir, idir) = stress_ewald(idir, idir) + factor
1051 end do
1052
1053 end do
1054 end do
1055 end do
1056
1057
1058 ! The G = 0 term of the Ewald summation
1059 factor = m_half*m_pi*charge**2/(latt%rcell_volume*this%alpha**2)
1060 do idir = 1,3
1061 stress_ewald(idir,idir) = stress_ewald(idir,idir) - factor
1062 end do
1063
1064 stress_ewald = stress_ewald / latt%rcell_volume
1065
1066
1067 call profiling_out("STRESS_3D_EWALD")
1068 pop_sub(ewald_3d_stress)
1069
1070 end subroutine ewald_3d_stress
1071
1072 ! ---------------------------------------------------------
1085 subroutine ewald_2d_stress(this, space, latt, atom, natoms, pos, stress_Ewald)
1086 type(ion_interaction_t), intent(inout) :: this
1087 type(space_t), intent(in) :: space
1088 type(lattice_vectors_t), intent(in) :: latt
1089 type(atom_t), intent(in) :: atom(:)
1090 integer, intent(in) :: natoms
1091 real(real64), intent(in) :: pos(1:space%dim,1:natoms)
1092 real(real64), intent(out) :: stress_Ewald(3, 3)
1093
1094 real(real64) :: rcut, efourier
1095 integer :: iatom, jatom, idir, jdir
1096 integer :: ix, iy, ix_max, iy_max
1097 real(real64) :: gvec(3), gred(3), gg2, cos_gx, gg_abs, gmax_squared
1098 real(real64) :: factor,factor1,factor2, coeff, e_ewald
1099 real(real64) :: dz_max, z_ij, erfc1, erfc2, diff(3)
1100 real(real64), parameter :: tol = 1e-10_real64
1101
1102 push_sub(ewald_2d_stress)
1103
1104 assert(space%periodic_dim == 2)
1105 assert(space%dim == 3)
1106
1107 stress_ewald = m_zero
1108
1109 ! Searching maximum distance
1110 dz_max = m_zero
1111 do iatom = 1, natoms
1112 do jatom = iatom + 1, natoms
1113 dz_max = max(dz_max, abs(pos(3, iatom) - pos(3, jatom)))
1114 end do
1115 end do
1116
1117 !get a converged value for the cutoff in g
1118 ! Note: to understand these numbers, one needs to look into the energy routine for Ewald 2D
1119 rcut = m_two*this%alpha*4.6_real64 + m_two*this%alpha**2*dz_max
1120 if (dz_max > tol) then ! Else the code here does not work properly
1121 do
1122 if (rcut * dz_max >= m_max_exp_arg) exit !Maximum double precision number
1123 erfc1 = m_one - loct_erf(this%alpha*dz_max + m_half*rcut/this%alpha)
1124 if (erfc1 * exp(rcut*dz_max) < tol) exit
1125 rcut = rcut * 1.414_real64
1126 end do
1127 end if
1128
1129 ! First the G = 0 term
1130 efourier = m_zero
1131 factor = m_pi/latt%rcell_volume
1132 !$omp parallel do private(jatom, z_ij, factor1, factor2) reduction(+:efourier) collapse(2)
1133 do iatom = 1, natoms
1134 do jatom = 1, natoms
1135 z_ij = pos(3, iatom) - pos(3, jatom)
1136
1137 factor1 = z_ij * loct_erf(this%alpha*z_ij)
1138 factor2 = exp(-(this%alpha*z_ij)**2)/(this%alpha*sqrt(m_pi))
1139
1140 efourier = efourier - factor &
1141 * atom(iatom)%species%get_zval()*atom(jatom)%species%get_zval() * (factor1 + factor2)
1142 end do
1143 end do
1144
1145 ! Adding the G=0 term
1146 do idir = 1, 2
1147 stress_ewald(idir, idir) = efourier
1148 end do
1149
1150 ! Getting the G-shell cutoff
1151 ix_max = ceiling(rcut/norm2(latt%klattice(:, 1)))
1152 iy_max = ceiling(rcut/norm2(latt%klattice(:, 2)))
1153 gmax_squared = sum(ix_max*latt%klattice(:, 1)**2)
1154 gmax_squared = min(gmax_squared, sum(iy_max*latt%klattice(:, 2)**2))
1155
1156 !$omp parallel do private(iy, gvec, gg2, gg_abs, factor, iatom, jatom, diff, cos_gx, z_ij, idir, jdir, erfc1, factor1) &
1157 !$omp& private(erfc2, factor2, coeff, e_ewald) &
1158 !$omp& collapse(2) reduction(+:stress_Ewald)
1159 do ix = -ix_max, ix_max
1160 do iy = -iy_max, iy_max
1161
1162 gred = [ix, iy, 0]
1163 call kpoints_to_absolute(latt, gred, gvec)
1164 gg2 = dot_product(gvec,gvec)
1165
1166 ! g=0 must be removed from the sum
1167 if (gg2 < m_epsilon .or. gg2 > gmax_squared*1.001_real64) cycle
1168
1169 gg_abs = sqrt(gg2)
1170 factor = m_fourth*m_pi/(latt%rcell_volume*this%alpha*gg2)
1171
1172 do iatom = 1, natoms
1173 do jatom = iatom, natoms
1174 diff = pos(:, iatom) - pos(:, jatom)
1175 cos_gx = cos(sum(gvec(1:2) * diff(1:2)))
1176 z_ij = diff(3)
1177
1178 factor1 = screening_function_2d(this%alpha, z_ij, gg_abs, erfc1)
1179 factor2 = screening_function_2d(this%alpha,-z_ij, gg_abs, erfc2)
1180
1181 if (iatom == jatom) then
1182 coeff = m_one
1183 else
1184 coeff = m_two
1185 end if
1186
1187 do idir = 1, 2
1188 do jdir = 1, 2
1189 stress_ewald(idir, jdir) = stress_ewald(idir, jdir) &
1190 - factor*gvec(idir)*gvec(jdir) * cos_gx * (factor1 + factor2) * coeff&
1191 * atom(iatom)%species%get_zval()*atom(jatom)%species%get_zval()
1192 end do
1193 end do
1194
1195 if (abs(erfc1) > m_epsilon) then
1196 factor1 = exp(-gg_abs*z_ij)*erfc1
1197 else
1198 factor1 = m_zero
1199 end if
1200 if (abs(erfc2) > m_epsilon) then
1201 factor2 = exp(gg_abs*z_ij)*erfc2
1202 else
1203 factor2 = m_zero
1204 end if
1205
1206 e_ewald = m_half * m_pi/latt%rcell_volume * coeff &
1207 * atom(iatom)%species%get_zval() * atom(jatom)%species%get_zval() &
1208 * cos_gx / gg_abs * (factor1 + factor2)
1209
1210 do idir = 1, 2
1211 stress_ewald(idir, idir) = stress_ewald(idir, idir) + e_ewald
1212 end do
1213
1214 end do !jatom
1215 end do !iatom
1216 end do !iy
1217 end do !ix
1218
1219 !call comm_allreduce(this%dist%mpi_grp, stress_Ewald)
1220
1221 stress_ewald = stress_ewald / latt%rcell_volume
1222
1223 pop_sub(ewald_2d_stress)
1224 end subroutine ewald_2d_stress
1225
1226 ! ---------------------------------------------------------
1228 real(real64) function screening_function_2d(alpha, z_ij, gg_abs, erfc) result(factor)
1229 real(real64), intent(in) :: alpha
1230 real(real64), intent(in) :: z_ij
1231 real(real64), intent(in) :: gg_abs
1232 real(real64), intent(out) :: erfc
1233
1234 real(real64) :: arg
1235
1236 arg = -alpha*z_ij + m_half*gg_abs/alpha
1237 erfc = m_one - loct_erf(arg)
1238 factor = m_two*alpha*(m_one/gg_abs + z_ij)*erfc - m_two/sqrt(m_pi)*exp(-arg**2)
1239 factor = factor*exp(-gg_abs*z_ij)
1240
1241 end function screening_function_2d
1242
1243 ! ---------------------------------------------------------
1244
1245 subroutine ion_interaction_test(space, latt, atom, natoms, pos, lsize, &
1246 namespace, mc)
1247 class(space_t), intent(in) :: space
1248 type(lattice_vectors_t), intent(in) :: latt
1249 type(atom_t), intent(in) :: atom(:)
1250 integer, intent(in) :: natoms
1251 real(real64), intent(in) :: pos(1:space%dim,1:natoms)
1252 real(real64), intent(in) :: lsize(:)
1253 type(namespace_t), intent(in) :: namespace
1254 type(multicomm_t), intent(in) :: mc
1255
1256 type(ion_interaction_t) :: ion_interaction
1257 real(real64) :: energy
1258 real(real64), allocatable :: force(:, :), force_components(:, :, :)
1259 real(real64) :: energy_components(1:ION_NUM_COMPONENTS)
1260 integer :: iatom, idir
1261
1262 push_sub(ion_interaction_test)
1263
1264 call ion_interaction_init(ion_interaction, namespace, space, natoms)
1265 call ion_interaction_init_parallelization(ion_interaction, natoms, mc)
1266
1267 safe_allocate(force(1:space%dim, 1:natoms))
1268 safe_allocate(force_components(1:space%dim, 1:natoms, 1:ion_num_components))
1269
1270 call ion_interaction_calculate(ion_interaction, space, latt, atom, natoms, pos, lsize, energy, force, &
1271 energy_components = energy_components, force_components = force_components)
1272
1273 call messages_write('Ionic energy =')
1274 call messages_write(energy, fmt = '(f20.10)')
1275 call messages_info(namespace=namespace)
1276
1277 call messages_write('Real space energy =')
1278 call messages_write(energy_components(ion_component_real), fmt = '(f20.10)')
1279 call messages_info(namespace=namespace)
1280
1281 call messages_write('Self energy =')
1282 call messages_write(energy_components(ion_component_self), fmt = '(f20.10)')
1283 call messages_info(namespace=namespace)
1284
1285 call messages_write('Fourier energy =')
1286 call messages_write(energy_components(ion_component_fourier), fmt = '(f20.10)')
1287 call messages_info(namespace=namespace)
1288
1289 call messages_info(namespace=namespace)
1290
1291 do iatom = 1, natoms
1292 call messages_write('Ionic force atom')
1293 call messages_write(iatom)
1294 call messages_write(' =')
1295 do idir = 1, space%dim
1296 call messages_write(force(idir, iatom), fmt = '(f20.10)')
1297 end do
1298 call messages_info(namespace=namespace)
1299
1300 call messages_write('Real space force atom')
1301 call messages_write(iatom)
1302 call messages_write(' =')
1303 do idir = 1, space%dim
1304 call messages_write(force_components(idir, iatom, ion_component_real), fmt = '(f20.10)')
1305 end do
1306 call messages_info(namespace=namespace)
1307
1308 call messages_write('Fourier space force atom')
1309 call messages_write(iatom)
1310 call messages_write(' =')
1311 do idir = 1, space%dim
1312 call messages_write(force_components(idir, iatom, ion_component_fourier), fmt = '(f20.10)')
1313 end do
1314 call messages_info(namespace=namespace)
1315
1316 call messages_info(namespace=namespace)
1317 end do
1318
1319 safe_deallocate_a(force)
1320 safe_deallocate_a(force_components)
1322 call ion_interaction_end(ion_interaction)
1323
1324 pop_sub(ion_interaction_test)
1325 end subroutine ion_interaction_test
1326
1327end module ion_interaction_oct_m
1328
1329!! Local Variables:
1330!! mode: f90
1331!! coding: utf-8
1332!! End:
double exp(double __x) __attribute__((__nothrow__
double sin(double __x) __attribute__((__nothrow__
double sqrt(double __x) __attribute__((__nothrow__
double cos(double __x) __attribute__((__nothrow__
pure logical function, public all_species_are_jellium_slab(atom)
Check if all species are jellium slab.
Definition: atom.F90:292
pure logical function, public any_species_is_jellium_sphere(atom)
Check if any species is a jellium sphere.
Definition: atom.F90:309
subroutine, public distributed_end(this)
subroutine, public distributed_nullify(this, total)
subroutine, public distributed_init(this, total, comm, tag, scalapack_compat)
Distribute N instances across M processes of communicator comm
real(real64), parameter, public m_two
Definition: global.F90:189
real(real64), parameter, public m_max_exp_arg
Definition: global.F90:207
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_fourth
Definition: global.F90:196
complex(real64), parameter, public m_z0
Definition: global.F90:197
complex(real64), parameter, public m_zi
Definition: global.F90:201
real(real64), parameter, public r_min_atom_dist
Minimal distance between two distinguishable atoms.
Definition: global.F90:182
real(real64), parameter, public m_epsilon
Definition: global.F90:203
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
real(real64), parameter, public m_five
Definition: global.F90:192
real(real64) function screening_function_2d(alpha, z_ij, gg_abs, erfc)
Auxiliary function for the Ewald 2D stress.
subroutine, public ion_interaction_stress(this, space, latt, atom, natoms, pos, stress_ii)
Computes the contribution to the stress tensor the ion-ion energy.
subroutine, public ion_interaction_init_parallelization(this, natoms, mc)
integer, parameter ion_component_self
real(real64) function jellium_slab_energy_periodic(space, latt, atom, lsize)
Electrostatic energy of a periodic jellium slab.
subroutine, public ion_interaction_test(space, latt, atom, natoms, pos, lsize, namespace, mc)
subroutine ewald_long_2d(this, space, latt, atom, natoms, pos, efourier, force)
In-Chul Yeh and Max L. Berkowitz, J. Chem. Phys. 111, 3155 (1999).
subroutine ion_interaction_stress_short(this, space, latt, atom, natoms, pos, stress_short)
Computes the short-range contribution to the stress tensor the ion-ion energy.
subroutine ion_interaction_periodic(this, space, latt, atom, natoms, pos, energy, force, energy_components, force_components)
Total Ewald electrostatic energy and forces, for 1D, 2D and 3D systems.
real(real64) function jellium_self_energy_finite(dist, latt, atom, lsize)
Electrostatic self-interaction for jellium instances, with orthogonal cells.
subroutine, public ion_interaction_init(this, namespace, space, natoms)
subroutine ewald_short(dist, space, latt, atom, pos, alpha, ereal, force)
Short range component of the Ewald electrostatic energy and force.
subroutine pseudopotential_correction_3d(dist, latt, atom, charge, epseudo)
G=0 component of Ewald energy arising from the pseudopotentials, for 3D systems.
subroutine ewald_long_3d(this, space, latt, atom, natoms, pos, efourier, force, charge)
Computes the long-range part of the 3D Ewald summation.
integer, parameter ion_component_real
integer, parameter ion_num_components
subroutine ewald_3d_stress(this, space, latt, atom, natoms, pos, stress_Ewald)
Computes the contribution to the stress tensor from the 3D Ewald sum.
integer, parameter ion_component_fourier
subroutine ion_interaction_finite(dist, space, atom, pos, lsize, energy, force)
Electrostatic Ewald energy and forces for finite systems.
subroutine, public ion_interaction_end(this)
subroutine, public ion_interaction_calculate(this, space, latt, atom, natoms, pos, lsize, energy, force, energy_components, force_components)
Top level routine for computing electrostatic energies and forces between ions.
subroutine ewald_2d_stress(this, space, latt, atom, natoms, pos, stress_Ewald)
Computes the contribution to the stress tensor from the 2D Ewald sum.
subroutine ewald_self_interaction(dist, atom, alpha, eself, charge)
@ brief Ewald self-interaction energy
subroutine, public kpoints_to_absolute(latt, kin, kout)
Definition: kpoints.F90:1031
subroutine, public messages_not_implemented(feature, namespace)
Definition: messages.F90:1125
subroutine, public messages_warning(no_lines, all_nodes, namespace)
Definition: messages.F90:543
This module handles the communicators for the various parallelization strategies.
Definition: multicomm.F90:145
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
Distribution of N instances over mpi_grpsize processes, for the local rank mpi_grprank....
The following class implements a lattice iterator. It allows one to loop over all cells that are with...
An abstract class for species. Derived classes include jellium, all electron, and pseudopotential spe...
Definition: species.F90:143
int true(void)