Realspace cutoffs reproducing the two-body dispersion energy within a requested accuracy per atom.
Beyond the damping region the pair sum is dominated by the bare C6 tail. Integrating it over the d periodic dimensions gives the truncation error
dE/atom = rho *
with the number density rho of the periodic cell, the mean pair coefficient
Only the two-body cutoff is derived, the coordination number cutoff is not an accuracy parameter because the counting function has a non-vanishing limit, and the three-body cutoff is left at its default.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(structure_type), | intent(in) | :: | mol |
Molecular structure data |
||
| class(d3_model), | intent(in) | :: | disp |
Dispersion model |
||
| real(kind=wp), | intent(in) | :: | accuracy |
Requested accuracy of the two-body dispersion energy in Hartree per atom |
Realspace cutoffs
function get_realspace_cutoff(mol, disp, accuracy) result(cutoff) !> Molecular structure data class(structure_type), intent(in) :: mol !> Dispersion model class(d3_model), intent(in) :: disp !> Requested accuracy of the two-body dispersion energy in Hartree per atom real(wp), intent(in) :: accuracy !> Realspace cutoffs type(realspace_cutoff) :: cutoff integer :: mref, ndim, iat, izp, isp, jsp, iref, jref, jat real(wp) :: measure, c6mean, amp, r2 real(wp), allocatable :: cn(:), gwvec(:, :), wsum(:, :), lattr(:, :) cutoff = realspace_cutoff() if (accuracy <= 0.0_wp) return mref = maxval(disp%ref) allocate(cn(mol%nat), gwvec(mref, mol%nat)) call get_lattice_points(mol%periodic, mol%lattice, cutoff%cn, lattr) call get_coordination_number(mol, lattr, cutoff%cn, disp%rcov, cn) call disp%weight_references(mol, cn, gwvec) ! contract the reference coefficients with the accumulated weights per species allocate(wsum(mref, mol%nid), source=0.0_wp) do iat = 1, mol%nat if (disp%ghost(iat)) cycle izp = mol%id(iat) wsum(:, izp) = wsum(:, izp) + gwvec(:, iat) end do c6mean = 0.0_wp do isp = 1, mol%nid do jsp = 1, mol%nid do iref = 1, disp%ref(isp) do jref = 1, disp%ref(jsp) c6mean = c6mean + disp%c6(iref, jref, isp, jsp) & & * wsum(iref, isp) * wsum(jref, jsp) end do end do end do end do c6mean = c6mean / mol%nat**2 ndim = count(mol%periodic) measure = get_periodic_measure(mol, ndim) select case(ndim) case(3) amp = 2.0_wp*pi/3.0_wp * mol%nat/measure * c6mean cutoff%disp2 = (cutoff_safety * amp / accuracy)**(1.0_wp/3.0_wp) case(2) amp = 0.25_wp*pi * mol%nat/measure * c6mean cutoff%disp2 = (cutoff_safety * amp / accuracy)**(0.25_wp) case(1) amp = 0.2_wp * mol%nat/measure * c6mean cutoff%disp2 = (cutoff_safety * amp / accuracy)**(0.2_wp) case default ! a finite system is summed exactly once all pairs are covered r2 = 0.0_wp do iat = 1, mol%nat do jat = 1, iat - 1 r2 = max(r2, sum((mol%xyz(:, iat) - mol%xyz(:, jat))**2)) end do end do cutoff%disp2 = sqrt(r2) end select cutoff%disp2 = max(cutoff%disp2, cutoff_minimum) cutoff%disp3 = min(cutoff%disp3, cutoff%disp2) end function get_realspace_cutoff