potential_j Function

public function potential_j(p, g, a, rho, q_a, dipole_a) result(v_j)

calculating the direct Coulomb potential a.k.a. Hartree potential or classical electron-electron repulsion potential

v_J(x) = INT{ rho(x') / |x-x'| } d^3x' where x and x' indicate a vector in 3D.

  • potential_J( P, G, A(:), rho ): rho is represented on molecular grids
  • potential_J_atom( P, G, A, rho_A ): rho_A is represented on atomic grids

Basically, its complexity is O(N^2), where N is # of atoms. When molecular grids are used, it becomes O(N_MG^2), where N_MG is # of MG. Here, we aim for linear-scaling, i.e., ~O(N_MG) or ~O(N), by utilizing (a) multicenter decomposition, (b) spherical harmonics expansion, and (c) multipole expansion techniques, (d) screening w.r.t. distance.

(a) Multicenter decomposition: implemented in potential_J via rho_A rho(x) = SUM_A rho_A(x) where rho_A(x) = w_A(x) rho(x) and SUM_A w_A(x) = 1 for all x. complexity: O(N_MG^2) ==> O(N_NG) O(N) O(N_AG)

(b) Spherical harmonics expansion: implemented in potential_J_atom via rho_lm rho_A(x) = SUM_{l=0}^{inf} SUM_{m=-l}^{l} rho_A,lm(r) Y_l^m(th,phi) where rho_A,lm(r) = INT d{Omega} rho_A(x) Y_l^m*(th,phi) complexity: O(N_MG) O(N) O(N_AG) ==> O(N_MG) O(N) O(N_r) O(lmax^2) Practically, it helps a lot because lmax can be quickly trucated. Truncation of lmax can be controlled by absolute accuracy, "-EPS_abs".

(c) Multipole expansion: implemented in potential_J_atom by finding rmax 1/|x-x'| = SUM_{l=0}^{inf}( r_<^l / r_>^{l+1} ) P_l( cos(gamma) ) where cos(gamma) = cos(th)cos(th') - sin(th)sin(th')cos(phi-phi') complexity: O(N_MG) O(N) O(N_r) O(lmax^2) ------- ------ ==> O(N) O(lmax^2) [ O(N_r^2) + O(N_r) + O(N_MG) ] depending on how much MGs are close to A (r of MG < rmax). The O(N_MG) at the end is trivial, just assigning a value rather than performing integrals, so it would be greatly helpful for a large system. Choosing rmax can be controlled by relative accuracy, "-EPS_rel".

(d) Screening with respect to the distance if r_A < r_J (cut-off radius), then just use a monopole (l=0 and m=0).


Arguments

Type IntentOptional Attributes Name
type(param), intent(in) :: p
type(grid3d), intent(in) :: g
type(atom_set), intent(in) :: a(:)
real(kind=long), intent(in) :: rho(:)
real(kind=long), intent(out), optional :: q_a(:)
real(kind=long), intent(out), optional :: dipole_a(:,:)

Return Value real(kind=long), (g%n_grid)