Forces
Table of Contents
- 1. Introduction
- 2. Context
- 3. Finite-difference function
- 4. Forces of the Jastrow function
- 4.1. Electron-nucleus Jastrow
- 4.2. Electron-electron-nucleus Jastrow
- 4.2.1. Force of P matrix
- 4.2.2. Force of derivative of the \(P\) matrix
- 4.2.3. Force of electron-electron-nucleus Jastrow value
- 4.2.4. Force of derivatives of electron-nucleus rescaled distance
- 4.2.5. Force of electron-electron-nucleus Jastrow gradient
- 4.2.6. Force of electron-electron-nucleus Jastrow Laplacian
- 4.2.7. Force of \(\delta P\) matrix
- 4.2.8. Force of single electron-electron-nucleus Jastrow value
- 5. Forces of the orbitals
1. Introduction
To calculate interatomic forces, a derivative (with respect to nuclei) of the values, gradient and Laplacian of the Jastrow and the molecular orbitals (MO) is required. Furthermore, for the nonlocal pseudopotential, also the forces of the values of the single-electron move Jastrows are required.
2. Context
2.1. Data structure
typedef struct qmckl_forces_struct{ double * restrict forces_jastrow_en; uint64_t forces_jastrow_en_date; double * restrict forces_jastrow_en_g; uint64_t forces_jastrow_en_g_date; double * restrict forces_jastrow_en_l; uint64_t forces_jastrow_en_l_date; double * restrict forces_tmp_c; uint64_t forces_tmp_c_date; double * restrict forces_dtmp_c; uint64_t forces_dtmp_c_date; double * restrict forces_een_n; uint64_t forces_een_n_date; double * restrict forces_jastrow_een; uint64_t forces_jastrow_een_date; double * restrict forces_jastrow_een_g; uint64_t forces_jastrow_een_g_date; double * restrict forces_jastrow_een_l; uint64_t forces_jastrow_een_l_date; double * restrict forces_ao_value; uint64_t forces_ao_value_date; uint64_t forces_ao_value_maxsize; double * restrict forces_mo_value; uint64_t forces_mo_value_date; uint64_t forces_mo_value_maxsize; double * restrict forces_mo_g; uint64_t forces_mo_g_date; double * restrict forces_mo_l; uint64_t forces_mo_l_date; double * forces_jastrow_single_en; uint64_t forces_jastrow_single_en_date; double * forces_jastrow_single_een; uint64_t forces_jastrow_single_een_date; double * forces_delta_p; uint64_t forces_delta_p_date; } qmckl_forces_struct;
3. Finite-difference function
We introduce here a general function to compute the derivatives of any quantity with respect to nuclear coordinates. using finite-differences.
qmckl_exit_code qmckl_finite_difference_deriv_n( qmckl_context context, const double delta_x, function_callback get_function, double* const derivative_output, int64_t const size) { // Finite difference coefficients for a 9-point stencil double coef[9] = { 1.0/280.0, -4.0/105.0, 1.0/5.0, -4.0/5.0, 0.0, 4.0/5.0, -1.0/5.0, 4.0/105.0, -1.0/280.0 }; qmckl_exit_code rc; int64_t walk_num; rc = qmckl_get_electron_walk_num(context, &walk_num); if (rc != QMCKL_SUCCESS) { return rc; } int64_t nucl_num; rc = qmckl_get_nucleus_num(context, &nucl_num); if (rc != QMCKL_SUCCESS) { return rc; } double* nucleus_coord = (double*) malloc(3 * nucl_num * sizeof(double)); if (nucleus_coord == NULL) { return QMCKL_ALLOCATION_FAILED; } rc = qmckl_get_nucleus_coord (context, 'N', nucleus_coord, 3*nucl_num); double* temp_coord = (double*) malloc(3 * nucl_num * sizeof(double)); if (temp_coord == NULL) { free(nucleus_coord); return QMCKL_ALLOCATION_FAILED; } double* function_values = (double*) malloc(walk_num*size * sizeof(double)); if (function_values == NULL) { free(nucleus_coord); free(temp_coord); return QMCKL_ALLOCATION_FAILED; } memset(derivative_output, 0, nucl_num*3*walk_num*size*sizeof(double)); // Copy original coordinates for (int i = 0; i < 3 * nucl_num; i++) { temp_coord[i] = nucleus_coord[i]; } for (int64_t a = 0; a < nucl_num; a++) { for (int64_t k = 0; k < 3; k++) { for (int64_t m = -4; m <= 4; m++) { // Apply finite difference displacement temp_coord[k+a*3] = nucleus_coord[k+3*a] + (double) m * delta_x; // Update coordinates in the context rc = qmckl_set_nucleus_coord(context, 'N', temp_coord, 3*nucl_num); assert(rc == QMCKL_SUCCESS); rc = qmckl_context_touch(context); assert(rc == QMCKL_SUCCESS); rc = qmckl_single_touch(context); assert(rc == QMCKL_SUCCESS); // Call the provided function rc = get_function(context, function_values, walk_num*size); assert(rc == QMCKL_SUCCESS); // Accumulate derivative using finite-difference coefficients for (int64_t nw=0 ; nw<walk_num ; nw++) { int64_t shift = nucl_num*3*size*nw + size*(k + 3*a); for (int64_t i = 0; i < size; i++) { derivative_output[i+shift] += coef[m + 4] * function_values[nw*size+i]; } } } temp_coord[k+a*3] = nucleus_coord[k+3*a]; } } // Reset coordinates in the context rc = qmckl_set_nucleus_coord(context, 'N', temp_coord, 3*nucl_num); assert(rc == QMCKL_SUCCESS); rc = qmckl_context_touch(context); assert(rc == QMCKL_SUCCESS); // Normalize by the step size for (int64_t i = 0; i < size*3*nucl_num*walk_num ; i++) { derivative_output[i] /= delta_x; } free(nucleus_coord); free(temp_coord); free(function_values); return QMCKL_SUCCESS; }
4. Forces of the Jastrow function
For the forces of the Jastrow function, there is only a contribution from the electron-nucleus and electron-electron-nucleus Jastrow, since the electron-electron Jastrow does not depend on nuclear coordinates.
4.1. Electron-nucleus Jastrow
4.1.1. Force of electron-nucleus Jastrow value
Calculates the force of the electron-nucleus Jastrow value. The terms of the force of the electron-nucleus Jastrow value are identical to the gradient of this Jastrow, up to a minus sign. \[ \partial_{\alpha,m} J_{en} = -\sum_i \left( \frac{a_1 \partial_{i,m} \widetilde{R}_{i\alpha}}{(1+a_2 \widetilde{R}_{i\alpha} )^2} + \sum_{k=2}^{N_\text{aord}} a_k k \widetilde{R}_{i\alpha}^{k-1} \partial_{i,m} \widetilde{R}_{i\alpha} \right) \]
4.1.1.1. Get
qmckl_exit_code qmckl_get_forces_jastrow_en(qmckl_context context, double* const forces_jastrow_en, const int64_t size_max);
interface integer(qmckl_exit_code) function qmckl_get_forces_jastrow_en (context, & forces_jastrow_en, size_max) bind(C) use, intrinsic :: iso_c_binding import implicit none integer (qmckl_context) , intent(in), value :: context integer(c_int64_t), intent(in), value :: size_max real(c_double), intent(out) :: forces_jastrow_en(size_max) end function qmckl_get_forces_jastrow_en end interface
4.1.1.2. Compute
Variable | Type | In/Out | Description |
---|---|---|---|
context |
qmckl_context |
in | Global state |
walk_num |
int64_t |
in | Number of walkers |
elec_num |
int64_t |
in | Number of electrons |
nucl_num |
int64_t |
in | Number of nuclei |
type_nucl_num |
int64_t |
in | Number of unique nuclei |
type_nucl_vector |
int64_t[nucl_num] |
in | IDs of unique nuclei |
aord_num |
int64_t |
in | Number of coefficients |
a_vector |
double[type_nucl_num][aord_num+1] |
in | List of coefficients |
en_distance_rescaled |
double[walk_num][nucl_num][elec_num] |
in | Electron-nucleus distances |
en_distance_rescaled_gl |
double[walk_num][nucl_num][elec_num][4] |
in | Electron-nucleus distance derivatives |
forces_jastrow_en |
double[walk_num][nucl_num][3] |
out | Electron-nucleus forces |
function qmckl_compute_forces_jastrow_en_doc( & context, walk_num, elec_num, nucl_num, type_nucl_num, & type_nucl_vector, aord_num, a_vector, & en_distance_rescaled, en_distance_rescaled_gl, forces_jastrow_en) & bind(C) result(info) use qmckl implicit none integer (qmckl_context), intent(in), value :: context integer (c_int64_t) , intent(in) , value :: walk_num integer (c_int64_t) , intent(in) , value :: elec_num integer (c_int64_t) , intent(in) , value :: nucl_num integer (c_int64_t) , intent(in) , value :: type_nucl_num integer (c_int64_t) , intent(in) :: type_nucl_vector(nucl_num) integer (c_int64_t) , intent(in) , value :: aord_num real (c_double ) , intent(in) :: a_vector(aord_num+1,type_nucl_num) real (c_double ) , intent(in) :: en_distance_rescaled(elec_num,nucl_num,walk_num) real (c_double ) , intent(in) :: en_distance_rescaled_gl(4, elec_num,nucl_num,walk_num) real (c_double ) , intent(out) :: forces_jastrow_en(3,nucl_num,walk_num) integer(qmckl_exit_code) :: info integer*8 :: i, a, k, nw, ii double precision :: x, x1, kf double precision :: denom, invdenom, invdenom2, f double precision :: dx(3) info = QMCKL_SUCCESS if (context == QMCKL_NULL_CONTEXT) then info = QMCKL_INVALID_CONTEXT return endif if (walk_num <= 0) then info = QMCKL_INVALID_ARG_2 return endif if (elec_num <= 0) then info = QMCKL_INVALID_ARG_3 return endif if (nucl_num <= 0) then info = QMCKL_INVALID_ARG_4 return endif if (aord_num < 0) then info = QMCKL_INVALID_ARG_7 return endif do nw =1, walk_num forces_jastrow_en(:,:,nw) = 0.0d0 do a = 1, nucl_num do i = 1, elec_num x = en_distance_rescaled(i,a,nw) if(abs(x) < 1.d-12) continue denom = 1.0d0 + a_vector(2, type_nucl_vector(a)+1) * x invdenom = 1.0d0 / denom invdenom2 = invdenom*invdenom dx(1) = -en_distance_rescaled_gl(1,i,a,nw) dx(2) = -en_distance_rescaled_gl(2,i,a,nw) dx(3) = -en_distance_rescaled_gl(3,i,a,nw) f = a_vector(1, type_nucl_vector(a)+1) * invdenom2 forces_jastrow_en(1,a,nw) = forces_jastrow_en(1,a,nw) + f * dx(1) forces_jastrow_en(2,a,nw) = forces_jastrow_en(2,a,nw) + f * dx(2) forces_jastrow_en(3,a,nw) = forces_jastrow_en(3,a,nw) + f * dx(3) kf = 2.d0 x1 = x x = 1.d0 do k=2, aord_num f = a_vector(k+1,type_nucl_vector(a)+1) * kf * x forces_jastrow_en(1,a,nw) = forces_jastrow_en(1,a,nw) + f * x1 * dx(1) forces_jastrow_en(2,a,nw) = forces_jastrow_en(2,a,nw) + f * x1 * dx(2) forces_jastrow_en(3,a,nw) = forces_jastrow_en(3,a,nw) + f * x1 * dx(3) x = x*x1 kf = kf + 1.d0 end do end do end do end do end function qmckl_compute_forces_jastrow_en_doc
4.1.2. Force of electron-nucleus Jastrow gradient
To avoid having to create new arrays for the Hessian of the rescaled distances, we compute parts of it manually in this routine.
\begin{eqnarray} \partial_{\alpha,m} \partial_{i,n} J_{en} & = \frac{a_1 \partial_{\alpha,m} \partial_{i,n} \widetilde{R}_{i\alpha} }{(1+a_2 \widetilde{R}_{i\alpha})^2} - 2 \frac{a_1 a_2 \partial_{\alpha,m} \widetilde{R}_{i\alpha} \partial_{i,n} \widetilde{R}_{i\alpha}}{(1+a_2 \widetilde{R}_{i\alpha})^3} + \sum_{k=2}^{N_\text{aord}} a_k k \left((k-1) \widetilde{R}_{i\alpha}^{k-2} \partial_{\alpha,m} \widetilde{R}_{i\alpha} \partial_{i,n} \widetilde{R}_{i\alpha} + \widetilde{R}_{i\alpha}^{k-1} \partial_{\alpha,m}\partial_{i,n} \widetilde{R}_{i\alpha} \right) \\ & = -\frac{a_1 e^{-\kappa R_{i\alpha}}}{R_{i\alpha }(1+a_2 \widetilde{R}_{i\alpha})^2} + \frac{a_1 \partial_{i,m} \widetilde{R}_{i\alpha} \partial_{i,n} \widetilde{R}_{i\alpha} }{(1+a_2 \widetilde{R}_{i\alpha})^2}\left (\frac{e^{\kappa R_{i\alpha}}}{R_{i\alpha}} + \kappa e^{\kappa R_{i\alpha}} \right) + 2 \frac{a_1 a_2 \partial_{i,m} \widetilde{R}_{i\alpha} \partial_{i,n} \widetilde{R}_{i\alpha}}{(1+a_2 \widetilde{R}_{i\alpha})^3} \\ &- \sum_{k=2}^{N_\text{aord}} a_k k \left((k-1) \widetilde{R}_{i\alpha}^{k-2} \partial_{\alpha,m} \widetilde{R}_{i\alpha} \partial_{i,n} \widetilde{R}_{i\alpha} - \widetilde{R}_{i\alpha}^{k-1} \partial_{i,m}\widetilde{R}_{i\alpha}\partial_{i,n} \widetilde{R}_{i\alpha} e^{\kappa R_{i\alpha}} (\kappa + \frac{1}{R_{i\alpha}}) + \delta_{n,m} e^{-\kappa R_{i\alpha}}\frac{1}{R_{i\alpha}} \right)\\ \end{eqnarray}4.1.2.1. Get
qmckl_exit_code qmckl_get_forces_jastrow_en_g(qmckl_context context, double* const forces_jastrow_en_g, const int64_t size_max);
interface integer(qmckl_exit_code) function qmckl_get_forces_jastrow_en_g (context, & forces_jastrow_en_g, size_max) bind(C) use, intrinsic :: iso_c_binding import implicit none integer (qmckl_context) , intent(in), value :: context integer(c_int64_t), intent(in), value :: size_max real(c_double), intent(out) :: forces_jastrow_en_g(size_max) end function qmckl_get_forces_jastrow_en_g end interface
4.1.2.2. Compute
Variable | Type | In/Out | Description |
---|---|---|---|
context |
qmckl_context |
in | Global state |
walk_num |
int64_t |
in | Number of walkers |
elec_num |
int64_t |
in | Number of electrons |
nucl_num |
int64_t |
in | Number of nuclei |
type_nucl_num |
int64_t |
in | Number of unique nuclei |
type_nucl_vector |
int64_t[nucl_num] |
in | IDs of unique nuclei |
aord_num |
int64_t |
in | Number of coefficients |
a_vector |
double[type_nucl_num][aord_num+1] |
in | List of coefficients |
rescale_factor_en |
double[type_nucl_num] |
in | Rescale factor for electron-nucleus |
en_distance |
double[walk_num][elec_num][nucl_num] |
in | Electron-nucleus distances |
en_distance_rescaled |
double[walk_num][nucl_num][elec_num] |
in | Electron-nucleus distances |
en_distance_rescaled_gl |
double[walk_num][nucl_num][elec_num][4] |
in | Electron-nucleus distance derivatives |
forces_jastrow_en_g |
double[walk_num][nucl_num][3][elec_num][3] |
out | Force of electron-nucleus gradient |
function qmckl_compute_forces_jastrow_en_g_doc( & context, walk_num, elec_num, nucl_num, type_nucl_num, & type_nucl_vector, aord_num, a_vector, rescale_factor_en, en_distance, & en_distance_rescaled, en_distance_rescaled_gl, forces_jastrow_en_g) & bind(C) result(info) use qmckl implicit none integer (qmckl_context), intent(in), value :: context integer (c_int64_t) , intent(in) , value :: walk_num integer (c_int64_t) , intent(in) , value :: elec_num integer (c_int64_t) , intent(in) , value :: nucl_num integer (c_int64_t) , intent(in) , value :: type_nucl_num integer (c_int64_t) , intent(in) :: type_nucl_vector(nucl_num) integer (c_int64_t) , intent(in) , value :: aord_num real (c_double ) , intent(in) :: a_vector(aord_num+1,type_nucl_num) real (c_double ) , intent(in) :: rescale_factor_en(type_nucl_num) real (c_double ) , intent(in) :: en_distance(nucl_num,elec_num,walk_num) real (c_double ) , intent(in) :: en_distance_rescaled(elec_num,nucl_num,walk_num) real (c_double ) , intent(in) :: en_distance_rescaled_gl(4, elec_num,nucl_num,walk_num) real (c_double ) , intent(out) :: forces_jastrow_en_g(3,elec_num,3,nucl_num,walk_num) integer(qmckl_exit_code) :: info integer*8 :: i, a, k, nw, ii, m,l double precision :: x, x1, kf double precision :: denom, invdenom, invdenom2, f, f2, expk, invdist double precision :: dx(4) info = QMCKL_SUCCESS if (context == QMCKL_NULL_CONTEXT) then info = QMCKL_INVALID_CONTEXT return endif if (walk_num <= 0) then info = QMCKL_INVALID_ARG_2 return endif if (elec_num <= 0) then info = QMCKL_INVALID_ARG_3 return endif if (nucl_num <= 0) then info = QMCKL_INVALID_ARG_4 return endif if (aord_num < 0) then info = QMCKL_INVALID_ARG_7 return endif do nw =1, walk_num forces_jastrow_en_g(:,:,:,:,nw) = 0.0d0 do a = 1, nucl_num do i = 1, elec_num expk = dexp(rescale_factor_en(type_nucl_vector(a)+1) * en_distance(a,i,nw)) invdist = 1.d0 / en_distance(a,i,nw) x = en_distance_rescaled(i,a,nw) if(abs(x) < 1.d-12) continue denom = 1.0d0 + a_vector(2, type_nucl_vector(a)+1) * x invdenom = 1.0d0 / denom invdenom2 = invdenom*invdenom f = a_vector(1, type_nucl_vector(a)+1) * invdenom2 do m = 1, 3 dx(m) = en_distance_rescaled_gl(m,i,a,nw) end do do m = 1, 3 do l = 1,3 if (m == l) then forces_jastrow_en_g(m,i,l,a,nw) = forces_jastrow_en_g(m,i,l,a,nw) - f * invdist / expk end if forces_jastrow_en_g(m,i,l,a,nw) = forces_jastrow_en_g(m,i,l,a,nw) + & f * dx(m) * dx(l) * expk * (invdist + rescale_factor_en(type_nucl_vector(a)+1)) forces_jastrow_en_g(m,i,l,a,nw) = forces_jastrow_en_g(m,i,l,a,nw) + 2.d0 * f * invdenom * & a_vector(2, type_nucl_vector(a)+1) * dx(m) * dx(l) end do end do kf = 2.d0 x1 = x x = 1.d0 do k=2, aord_num f = a_vector(k+1,type_nucl_vector(a)+1) * kf * x f2 = a_vector(k+1,type_nucl_vector(a)+1) * kf * x * (kf-1.d0) do m = 1, 3 do l = 1, 3 if (m == l) then forces_jastrow_en_g(m,i,l,a,nw) = forces_jastrow_en_g(m,i,l,a,nw) - f * x1 * invdist / expk end if forces_jastrow_en_g(m,i,l,a,nw) = forces_jastrow_en_g(m,i,l,a,nw) - f2 * dx(m) * dx(l) & + f * x1 * dx(m) * dx(l) * rescale_factor_en(type_nucl_vector(a)+1) * expk & + f * x1 * dx(m) * dx(l) * invdist * expk end do end do x = x*x1 kf = kf + 1.d0 end do end do end do end do end function qmckl_compute_forces_jastrow_en_g_doc
4.1.3. Force of electron-nucleus Jastrow Laplacian
Calculates the force of the electron-nucleus Jastrow Laplacian. To avoid having to calculate higher order derivatives of the rescaled distances elsewhere, the neccessery terms are calcuculated on the fly.
\begin{eqnarray} \partial_{\alpha,m} \nabla^2 J_{en} =& \sum_i \left(\partial_{\alpha,m}\frac{a_1 \nabla^2 \widetilde{R}_{i\alpha}}{(1+a_2 \widetilde{R}_{i\alpha})^2} - \partial_{\alpha,m} \frac{2a_1a_2 (\nabla\widetilde{R}_{i\alpha}\cdot \nabla \widetilde{R}_{i\alpha})}{(1+a_2\widetilde{R}_{i\alpha})^3} + \partial_{\alpha,m} \sum_{k=2}^{N_\text{aord}} a_k k \left( \widetilde{R}_{i\alpha}^{k-1} \nabla^2\widetilde{R}_{i\alpha} + (k-1)\widetilde{R}_{i\alpha}^{k-2} (\nabla \widetilde{R}_{i\alpha}\cdot \nabla \widetilde{R}_{i\alpha} ) \right) \right)\\ =&\sum_i \left( \frac{a_1 \partial_{i,m} \widetilde{R}_{i\alpha}}{(1+a_2 \widetilde{R}_{i\alpha})^2}\left( \frac{2\kappa}{R_{i\alpha}} - \kappa^2 + \frac{2}{R^2_{i\alpha}}\right) + \frac{2a_1a_2\partial_{i,m}\widetilde{R}_{i\alpha}\nabla^2\widetilde{R}_{i\alpha}}{(1+a_2 \widetilde{R}_{i\alpha})^3} - \frac{4a_1a_2\kappa e^{-\kappa R_{i\alpha}}\partial_{i,m}\widetilde{R}_{i\alpha}}{(1+a_2 \widetilde{R}_{i\alpha})^3} - \frac{6 a_1 a_2^2 (\nabla \widetilde{R}_{i\alpha} \cdot \nabla \widetilde{R}_{i\alpha})\partial_{i,m}\widetilde{R}_{i\alpha}}{(1+a_2 \widetilde{R}_{i\alpha})^4} \right.\\ &\left.+ \sum_{k=2}^{N_\text{aord}} a_k k \left( -(k-1) \widetilde{R}_{i\alpha}^{k-2}\partial_{i,m}\widetilde{R}_{i\alpha} \nabla^2\widetilde{R}_{i\alpha} + \widetilde{R}_{i\alpha}^{k-1}\partial_{i,m}\widetilde{R}_{i\alpha}\left(\frac{2\kappa}{R_{i\alpha}} - \kappa^2 + \frac{2}{R_{i\alpha}^2} \right) - (k-1)(k-2)\widetilde{R}_{i\alpha}^{k-3}\partial_{i,m}\widetilde{R}_{i\alpha}(\nabla\widetilde{R}_{i\alpha} \cdot \nabla \widetilde{R}_{i\alpha}) + 2\kappa(k-1)\widetilde{R}_{i\alpha}^{k-2} e^{-\kappa R_{i\alpha}} \partial_{i,m}\widetilde{R}_{i\alpha} \right) \right) \end{eqnarray}4.1.3.1. Get
qmckl_exit_code qmckl_get_forces_jastrow_en_l(qmckl_context context, double* const forces_jastrow_en_l, const int64_t size_max);
interface integer(qmckl_exit_code) function qmckl_get_forces_jastrow_en_l (context, & forces_jastrow_en_l, size_max) bind(C) use, intrinsic :: iso_c_binding import implicit none integer (qmckl_context) , intent(in), value :: context integer(c_int64_t), intent(in), value :: size_max real(c_double), intent(out) :: forces_jastrow_en_l(size_max) end function qmckl_get_forces_jastrow_en_l end interface
4.1.3.2. Compute
Variable | Type | In/Out | Description |
---|---|---|---|
context |
qmckl_context |
in | Global state |
walk_num |
int64_t |
in | Number of walkers |
elec_num |
int64_t |
in | Number of electrons |
nucl_num |
int64_t |
in | Number of nuclei |
type_nucl_num |
int64_t |
in | Number of unique nuclei |
type_nucl_vector |
int64_t[nucl_num] |
in | IDs of unique nuclei |
aord_num |
int64_t |
in | Number of coefficients |
a_vector |
double[type_nucl_num][aord_num+1] |
in | List of coefficients |
rescale_factor_en |
double[type_nucl_num] |
in | Rescale factor for electron-nucleus |
en_distance |
double[walk_num][elec_num][nucl_num] |
in | Electron-nucleus distances |
en_distance_rescaled |
double[walk_num][nucl_num][elec_num] |
in | Electron-nucleus distances |
en_distance_rescaled_gl |
double[walk_num][nucl_num][elec_num][4] |
in | Electron-nucleus distance derivatives |
forces_jastrow_en_l |
double[walk_num][nucl_num][3] |
out | Forces of electron-nucleus Laplacian |
function qmckl_compute_forces_jastrow_en_l_doc( & context, walk_num, elec_num, nucl_num, type_nucl_num, & type_nucl_vector, aord_num, a_vector, rescale_factor_en, en_distance, & en_distance_rescaled, en_distance_rescaled_gl, forces_jastrow_en_l) & bind(C) result(info) use qmckl implicit none integer (qmckl_context), intent(in), value :: context integer (c_int64_t) , intent(in) , value :: walk_num integer (c_int64_t) , intent(in) , value :: elec_num integer (c_int64_t) , intent(in) , value :: nucl_num integer (c_int64_t) , intent(in) , value :: type_nucl_num integer (c_int64_t) , intent(in) :: type_nucl_vector(nucl_num) integer (c_int64_t) , intent(in) , value :: aord_num real (c_double ) , intent(in) :: a_vector(aord_num+1,type_nucl_num) real (c_double ) , intent(in) :: rescale_factor_en(type_nucl_num) real (c_double ) , intent(in) :: en_distance(nucl_num, elec_num, walk_num) real (c_double ) , intent(in) :: en_distance_rescaled(elec_num,nucl_num,walk_num) real (c_double ) , intent(in) :: en_distance_rescaled_gl(4, elec_num,nucl_num,walk_num) real (c_double ) , intent(out) :: forces_jastrow_en_l(3,nucl_num,walk_num) integer(qmckl_exit_code) :: info integer*8 :: i, a, k, nw, ii, m,l double precision :: x, x1, kf, grad_c2 double precision :: denom, invdenom, invdenom2, f, f2, expk, invdist double precision :: dx(4) info = QMCKL_SUCCESS if (context == QMCKL_NULL_CONTEXT) then info = QMCKL_INVALID_CONTEXT return endif if (walk_num <= 0) then info = QMCKL_INVALID_ARG_2 return endif if (elec_num <= 0) then info = QMCKL_INVALID_ARG_3 return endif if (nucl_num <= 0) then info = QMCKL_INVALID_ARG_4 return endif if (aord_num < 0) then info = QMCKL_INVALID_ARG_7 return endif do nw =1, walk_num forces_jastrow_en_l(:,:,nw) = 0.0d0 do a = 1, nucl_num do i = 1, elec_num expk = dexp(rescale_factor_en(type_nucl_vector(a)+1) * en_distance(a,i,nw)) invdist = 1.d0 / en_distance(a,i,nw) x = en_distance_rescaled(i,a,nw) if(abs(x) < 1.d-12) continue denom = 1.0d0 + a_vector(2, type_nucl_vector(a)+1) * x invdenom = 1.0d0 / denom invdenom2 = invdenom*invdenom f = a_vector(1, type_nucl_vector(a)+1) * invdenom2 do m = 1, 4 dx(m) = en_distance_rescaled_gl(m,i,a,nw) end do grad_c2 = dx(1)*dx(1) + dx(2)*dx(2) + dx(3)*dx(3) do m = 1, 3 forces_jastrow_en_l(m,a,nw) = forces_jastrow_en_l(m,a,nw) + f * dx(m) * & (rescale_factor_en(type_nucl_vector(a)+1) & * (2 *invdist - rescale_factor_en(type_nucl_vector(a)+1)) + 2*invdist*invdist) forces_jastrow_en_l(m,a,nw) = forces_jastrow_en_l(m,a,nw) + 2.d0 * f & * invdenom * a_vector(2, type_nucl_vector(a)+1) * dx(m) * dx(4) forces_jastrow_en_l(m,a,nw) = forces_jastrow_en_l(m,a,nw) - 4.d0 * f & * invdenom * a_vector(2, type_nucl_vector(a)+1) * rescale_factor_en(type_nucl_vector(a)+1) & * dx(m)/expk forces_jastrow_en_l(m,a,nw) = forces_jastrow_en_l(m,a,nw) - 6.d0 * f & * invdenom * invdenom * a_vector(2, type_nucl_vector(a)+1) * a_vector(2, type_nucl_vector(a)+1) & * grad_c2 * dx(m) end do kf = 2.d0 x1 = x x = 1.d0 do k=2, aord_num f = a_vector(k+1,type_nucl_vector(a)+1) * kf * x do m = 1, 3 forces_jastrow_en_l(m,a,nw) = forces_jastrow_en_l(m,a,nw) & - f * dx(m) * dx(4) * (kf-1.d0) & - f / x1 * (kf-1.d0) * (kf-2.d0) * dx(m) /expk /expk & + f * x1 * rescale_factor_en(type_nucl_vector(a)+1) * dx(m) * dx(4) * expk & + f * x1 * 2 * dx(m) * invdist * invdist & + 2 * f * (kf-1.d0) * dx(m) * rescale_factor_en(type_nucl_vector(a)+1) / expk end do x = x*x1 kf = kf + 1.d0 end do end do end do end do end function qmckl_compute_forces_jastrow_en_l_doc
4.1.4. Force of single electron-nucleus Jastrow value
Calculate the force of the single-electron contribution ot the electron-nucleus Jastrow value. \[ \delta\partial_{\alpha,m} J_{en} = -\left( \frac{a_1 \partial_{i,m} \widetilde{R}_{i\alpha}^{\text{new}}}{(1+a_2 \widetilde{R}_{i\alpha}^{\text{new}} )^2} + \sum_{k=2}^{N_\text{aord}} a_k k {\widetilde{R}_{i\alpha}^{\text{new}}}^{k-1} \partial_{i,m} \widetilde{R}_{i\alpha}^{\text{new}} \right) + \left( \frac{a_1 \partial_{i,m} \widetilde{R}_{i\alpha}^{\text{old}}}{(1+a_2 \widetilde{R}_{i\alpha}^{\text{old}} )^2} + \sum_{k=2}^{N_\text{aord}} a_k k {\widetilde{R}_{i\alpha}^{\text{old}}}^{k-1} \partial_{i,m} \widetilde{R}_{i\alpha}^{\text{old}} \right) \]
The function qmckl_set_single_point
has to be called before this function to set the new electron position.
4.1.4.1. Get
qmckl_exit_code qmckl_get_forces_jastrow_single_en(qmckl_context context, double* const forces_jastrow_single_en, const int64_t size_max);
4.1.4.2. Compute
Variable | Type | In/Out | Description |
---|---|---|---|
context |
qmckl_context |
in | Global state |
num |
int64_t |
in | Index of single electron |
walk_num |
int64_t |
in | Number of walkers |
elec_num |
int64_t |
in | Number of electrons |
nucl_num |
int64_t |
in | Number of nuclei |
type_nucl_num |
int64_t |
in | Number of unique nuclei |
type_nucl_vector |
int64_t[nucl_num] |
in | IDs of unique nuclei |
aord_num |
int64_t |
in | Number of coefficients |
a_vector |
double[type_nucl_num][aord_num+1] |
in | List of coefficients |
en_distance_rescaled |
double[walk_num][nucl_num][elec_num] |
in | Electron-nucleus rescaled distances |
en_distance_rescaled_gl |
double[walk_num][nucl_num][elec_num][4] |
in | Electron-nucleus rescaled distance derivatives |
en_rescaled_single |
double[walk_num][nucl_num] |
in | Electron-nucleus rescaled single distances |
en_rescaled_single_gl |
double[walk_num][nucl_num][4] |
in | Electron-nucleus rescaled single distance derivatives |
forces_jastrow_single_en |
double[walk_num][nucl_num][3] |
out | Single electron-nucleus forces |
function qmckl_compute_forces_jastrow_single_en_doc( & context, num_in, walk_num, elec_num, nucl_num, type_nucl_num, & type_nucl_vector, aord_num, a_vector, & en_distance_rescaled, en_distance_rescaled_gl, en_rescaled_single, en_rescaled_single_gl, forces_jastrow_single_en) & bind(C) result(info) use qmckl implicit none integer (qmckl_context), intent(in), value :: context integer (c_int64_t) , intent(in) , value :: num_in integer (c_int64_t) , intent(in) , value :: walk_num integer (c_int64_t) , intent(in) , value :: elec_num integer (c_int64_t) , intent(in) , value :: nucl_num integer (c_int64_t) , intent(in) , value :: type_nucl_num integer (c_int64_t) , intent(in) :: type_nucl_vector(nucl_num) integer (c_int64_t) , intent(in) , value :: aord_num real (c_double ) , intent(in) :: a_vector(aord_num+1,type_nucl_num) real (c_double ) , intent(in) :: en_distance_rescaled(elec_num,nucl_num,walk_num) real (c_double ) , intent(in) :: en_distance_rescaled_gl(4, elec_num,nucl_num,walk_num) real (c_double ) , intent(in) :: en_rescaled_single(nucl_num,walk_num) real (c_double ) , intent(in) :: en_rescaled_single_gl(4, nucl_num,walk_num) real (c_double ) , intent(out) :: forces_jastrow_single_en(3,nucl_num,walk_num) integer(qmckl_exit_code) :: info integer*8 :: i, a, k, nw, ii, num double precision :: x, x1, kf, x_old, x1_old double precision :: denom, invdenom, invdenom2, f double precision :: denom_old, invdenom_old, invdenom2_old, f_old double precision :: dx(3), dx_old(3) num = num_in + 1 info = QMCKL_SUCCESS if (context == QMCKL_NULL_CONTEXT) then info = QMCKL_INVALID_CONTEXT return endif if (walk_num <= 0) then info = QMCKL_INVALID_ARG_3 return endif if (elec_num <= 0) then info = QMCKL_INVALID_ARG_4 return endif if (nucl_num <= 0) then info = QMCKL_INVALID_ARG_5 return endif if (aord_num < 0) then info = QMCKL_INVALID_ARG_8 return endif do nw =1, walk_num forces_jastrow_single_en(:,:,nw) = 0.0d0 do a = 1, nucl_num x_old = en_distance_rescaled(num,a,nw) x = en_rescaled_single(a,nw) denom = 1.0d0 + a_vector(2, type_nucl_vector(a)+1) * x invdenom = 1.0d0 / denom invdenom2 = invdenom*invdenom denom_old = 1.0d0 + a_vector(2, type_nucl_vector(a)+1) * x_old invdenom_old = 1.0d0 / denom_old invdenom2_old = invdenom_old*invdenom_old dx(1) = -en_rescaled_single_gl(1,a,nw) dx(2) = -en_rescaled_single_gl(2,a,nw) dx(3) = -en_rescaled_single_gl(3,a,nw) dx_old(1) = -en_distance_rescaled_gl(1,num,a,nw) dx_old(2) = -en_distance_rescaled_gl(2,num,a,nw) dx_old(3) = -en_distance_rescaled_gl(3,num,a,nw) f = a_vector(1, type_nucl_vector(a)+1) * invdenom2 f_old = a_vector(1, type_nucl_vector(a)+1) * invdenom2_old forces_jastrow_single_en(1,a,nw) = forces_jastrow_single_en(1,a,nw) + f * dx(1) - f_old * dx_old(1) forces_jastrow_single_en(2,a,nw) = forces_jastrow_single_en(2,a,nw) + f * dx(2) - f_old * dx_old(2) forces_jastrow_single_en(3,a,nw) = forces_jastrow_single_en(3,a,nw) + f * dx(3) - f_old * dx_old(3) kf = 2.d0 x1 = x x = 1.d0 x1_old = x_old x_old = 1.d0 do k=2, aord_num f = a_vector(k+1,type_nucl_vector(a)+1) * kf * x f_old = a_vector(k+1,type_nucl_vector(a)+1) * kf * x_old forces_jastrow_single_en(1,a,nw) = forces_jastrow_single_en(1,a,nw) + f * x1 * dx(1) - f_old * x1_old * dx_old(1) forces_jastrow_single_en(2,a,nw) = forces_jastrow_single_en(2,a,nw) + f * x1 * dx(2) - f_old * x1_old * dx_old(2) forces_jastrow_single_en(3,a,nw) = forces_jastrow_single_en(3,a,nw) + f * x1 * dx(3) - f_old * x1_old * dx_old(3) x = x*x1 x_old = x_old*x1_old kf = kf + 1.d0 end do end do end do end function qmckl_compute_forces_jastrow_single_en_doc
4.2. Electron-electron-nucleus Jastrow
4.2.1. Force of P matrix
Calculates the force of the P matrix. This is a required component to calculate the force on the 3-body Jastrow. \[ \partial_{\alpha,m} P_{i,\alpha,k,l} = \sum_j \widetilde{r}_{i,j,k} \partial_{\alpha,m}\widetilde{R}_{j,\alpha,l} = -\sum_j \widetilde{r}_{i,j,k} \partial_{j,m}\widetilde{R}_{j,\alpha,l} \]
4.2.1.1. Get
qmckl_exit_code qmckl_get_forces_tmp_c(qmckl_context context, double* const forces_tmp_c, const int64_t size_max);
4.2.1.2. Compute
Variable | Type | In/Out | Description |
---|---|---|---|
context |
qmckl_context |
in | Global state |
walk_num |
int64_t |
in | Number of walkers |
elec_num |
int64_t |
in | Number of electrons |
nucl_num |
int64_t |
in | Number of nuclei |
cord_num |
int64_t |
in | order of polynomials |
een_rescaled_e |
double[walk_num][0:cord_num][elec_num][elec_num] |
in | Electron-nucleus rescaled |
een_rescaled_n_gl |
double[walk_num][0:cord_num][nucl_num][4][elec_num] |
in | Electron-nucleus rescaled derivatives |
forces_tmp_c |
double[walk_num][0:cord_num-1][0:cord_num][nucl_num][4][elec_num] |
out | Force on the P matrix |
integer(qmckl_exit_code) function qmckl_compute_forces_tmp_c( & context, walk_num, elec_num, nucl_num, cord_num,& een_rescaled_e, een_rescaled_n_gl, forces_tmp_c) & result(info) bind(C) use, intrinsic :: iso_c_binding use qmckl implicit none integer(qmckl_context), intent(in) :: context integer (c_int64_t) , intent(in), value :: walk_num, elec_num, cord_num, nucl_num real (c_double ) , intent(in) :: een_rescaled_e(elec_num, elec_num, 0:cord_num, walk_num) real (c_double ) , intent(in) :: een_rescaled_n_gl(elec_num, 4, nucl_num, 0:cord_num, walk_num) real (c_double ) , intent(out) :: forces_tmp_c(elec_num, 4, nucl_num,0:cord_num, 0:cord_num-1, walk_num) integer*8 :: nw, i integer*8 :: l, m, k, a,j info = QMCKL_SUCCESS if (context == QMCKL_NULL_CONTEXT) info = QMCKL_INVALID_CONTEXT if (walk_num <= 0) info = QMCKL_INVALID_ARG_2 if (elec_num <= 0) info = QMCKL_INVALID_ARG_3 if (nucl_num <= 0) info = QMCKL_INVALID_ARG_4 if (cord_num < 0) info = QMCKL_INVALID_ARG_5 if (info /= QMCKL_SUCCESS) return do nw=1, walk_num do i=0, cord_num-1 info = qmckl_dgemm(context,'N','N',elec_num*1_8,& nucl_num*(cord_num+1)*4_8, elec_num*1_8, -1.0d0, & een_rescaled_e(1,1,i,nw),1_8*elec_num, & een_rescaled_n_gl(1,1,1,0,nw),elec_num*1_8, & 0.0d0, & forces_tmp_c(1,1,1,0,i,nw),1_8*elec_num) end do end do end function qmckl_compute_forces_tmp_c
4.2.2. Force of derivative of the \(P\) matrix
Calculates the force of the derivative of the \(P\) matrix. \[ \partial_{\alpha,m} \partial_{i,n} P_{i,\alpha,k,l} = \sum_j \partial_{i,n} \widetilde{r}_{i,j,k} \partial_{\alpha,m}\widetilde{R}_{j,\alpha,l} = -\sum_j \partial_{i,n}\widetilde{r}_{i,j,k} \partial_{j,m}\widetilde{R}_{j,\alpha,l} \]
4.2.2.1. Get
qmckl_exit_code qmckl_get_forces_dtmp_c(qmckl_context context, double* const forces_dtmp_c, const int64_t size_max);
4.2.2.2. Compute
Variable | Type | In/Out | Description |
---|---|---|---|
context |
qmckl_context |
in | Global state |
walk_num |
int64_t |
in | Number of walkers |
elec_num |
int64_t |
in | Number of electrons |
nucl_num |
int64_t |
in | Number of nuclei |
cord_num |
int64_t |
in | order of polynomials |
een_rescaled_e_gl |
double[walk_num][0:cord_num][elec_num][4][elec_num] |
in | Electron-nucleus rescaled |
een_rescaled_n_gl |
double[walk_num][0:cord_num][nucl_num][4][elec_num] |
in | Electron-nucleus rescaled derivatives |
forces_dtmp_c |
double[walk_num][0:cord_num-1][0:cord_num][4][nucl_num][4][elec_num] |
out | Force of derivative of the P matrix |
integer(qmckl_exit_code) function qmckl_compute_forces_dtmp_c_doc( & context, walk_num, elec_num, nucl_num, cord_num,& een_rescaled_e_gl, een_rescaled_n_gl, forces_dtmp_c) & result(info) bind(C) use, intrinsic :: iso_c_binding use qmckl implicit none integer(qmckl_context), intent(in) :: context integer (c_int64_t) , intent(in), value :: walk_num, elec_num, cord_num, nucl_num real (c_double ) , intent(in) :: een_rescaled_e_gl(elec_num, 4, elec_num, 0:cord_num, walk_num) real (c_double ) , intent(in) :: een_rescaled_n_gl(elec_num, 4, nucl_num, 0:cord_num, walk_num) real (c_double ) , intent(out) :: forces_dtmp_c(elec_num, 4, nucl_num,4,0:cord_num, 0:cord_num-1, walk_num) integer*8 :: nw, i, k integer*8 :: l, m, a,j, kk info = QMCKL_SUCCESS if (context == QMCKL_NULL_CONTEXT) info = QMCKL_INVALID_CONTEXT if (walk_num <= 0) info = QMCKL_INVALID_ARG_2 if (elec_num <= 0) info = QMCKL_INVALID_ARG_3 if (nucl_num <= 0) info = QMCKL_INVALID_ARG_4 if (cord_num < 0) info = QMCKL_INVALID_ARG_5 if (info /= QMCKL_SUCCESS) return do nw = 1, walk_num do l = 0, cord_num-1 do m = 1, cord_num do k = 1, 4 do a = 1, nucl_num do kk = 1, 4 do i = 1, elec_num forces_dtmp_c(i,kk,a,k,m,l,nw) = 0.d0 do j = 1, elec_num forces_dtmp_c(i,kk,a,k,m,l,nw) = forces_dtmp_c(i,kk,a,k,m,l,nw) - & een_rescaled_e_gl(i,kk,j,l,nw) * een_rescaled_n_gl(j,k,a,m,nw) end do end do end do end do end do end do end do end do end function qmckl_compute_forces_dtmp_c_doc
integer(qmckl_exit_code) function qmckl_compute_forces_dtmp_c_hpc( & context, walk_num, elec_num, nucl_num, cord_num,& een_rescaled_e_gl, een_rescaled_n_gl, forces_dtmp_c) & result(info) bind(C) use, intrinsic :: iso_c_binding use qmckl implicit none integer(qmckl_context), intent(in) :: context integer (c_int64_t) , intent(in), value :: walk_num, elec_num, cord_num, nucl_num real (c_double ) , intent(in) :: een_rescaled_e_gl(elec_num, 4, elec_num, 0:cord_num, walk_num) real (c_double ) , intent(in) :: een_rescaled_n_gl(elec_num, 4, nucl_num, 0:cord_num, walk_num) real (c_double ) , intent(out) :: forces_dtmp_c(elec_num, 4, nucl_num,4,0:cord_num, 0:cord_num-1, walk_num) integer*8 :: nw, i, k integer*8 :: l, m, a,j, kk double precision, allocatable :: tmp(:,:,:,:) info = QMCKL_SUCCESS if (context == QMCKL_NULL_CONTEXT) info = QMCKL_INVALID_CONTEXT if (walk_num <= 0) info = QMCKL_INVALID_ARG_2 if (elec_num <= 0) info = QMCKL_INVALID_ARG_3 if (nucl_num <= 0) info = QMCKL_INVALID_ARG_4 if (cord_num < 0) info = QMCKL_INVALID_ARG_5 if (info /= QMCKL_SUCCESS) return allocate(tmp(elec_num, 4, 4, nucl_num)) do nw = 1, walk_num do l = 0, cord_num-1 do m = 1, cord_num info = qmckl_dgemm(context,'N','N', elec_num*4, 4*nucl_num, elec_num, -1.d0, & een_rescaled_e_gl(1,1,1,l,nw), elec_num*4_8, & een_rescaled_n_gl(1,1,1,m,nw), elec_num, 0.d0, & tmp, elec_num*4_8) do k = 1, 4 do a = 1, nucl_num forces_dtmp_c(:,:,a,k,m,l,nw) = tmp(:,:,k,a) end do end do end do end do end do deallocate(tmp) end function qmckl_compute_forces_dtmp_c_hpc
4.2.3. Force of electron-electron-nucleus Jastrow value
Calculates the force of the eleectron-electorn-nucleus Jastrow value. \[ \partial_{\alpha,m}J_{een} = \sum_{p=2}^{N_\text{nord}} \sum_{k=0}^{p-1} \sum_{l=0}^{p-k-2\delta_{k,0}} c_{l,k,p,\alpha} \sum_{i=1}^{N_\text{elec}} \left(\widetilde{R}_{i\alpha}^{(p-k+l)/2} \partial_{\alpha,m}P_{i\alpha,k,(p-k-l)/2} + \partial_{\alpha,m}\widetilde{R}_{i\alpha}^{(p-k+l)/2} P_{i\alpha,k,(p-k-l)/2}\right) \]
4.2.3.1. Get
qmckl_exit_code qmckl_get_forces_jastrow_een(qmckl_context context, double* const forces_jastrow_een, const int64_t size_max);
interface integer(qmckl_exit_code) function qmckl_get_forces_jastrow_een (context, & forces_jastrow_een, size_max) bind(C) use, intrinsic :: iso_c_binding import implicit none integer (qmckl_context) , intent(in), value :: context integer(c_int64_t), intent(in), value :: size_max real(c_double), intent(out) :: forces_jastrow_een(size_max) end function qmckl_get_forces_jastrow_een end interface
4.2.3.2. Compute
Variable | Type | In/Out | Description |
---|---|---|---|
context |
qmckl_context |
in | Global state |
walk_num |
int64_t |
in | Number of walkers |
elec_num |
int64_t |
in | Number of electrons |
nucl_num |
int64_t |
in | Number of nuclei |
cord_num |
int64_t |
in | order of polynomials |
dim_c_vector |
int64_t |
in | dimension of full coefficient vector |
c_vector_full |
double[dim_c_vector][nucl_num] |
in | full coefficient vector |
lkpm_combined_index |
int64_t[4][dim_c_vector] |
in | combined indices |
een_rescaled_n |
double[walk_num][0:cord_num][nucl_num][elec_num] |
in | Electron-nucleus rescaled |
een_rescaled_n_gl |
double[walk_num][0:cord_num][nucl_num][4][elec_num] |
in | Electron-nucleus rescaled derivatives |
tmp_c |
double[walk_num][0:cord_num-1][0:cord_num][nucl_num][elec_num] |
in | P matrix |
forces_tmp_c |
double[walk_num][0:cord_num-1][0:cord_num][nucl_num][4][elec_num] |
in | Force of P matrix |
forces_jastrow_een |
double[walk_num][nucl_num][3] |
out | Force of electron-electron-nucleus Jastrow value |
integer(qmckl_exit_code) function qmckl_compute_forces_jastrow_een( & context, walk_num, elec_num, nucl_num, cord_num,& dim_c_vector, c_vector_full, lkpm_combined_index, & een_rescaled_n, een_rescaled_n_gl, tmp_c, forces_tmp_c,forces_jastrow_een) & result(info) bind(C) use, intrinsic :: iso_c_binding use qmckl implicit none integer(qmckl_context), intent(in) :: context integer (c_int64_t) , intent(in), value :: walk_num, elec_num, cord_num, nucl_num, dim_c_vector integer (c_int64_t) , intent(in) :: lkpm_combined_index(dim_c_vector,4) real (c_double ) , intent(in) :: c_vector_full(nucl_num, dim_c_vector) real (c_double ) , intent(in) :: een_rescaled_n(elec_num, nucl_num, 0:cord_num, walk_num) real (c_double ) , intent(in) :: een_rescaled_n_gl(elec_num, 4, nucl_num, 0:cord_num, walk_num) real (c_double ) , intent(in) :: tmp_c(elec_num, nucl_num,0:cord_num, 0:cord_num-1, walk_num) real (c_double ) , intent(in) :: forces_tmp_c(elec_num,4, nucl_num,0:cord_num, 0:cord_num-1, walk_num) real (c_double ) , intent(out) :: forces_jastrow_een(3, nucl_num, walk_num) integer*8 :: i, a, j, l, k, p, m, n, nw, ii double precision :: accu, accu2, cn info = QMCKL_SUCCESS if (context == QMCKL_NULL_CONTEXT) info = QMCKL_INVALID_CONTEXT if (walk_num <= 0) info = QMCKL_INVALID_ARG_2 if (elec_num <= 0) info = QMCKL_INVALID_ARG_3 if (nucl_num <= 0) info = QMCKL_INVALID_ARG_4 if (cord_num < 0) info = QMCKL_INVALID_ARG_5 if (info /= QMCKL_SUCCESS) return forces_jastrow_een = 0.d0 if (cord_num == 0) return do nw =1, walk_num do n = 1, dim_c_vector l = lkpm_combined_index(n, 1) k = lkpm_combined_index(n, 2) p = lkpm_combined_index(n, 3) m = lkpm_combined_index(n, 4) do a = 1, nucl_num cn = c_vector_full(a, n) if(cn == 0.d0) cycle do j = 1, elec_num do ii = 1, 3 accu = een_rescaled_n(j,a,m,nw) * forces_tmp_c(j,ii,a,m+l,k,nw) & - een_rescaled_n_gl(j,ii,a,m,nw) * tmp_c(j,a,m+l,k,nw) forces_jastrow_een(ii, a, nw) = forces_jastrow_een(ii, a, nw) + accu * cn end do end do end do end do end do end function qmckl_compute_forces_jastrow_een
4.2.4. Force of derivatives of electron-nucleus rescaled distance
Calculates the force of the derivatives of the electron-nucleus rescaled distance.
\begin{eqnarray} \partial_{\alpha,m}\partial_{i,n} \widetilde{R}_{i\alpha} =& \partial_{\alpha,m} \left( -\frac{r_{i,n} - R_{\alpha,n}}{R_{i\alpha}} \kappa l e^{-\kappa l R_{i\alpha}}\right)\\ =& - \frac{(r_{i,n} - R_{\alpha,n})(r_{i,m} - R_{\alpha,m})}{R_{i\alpha}^3}l\kappa e^{-\kappa l R_{i\alpha}} - \frac{(r_{i,n} - R_{\alpha,n})(r_{i,m} - R_{\alpha,m})}{R_{i\alpha}^2} \kappa^2 l^2 e^{-\kappa l R_{i\alpha}} + \delta_{n,m} \frac{1}{r}\kappa l e^{-\kappa l R_{i\alpha}}\\ \partial_{\alpha,m}\nabla^2 \widetilde{R}_{i\alpha} =& \partial_{\alpha,m} \left( \kappa l \left( \kappa l - \frac{2}{R_{i\alpha}}\right) e^{-\kappa l R_{i\alpha}}\right)\\ =&-2\kappa l \frac{r_{i,m} - R_{\alpha,m}}{R_{i\alpha}^3}e^{-\kappa l R_{i\alpha}} + \kappa^2 l^2 \left(\kappa l - \frac{2}{R_{i\alpha}} \right) \frac{r_{i,m}-R_{\alpha,m}}{R_{i\alpha}} e^{-\kappa l R_{i\alpha}} \end{eqnarray}4.2.4.1. Get
qmckl_exit_code qmckl_get_forces_een_rescaled_n_gl(qmckl_context context, double* const forces_een_n, const int64_t size_max);
4.2.4.2. Compute
Variable | Type | In/Out | Description |
---|---|---|---|
context |
qmckl_context |
in | Global state |
walk_num |
int64_t |
in | Number of walkers |
elec_num |
int64_t |
in | Number of electrons |
nucl_num |
int64_t |
in | Number of atoms |
type_nucl_num |
int64_t |
in | Number of atom types |
type_nucl_vector |
int64_t[nucl_num] |
in | Types of atoms |
cord_num |
int64_t |
in | Order of polynomials |
rescale_factor_en |
double[nucl_num] |
in | Factor to rescale ee distances |
en_distance |
double[walk_num][elec_num][nucl_num] |
in | Electron-nucleus distances |
een_rescaled_n |
double[walk_num][0:cord_num][nucl_num][elec_num] |
in | Electron-nucleus rescaled distances |
een_rescaled_n_gl |
double[walk_num][0:cord_num][nucl_num][4][elec_num] |
in | Electron-nucleus rescaled distances derivativies |
forces_een_n |
double[walk_num][0:cord_num][3][nucl_num][4][elec_num] |
out | Force of electron-nucleus rescaled distances derivatives |
integer(qmckl_exit_code) function qmckl_compute_forces_een_rescaled_n_gl( & context, walk_num, elec_num, nucl_num, type_nucl_num, type_nucl_vector, & cord_num, rescale_factor_en, & en_distance, een_rescaled_n, een_rescaled_n_gl,forces_een_n) & result(info) bind(C) use, intrinsic :: iso_c_binding use qmckl implicit none integer(qmckl_context), intent(in) :: context integer (c_int64_t) , intent(in),value :: walk_num, elec_num, nucl_num, type_nucl_num, cord_num integer (c_int64_t) , intent(in) :: type_nucl_vector(nucl_num) real (c_double ) , intent(in) :: rescale_factor_en(type_nucl_num) real (c_double ) , intent(in) :: en_distance(nucl_num,elec_num,walk_num) real (c_double ) , intent(in) :: een_rescaled_n(elec_num,nucl_num,0:cord_num,walk_num) real (c_double ) , intent(in) :: een_rescaled_n_gl(elec_num,4,nucl_num,0:cord_num,walk_num) real (c_double ) , intent(out) :: forces_een_n(elec_num,4,nucl_num,3,0:cord_num,walk_num) double precision :: x, ria_inv, kappa_l, temp integer*8 :: i, a, k, l, nw, m, n info = QMCKL_SUCCESS if (context == QMCKL_NULL_CONTEXT) then info = QMCKL_INVALID_CONTEXT return endif if (walk_num <= 0) then info = QMCKL_INVALID_ARG_2 return endif if (elec_num <= 0) then info = QMCKL_INVALID_ARG_3 return endif if (nucl_num <= 0) then info = QMCKL_INVALID_ARG_4 return endif if (cord_num < 0) then info = QMCKL_INVALID_ARG_5 return endif !forces_een_n = 0.0d0 !do nw = 1, walk_num ! do l = 0, cord_num ! do a = 1, nucl_num ! kappa_l = dble(l)*rescale_factor_en(type_nucl_vector(a)+1) ! do i = 1, elec_num ! ria_inv = 1.0d0 / en_distance(a,i,nw) ! do n = 1, 3 ! do m = 1, 3 ! if (m == n) then ! forces_een_n(i,m,a,n,l,nw) = forces_een_n(i,m,a,n,l,nw) + & ! kappa_l*een_rescaled_n(i,a,l,nw) * ria_inv ! end if ! temp = een_rescaled_n_gl(i,m,a,l,nw) * een_rescaled_n_gl(i,n,a,l,nw) / een_rescaled_n(i,a,l,nw) ! forces_een_n(i,m,a,n,l,nw) = forces_een_n(i,m,a,n,l,nw) - & ! temp * ria_inv / kappa_l - temp ! end do ! forces_een_n(i,4,a,n,l,nw) = forces_een_n(i,4,a,n,l,nw) + & ! (2.0d0 * ria_inv * ria_inv & ! - een_rescaled_n_gl(i,4,a,l,nw)/een_rescaled_n(i,a,l,nw)) * & ! een_rescaled_n_gl(i,n,a,l,nw) ! end do ! end do ! end do ! end do !end do forces_een_n = 0.0d0 do nw = 1, walk_num do i = 1, elec_num do a = 1, nucl_num do l = 0, cord_num kappa_l = dble(l)*rescale_factor_en(type_nucl_vector(a)+1) do m = 1, 4 do n = 1, 3 if (l == 0) then forces_een_n(i,m,a,n,l,nw) = 0.0d0 else if (m == n) then forces_een_n(i,m,a,n,l,nw) = forces_een_n(i,m,a,n,l,nw) + & kappa_l*een_rescaled_n(i,a,l,nw)/en_distance(a,i,nw) end if if (m < 4) then forces_een_n(i,m,a,n,l,nw) = forces_een_n(i,m,a,n,l,nw) - & een_rescaled_n_gl(i,m,a,l,nw) * een_rescaled_n_gl(i,n,a,l,nw) / & (kappa_l*een_rescaled_n(i,a,l,nw)*en_distance(a,i,nw)) - & een_rescaled_n_gl(i,m,a,l,nw) * & een_rescaled_n_gl(i,n,a,l,nw)/een_rescaled_n(i,a,l,nw) else forces_een_n(i,m,a,n,l,nw) = forces_een_n(i,m,a,n,l,nw) + & 2.0d0 * een_rescaled_n_gl(i,n,a,l,nw) / & (en_distance(a,i,nw)*en_distance(a,i,nw)) - & een_rescaled_n_gl(i,m,a,l,nw) * & een_rescaled_n_gl(i,n,a,l,nw)/een_rescaled_n(i,a,l,nw) end if end if end do end do end do end do end do end do end function qmckl_compute_forces_een_rescaled_n_gl
4.2.5. Force of electron-electron-nucleus Jastrow gradient
Calculates the force of the electron-electron-nucleus Jastrow gradient (and not the Laplacian).
\begin{eqnarray} \partial_{\alpha,m} \partial_{i,n}J_{een} =& \partial_{\alpha,m} \sum_{p=2}^{N_\text{nord}} \sum_{k=0}^{p-1} \sum_{l=0}^{p-k-2\delta_{k,0}} c_{l,k,p,\alpha} \left(\partial_{i,n}\widetilde{R}_{i\alpha}^{(p-k+l)/2} P_{i\alpha,k,(p-k-l)/2} + \partial_{i,n}\widetilde{R}_{i\alpha}^{(p-k-l)/2} P_{i\alpha,k,(p-k+l)/2} + \widetilde{R}_{i\alpha}^{(p-k+l)/2} \partial_{i,n} P_{i\alpha,k,(p-k-l)/2} + \widetilde{R}_{i\alpha}^{(p-k-l)/2} \partial_{i,n} P_{i\alpha,k,(p-k+l)/2} \right)\\ =& \sum_{p=2}^{N_\text{nord}} \sum_{k=0}^{p-1} \sum_{l=0}^{p-k-2\delta_{k,0}} c_{l,k,p,\alpha} \left(\partial_{\alpha,m}\partial_{i,n}\widetilde{R}_{i\alpha}^{(p-k+l)/2} P_{i\alpha,k,(p-k-l)/2} + \partial_{\alpha,m}\partial_{i,n}\widetilde{R}_{i\alpha}^{(p-k-l)/2} P_{i\alpha,k,(p-k+l)/2} + \partial_{\alpha,m}\widetilde{R}_{i\alpha}^{(p-k+l)/2} \partial_{i,n} P_{i\alpha,k,(p-k-l)/2} + \partial_{\alpha,m}\widetilde{R}_{i\alpha}^{(p-k-l)/2} \partial_{i,n} P_{i\alpha,k,(p-k+l)/2} \right.\\ &+ \left.\partial_{i,n}\widetilde{R}_{i\alpha}^{(p-k+l)/2} \partial_{\alpha,m}P_{i\alpha,k,(p-k-l)/2} + \partial_{i,n}\widetilde{R}_{i\alpha}^{(p-k-l)/2} \partial_{\alpha,m}P_{i\alpha,k,(p-k+l)/2} + \widetilde{R}_{i\alpha}^{(p-k+l)/2} \partial_{\alpha,m}\partial_{i,n} P_{i\alpha,k,(p-k-l)/2} + \widetilde{R}_{i\alpha}^{(p-k-l)/2} \partial_{\alpha,m}\partial_{i,n} P_{i\alpha,k,(p-k+l)/2}\right)\\ =& \sum_{p=2}^{N_\text{nord}} \sum_{k=0}^{p-1} \sum_{l=0}^{p-k-2\delta_{k,0}} c_{l,k,p,\alpha} \left(\partial_{\alpha,m}\partial_{i,n}\widetilde{R}_{i\alpha}^{(p-k+l)/2} P_{i\alpha,k,(p-k-l)/2} + \partial_{\alpha,m}\partial_{i,n}\widetilde{R}_{i\alpha}^{(p-k-l)/2} P_{i\alpha,k,(p-k+l)/2} - \partial_{i,m}\widetilde{R}_{i\alpha}^{(p-k+l)/2} \partial_{i,n} P_{i\alpha,k,(p-k-l)/2} - \partial_{i,m}\widetilde{R}_{i\alpha}^{(p-k-l)/2} \partial_{i,n} P_{i\alpha,k,(p-k+l)/2} \right.\\ &+ \left.\partial_{i,n}\widetilde{R}_{i\alpha}^{(p-k+l)/2} \partial_{\alpha,m}P_{i\alpha,k,(p-k-l)/2} + \partial_{i,n}\widetilde{R}_{i\alpha}^{(p-k-l)/2} \partial_{\alpha,m}P_{i\alpha,k,(p-k+l)/2} + \widetilde{R}_{i\alpha}^{(p-k+l)/2} \partial_{\alpha,m}\partial_{i,n} P_{i\alpha,k,(p-k-l)/2} + \widetilde{R}_{i\alpha}^{(p-k-l)/2} \partial_{\alpha,m}\partial_{i,n} P_{i\alpha,k,(p-k+l)/2}\right)\\ \end{eqnarray}4.2.5.1. Get
qmckl_exit_code qmckl_get_forces_jastrow_een_g(qmckl_context context, double* const forces_jastrow_een_g, const int64_t size_max);
interface integer(qmckl_exit_code) function qmckl_get_forces_jastrow_een_g (context, & forces_jastrow_een_g, size_max) bind(C) use, intrinsic :: iso_c_binding import implicit none integer (qmckl_context) , intent(in), value :: context integer(c_int64_t), intent(in), value :: size_max real(c_double), intent(out) :: forces_jastrow_een_g(size_max) end function qmckl_get_forces_jastrow_een_g end interface
4.2.5.2. Compute
Variable | Type | In/Out | Description |
---|---|---|---|
context |
qmckl_context |
in | Global state |
walk_num |
int64_t |
in | Number of walkers |
elec_num |
int64_t |
in | Number of electrons |
nucl_num |
int64_t |
in | Number of nuclei |
cord_num |
int64_t |
in | order of polynomials |
dim_c_vector |
int64_t |
in | dimension of full coefficient vector |
c_vector_full |
double[dim_c_vector][nucl_num] |
in | full coefficient vector |
lkpm_combined_index |
int64_t[4][dim_c_vector] |
in | combined indices |
en_distance |
double[elec_num][nucl_num] |
in | Electron-nucleus distance |
tmp_c |
double[walk_num][0:cord_num-1][0:cord_num][nucl_num][elec_num] |
in | P matrix |
dtmp_c |
double[walk_num][0:cord_num-1][0:cord_num][nucl_num][4][elec_num] |
in | Derivative of P matrix |
forces_tmp_c |
double[walk_num][0:cord_num-1][0:cord_num][nucl_num][4][elec_num] |
in | Force of P matrix |
forces_dtmp_c |
double[walk_num][0:cord_num-1][0:cord_num][4][nucl_num][4][elec_num] |
in | Force of derivative of P matrix |
forces_een_n |
double[walk_num][0:cord_num][3][nucl_num][4][elec_num] |
in | Force of derivatives of electron-nucleus rescaled factor |
een_rescaled_n |
double[walk_num][0:cord_num][nucl_num][elec_num] |
in | Electron-nucleus rescaled factor |
een_rescaled_n_gl |
double[walk_num][0:cord_num][nucl_num][4][elec_num] |
in | Derivative of electron-nucleus rescaled factor |
forces_jastrow_een_g |
double[walk_num][3][nucl_num][3][elec_num] |
out | Force of the electron-electron-nucleus Jastrow gradient |
integer(qmckl_exit_code) function qmckl_compute_forces_jastrow_een_g( & context, walk_num, elec_num, nucl_num, & cord_num, dim_c_vector, c_vector_full, lkpm_combined_index, & en_distance, tmp_c, dtmp_c, forces_tmp_c, forces_dtmp_c, forces_een_n, een_rescaled_n, & een_rescaled_n_gl, forces_jastrow_een_g)& result(info) bind(C) use, intrinsic :: iso_c_binding use qmckl implicit none integer(qmckl_context), intent(in) :: context integer (c_int64_t) , intent(in),value :: walk_num, elec_num, cord_num, nucl_num, dim_c_vector integer (c_int64_t) , intent(in) :: lkpm_combined_index(dim_c_vector,4) real (c_double ) , intent(in) :: c_vector_full(nucl_num, dim_c_vector) real (c_double ) , intent(in) :: en_distance(nucl_num, elec_num) real (c_double ) , intent(in) :: tmp_c(elec_num, nucl_num,0:cord_num, 0:cord_num-1, walk_num) real (c_double ) , intent(in) :: dtmp_c(elec_num, 4, nucl_num,0:cord_num, 0:cord_num-1, walk_num) real (c_double ) , intent(in) :: forces_tmp_c(elec_num, 4,nucl_num,0:cord_num, 0:cord_num-1, walk_num) real (c_double ) , intent(in) :: forces_dtmp_c(elec_num, 4, nucl_num,4,0:cord_num, 0:cord_num-1, walk_num) real (c_double ) , intent(in) :: forces_een_n(elec_num, 4, nucl_num, 3, 0:cord_num, walk_num) real (c_double ) , intent(in) :: een_rescaled_n(elec_num, nucl_num, 0:cord_num, walk_num) real (c_double ) , intent(in) :: een_rescaled_n_gl(elec_num, 4, nucl_num, 0:cord_num, walk_num) real (c_double ) , intent(out) :: forces_jastrow_een_g(elec_num,3,nucl_num,3,walk_num) integer*8 :: i, a, j, l, k, m, n, nw, ii, jj double precision :: accu, accu2, cn info = QMCKL_SUCCESS if (context == QMCKL_NULL_CONTEXT) info = QMCKL_INVALID_CONTEXT if (walk_num <= 0) info = QMCKL_INVALID_ARG_2 if (elec_num <= 0) info = QMCKL_INVALID_ARG_3 if (nucl_num <= 0) info = QMCKL_INVALID_ARG_4 if (cord_num < 0) info = QMCKL_INVALID_ARG_5 if (info /= QMCKL_SUCCESS) return if (cord_num == 0) return forces_jastrow_een_g = 0.0d0 do nw =1, walk_num do n = 1, dim_c_vector l = lkpm_combined_index(n, 1) k = lkpm_combined_index(n, 2) m = lkpm_combined_index(n, 4) do a = 1, nucl_num cn = c_vector_full(a, n) if(cn == 0.d0) cycle do ii = 1, 3 do i = 1, elec_num do jj = 1, 3 forces_jastrow_een_g(i, ii, a, jj, nw) = forces_jastrow_een_g(i, ii, a, jj, nw) + (& tmp_c(i,a, m, k,nw) * forces_een_n(i,ii,a,jj ,m+l,nw) & + forces_tmp_c(i,jj,a, m, k,nw) * een_rescaled_n_gl(i,ii,a,m+l,nw) & + tmp_c(i,a, m+l,k,nw) * forces_een_n(i,ii,a,jj, m, nw) & + forces_tmp_c(i,jj,a, m+l,k,nw) * een_rescaled_n_gl(i,ii,a,m, nw) & - dtmp_c(i,ii,a, m, k,nw) * een_rescaled_n_gl(i,jj,a,m+l,nw) & + forces_dtmp_c(i,ii,a,jj,m, k,nw) * een_rescaled_n(i,a, m+l,nw) & - dtmp_c(i,ii,a, m+l,k,nw) * een_rescaled_n_gl(i,jj,a,m, nw) & + forces_dtmp_c(i,ii,a,jj,m+l,k,nw) * een_rescaled_n(i,a, m, nw) & ) * cn end do end do end do end do end do end do end function qmckl_compute_forces_jastrow_een_g
4.2.6. Force of electron-electron-nucleus Jastrow Laplacian
Calculates the force of the electron-electron-nucleus Jastrow Laplacian.
\begin{eqnarray} \partial_{\alpha,m} \nabla^2 J_{een} &=& \partial_{\alpha,m} \sum_{i=1}^{N_\text{elec}}\sum_{p=2}^{N_\text{nord}} \sum_{k=0}^{p-1} \sum_{l=0}^{p-k-2\delta_{k,0}} c_{l,k,p,\alpha} \left(\nabla^2\widetilde{R}_{i\alpha}^{(p-k+l)/2} P_{i\alpha,k,(p-k-l)/2} + \nabla^2\widetilde{R}_{i\alpha}^{(p-k-l)/2} P_{i\alpha,k,(p-k+l)/2} + \widetilde{R}_{i\alpha}^{(p-k+l)/2} \nabla^2 P_{i\alpha,k,(p-k-l)/2} + \widetilde{R}_{i\alpha}^{(p-k-l)/2} \nabla^2 P_{i\alpha,k,(p-k+l)/2} \right.\\ &&+ \left. 2 \nabla \widetilde{R}_{i\alpha}^{(p-k+l)/2} \cdot \nabla P_{i\alpha,k,(p-k-l)/2} + 2 \nabla \widetilde{R}_{i\alpha}^{(p-k-l)/2} \cdot \nabla P_{i\alpha,k,(p-k+l)/2} \right)\\ &=& \sum_{i=1}^{N_\text{elec}}\sum_{p=2}^{N_\text{nord}} \sum_{k=0}^{p-1} \sum_{l=0}^{p-k-2\delta_{k,0}} c_{l,k,p,\alpha} \left( \partial_{\alpha,m} \nabla^2\widetilde{R}_{i\alpha}^{(p-k+l)/2} P_{i\alpha,k,(p-k-l)/2} + \partial_{\alpha,m} \nabla^2\widetilde{R}_{i\alpha}^{(p-k-l)/2} P_{i\alpha,k,(p-k+l)/2} + \partial_{\alpha,m} \widetilde{R}_{i\alpha}^{(p-k+l)/2} \nabla^2 P_{i\alpha,k,(p-k-l)/2} + \partial_{\alpha,m} \widetilde{R}_{i\alpha}^{(p-k-l)/2} \nabla^2 P_{i\alpha,k,(p-k+l)/2} \right.\\ &&+\nabla^2\widetilde{R}_{i\alpha}^{(p-k+l)/2} \partial_{\alpha,m} P_{i\alpha,k,(p-k-l)/2} + \nabla^2\widetilde{R}_{i\alpha}^{(p-k-l)/2} \partial_{\alpha,m} P_{i\alpha,k,(p-k+l)/2} + \widetilde{R}_{i\alpha}^{(p-k+l)/2} \partial_{\alpha,m} \nabla^2 P_{i\alpha,k,(p-k-l)/2} + \widetilde{R}_{i\alpha}^{(p-k-l)/2} \partial_{\alpha,m} \nabla^2 P_{i\alpha,k,(p-k+l)/2} \\ &&+ \left. 2 \partial_{\alpha,m} \nabla \widetilde{R}_{i\alpha}^{(p-k+l)/2} \cdot \nabla P_{i\alpha,k,(p-k-l)/2} + 2 \partial_{\alpha,m} \nabla \widetilde{R}_{i\alpha}^{(p-k-l)/2} \cdot \nabla P_{i\alpha,k,(p-k+l)/2} + 2 \nabla \widetilde{R}_{i\alpha}^{(p-k+l)/2} \cdot \partial_{\alpha,m} \nabla P_{i\alpha,k,(p-k-l)/2} + 2 \nabla \widetilde{R}_{i\alpha}^{(p-k-l)/2} \cdot \partial_{\alpha,m} \nabla P_{i\alpha,k,(p-k+l)/2} \right)\\ &=& \sum_{i=1}^{N_\text{elec}}\sum_{p=2}^{N_\text{nord}} \sum_{k=0}^{p-1} \sum_{l=0}^{p-k-2\delta_{k,0}} c_{l,k,p,\alpha} \left( \partial_{\alpha,m} \nabla^2\widetilde{R}_{i\alpha}^{(p-k+l)/2} P_{i\alpha,k,(p-k-l)/2} + \partial_{\alpha,m} \nabla^2\widetilde{R}_{i\alpha}^{(p-k-l)/2} P_{i\alpha,k,(p-k+l)/2} - \partial_{i,m} \widetilde{R}_{i\alpha}^{(p-k+l)/2} \nabla^2 P_{i\alpha,k,(p-k-l)/2} - \partial_{i,m} \widetilde{R}_{i\alpha}^{(p-k-l)/2} \nabla^2 P_{i\alpha,k,(p-k+l)/2} \right.\\ &&+\nabla^2\widetilde{R}_{i\alpha}^{(p-k+l)/2} \partial_{\alpha,m} P_{i\alpha,k,(p-k-l)/2} + \nabla^2\widetilde{R}_{i\alpha}^{(p-k-l)/2} \partial_{\alpha,m} P_{i\alpha,k,(p-k+l)/2} + \widetilde{R}_{i\alpha}^{(p-k+l)/2} \partial_{\alpha,m} \nabla^2 P_{i\alpha,k,(p-k-l)/2} + \widetilde{R}_{i\alpha}^{(p-k-l)/2} \partial_{\alpha,m} \nabla^2 P_{i\alpha,k,(p-k+l)/2} \\ &&+ \left. 2 \partial_{\alpha,m} \nabla \widetilde{R}_{i\alpha}^{(p-k+l)/2} \cdot \nabla P_{i\alpha,k,(p-k-l)/2} + 2 \partial_{\alpha,m} \nabla \widetilde{R}_{i\alpha}^{(p-k-l)/2} \cdot \nabla P_{i\alpha,k,(p-k+l)/2} + 2 \nabla \widetilde{R}_{i\alpha}^{(p-k+l)/2} \cdot \partial_{\alpha,m} \nabla P_{i\alpha,k,(p-k-l)/2} + 2 \nabla \widetilde{R}_{i\alpha}^{(p-k-l)/2} \cdot \partial_{\alpha,m} \nabla P_{i\alpha,k,(p-k+l)/2} \right) \end{eqnarray}4.2.6.1. Get
qmckl_exit_code qmckl_get_forces_jastrow_een_l(qmckl_context context, double* const forces_jastrow_een_l, const int64_t size_max);
interface integer(qmckl_exit_code) function qmckl_get_forces_jastrow_een_l (context, & forces_jastrow_een_l, size_max) bind(C) use, intrinsic :: iso_c_binding import implicit none integer (qmckl_context) , intent(in), value :: context integer(c_int64_t), intent(in), value :: size_max real(c_double), intent(out) :: forces_jastrow_een_l(size_max) end function qmckl_get_forces_jastrow_een_l end interface
4.2.6.2. Compute
Variable | Type | In/Out | Description |
---|---|---|---|
context |
qmckl_context |
in | Global state |
walk_num |
int64_t |
in | Number of walkers |
elec_num |
int64_t |
in | Number of electrons |
nucl_num |
int64_t |
in | Number of nuclei |
cord_num |
int64_t |
in | order of polynomials |
dim_c_vector |
int64_t |
in | dimension of full coefficient vector |
c_vector_full |
double[dim_c_vector][nucl_num] |
in | full coefficient vector |
lkpm_combined_index |
int64_t[4][dim_c_vector] |
in | combined indices |
en_distance |
double[elec_num][nucl_num] |
in | Electron-nucleus distance |
tmp_c |
double[walk_num][0:cord_num-1][0:cord_num][nucl_num][elec_num] |
in | P matrix |
dtmp_c |
double[walk_num][0:cord_num-1][0:cord_num][nucl_num][4][elec_num] |
in | Derivative of P matrix |
forces_tmp_c |
double[walk_num][0:cord_num-1][0:cord_num][nucl_num][4][elec_num] |
in | Force of P matrix |
forces_dtmp_c |
double[walk_num][0:cord_num-1][0:cord_num][4][nucl_num][4][elec_num] |
in | Force of derivative of P matrix |
forces_een_n |
double[walk_num][0:cord_num][3][nucl_num][4][elec_num] |
in | Force of derivative of electron-nucleus rescaled factor |
een_rescaled_n |
double[walk_num][0:cord_num][nucl_num][elec_num] |
in | Electron-nucleus rescaled factor |
een_rescaled_n_gl |
double[walk_num][0:cord_num][nucl_num][4][elec_num] |
in | Derivative of electron-nucleus rescaled factor |
forces_jastrow_een_l |
double[walk_num][3][nucl_num] |
out | Force of electron-electron-nucleus Jastrow Laplacian |
integer(qmckl_exit_code) function qmckl_compute_forces_jastrow_een_l( & context, walk_num, elec_num, nucl_num, & cord_num, dim_c_vector, c_vector_full, lkpm_combined_index, & en_distance, tmp_c, dtmp_c, forces_tmp_c, forces_dtmp_c, forces_een_n, een_rescaled_n, & een_rescaled_n_gl, forces_jastrow_een_l)& result(info) bind(C) use, intrinsic :: iso_c_binding use qmckl implicit none integer(qmckl_context), intent(in) :: context integer (c_int64_t) , intent(in),value :: walk_num, elec_num, cord_num, nucl_num, dim_c_vector integer (c_int64_t) , intent(in) :: lkpm_combined_index(dim_c_vector,4) real (c_double ) , intent(in) :: c_vector_full(nucl_num, dim_c_vector) real (c_double ) , intent(in) :: en_distance(nucl_num, elec_num) real (c_double ) , intent(in) :: tmp_c(elec_num, nucl_num,0:cord_num, 0:cord_num-1, walk_num) real (c_double ) , intent(in) :: dtmp_c(elec_num, 4, nucl_num,0:cord_num, 0:cord_num-1, walk_num) real (c_double ) , intent(in) :: forces_tmp_c(elec_num, 4,nucl_num,0:cord_num, 0:cord_num-1, walk_num) real (c_double ) , intent(in) :: forces_dtmp_c(elec_num, 4, nucl_num,4,0:cord_num, 0:cord_num-1, walk_num) real (c_double ) , intent(in) :: forces_een_n(elec_num, 4, nucl_num, 3, 0:cord_num, walk_num) real (c_double ) , intent(in) :: een_rescaled_n(elec_num, nucl_num, 0:cord_num, walk_num) real (c_double ) , intent(in) :: een_rescaled_n_gl(elec_num, 4, nucl_num, 0:cord_num, walk_num) real (c_double ) , intent(out) :: forces_jastrow_een_l(nucl_num,3,walk_num) integer*8 :: i, a, j, l, k, m, n, nw, ii, jj double precision :: accu, accu2, cn info = QMCKL_SUCCESS if (context == QMCKL_NULL_CONTEXT) info = QMCKL_INVALID_CONTEXT if (walk_num <= 0) info = QMCKL_INVALID_ARG_2 if (elec_num <= 0) info = QMCKL_INVALID_ARG_3 if (nucl_num <= 0) info = QMCKL_INVALID_ARG_4 if (cord_num < 0) info = QMCKL_INVALID_ARG_5 if (info /= QMCKL_SUCCESS) return if (cord_num == 0) return forces_jastrow_een_l = 0.0d0 do nw =1, walk_num do n = 1, dim_c_vector l = lkpm_combined_index(n, 1) k = lkpm_combined_index(n, 2) m = lkpm_combined_index(n, 4) do a = 1, nucl_num cn = c_vector_full(a, n) if(cn == 0.d0) cycle do ii = 1, 3 do i = 1, elec_num forces_jastrow_een_l(a, ii, nw) = forces_jastrow_een_l(a, ii, nw) + (& tmp_c(i,a, m, k,nw) * forces_een_n(i,4,a,ii ,m+l,nw) & + forces_tmp_c(i,ii,a, m, k,nw) * een_rescaled_n_gl(i,4,a,m+l,nw) & + tmp_c(i,a, m+l,k,nw) * forces_een_n(i,4,a,ii, m, nw) & + forces_tmp_c(i,ii,a, m+l,k,nw) * een_rescaled_n_gl(i,4,a,m, nw) & - dtmp_c(i,4,a, m, k,nw) * een_rescaled_n_gl(i,ii,a,m+l,nw) & + forces_dtmp_c(i,4,a,ii,m, k,nw) * een_rescaled_n(i,a, m+l,nw) & - dtmp_c(i,4,a, m+l,k,nw) * een_rescaled_n_gl(i,ii,a,m, nw) & + forces_dtmp_c(i,4,a,ii,m+l,k,nw) * een_rescaled_n(i,a, m, nw) & ) * cn end do end do cn = cn + cn do ii = 1, 3 do i = 1, elec_num do jj = 1, 3 forces_jastrow_een_l(a, ii, nw) = forces_jastrow_een_l(a, ii, nw) + (& dtmp_c(i,jj,a,m, k,nw) * forces_een_n(i,jj,a,ii ,m+l,nw) + & dtmp_c(i,jj,a,m+l, k,nw) * forces_een_n(i,jj,a,ii ,m,nw) + & forces_dtmp_c(i,jj,a,ii,m, k,nw) * een_rescaled_n_gl(i,jj,a,m+l,nw) + & forces_dtmp_c(i,jj,a,ii,m+l, k,nw) * een_rescaled_n_gl(i,jj,a,m,nw) & ) * cn end do end do end do end do end do end do end function qmckl_compute_forces_jastrow_een_l
4.2.7. Force of \(\delta P\) matrix
Calculates the force of the \(\delta P\) matrix, required for force in a single-electron move. Here, the \(r^\text{new}\) and \(R^\text{new}\) are the new electron and nucleus positions of the electron that is being moved.
\begin{eqnarray*} \partial_{\alpha,m}\delta P_{i,\alpha,k,l} &=& \partial_{\alpha,m} \left(\sum_{j=1}^{N_\text{elec}} \left( \delta \widetilde{r}_{ij}^k \widetilde{R}_{j\alpha}^l \delta_{i,\text{num}} \right) + \widetilde{r}_{i,\text{num}}^k \delta \widetilde{R}_{\text{num},\alpha}^l + \delta \widetilde{r}_{i,\text{num}}^k \left( \widetilde{R}_{\text{num},\alpha}^l + \delta \widetilde{R}_{\text{num},\alpha}^l \right)\right) \\ &=& \partial_{\alpha,m} \left(\sum_{j=1}^{N_\text{elec}} \left( \delta \widetilde{r}_{ij}^k \widetilde{R}_{j\alpha}^l \delta_{i,\text{num}} \right) + \widetilde{r}_{i,\text{num}}^k \widetilde{R}_{\text{num},\alpha}^l + {\widetilde{r}_{i,\text{num}}^{\text{new}}}^k {\widetilde{R}_{\text{num},\alpha}^{\text{new}}}^l \right) \\ &=& \left(\sum_{j=1}^{N_\text{elec}} \left( \delta \widetilde{r}_{ij}^k \partial_{\alpha,m} \widetilde{R}_{j\alpha}^l \delta_{i,\text{num}} \right) + \widetilde{r}_{i,\text{num}}^k \partial_{\alpha,m}\widetilde{R}_{\text{num},\alpha}^l + {\widetilde{r}_{i,\text{num}}^{\text{new}}}^k \partial_{\alpha,m}{\widetilde{R}_{\text{num},\alpha}^{\text{new}}}^l \right) \\ &=& \left(\sum_{j=1}^{N_\text{elec}} \left( -\delta \widetilde{r}_{ij}^k \partial_{i,m} \widetilde{R}_{j\alpha}^l \delta_{i,\text{num}} \right) - \widetilde{r}_{i,\text{num}}^k \partial_{i,m}\widetilde{R}_{\text{num},\alpha}^l - {\widetilde{r}_{i,\text{num}}^{\text{new}}}^k \partial_{i,m}{\widetilde{R}_{\text{num},\alpha}^{\text{new}}}^l \right) \\ \end{eqnarray*}
The function qmckl_set_single_point
has to be called before this function to set the new electron position.
4.2.7.1. Get
qmckl_exit_code qmckl_get_forces_jastrow_delta_p(qmckl_context context, double* const forces_delta_p, const int64_t size_max);
4.2.7.2. Compute
Variable | Type | In/Out | Description |
---|---|---|---|
context |
qmckl_context |
in | Global state |
num |
int64_t |
in | Index of single electron |
walk_num |
int64_t |
in | Number of walkers |
elec_num |
int64_t |
in | Number of electrons |
nucl_num |
int64_t |
in | Number of nuclei |
cord_num |
int64_t |
in | order of polynomials |
een_rescaled_n |
double[walk_num][0:cord_num][nucl_num][elec_num] |
in | Electron-nucleus rescaled distances |
een_rescaled_e |
double[walk_num][0:cord_num][elec_num][elec_num] |
in | Electron-electron rescaled distances |
een_rescaled_single_n |
double[walk_num][0:cord_num][nucl_num] |
in | Electron-nucleus single rescaled distances |
een_rescaled_single_e |
double[walk_num][0:cord_num][elec_num] |
in | Electron-electron single rescaled distances |
een_rescaled_n_gl |
double[walk_num][0:cord_num][nucl_num][4][elec_num] |
in | Electron-nucleus rescaled distances derivatives |
een_rescaled_single_n_gl |
double[walk_num][0:cord_num][nucl_num][4] |
in | Electron-nucleus single rescaled distances derivatives |
forces_delta_p |
double[walk_num][0:cord_num-1][0:cord_num][nucl_num][3][elec_num] |
out | Force of \(\delta P\) matrix |
integer(qmckl_exit_code) function qmckl_compute_forces_jastrow_delta_p_doc( & context, num_in, walk_num, elec_num, nucl_num, cord_num, & een_rescaled_n, een_rescaled_e, een_rescaled_single_n, een_rescaled_single_e, & een_rescaled_n_gl, een_rescaled_single_n_gl, forces_delta_p) & result(info) bind(C) use, intrinsic :: iso_c_binding use qmckl implicit none integer(qmckl_context), intent(in) :: context integer(c_int64_t) , intent(in), value :: num_in, walk_num, elec_num, cord_num, nucl_num real(c_double) , intent(in) :: een_rescaled_n(elec_num, nucl_num, 0:cord_num, walk_num) real(c_double) , intent(in) :: een_rescaled_e(elec_num, elec_num, 0:cord_num, walk_num) real(c_double) , intent(in) :: een_rescaled_single_n(nucl_num, 0:cord_num, walk_num) real(c_double) , intent(in) :: een_rescaled_single_e(elec_num, 0:cord_num, walk_num) real(c_double) , intent(in) :: een_rescaled_n_gl(elec_num, 4, nucl_num, 0:cord_num, walk_num) real(c_double) , intent(in) :: een_rescaled_single_n_gl(4, nucl_num, 0:cord_num, walk_num) real(c_double) , intent(out) :: forces_delta_p(elec_num,3,nucl_num,0:cord_num, 0:cord_num-1, walk_num) double precision :: tmp1, tmp2 double precision :: delta_e(elec_num) integer*8 :: i, a, j, l, k, p, m, n, nw, num double precision :: tmp, accu integer*8 :: LDA, LDB, LDC num = num_in + 1_8 info = QMCKL_SUCCESS if (context == QMCKL_NULL_CONTEXT) info = QMCKL_INVALID_CONTEXT if (walk_num <= 0) info = QMCKL_INVALID_ARG_3 if (elec_num <= 0) info = QMCKL_INVALID_ARG_4 if (nucl_num <= 0) info = QMCKL_INVALID_ARG_5 if (cord_num < 0) info = QMCKL_INVALID_ARG_6 if (info /= QMCKL_SUCCESS) return if (cord_num == 0) then forces_delta_p = 0.d0 return endif do nw=1, walk_num do m=0, cord_num-1 do j = 1, elec_num delta_e(j) = een_rescaled_e(j,num,m,nw) - een_rescaled_single_e(j,m,nw) end do do l=1, cord_num do a = 1, nucl_num do k = 1, 3 tmp1 = een_rescaled_n_gl(num, k, a, l, nw) tmp2 = een_rescaled_single_n_gl(k,a,l,nw) accu = 0.d0 do j = 1, elec_num forces_delta_p(j,k,a,l,m,nw) = een_rescaled_e(j,num,m,nw) * tmp1 - & een_rescaled_single_e(j,m,nw) * tmp2 accu = accu + delta_e(j) * een_rescaled_n_gl(j,k,a,l,nw) end do forces_delta_p(num,k,a,l,m,nw) = forces_delta_p(num,k,a,l,m,nw) + accu end do end do end do end do end do end function qmckl_compute_forces_jastrow_delta_p_doc
qmckl_exit_code qmckl_compute_forces_jastrow_delta_p_hpc (const qmckl_context context, const int64_t num, const int64_t walk_num, const int64_t elec_num, const int64_t nucl_num, const int64_t cord_num, const double* een_rescaled_n, const double* een_rescaled_e, const double* een_rescaled_single_n, const double* een_rescaled_single_e, const double* een_rescaled_n_gl, const double* een_rescaled_single_n_gl, double* const forces_delta_p ) { if (context == QMCKL_NULL_CONTEXT) return QMCKL_INVALID_CONTEXT; if (num < 0) return QMCKL_INVALID_ARG_2; if (walk_num <= 0) return QMCKL_INVALID_ARG_3; if (elec_num <= 0) return QMCKL_INVALID_ARG_4; if (nucl_num <= 0) return QMCKL_INVALID_ARG_5; if (cord_num < 0) return QMCKL_INVALID_ARG_6; if (een_rescaled_n == NULL) return QMCKL_INVALID_ARG_7; if (een_rescaled_e == NULL) return QMCKL_INVALID_ARG_8; if (een_rescaled_single_n == NULL) return QMCKL_INVALID_ARG_9; if (een_rescaled_single_e == NULL) return QMCKL_INVALID_ARG_10; if (een_rescaled_n_gl == NULL) return QMCKL_INVALID_ARG_11; if (een_rescaled_single_n_gl == NULL) return QMCKL_INVALID_ARG_12; if (cord_num == 0) { const size_t dim = elec_num*3*nucl_num*(cord_num+1)*cord_num; #pragma omp parallel for for (int64_t nw = 0; nw < walk_num; ++nw) { memset(&forces_delta_p[dim*nw],0,dim*sizeof(double)); } return QMCKL_SUCCESS; } #pragma omp parallel for for (int64_t nw = 0; nw < walk_num; ++nw) { for (int64_t m = 0; m <= cord_num-1; ++m) { double delta_e[elec_num]; const double* een_rescaled_e_ = &een_rescaled_e[elec_num*(num+elec_num*(m+(cord_num+1)*nw))]; const double* een_rescaled_single_e_ = &een_rescaled_single_e[elec_num*(m+(cord_num+1)*nw)]; for (int64_t j = 0; j < elec_num; ++j) { delta_e[j] = een_rescaled_e_[j] - een_rescaled_single_e_[j]; } for (int64_t l = 1; l <= cord_num; ++l) { for (int64_t a = 0; a < nucl_num; ++a) { for (int64_t k = 0; k < 3; ++k) { const double* een_rescaled_n_gl_ = &een_rescaled_n_gl[elec_num*(k+4*(a+nucl_num*(l+(cord_num+1)*nw)))]; const double tmp1 = een_rescaled_n_gl_[num]; const double tmp2 = een_rescaled_single_n_gl[k+4*(a+nucl_num*(l+(cord_num+1)*nw))]; double* forces_delta_p_ = &forces_delta_p[elec_num*(k+3*(a+nucl_num*(l+(cord_num+1)*(m+cord_num*nw))))]; double accu = 0.0; #pragma omp simd reduction(+:accu) for (int64_t j = 0; j < elec_num; ++j) { forces_delta_p_[j] = een_rescaled_e_[j] * tmp1 - een_rescaled_single_e_[j] * tmp2; accu += delta_e[j] * een_rescaled_n_gl_[j]; } forces_delta_p_[num] += accu; } } } } } return QMCKL_SUCCESS; }
4.2.8. Force of single electron-electron-nucleus Jastrow value
Computes the single-electron contribution to the electron-electron-nucleus Jastrow value force.
\begin{eqnarray*} \partial_{\alpha,m} \delta J_{een} &=& \partial_{\alpha,m} \sum_{p=2}^{N_\text{nord}} \sum_{k=0}^{p-1} \sum_{l=0}^{p-k-2\delta_{k,0}} c_{l,k,p,\alpha} \left( \sum_{i=1}^{N_\text{elec}} \left( \widetilde{R}_{i,\alpha,(p-k-l)/2} \delta P_{i,\alpha,k,(p-k+l)/2} \right) + \delta \widetilde{R}_{\text{num},\alpha,(p-k-l)/2} \left(P_{\text{num},\alpha,k,(p-k+l)/2} + \delta P_{\text{num},\alpha,k,(p-k+l)/2} \right)\right)\\ &=& \sum_{p=2}^{N_\text{nord}} \sum_{k=0}^{p-1} \sum_{l=0}^{p-k-2\delta_{k,0}} c_{l,k,p,\alpha} \left( \sum_{i=1}^{N_\text{elec}} \left( \partial_{\alpha,m}\widetilde{R}_{i,\alpha,(p-k-l)/2} \delta P_{i,\alpha,k,(p-k+l)/2} + \widetilde{R}_{i,\alpha,(p-k-l)/2} \partial_{\alpha,m}\delta P_{i,\alpha,k,(p-k+l)/2} \right) \right.\\ &&\left. + \partial_{\alpha,m}\delta \widetilde{R}_{\text{num},\alpha,(p-k-l)/2} \left(P_{\text{num},\alpha,k,(p-k+l)/2} + \delta P_{\text{num},\alpha,k,(p-k+l)/2} \right) + \delta \widetilde{R}_{\text{num},\alpha,(p-k-l)/2} \left(\partial_{\alpha,m}P_{\text{num},\alpha,k,(p-k+l)/2} + \partial_{\alpha,m}\delta P_{\text{num},\alpha,k,(p-k+l)/2} \right)\right)\\ &=& \sum_{p=2}^{N_\text{nord}} \sum_{k=0}^{p-1} \sum_{l=0}^{p-k-2\delta_{k,0}} c_{l,k,p,\alpha} \left( \sum_{i=1}^{N_\text{elec}} \left( -\partial_{i,m}\widetilde{R}_{i,\alpha,(p-k-l)/2} \delta P_{i,\alpha,k,(p-k+l)/2} + \widetilde{R}_{i,\alpha,(p-k-l)/2} \partial_{\alpha,m}\delta P_{i,\alpha,k,(p-k+l)/2} \right) \right.\\ &&\left. - \partial_{i,m}\delta \widetilde{R}_{\text{num},\alpha,(p-k-l)/2} \left(P_{\text{num},\alpha,k,(p-k+l)/2} + \delta P_{\text{num},\alpha,k,(p-k+l)/2} \right) + \delta \widetilde{R}_{\text{num},\alpha,(p-k-l)/2} \left(\partial_{\alpha,m}P_{\text{num},\alpha,k,(p-k+l)/2} + \partial_{\alpha,m}\delta P_{\text{num},\alpha,k,(p-k+l)/2} \right)\right)\\ \end{eqnarray*}
The function qmckl_set_single_point
has to be called before this function to set the new electron position.
4.2.8.1. Get
qmckl_exit_code qmckl_get_forces_jastrow_single_een(qmckl_context context, double* const forces_jastrow_single_een, const int64_t size_max);
4.2.8.2. Compute
Variable | Type | In/Out | Description |
---|---|---|---|
context |
qmckl_context |
in | Global state |
num |
int64_t |
in | Index of single electron |
walk_num |
int64_t |
in | Number of walkers |
elec_num |
int64_t |
in | Number of electrons |
nucl_num |
int64_t |
in | Number of nuclei |
cord_num |
int64_t |
in | order of polynomials |
dim_c_vector |
int64_t |
in | dimension of full coefficient vector |
c_vector_full |
double[dim_c_vector][nucl_num] |
in | full coefficient vector |
lkpm_combined_index |
int64_t[4][dim_c_vector] |
in | combined indices |
delta_p |
double[walk_num][0:cord_num-1][0:cord_num][nucl_num][elec_num] |
in | \(\delta P\) matrix |
forces_delta_p |
double[walk_num][0:cord_num-1][0:cord_num][nucl_num][3][elec_num] |
in | Force of $δ P$matrix |
tmp_c |
double[walk_num][0:cord_num-1][0:cord_num][nucl_num][elec_num] |
in | P matrix |
forces_tmp_c |
double[walk_num][0:cord_num-1][0:cord_num][nucl_num][4][elec_num] |
in | Force of P matrix |
een_rescaled_n |
double[walk_num][0:cord_num][nucl_num][elec_num] |
in | Electron-nucleus rescaled distances |
een_rescaled_single_n |
double[walk_num][0:cord_num][nucl_num] |
in | Electron-nucleus single rescaled distances |
een_rescaled_n_gl |
double[walk_num][0:cord_num][nucl_num][4][elec_num] |
in | Electron-nucleus rescaled distances derivatives |
een_rescaled_single_n_gl |
double[walk_num][0:cord_num][nucl_num][4] |
in | Electron-nucleus single rescaled distances derivatives |
forces_jastrow_single_een |
double[walk_num][nucl_num][3] |
out | Single electron–electron-nucleus Jastrow forces |
function qmckl_compute_forces_jastrow_single_een_doc( & context, num_in, walk_num, elec_num, nucl_num, cord_num, & dim_c_vector, c_vector_full, lkpm_combined_index, & delta_p, forces_delta_p, tmp_c, forces_tmp_c, & een_rescaled_n, een_rescaled_single_n, een_rescaled_n_gl, een_rescaled_single_n_gl, forces_jastrow_single_een) & bind(C) result(info) use qmckl implicit none integer (qmckl_context), intent(in), value :: context integer (c_int64_t) , intent(in) , value :: num_in integer (c_int64_t) , intent(in) , value :: walk_num integer (c_int64_t) , intent(in) , value :: elec_num integer (c_int64_t) , intent(in) , value :: nucl_num integer (c_int64_t) , intent(in) , value :: dim_c_vector integer (c_int64_t) , intent(in) , value :: cord_num integer(c_int64_t) , intent(in) :: lkpm_combined_index(dim_c_vector,4) real(c_double) , intent(in) :: c_vector_full(nucl_num, dim_c_vector) real (c_double ) , intent(in) :: delta_p(elec_num, nucl_num,0:cord_num, 0:cord_num-1, walk_num) real (c_double ) , intent(in) :: forces_delta_p(elec_num, 3, nucl_num,0:cord_num, 0:cord_num-1, walk_num) real (c_double ) , intent(in) :: tmp_c(elec_num, nucl_num,0:cord_num, 0:cord_num-1, walk_num) real (c_double ) , intent(in) :: forces_tmp_c(elec_num, 4, nucl_num,0:cord_num, 0:cord_num-1, walk_num) real (c_double ) , intent(in) :: een_rescaled_n(elec_num, nucl_num, 0:cord_num, walk_num) real (c_double ) , intent(in) :: een_rescaled_single_n(nucl_num, 0:cord_num, walk_num) real (c_double ) , intent(in) :: een_rescaled_n_gl(elec_num, 4, nucl_num, 0:cord_num, walk_num) real (c_double ) , intent(in) :: een_rescaled_single_n_gl(4, nucl_num, 0:cord_num, walk_num) real (c_double ) , intent(out) :: forces_jastrow_single_een(3,nucl_num,walk_num) integer(qmckl_exit_code) :: info double precision :: een_rescaled_delta_n(nucl_num, 0:cord_num), een_rescaled_delta_n_gl(3,nucl_num, 0:cord_num) integer*8 :: i, a, j, l, k, p, m, n, nw, num, kk double precision :: accu, accu2, cn integer*8 :: LDA, LDB, LDC num = num_in + 1 info = QMCKL_SUCCESS if (context == QMCKL_NULL_CONTEXT) info = QMCKL_INVALID_CONTEXT if (walk_num <= 0) info = QMCKL_INVALID_ARG_3 if (elec_num <= 0) info = QMCKL_INVALID_ARG_4 if (nucl_num <= 0) info = QMCKL_INVALID_ARG_5 if (cord_num < 0) info = QMCKL_INVALID_ARG_6 if (info /= QMCKL_SUCCESS) return forces_jastrow_single_een = 0.0d0 if (cord_num == 0) return do nw =1, walk_num een_rescaled_delta_n(:,:) = een_rescaled_single_n(:,:,nw) - een_rescaled_n(num,:,:,nw) do kk = 1,3 een_rescaled_delta_n_gl(kk,:,:) = een_rescaled_single_n_gl(kk,:,:,nw) - een_rescaled_n_gl(num,kk,:,:,nw) end do do n = 1, dim_c_vector l = lkpm_combined_index(n, 1) k = lkpm_combined_index(n, 2) p = lkpm_combined_index(n, 3) m = lkpm_combined_index(n, 4) do a = 1, nucl_num cn = c_vector_full(a, n) if(cn == 0.d0) cycle do kk = 1, 3 accu = 0.0d0 do j = 1, elec_num accu = accu - een_rescaled_n_gl(j,kk,a,m,nw) * delta_p(j,a,m+l,k,nw) + & een_rescaled_n(j,a,m,nw) * forces_delta_p(j,kk,a,m+l,k,nw) end do accu = accu - een_rescaled_delta_n_gl(kk,a,m) * (tmp_c(num,a,m+l,k,nw) + delta_p(num,a,m+l,k,nw)) + & een_rescaled_delta_n(a,m) * (forces_tmp_c(num,kk,a,m+l,k,nw) + forces_delta_p(num,kk,a,m+l,k,nw)) forces_jastrow_single_een(kk,a,nw) = forces_jastrow_single_een(kk,a,nw) + accu * cn end do end do end do end do end function qmckl_compute_forces_jastrow_single_een_doc
function qmckl_compute_forces_jastrow_single_een_hpc( & context, num_in, walk_num, elec_num, nucl_num, cord_num, & dim_c_vector, c_vector_full, lkpm_combined_index, & delta_p, forces_delta_p, tmp_c, forces_tmp_c, & een_rescaled_n, een_rescaled_single_n, een_rescaled_n_gl, een_rescaled_single_n_gl, forces_jastrow_single_een) & bind(C) result(info) use qmckl implicit none integer (qmckl_context), intent(in), value :: context integer (c_int64_t) , intent(in) , value :: num_in integer (c_int64_t) , intent(in) , value :: walk_num integer (c_int64_t) , intent(in) , value :: elec_num integer (c_int64_t) , intent(in) , value :: nucl_num integer (c_int64_t) , intent(in) , value :: dim_c_vector integer (c_int64_t) , intent(in) , value :: cord_num integer(c_int64_t) , intent(in) :: lkpm_combined_index(dim_c_vector,4) real(c_double) , intent(in) :: c_vector_full(nucl_num, dim_c_vector) real (c_double ) , intent(in) :: delta_p(elec_num, nucl_num,0:cord_num, 0:cord_num-1, walk_num) real (c_double ) , intent(in) :: forces_delta_p(elec_num, 3, nucl_num,0:cord_num, 0:cord_num-1, walk_num) real (c_double ) , intent(in) :: tmp_c(elec_num, nucl_num,0:cord_num, 0:cord_num-1, walk_num) real (c_double ) , intent(in) :: forces_tmp_c(elec_num, 4, nucl_num,0:cord_num, 0:cord_num-1, walk_num) real (c_double ) , intent(in) :: een_rescaled_n(elec_num, nucl_num, 0:cord_num, walk_num) real (c_double ) , intent(in) :: een_rescaled_single_n(nucl_num, 0:cord_num, walk_num) real (c_double ) , intent(in) :: een_rescaled_n_gl(elec_num, 4, nucl_num, 0:cord_num, walk_num) real (c_double ) , intent(in) :: een_rescaled_single_n_gl(4, nucl_num, 0:cord_num, walk_num) real (c_double ) , intent(out) :: forces_jastrow_single_een(3,nucl_num,walk_num) integer(qmckl_exit_code) :: info double precision, allocatable :: een_rescaled_delta_n(:, :), een_rescaled_delta_n_gl(:,:,:) integer*8 :: i, a, j, l, k, p, m, n, nw, num, kk double precision :: accu2, cn double precision, allocatable :: accu(:,:), tmp(:) double precision, external :: ddot integer :: elec_num4 num = num_in + 1 info = QMCKL_SUCCESS if (context == QMCKL_NULL_CONTEXT) info = QMCKL_INVALID_CONTEXT if (walk_num <= 0) info = QMCKL_INVALID_ARG_3 if (elec_num <= 0) info = QMCKL_INVALID_ARG_4 if (nucl_num <= 0) info = QMCKL_INVALID_ARG_5 if (cord_num < 0) info = QMCKL_INVALID_ARG_6 if (info /= QMCKL_SUCCESS) return forces_jastrow_single_een = 0.0d0 if (cord_num == 0) return allocate(een_rescaled_delta_n(nucl_num, 0:cord_num), een_rescaled_delta_n_gl(3,nucl_num, 0:cord_num), & accu(3,nucl_num), tmp(nucl_num)) elec_num4 = int(elec_num,4) do nw =1, walk_num een_rescaled_delta_n(:,:) = een_rescaled_single_n(:,:,nw) - een_rescaled_n(num,:,:,nw) een_rescaled_delta_n_gl(1:3,:,:) = een_rescaled_single_n_gl(1:3,:,:,nw) - een_rescaled_n_gl(num,1:3,:,:,nw) do n = 1, dim_c_vector l = lkpm_combined_index(n, 1) k = lkpm_combined_index(n, 2) p = lkpm_combined_index(n, 3) m = lkpm_combined_index(n, 4) do a = 1, nucl_num cn = c_vector_full(a, n) accu(1:3,a) = 0.0d0 if(cn == 0.d0) cycle tmp(a) = tmp_c(num,a,m+l,k,nw) + delta_p(num,a,m+l,k,nw) call dgemv('T', elec_num4, 3, -1.d0, een_rescaled_n_gl(1,1,a,m,nw), elec_num4, & delta_p(1,a,m+l,k,nw), 1, 0.d0, accu(1,a), 1) call dgemv('T', elec_num4, 3, 1.d0, forces_delta_p(1,1,a,m+l,k,nw), elec_num4, & een_rescaled_n(1,a,m,nw), 1, 1.d0, accu(1,a), 1) enddo accu(1,:) = accu(1,:) - een_rescaled_delta_n_gl(1,:,m)*tmp(:) accu(2,:) = accu(2,:) - een_rescaled_delta_n_gl(2,:,m)*tmp(:) accu(3,:) = accu(3,:) - een_rescaled_delta_n_gl(3,:,m)*tmp(:) accu(1,:) = accu(1,:) + een_rescaled_delta_n(:,m)*forces_tmp_c(num,1,:,m+l,k,nw) accu(2,:) = accu(2,:) + een_rescaled_delta_n(:,m)*forces_tmp_c(num,2,:,m+l,k,nw) accu(3,:) = accu(3,:) + een_rescaled_delta_n(:,m)*forces_tmp_c(num,3,:,m+l,k,nw) accu(1,:) = accu(1,:) + een_rescaled_delta_n(:,m)*forces_delta_p(num,1,:,m+l,k,nw) accu(2,:) = accu(2,:) + een_rescaled_delta_n(:,m)*forces_delta_p(num,2,:,m+l,k,nw) accu(3,:) = accu(3,:) + een_rescaled_delta_n(:,m)*forces_delta_p(num,3,:,m+l,k,nw) forces_jastrow_single_een(1,:,nw) = forces_jastrow_single_een(1,:,nw) + accu(1,:) * c_vector_full(:,n) forces_jastrow_single_een(2,:,nw) = forces_jastrow_single_een(2,:,nw) + accu(2,:) * c_vector_full(:,n) forces_jastrow_single_een(3,:,nw) = forces_jastrow_single_een(3,:,nw) + accu(3,:) * c_vector_full(:,n) end do end do end function qmckl_compute_forces_jastrow_single_een_hpc
5. Forces of the orbitals
5.1. Force of AO value
Computes the forces on the values of the atomic orbitals (AO). These are equal to the gradients of the AOs multiplied with a minus sign, and summed over different indices.
5.1.1. Get
qmckl_exit_code qmckl_get_forces_ao_value(qmckl_context context, double* const forces_ao_value, const int64_t size_max);
5.1.2. Compute
Variable | Type | In/Out | Description |
---|---|---|---|
context |
qmckl_context |
in | Global state |
ao_num |
int64_t |
in | Number of AOs |
shell_num |
int64_t |
in | Number of shells |
point_num |
int64_t |
in | Number of points |
nucl_num |
int64_t |
in | Number of nuclei |
nucleus_index |
int64_t[nucl_num] |
in | Index of the 1st shell of each nucleus |
nucleus_shell_num |
int64_t[nucl_num] |
in | Number of shells per nucleus |
shell_ang_mom |
int32_t[shell_num] |
in | Angular momentum of each shell |
ao_factor |
double[ao_num] |
in | Normalization factor of the AOs |
ao_vgl |
double[point_num][5][shell_num] |
in | Value, gradients and Laplacian of the shells |
forces_ao_value |
double[nucl_num][point_num][3][ao_num] |
out | Forces of the AOs |
function qmckl_compute_forces_ao_value_doc(context, & ao_num, shell_num, point_num, nucl_num, & nucleus_index, nucleus_shell_num, & shell_ang_mom, ao_factor, ao_vgl, forces_ao_value) & bind(C) result(info) use qmckl_constants use qmckl, only : qmckl_ao_polynomial_vgl, qmckl_get_numprec_precision implicit none integer (qmckl_context), intent(in) , value :: context integer (c_int64_t) , intent(in) , value :: ao_num integer (c_int64_t) , intent(in) , value :: shell_num integer (c_int64_t) , intent(in) , value :: point_num integer (c_int64_t) , intent(in) , value :: nucl_num integer (c_int64_t) , intent(in) :: nucleus_index(nucl_num) integer (c_int64_t) , intent(in) :: nucleus_shell_num(nucl_num) integer (c_int32_t) , intent(in) :: shell_ang_mom(shell_num) real (c_double ) , intent(in) :: ao_factor(ao_num) real (c_double ) , intent(in) :: ao_vgl(ao_num,5,point_num) real (c_double ) , intent(out) :: forces_ao_value(ao_num,3,point_num,nucl_num) integer(qmckl_exit_code) :: info integer :: l, il, k integer*8 :: ipoint, inucl integer*8 :: ishell_start, ishell_end, ishell integer :: lstart(0:20) double precision :: x, y, z, r2 double precision :: cutoff integer , allocatable :: ao_index(:) allocate(ao_index(ao_num)) !forces_ao_value = 0.d0 ! Pre-computed data do l=0,20 lstart(l) = l*(l+1)*(l+2)/6 +1 end do k=1 do inucl=1,nucl_num ishell_start = nucleus_index(inucl) + 1 ishell_end = nucleus_index(inucl) + nucleus_shell_num(inucl) do ishell = ishell_start, ishell_end l = shell_ang_mom(ishell) ao_index(ishell) = k k = k + lstart(l+1) - lstart(l) end do end do info = QMCKL_SUCCESS do ipoint = 1, point_num do inucl=1,nucl_num ! Loop over shells ishell_start = nucleus_index(inucl) + 1 ishell_end = nucleus_index(inucl) + nucleus_shell_num(inucl) do ishell = ishell_start, ishell_end l = shell_ang_mom(ishell) do k = ao_index(ishell), ao_index(ishell) + lstart(l+1)-lstart(l) -1 forces_ao_value(k,1,ipoint,inucl) = -ao_vgl(k,2,ipoint) forces_ao_value(k,2,ipoint,inucl) = -ao_vgl(k,3,ipoint) forces_ao_value(k,3,ipoint,inucl) = -ao_vgl(k,4,ipoint) end do end do end do end do deallocate(ao_index) end function qmckl_compute_forces_ao_value_doc
5.2. Force of MO value
Calculates the force on the molecular orbitals (MO) values. These are calculated by taking a linear combination of AOs.
5.2.1. Get
qmckl_exit_code qmckl_get_forces_mo_value(qmckl_context context, double* const forces_mo_value, const int64_t size_max);
qmckl_exit_code qmckl_get_forces_mo_value_inplace (qmckl_context context, double* const forces_mo_value, const int64_t size_max);
5.2.2. Compute
Variable | Type | In/Out | Description |
---|---|---|---|
context |
qmckl_context |
in | Global state |
nucl_num |
int64_t |
in | Number of AOs |
ao_num |
int64_t |
in | Number of AOs |
mo_num |
int64_t |
in | Number of MOs |
point_num |
int64_t |
in | Number of points |
shell_num |
int64_t |
in | Number of shells |
nucleus_index |
int64_t[nucl_num] |
in | Index of the 1st shell of each nucleus |
nucleus_shell_num |
int64_t[nucl_num] |
in | Number of shells per nucleus |
shell_ang_mom |
int32_t[shell_num] |
in | Angular momentum of each shell |
coefficient_t |
double[mo_num][ao_num] |
in | Transpose of the AO to MO transformation matrix |
ao_vgl |
double[point_num][3][ao_num] |
in | AO values, gradient and Laplacian |
forces_mo_value |
double[nucl_num][point_num][3][mo_num] |
out | Forces of MOs |
integer(qmckl_exit_code) function qmckl_compute_forces_mo_value_doc(context, & nucl_num,ao_num, mo_num, point_num, shell_num, nucleus_index, nucleus_shell_num, & shell_ang_mom, coefficient_t, ao_vgl, forces_mo_value) & result(info) bind(C) use, intrinsic :: iso_c_binding use qmckl implicit none integer(qmckl_context), intent(in) :: context integer(c_int64_t) , intent(in), value ::nucl_num, ao_num, mo_num, point_num, shell_num real(c_double) , intent(in) :: ao_vgl(ao_num,5,point_num) real(c_double) , intent(in) :: coefficient_t(mo_num,ao_num) integer (c_int64_t) , intent(in) :: nucleus_index(nucl_num) integer (c_int64_t) , intent(in) :: nucleus_shell_num(nucl_num) integer (c_int32_t) , intent(in) :: shell_ang_mom(shell_num) real(c_double) , intent(out) :: forces_mo_value(mo_num,3,point_num,nucl_num) integer*8 :: i,j,a, m, ishell_start, ishell_end, il, ishell integer :: l, k double precision :: c1, c2, c3, coef integer, allocatable :: ao_index(:) integer :: lstart(0:20) allocate(ao_index(ao_num)) do l=0,20 lstart(l) = l*(l+1)*(l+2)/6 +1 end do k=1 do a=1,nucl_num ishell_start = nucleus_index(a) + 1 ishell_end = nucleus_index(a) + nucleus_shell_num(a) do ishell = ishell_start, ishell_end l = shell_ang_mom(ishell) ao_index(ishell) = k k = k + lstart(l+1) - lstart(l) end do end do info = QMCKL_SUCCESS do a=1,nucl_num ishell_start = nucleus_index(a) + 1 ishell_end = nucleus_index(a) + nucleus_shell_num(a) do j=1,point_num forces_mo_value(:,:,j,a) = 0.0d0 do ishell = ishell_start, ishell_end l = shell_ang_mom(ishell) do k=ao_index(ishell), ao_index(ishell) + lstart(l+1)-lstart(l)-1 c1 = ao_vgl(k,2,j) c2 = ao_vgl(k,3,j) c3 = ao_vgl(k,4,j) do i=1,mo_num coef = coefficient_t(i,k) forces_mo_value(i,1,j,a) = forces_mo_value(i,1,j,a) - c1 * coef forces_mo_value(i,2,j,a) = forces_mo_value(i,2,j,a) - c2 * coef forces_mo_value(i,3,j,a) = forces_mo_value(i,3,j,a) - c3 * coef end do end do end do end do end do deallocate(ao_index) end function qmckl_compute_forces_mo_value_doc
qmckl_exit_code qmckl_compute_forces_mo_value_doc ( const qmckl_context context, const int64_t nucl_num, const int64_t ao_num, const int64_t mo_num, const int64_t point_num, const int64_t shell_num, const int64_t* nucleus_index, const int64_t* nucleus_shell_num, const int32_t* shell_ang_mom, const double* coefficient_t, const double* ao_vgl, double* const forces_mo_value );
5.3. Force of MO gradient
Calculates the forces of the gradients of the MOs. These are calculated by taking a linear combination of the required components of the Hessian of the AOs.
5.3.1. Get
qmckl_exit_code qmckl_get_forces_mo_g(qmckl_context context, double* const forces_mo_g, const int64_t size_max); qmckl_exit_code qmckl_get_forces_mo_g_inplace(qmckl_context context, double* const forces_mo_g, const int64_t size_max);
5.3.2. Compute
Variable | Type | In/Out | Description |
---|---|---|---|
context |
qmckl_context |
in | Global state |
ao_num |
int64_t |
in | Number of AOs |
mo_num |
int64_t |
in | Number of MOs |
point_num |
int64_t |
in | Number of points |
nucl_num |
int64_t |
in | Number of nuclei |
shell_num |
int64_t |
in | Number of shells |
nucleus_index |
int64_t[nucl_num] |
in | Index of the 1st shell of each nucleus |
nucleus_shell_num |
int64_t[nucl_num] |
in | Number of shells per nucleus |
shell_ang_mom |
int32_t[shell_num] |
in | Angular momentum of each shell |
coefficient_t |
double[mo_num][ao_num] |
in | Transpose of the AO to MO transformation matrix |
ao_hessian |
double[3][point_num][4][ao_num] |
in | Hessian of AOs |
forces_mo_g |
double[nucl_num][3][point_num][3][mo_num] |
out | Forces on gradients of MOs |
integer function qmckl_compute_forces_mo_g_doc(context, & ao_num, mo_num, point_num, nucl_num, & shell_num, nucleus_index, nucleus_shell_num, shell_ang_mom, & coefficient_t, ao_hessian, forces_mo_g) & bind(C) result(info) use qmckl implicit none integer(qmckl_context), intent(in), value :: context integer (c_int64_t) , intent(in), value :: nucl_num, ao_num, mo_num, point_num, shell_num integer (c_int64_t) , intent(in) :: nucleus_index(nucl_num) integer (c_int64_t) , intent(in) :: nucleus_shell_num(nucl_num) integer (c_int32_t) , intent(in) :: shell_ang_mom(shell_num) real (c_double ) , intent(in) :: coefficient_t(mo_num,ao_num) real (c_double ) , intent(in) :: ao_hessian(ao_num,4,point_num,3) real (c_double ) , intent(out) :: forces_mo_g(mo_num,3,point_num,3,nucl_num) integer*8 :: i,j, m, n,a double precision :: c1 double precision, allocatable :: tmp(:,:,:,:) allocate(tmp(ao_num,3,point_num,3)) do a=1,nucl_num ! BROKEN tmp(:,1:3,:,:) = ao_hessian(:,1:3,:,:) info = qmckl_dgemm(context, 'N', 'N', mo_num, 3*point_num*3, ao_num, & -1.d0, coefficient_t, mo_num, & tmp, ao_num, 0.d0, forces_mo_g(1,1,1,1,a), mo_num) if (info /= 0) return end do deallocate(tmp) end function qmckl_compute_forces_mo_g_doc
integer function qmckl_compute_forces_mo_g_hpc(context, & ao_num, mo_num, point_num, nucl_num, & shell_num, nucleus_index, nucleus_shell_num, shell_ang_mom, & coefficient_t, ao_hessian, forces_mo_g) & bind(C) result(info) use qmckl implicit none integer(qmckl_context), intent(in), value :: context integer (c_int64_t) , intent(in), value :: nucl_num, ao_num, mo_num, point_num, shell_num integer (c_int64_t) , intent(in) :: nucleus_index(nucl_num) integer (c_int64_t) , intent(in) :: nucleus_shell_num(nucl_num) integer (c_int32_t) , intent(in) :: shell_ang_mom(shell_num) real (c_double ) , intent(in) :: coefficient_t(mo_num,ao_num) real (c_double ) , intent(in) :: ao_hessian(ao_num,4,point_num,3) real (c_double ) , intent(out) :: forces_mo_g(mo_num,3,point_num,3,nucl_num) integer*8 :: i,j, m, n,a double precision :: c1 integer :: l, il, k, ao_ind integer*8 :: ishell_start, ishell_end, ishell integer :: lstart(0:20) integer , allocatable :: ao_index(:) allocate(ao_index(ao_num)) do l=0,20 lstart(l) = l*(l+1)*(l+2)/6 +1 end do k=1 do a=1,nucl_num ishell_start = nucleus_index(a) + 1 ishell_end = nucleus_index(a) + nucleus_shell_num(a) do ishell = ishell_start, ishell_end l = shell_ang_mom(ishell) ao_index(ishell) = k k = k + lstart(l+1) - lstart(l) end do end do info = QMCKL_SUCCESS do a=1,nucl_num ishell_start = nucleus_index(a) + 1 ishell_end = nucleus_index(a) + nucleus_shell_num(a) do n = 1, 3 do j=1,point_num forces_mo_g(:,:,j,n,a) = 0.d0 do m = 1, 3 do ishell = ishell_start, ishell_end l = shell_ang_mom(ishell) il = lstart(l+1)-lstart(l) ao_ind = ao_index(ishell) do k = ao_ind, ao_ind + il - 1 c1 = ao_hessian(k, m, j, n) if (c1 /= 0.d0) then do i=1,mo_num forces_mo_g(i, m, j, n, a) = forces_mo_g(i, m, j, n, a) - & coefficient_t(i,k) * c1 end do end if end do end do end do end do end do end do deallocate(ao_index) end function qmckl_compute_forces_mo_g_hpc
qmckl_exit_code qmckl_compute_forces_mo_g ( const qmckl_context context, const int64_t ao_num, const int64_t mo_num, const int64_t point_num, const int64_t nucl_num, const int64_t shell_num, const int64_t* nucleus_index, const int64_t* nucleus_shell_num, const int32_t* shell_ang_mom, const double* coefficient_t, const double* ao_hessian, double* const forces_mo_g ); qmckl_exit_code qmckl_compute_forces_mo_g_doc ( const qmckl_context context, const int64_t ao_num, const int64_t mo_num, const int64_t point_num, const int64_t nucl_num, const int64_t shell_num, const int64_t* nucleus_index, const int64_t* nucleus_shell_num, const int32_t* shell_ang_mom, const double* coefficient_t, const double* ao_hessian, double* const forces_mo_g ); qmckl_exit_code qmckl_compute_forces_mo_g_hpc ( const qmckl_context context, const int64_t ao_num, const int64_t mo_num, const int64_t point_num, const int64_t nucl_num, const int64_t shell_num, const int64_t* nucleus_index, const int64_t* nucleus_shell_num, const int32_t* shell_ang_mom, const double* coefficient_t, const double* ao_hessian, double* const forces_mo_g );
5.4. Force of MO Laplacian
Computes the forces on the Laplacian of the MOs. They are calculated by taking a linear combination of the ao_hessian[:,:,:,3,:]
components of the AO Hessian. These store the derivatives of the Laplacian of the AO.
5.4.1. Get
qmckl_exit_code qmckl_get_forces_mo_l(qmckl_context context, double* const forces_mo_l, const int64_t size_max);
5.4.2. Compute
Variable | Type | In/Out | Description |
---|---|---|---|
context |
qmckl_context |
in | Global state |
ao_num |
int64_t |
in | Number of AOs |
mo_num |
int64_t |
in | Number of MOs |
point_num |
int64_t |
in | Number of points |
nucl_num |
int64_t |
in | Number of nuclei |
shell_num |
int64_t |
in | Number of shells |
nucleus_index |
int64_t[nucl_num] |
in | Index of the 1st shell of each nucleus |
nucleus_shell_num |
int64_t[nucl_num] |
in | Number of shells per nucleus |
shell_ang_mom |
int32_t[shell_num] |
in | Angular momentum of each shell |
coefficient_t |
double[mo_num][ao_num] |
in | Transpose of the AO to MO transformation matrix |
ao_hessian |
double[3][point_num][4][ao_num] |
in | Hessian of AOs |
forces_mo_l |
double[nucl_num][3][point_num][mo_num] |
out | Forces on MO Laplacian |
integer function qmckl_compute_forces_mo_l_doc(context, & ao_num, mo_num, point_num, nucl_num, & shell_num, nucleus_index, nucleus_shell_num, shell_ang_mom, & coefficient_t, ao_hessian, forces_mo_l) & bind(C) result(info) use qmckl implicit none integer(qmckl_context), intent(in), value :: context integer (c_int64_t) , intent(in), value :: nucl_num, ao_num, mo_num, point_num, shell_num integer (c_int64_t) , intent(in) :: nucleus_index(nucl_num) integer (c_int64_t) , intent(in) :: nucleus_shell_num(nucl_num) integer (c_int32_t) , intent(in) :: shell_ang_mom(shell_num) real (c_double ) , intent(in) :: coefficient_t(mo_num,ao_num) real (c_double ) , intent(in) :: ao_hessian(ao_num,4,point_num,3) real (c_double ) , intent(out) :: forces_mo_l(mo_num,point_num,3,nucl_num) integer*8 :: i,j, m, n,a, il, ishell, ishell_start, ishell_end integer :: lstart(0:20) integer :: l, k double precision :: c1 integer , allocatable :: ao_index(:) allocate(ao_index(ao_num)) do l=0,20 lstart(l) = l*(l+1)*(l+2)/6 +1 end do k=1 do a=1,nucl_num ishell_start = nucleus_index(a) + 1 ishell_end = nucleus_index(a) + nucleus_shell_num(a) do ishell = ishell_start, ishell_end l = shell_ang_mom(ishell) ao_index(ishell) = k k = k + lstart(l+1) - lstart(l) end do end do forces_mo_l = 0.d0 info = QMCKL_SUCCESS do a=1, nucl_num ishell_start = nucleus_index(a) + 1 ishell_end = nucleus_index(a) + nucleus_shell_num(a) do j=1,point_num do n = 1, 3 do ishell = ishell_start, ishell_end k = ao_index(ishell) l = shell_ang_mom(ishell) do il = lstart(l), lstart(l+1)-1 c1 = ao_hessian(k, 4, j, n) if (c1 == 0.d0) then k = k + 1 cycle end if do i=1,mo_num forces_mo_l(i, j, n, a) = forces_mo_l(i, j, n, a) - coefficient_t(i,k) * c1 end do k = k+1 end do end do end do end do end do deallocate(ao_index) !do a=1,nucl_num ! do m = 1, 3 ! info = qmckl_dgemm(context,'N', 'N', mo_num, point_num, ao_num, & ! -1.d0, coefficient_t, mo_num, & ! ao_hessian(:, 4, :, m, a), ao_num, & ! 1.d0, forces_mo_l(:, :, m, a), mo_num) ! end do !end do end function qmckl_compute_forces_mo_l_doc