58 type(distributed_t) :: dist
61 integer,
parameter :: &
62 ION_COMPONENT_REAL = 1, &
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
87 call parse_variable(namespace,
'EwaldAlpha', 0.21_real64, this%alpha)
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.')
102 type(ion_interaction_t),
intent(inout) :: this
103 integer,
intent(in) :: natoms
104 type(multicomm_t),
intent(in) :: mc
120 type(ion_interaction_t),
intent(inout) :: this
136 energy_components, force_components)
137 type(ion_interaction_t),
intent(inout) :: this
138 class(space_t),
intent(in) :: space
139 type(lattice_vectors_t),
intent(in) :: latt
140 type(atom_t),
intent(in) :: atom(:)
141 integer,
intent(in) :: natoms
142 real(real64),
intent(in) :: pos(1:space%dim,1:natoms)
143 real(real64),
intent(in) :: lsize(:)
144 real(real64),
intent(out) :: energy
145 real(real64),
intent(out) :: force(:, :)
146 real(real64),
optional,
intent(out) :: energy_components(:)
147 real(real64),
optional,
intent(out) :: force_components(:, :, :)
153 if (
present(energy_components))
then
155 energy_components =
m_zero
158 if (
present(force_components))
then
167 if (space%is_periodic())
then
172 call ion_interaction_periodic(this, space, latt, atom, natoms, pos, energy, force, energy_components, force_components)
190 class(
space_t),
intent(in) :: space
191 type(
atom_t),
intent(in) :: atom(:)
192 real(real64),
intent(in) :: lsize(:)
193 real(real64) :: energy
198 assert(
size(atom) == 1)
200 assert(space%periodic_dim == 2)
202 select type(spec => atom(1)%species)
204 area = lsize(1) * lsize(2) *
m_four
205 energy =
m_pi * spec%get_density(lsize) **2 * area * spec%thickness()**3 /
m_three
227 type(
atom_t),
intent(in) :: atom(:)
228 real(real64),
intent(in) :: lsize(:)
229 real(real64) :: energy
233 logical :: lattice_is_orthogonal
239 lattice_is_orthogonal = .not. latt%nonorthogonal
241 do iatom = dist%start, dist%end
242 spec => atom(iatom)%species
253 assert(lattice_is_orthogonal)
254 energy = energy +
m_pi * zi**2 / (
m_four * lsize(1)*lsize(2)) * spec%thickness() /
m_three
269 class(
space_t),
intent(in) :: space
270 type(
atom_t),
intent(in) :: atom(:)
271 real(real64),
intent(in) :: pos(:,:)
272 real(real64),
intent(in) :: lsize(:)
273 real(real64),
intent(out) :: energy
274 real(real64),
intent(out) :: force(:, :)
276 class(
species_t),
pointer :: species_i, species_j
277 real(real64) :: r(space%dim),
f(space%dim)
278 real(real64) :: r_mag
280 real(real64) :: zi, zj
281 integer :: iatom, jatom, natoms
287 force(1:space%dim, 1:natoms) =
m_zero
289 do iatom = dist%start, dist%end
290 species_i => atom(iatom)%species
291 zi = species_i%get_zval()
293 do jatom = iatom + 1, natoms
294 species_j => atom(jatom)%species
295 zj = species_j%get_zval()
297 r = pos(:, iatom) - pos(:, jatom)
299 u_e = zi * zj / r_mag
301 energy = energy + u_e
302 f(1:space%dim) = (u_e / r_mag**2) * r(1:space%dim)
303 force(1:space%dim, iatom) = force(1:space%dim, iatom) +
f(1:space%dim)
304 force(1:space%dim, jatom) = force(1:space%dim, jatom) -
f(1:space%dim)
311 nullify(species_i, species_j)
319 energy_components, force_components)
321 class(
space_t),
intent(in) :: space
323 type(
atom_t),
intent(in) :: atom(:)
324 integer,
intent(in) :: natoms
325 real(real64),
intent(in) :: pos(1:space%dim,1:natoms)
326 real(real64),
intent(out) :: energy
327 real(real64),
intent(out) :: force(:, :)
328 real(real64),
optional,
intent(out) :: energy_components(:)
329 real(real64),
optional,
intent(out) :: force_components(:, :, :)
331 real(real64) :: ereal, efourier, epseudo, eself
332 real(real64) :: charge
337 force(1:space%dim, 1:natoms) =
m_zero
339 call ewald_short(this%dist, space, latt, atom, pos, this%alpha, ereal, force)
340 if (
present(force_components))
then
341 force_components(1:space%dim, 1:natoms, ion_component_real) = force(1:space%dim, 1:natoms)
347 select case (space%periodic_dim)
361 call ewald_long_2d(this, space, latt, atom, natoms, pos, efourier, force)
363 call ewald_long_3d(this, space, latt, atom, natoms, pos, efourier, force, charge)
369 if (
present(energy_components))
then
370 energy_components(ion_component_real) = ereal
375 if (
present(force_components))
then
378 force(1:space%dim, 1:natoms) - force_components(1:space%dim, 1:natoms, ion_component_real)
381 energy = ereal + efourier + eself + epseudo
408 subroutine ewald_short(dist, space, latt, atom, pos, alpha, ereal, force)
410 class(
space_t),
intent(in) :: space
412 type(
atom_t),
intent(in) :: atom(:)
413 real(real64),
intent(in) :: pos(:, :)
415 real(real64),
intent(in) :: alpha
416 real(real64),
intent(out) :: ereal
417 real(real64),
intent(inout) :: force(:, :)
419 integer :: iatom, jatom, icopy, natoms
420 real(real64) :: rnorm, xi(space%dim)
421 real(real64) :: force_real(space%dim)
422 real(real64) :: zi, zj
423 real(real64) :: erfc_rnorm
426 real(real64) :: charge, coeff
432 rcut = 6.0_real64 / alpha
437 do iatom = dist%start, dist%end
438 if (.not. atom(iatom)%species%represents_real_atom()) cycle
439 zi = atom(iatom)%species%get_zval()
440 charge = charge + zi**2
445 do icopy = 1, latt_iter%n_cells
446 rnorm = norm2(latt_iter%get(icopy))
448 if (rnorm > rcut) cycle
449 ereal = ereal +
m_half * charge * erfc(alpha * rnorm) /rnorm
457 do iatom = dist%start, dist%end
458 if (.not. atom(iatom)%species%represents_real_atom()) cycle
459 zi = atom(iatom)%species%get_zval()
462 do jatom = iatom + 1, natoms
463 zj = atom(jatom)%species%get_zval()
468 do icopy = 1, latt_iter%n_cells
469 xi = pos(:, iatom) + latt_iter%get(icopy)
470 rnorm = norm2(xi - pos(:, jatom))
471 if (rnorm > rcut) cycle
473 erfc_rnorm = erfc(alpha * rnorm) / rnorm
476 ereal = ereal + charge * erfc_rnorm
478 force_real(:) = charge * (xi - pos(:, jatom)) * &
479 (erfc_rnorm + coeff *
exp(-(alpha*rnorm)**2)) / rnorm**2
482 force(1:space%dim, jatom) = force(1:space%dim, jatom) - force_real
485 force(1:space%dim, iatom) = force(1:space%dim, iatom) + force_real
505 type(
atom_t),
intent(in) :: atom(:)
506 real(real64),
intent(in) :: alpha
507 real(real64),
intent(out) :: eself
508 real(real64),
intent(out) :: charge
518 do iatom = dist%start, dist%end
519 zi = atom(iatom)%species%get_zval()
521 eself = eself - alpha /
sqrt(
m_pi) * zi**2
531 subroutine ewald_long_3d(this, space, latt, atom, natoms, pos, efourier, force, charge)
533 class(
space_t),
intent(in) :: space
535 type(
atom_t),
intent(in) :: atom(:)
536 integer,
intent(in) :: natoms
537 real(real64),
intent(in) :: pos(:,:)
538 real(real64),
intent(inout) :: efourier
539 real(real64),
intent(inout) :: force(:, :)
540 real(real64),
intent(in) :: charge
542 real(real64) :: rcut, gmax_squared
544 integer :: ix, iy, iz, isph
545 real(real64) :: gvec(3), gred(3), gg2, gx
546 real(real64) :: factor
547 complex(real64) :: sumatoms, tmp(3), aa
549 complex(real64),
allocatable :: phase(:)
553 assert(space%dim == 3)
554 assert(space%periodic_dim == 3)
557 safe_allocate(phase(1:natoms))
560 rcut =
sqrt(minval(sum(latt%klattice**2, dim=1)))
563 isph = ceiling(9.5_real64*this%alpha/rcut)
566 efourier = -
m_pi*charge**2/(
m_two*this%alpha**2*latt%rcell_volume)
569 gmax_squared = isph**2 * minval(sum(latt%klattice**2, dim=1))
579 if (ix == 0 .and. iy < 0) cycle
580 if (ix == 0 .and. iy == 0 .and. iz <= 0) cycle
584 gg2 = dot_product(gvec, gvec)
586 if (gg2 > gmax_squared*1.001_real64) cycle
588 gx = -0.25_real64*gg2/this%alpha**2
590 if (gx < -36.0_real64) cycle
595 if (factor < epsilon(factor)) cycle
600 gx = sum(gvec*pos(:,iatom))
601 aa = atom(iatom)%species%get_zval()*cmplx(
cos(gx),
sin(gx), real64)
603 sumatoms = sumatoms + aa
606 efourier = efourier + factor * real(sumatoms*conjg(sumatoms), real64)
609 tmp =
m_zi*gvec*phase(iatom)
610 force(1:space%dim, iatom) = force(1:space%dim, iatom) - factor*real(conjg(tmp)*sumatoms + tmp*conjg(sumatoms), real64)
618 safe_deallocate_a(phase)
627 subroutine ewald_long_2d(this, space, latt, atom, natoms, pos, efourier, force)
629 class(
space_t),
intent(in) :: space
631 type(
atom_t),
intent(in) :: atom(:)
632 integer,
intent(in) :: natoms
633 real(real64),
intent(in) :: pos(1:space%dim,1:natoms)
634 real(real64),
intent(inout) :: efourier
635 real(real64),
intent(inout) :: force(:, :)
637 real(real64) :: rcut, gmax_squared
638 integer :: iatom, jatom
639 integer :: ix, iy, ix_max, iy_max
640 real(real64) :: gvec(space%dim), gg2, gx, gg_abs
641 real(real64) :: factor,factor1,factor2, coeff
642 real(real64) :: dz_max, dz_ij, erfc1, erfc2, tmp_erf
643 real(real64),
allocatable :: force_tmp(:,:)
644 real(real64),
parameter :: tol = 1e-10_real64
648 assert(space%periodic_dim == 2)
649 assert(space%dim == 2 .or. space%dim == 3)
654 if (space%dim == 3)
then
657 do jatom = iatom + 1, natoms
658 dz_max = max(dz_max, abs(pos(3, iatom) - pos(3, jatom)))
667 rcut =
m_two*this%alpha*4.6_real64 +
m_two*this%alpha**2*dz_max
668 if (dz_max > tol)
then
671 erfc1 = erfc(this%alpha*dz_max +
m_half*rcut/this%alpha)
672 if (erfc1 *
exp(rcut*dz_max) < 1.e-10_real64)
exit
673 rcut = rcut * 1.414_real64
677 ix_max = ceiling(rcut/norm2(latt%klattice(:, 1)))
678 iy_max = ceiling(rcut/norm2(latt%klattice(:, 2)))
680 safe_allocate(force_tmp(1:space%dim, 1:natoms))
685 factor =
m_pi/latt%rcell_volume
688 do iatom = this%dist%start, this%dist%end
691 if (space%dim == 3)
then
692 dz_ij = pos(3, iatom) - pos(3, jatom)
697 tmp_erf = erf(this%alpha*dz_ij)
698 factor1 = dz_ij*tmp_erf
699 factor2 =
exp(-(this%alpha*dz_ij)**2)/(this%alpha*
sqrt(
m_pi))
701 efourier = efourier - factor &
702 * atom(iatom)%species%get_zval()*atom(jatom)%species%get_zval() * (factor1 + factor2)
705 if (iatom == jatom)cycle
708 if (space%dim == 3)
then
709 force_tmp(3, iatom) = force_tmp(3, iatom) - (-
m_two*factor) &
710 * atom(iatom)%species%get_zval()*atom(jatom)%species%get_zval() * tmp_erf
717 gmax_squared = sum(ix_max*latt%klattice(:, 1)**2)
718 gmax_squared = min(gmax_squared, sum(iy_max*latt%klattice(:, 2)**2))
722 do ix = -ix_max, ix_max
723 do iy = -iy_max, iy_max
725 gvec = ix*latt%klattice(:, 1) + iy*latt%klattice(:, 2)
729 if (gg2 <
m_epsilon .or. gg2 > gmax_squared*1.001_real64) cycle
731 factor =
m_half*
m_pi/(latt%rcell_volume*gg_abs)
733 do iatom = this%dist%start, this%dist%end
734 do jatom = iatom, natoms
736 gx = sum(gvec(1:2) * (pos(1:2, iatom) - pos(1:2, jatom)))
737 gx = gvec(1)*(pos(1, iatom) - pos(1, jatom)) + gvec(2)*(pos(2, iatom) - pos(2, jatom))
738 if (space%dim == 3)
then
739 dz_ij = pos(3, iatom) - pos(3, jatom)
744 erfc1 = erfc(this%alpha*dz_ij +
m_half*gg_abs/this%alpha)
746 factor1 =
exp(gg_abs*dz_ij)*erfc1
750 erfc2 = erfc(-this%alpha*dz_ij +
m_half*gg_abs/this%alpha)
752 factor2 =
exp(-gg_abs*dz_ij)*erfc2
757 if (iatom == jatom)
then
763 efourier = efourier &
765 * atom(iatom)%species%get_zval()*atom(jatom)%species%get_zval() &
766 *
cos(gx)* ( factor1 + factor2)
769 if (iatom == jatom) cycle
771 force_tmp(1:2, iatom) = force_tmp(1:2, iatom) &
772 +
m_two * factor * gvec(1:2) &
773 * atom(iatom)%species%get_zval()*atom(jatom)%species%get_zval() &
774 *
sin(gx)*(factor1 + factor2)
776 force_tmp(1:2, jatom) = force_tmp(1:2, jatom) &
777 -
m_two * factor * gvec(1:2) &
778 * atom(iatom)%species%get_zval()*atom(jatom)%species%get_zval() &
779 *
sin(gx)*(factor1 + factor2)
781 factor1 = gg_abs*erfc1 &
784 factor1 = factor1*
exp(gg_abs*dz_ij)
789 factor2 = gg_abs*erfc2 &
792 factor2 = factor2*
exp(-gg_abs*dz_ij)
797 if (space%dim == 3)
then
798 force_tmp(3, iatom) = force_tmp(3, iatom) &
800 * atom(iatom)%species%get_zval()*atom(jatom)%species%get_zval() &
801 *
cos(gx)* ( factor1 - factor2)
802 force_tmp(3, jatom) = force_tmp(3, jatom) &
804 * atom(iatom)%species%get_zval()*atom(jatom)%species%get_zval() &
805 *
cos(gx)* ( factor1 - factor2)
818 force = force + force_tmp
820 safe_deallocate_a(force_tmp)
835 type(
atom_t),
intent(in) :: atom(:)
836 real(real64),
intent(out) :: epseudo
839 real(real64) :: charge
845 do iatom = dist%start, dist%end
846 select type(spec => atom(iatom)%species)
849 epseudo = epseudo +
m_pi *zi * &
850 (spec%ps%sigma_erf *
sqrt(
m_two))**2 / latt%rcell_volume * charge
862 class(
space_t),
intent(in) :: space
864 type(
atom_t),
intent(in) :: atom(:)
865 integer,
intent(in) :: natoms
866 real(real64),
intent(in) :: pos(1:space%dim,1:natoms)
867 real(real64),
intent(out) :: stress_ii(space%dim, space%dim)
869 real(real64) :: stress_short(1:space%dim, 1:space%dim), stress_Ewald(1:space%dim, 1:space%dim)
876 assert(space%is_periodic())
882 select case(space%periodic_dim)
884 call ewald_3d_stress(this, space, latt, atom, natoms, pos, stress_ewald)
886 call ewald_2d_stress(this, space, latt, atom, natoms, pos, stress_ewald)
891 stress_ii = stress_short + stress_ewald
917 class(
space_t),
intent(in) :: space
919 type(
atom_t),
intent(in) :: atom(:)
920 integer,
intent(in) :: natoms
921 real(real64),
intent(in) :: pos(1:space%dim,1:natoms)
922 real(real64),
intent(out) :: stress_short(1:space%dim, 1:space%dim)
924 real(real64) :: xi(space%dim)
925 real(real64) :: r_ij, zi, zj, Hp, factor
926 integer :: iatom, jatom, icopy, idir, jdir
927 real(real64) :: alpha, rcut
934 assert(space%is_periodic())
939 rcut = 6.0_real64/alpha
945 do iatom = this%dist%start, this%dist%end
946 select type(spec => atom(iatom)%species)
950 zi = atom(iatom)%species%get_zval()
952 do icopy = 1, latt_iter%n_cells
953 xi = pos(:, iatom) + latt_iter%get(icopy)
956 zj = atom(jatom)%species%get_zval()
957 r_ij = norm2(xi - pos(:, jatom))
961 hp = -
m_two/
sqrt(
m_pi)*
exp(-(alpha*r_ij)**2) - erfc(alpha*r_ij)/(alpha*r_ij)
962 factor =
m_half*zj*zi*alpha*hp
963 do idir = 1, space%periodic_dim
964 do jdir = 1, space%periodic_dim
965 stress_short(idir, jdir) = stress_short(idir, jdir) &
966 - factor*(xi(idir) - pos(idir, jatom))*(xi(jdir) - pos(jdir, jatom))/(r_ij**2)
974 if (this%dist%parallel)
then
978 stress_short = stress_short/latt%rcell_volume
1002 subroutine ewald_3d_stress(this, space, latt, atom, natoms, pos, stress_Ewald)
1004 class(
space_t),
intent(in) :: space
1006 type(
atom_t),
intent(in) :: atom(:)
1007 integer,
intent(in) :: natoms
1008 real(real64),
intent(in) :: pos(1:space%dim,1:natoms)
1009 real(real64),
intent(out) :: stress_ewald(3, 3)
1011 real(real64) :: zi, rcut, gmax_squared
1013 integer :: ix, iy, iz, isph, idim, idir, jdir
1014 real(real64) :: gred(3), gvec(3), gg2, gx
1015 real(real64) :: factor, charge, charge_sq, off_diagonal_weight
1016 complex(real64) :: sumatoms, aa
1022 assert(space%dim == 3)
1023 assert(space%periodic_dim == 3)
1032 do iatom = 1, natoms
1033 zi = atom(iatom)%species%get_zval()
1034 charge = charge + zi
1035 charge_sq = charge_sq + zi**2
1040 do idim = 1, space%periodic_dim
1041 rcut = min(rcut, sum(latt%klattice(1:space%periodic_dim, idim)**2))
1046 isph = ceiling(9.5_real64*this%alpha/rcut)
1049 gmax_squared = isph**2 * minval(sum(latt%klattice**2, dim=1))
1059 if (ix == 0 .and. iy < 0) cycle
1060 if (ix == 0 .and. iy == 0 .and. iz <= 0) cycle
1067 if (gg2 > gmax_squared*1.001_real64) cycle
1069 gx = -0.25_real64*gg2/this%alpha**2
1071 if (gx < -36.0_real64) cycle
1076 if (factor < epsilon(factor)) cycle
1080 do iatom = 1, natoms
1081 gx = sum(gvec*pos(:, iatom))
1082 aa = atom(iatom)%species%get_zval()*cmplx(
cos(gx),
sin(gx), real64)
1083 sumatoms = sumatoms + aa
1086 factor = factor*abs(sumatoms)**2
1087 off_diagonal_weight = -
m_two*factor/gg2*(0.25_real64*gg2/this%alpha**2+
m_one)
1091 stress_ewald(idir, jdir) = stress_ewald(idir, jdir) &
1092 + gvec(idir) * gvec(jdir) * off_diagonal_weight
1094 stress_ewald(idir, idir) = stress_ewald(idir, idir) + factor
1103 factor =
m_half*
m_pi*charge**2/(latt%rcell_volume*this%alpha**2)
1105 stress_ewald(idir,idir) = stress_ewald(idir,idir) - factor
1108 stress_ewald = stress_ewald / latt%rcell_volume
1132 subroutine ewald_2d_stress(this, space, latt, atom, natoms, pos, stress_Ewald)
1134 type(
space_t),
intent(in) :: space
1136 type(
atom_t),
intent(in) :: atom(:)
1137 integer,
intent(in) :: natoms
1138 real(real64),
intent(in) :: pos(1:space%dim,1:natoms)
1139 real(real64),
intent(out) :: stress_Ewald(3, 3)
1141 real(real64) :: rcut, efourier
1142 integer :: iatom, jatom, idir, jdir
1143 integer :: ix, iy, ix_max, iy_max
1144 real(real64) :: gvec(3), gred(3), gg2, cos_gx, gg_abs, gmax_squared
1145 real(real64) :: factor,factor1,factor2, coeff, e_ewald
1146 real(real64) :: dz_max, z_ij, erfc1, erfc2, diff(3)
1147 real(real64),
parameter :: tol = 1e-10_real64
1151 assert(space%periodic_dim == 2)
1152 assert(space%dim == 3)
1158 do iatom = 1, natoms
1159 do jatom = iatom + 1, natoms
1160 dz_max = max(dz_max, abs(pos(3, iatom) - pos(3, jatom)))
1166 rcut =
m_two*this%alpha*4.6_real64 +
m_two*this%alpha**2*dz_max
1167 if (dz_max > tol)
then
1170 erfc1 = erfc(this%alpha*dz_max +
m_half*rcut/this%alpha)
1171 if (erfc1 *
exp(rcut*dz_max) < tol)
exit
1172 rcut = rcut * 1.414_real64
1178 factor =
m_pi/latt%rcell_volume
1180 do iatom = 1, natoms
1181 do jatom = 1, natoms
1182 z_ij = pos(3, iatom) - pos(3, jatom)
1184 factor1 = z_ij * erf(this%alpha*z_ij)
1185 factor2 =
exp(-(this%alpha*z_ij)**2)/(this%alpha*
sqrt(
m_pi))
1187 efourier = efourier - factor &
1188 * atom(iatom)%species%get_zval()*atom(jatom)%species%get_zval() * (factor1 + factor2)
1194 stress_ewald(idir, idir) = efourier
1198 ix_max = ceiling(rcut/norm2(latt%klattice(:, 1)))
1199 iy_max = ceiling(rcut/norm2(latt%klattice(:, 2)))
1200 gmax_squared = sum(ix_max*latt%klattice(:, 1)**2)
1201 gmax_squared = min(gmax_squared, sum(iy_max*latt%klattice(:, 2)**2))
1206 do ix = -ix_max, ix_max
1207 do iy = -iy_max, iy_max
1211 gg2 = dot_product(gvec,gvec)
1214 if (gg2 <
m_epsilon .or. gg2 > gmax_squared*1.001_real64) cycle
1217 factor =
m_fourth*
m_pi/(latt%rcell_volume*this%alpha*gg2)
1219 do iatom = 1, natoms
1220 do jatom = iatom, natoms
1221 diff = pos(:, iatom) - pos(:, jatom)
1222 cos_gx =
cos(sum(gvec(1:2) * diff(1:2)))
1228 if (iatom == jatom)
then
1236 stress_ewald(idir, jdir) = stress_ewald(idir, jdir) &
1237 - factor*gvec(idir)*gvec(jdir) * cos_gx * (factor1 + factor2) * coeff&
1238 * atom(iatom)%species%get_zval()*atom(jatom)%species%get_zval()
1243 factor1 =
exp(-gg_abs*z_ij)*erfc1
1248 factor2 =
exp(gg_abs*z_ij)*erfc2
1253 e_ewald =
m_half *
m_pi/latt%rcell_volume * coeff &
1254 * atom(iatom)%species%get_zval() * atom(jatom)%species%get_zval() &
1255 * cos_gx / gg_abs * (factor1 + factor2)
1258 stress_ewald(idir, idir) = stress_ewald(idir, idir) + e_ewald
1268 stress_ewald = stress_ewald / latt%rcell_volume
1275 real(real64) function screening_function_2d(alpha, z_ij, gg_abs, erfc_arg) result(factor)
1276 real(real64),
intent(in) :: alpha
1277 real(real64),
intent(in) :: z_ij
1278 real(real64),
intent(in) :: gg_abs
1279 real(real64),
intent(out) :: erfc_arg
1283 arg = -alpha*z_ij +
m_half*gg_abs/alpha
1284 erfc_arg = erfc(arg)
1286 factor = factor*
exp(-gg_abs*z_ij)
1294 class(space_t),
intent(in) :: space
1295 type(lattice_vectors_t),
intent(in) :: latt
1296 type(atom_t),
intent(in) :: atom(:)
1297 integer,
intent(in) :: natoms
1298 real(real64),
intent(in) :: pos(1:space%dim,1:natoms)
1299 real(real64),
intent(in) :: lsize(:)
1300 type(namespace_t),
intent(in) :: namespace
1301 type(multicomm_t),
intent(in) :: mc
1304 real(real64) :: energy
1305 real(real64),
allocatable :: force(:, :), force_components(:, :, :)
1306 real(real64) :: energy_components(1:ION_NUM_COMPONENTS)
1307 integer :: iatom, idir
1314 safe_allocate(force(1:space%dim, 1:natoms))
1315 safe_allocate(force_components(1:space%dim, 1:natoms, 1:ion_num_components))
1318 energy_components = energy_components, force_components = force_components)
1320 call messages_write(
'Ionic energy =')
1321 call messages_write(energy, fmt =
'(f20.10)')
1322 call messages_info(namespace=namespace)
1324 call messages_write(
'Real space energy =')
1326 call messages_info(namespace=namespace)
1328 call messages_write(
'Self energy =')
1330 call messages_info(namespace=namespace)
1332 call messages_write(
'Fourier energy =')
1334 call messages_info(namespace=namespace)
1336 call messages_info(namespace=namespace)
1338 do iatom = 1, natoms
1339 call messages_write(
'Ionic force atom')
1340 call messages_write(iatom)
1341 call messages_write(
' =')
1342 do idir = 1, space%dim
1343 call messages_write(force(idir, iatom), fmt =
'(f20.10)')
1345 call messages_info(namespace=namespace)
1347 call messages_write(
'Real space force atom')
1348 call messages_write(iatom)
1349 call messages_write(
' =')
1350 do idir = 1, space%dim
1351 call messages_write(force_components(idir, iatom,
ion_component_real), fmt =
'(f20.10)')
1353 call messages_info(namespace=namespace)
1355 call messages_write(
'Fourier space force atom')
1356 call messages_write(iatom)
1357 call messages_write(
' =')
1358 do idir = 1, space%dim
1361 call messages_info(namespace=namespace)
1363 call messages_info(namespace=namespace)
1366 safe_deallocate_a(force)
1367 safe_deallocate_a(force_components)
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.
pure logical function, public any_species_is_jellium_sphere(atom)
Check if any species is a jellium sphere.
type(debug_t), save, public debug
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
real(real64), parameter, public m_max_exp_arg
real(real64), parameter, public m_zero
real(real64), parameter, public m_four
real(real64), parameter, public m_pi
some mathematical constants
real(real64), parameter, public m_fourth
complex(real64), parameter, public m_z0
complex(real64), parameter, public m_zi
real(real64), parameter, public r_min_atom_dist
Minimal distance between two distinguishable atoms.
real(real64), parameter, public m_epsilon
real(real64), parameter, public m_half
real(real64), parameter, public m_one
real(real64), parameter, public m_three
real(real64), parameter, public m_five
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, 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)
Computes the long-range part of the 2D Ewald summation.
real(real64) function screening_function_2d(alpha, z_ij, gg_abs, erfc_arg)
Auxiliary function for the Ewald 2D stress.
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)
subroutine, public messages_not_implemented(feature, namespace)
subroutine, public messages_warning(no_lines, all_nodes, namespace)
This module handles the communicators for the various parallelization strategies.
subroutine, public profiling_out(label)
Increment out counter and sum up difference between entry and exit time.
subroutine, public profiling_in(label, exclude)
Increment in counter and save entry time.
static double f(double w, void *p)
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...