1
0
mirror of https://github.com/TREX-CoE/qmckl.git synced 2025-04-30 04:15:00 +02:00

working mo gradient forces

This commit is contained in:
Emiel Slootman 2025-01-23 13:08:05 +01:00
parent 494c402cb4
commit e269729c47
3 changed files with 1273 additions and 2 deletions

View File

@ -324,6 +324,12 @@ typedef struct qmckl_ao_basis_struct {
double * restrict ao_value;
uint64_t ao_value_date;
double * restrict shell_hessian;
uint64_t shell_hessian_date;
double * restrict ao_hessian;
uint64_t ao_hessian_date;
int32_t uninitialized;
bool provided;
bool ao_cartesian;
@ -4207,6 +4213,405 @@ print ( "[1][4][26] : %25.15e"% lf(a,x,y))
#+end_src
** Hessian
#+begin_src c :comments org :tangle (eval h_func) :noweb yes
qmckl_exit_code
qmckl_get_ao_basis_shell_hessian (qmckl_context context,
double* const shell_hessian,
const int64_t size_max);
#+end_src
#+begin_src c :comments org :tangle (eval c) :noweb yes :exports none
qmckl_exit_code
qmckl_get_ao_basis_shell_hessian (qmckl_context context,
double* const shell_hessian,
const int64_t size_max)
{
if (qmckl_context_check(context) == QMCKL_NULL_CONTEXT) {
return qmckl_failwith( context,
QMCKL_INVALID_CONTEXT,
"qmckl_get_ao_basis_shell_hessian",
NULL);
}
qmckl_exit_code rc;
rc = qmckl_provide_ao_basis_shell_hessian(context);
if (rc != QMCKL_SUCCESS) return rc;
qmckl_context_struct* const ctx = (qmckl_context_struct*) context;
assert (ctx != NULL);
int64_t sze = ctx->ao_basis.shell_num * 3 * 3 * ctx->point.num;
if (size_max < sze) {
return qmckl_failwith( context,
QMCKL_INVALID_ARG_3,
"qmckl_get_ao_basis_shell_hessian",
"input array too small");
}
memcpy(shell_hessian, ctx->ao_basis.shell_hessian, (size_t)sze * sizeof(double));
return QMCKL_SUCCESS;
}
#+end_src
#+begin_src f90 :tangle (eval fh_func) :comments org :exports none
interface
integer(c_int32_t) function qmckl_get_ao_basis_shell_hessian &
(context, shell_hessian, size_max) &
bind(C)
use qmckl_constants
import
implicit none
integer (c_int64_t) , intent(in) , value :: context
real(c_double), intent(out) :: shell_hessian(*)
integer (c_int64_t) , intent(in) , value :: size_max
end function
end interface
#+end_src
*** Provide :noexport:
#+begin_src c :comments org :tangle (eval h_private_func) :noweb yes :export none
qmckl_exit_code qmckl_provide_ao_basis_shell_hessian(qmckl_context context);
#+end_src
#+begin_src c :comments org :tangle (eval c) :noweb yes :export none
qmckl_exit_code qmckl_provide_ao_basis_shell_hessian(qmckl_context context)
{
qmckl_exit_code rc = QMCKL_SUCCESS;
if (qmckl_context_check(context) == QMCKL_NULL_CONTEXT) {
return qmckl_failwith( context,
QMCKL_INVALID_CONTEXT,
"qmckl_provide_ao_basis_shell_hessian",
NULL);
}
qmckl_context_struct* const ctx = (qmckl_context_struct*) context;
assert (ctx != NULL);
if (!ctx->ao_basis.provided) {
return qmckl_failwith( context,
QMCKL_NOT_PROVIDED,
"qmckl_provide_ao_basis_shell_hessian",
NULL);
}
/* Compute if necessary */
if (ctx->point.date > ctx->ao_basis.shell_hessian_date) {
qmckl_memory_info_struct mem_info = qmckl_memory_info_struct_zero;
mem_info.size = ctx->ao_basis.shell_num * 3 * 3 * ctx->point.num * sizeof(double);
if (ctx->ao_basis.shell_hessian != NULL) {
qmckl_memory_info_struct mem_info_test = qmckl_memory_info_struct_zero;
rc = qmckl_get_malloc_info(context, ctx->ao_basis.shell_hessian, &mem_info_test);
if ((rc == QMCKL_SUCCESS) && (mem_info_test.size != mem_info.size)) {
rc = qmckl_free(context, ctx->ao_basis.shell_hessian);
assert (rc == QMCKL_SUCCESS);
ctx->ao_basis.shell_hessian = NULL;
}
}
/* Allocate array */
if (ctx->ao_basis.shell_hessian == NULL) {
double* shell_hessian = (double*) qmckl_malloc(context, mem_info);
if (shell_hessian == NULL) {
return qmckl_failwith( context,
QMCKL_ALLOCATION_FAILED,
"qmckl_ao_basis_shell_hessian",
NULL);
}
ctx->ao_basis.shell_hessian = shell_hessian;
}
if (ctx->ao_basis.type == 'G') {
rc = qmckl_compute_ao_basis_shell_gaussian_hessian(context,
ctx->ao_basis.prim_num,
ctx->ao_basis.shell_num,
ctx->point.num,
ctx->nucleus.num,
ctx->ao_basis.nucleus_shell_num,
ctx->ao_basis.nucleus_index,
ctx->ao_basis.nucleus_range,
ctx->ao_basis.shell_prim_index,
ctx->ao_basis.shell_prim_num,
ctx->point.coord.data,
ctx->nucleus.coord.data,
ctx->ao_basis.exponent,
ctx->ao_basis.coefficient_normalized,
ctx->ao_basis.shell_hessian);
} else {
return qmckl_failwith( context,
QMCKL_FAILURE,
"compute_ao_basis_shell_hessian",
"Not yet implemented");
}
if (rc != QMCKL_SUCCESS) {
return rc;
}
ctx->ao_basis.shell_hessian_date = ctx->date;
}
return QMCKL_SUCCESS;
}
#+end_src
*** Compute
:PROPERTIES:
:Name: qmckl_compute_ao_basis_shell_gaussian_hessian
:CRetType: qmckl_exit_code
:FRetType: qmckl_exit_code
:END:
#+NAME: qmckl_ao_basis_shell_gaussian_hessian_args
| Variable | Type | In/Out | Description |
|---------------------+-----------------------------------+--------+----------------------------------------------|
| ~context~ | ~qmckl_context~ | in | Global state |
| ~prim_num~ | ~int64_t~ | in | Number of primitives |
| ~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_shell_num~ | ~int64_t[nucl_num]~ | in | Number of shells for each nucleus |
| ~nucleus_index~ | ~int64_t[nucl_num]~ | in | Index of the 1st shell of each nucleus |
| ~nucleus_range~ | ~double[nucl_num]~ | in | Range of the nucleus |
| ~shell_prim_index~ | ~int64_t[shell_num]~ | in | Index of the 1st primitive of each shell |
| ~shell_prim_num~ | ~int64_t[shell_num]~ | in | Number of primitives per shell |
| ~coord~ | ~double[3][point_num]~ | in | Coordinates |
| ~nucl_coord~ | ~double[3][nucl_num]~ | in | Nuclear coordinates |
| ~expo~ | ~double[prim_num]~ | in | Exponents of the primitives |
| ~coef_normalized~ | ~double[prim_num]~ | in | Coefficients of the primitives |
| ~shell_hessian~ | ~double[point_num][3][3][shell_num]~ | out | Hessian of the shells |
#+begin_src c :tangle (eval h_func) :comments org
qmckl_exit_code qmckl_compute_ao_basis_shell_gaussian_hessian (
const qmckl_context context,
const int64_t prim_num,
const int64_t shell_num,
const int64_t point_num,
const int64_t nucl_num,
const int64_t* nucleus_shell_num,
const int64_t* nucleus_index,
const double* nucleus_range,
const int64_t* shell_prim_index,
const int64_t* shell_prim_num,
const double* coord,
const double* nucl_coord,
const double* expo,
const double* coef_normalized,
double* const shell_hessian );
#+end_src
#+begin_src f90 :comments org :tangle (eval f) :noweb yes
function qmckl_compute_ao_basis_shell_gaussian_hessian( &
context, prim_num, shell_num, point_num, nucl_num, &
nucleus_shell_num, nucleus_index, nucleus_range, &
shell_prim_index, shell_prim_num, coord, nucl_coord, &
expo, coef_normalized, shell_hessian) &
bind(C) result(info)
use qmckl_constants
use qmckl, only: qmckl_get_numprec_precision
implicit none
integer (qmckl_context), intent(in) , value :: context
integer (c_int64_t) , intent(in) , value :: prim_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_shell_num(nucl_num)
integer (c_int64_t) , intent(in) :: nucleus_index(nucl_num)
real (c_double ) , intent(in) :: nucleus_range(nucl_num)
integer (c_int64_t) , intent(in) :: shell_prim_index(shell_num)
integer (c_int64_t) , intent(in) :: shell_prim_num(shell_num)
real (c_double ) , intent(in) :: coord(point_num,3)
real (c_double ) , intent(in) :: nucl_coord(nucl_num,3)
real (c_double ) , intent(in) :: expo(prim_num)
real (c_double ) , intent(in) :: coef_normalized(prim_num)
real (c_double ) , intent(out) :: shell_hessian(shell_num,3,3,point_num)
integer(qmckl_exit_code) :: info
double precision :: xyz(3)
integer*8 :: inucl, iprim, ipoint, ishell
integer*8 :: ishell_start, ishell_end
integer*8 :: iprim_start , iprim_end, i, j
double precision :: x, y, z, two_a, ar2, r2, v, cutoff
info = QMCKL_SUCCESS
do ipoint = 1, point_num
do inucl=1,nucl_num
xyz(1) = coord(ipoint,1) - nucl_coord(inucl,1)
xyz(2) = coord(ipoint,2) - nucl_coord(inucl,2)
xyz(3) = coord(ipoint,3) - nucl_coord(inucl,3)
r2 = xyz(1)*xyz(1) + xyz(2)*xyz(2) + xyz(3)*xyz(3)
! C is zero-based, so shift bounds by one
ishell_start = nucleus_index(inucl) + 1
ishell_end = nucleus_index(inucl) + nucleus_shell_num(inucl)
do ishell=ishell_start, ishell_end
do i = 1, 3
do j = 1, 3
shell_hessian(ishell, i, j, ipoint) = 0.d0
end do
end do
iprim_start = shell_prim_index(ishell) + 1
iprim_end = shell_prim_index(ishell) + shell_prim_num(ishell)
do iprim = iprim_start, iprim_end
ar2 = expo(iprim)*r2
v = coef_normalized(iprim) * dexp(-ar2)
two_a = 2.d0 * expo(iprim)
do i = 1, 3
do j = 1, 3
if (i == j) then
shell_hessian(ishell, i, j, ipoint) = &
shell_hessian(ishell, i, j, ipoint) - two_a * v
end if
shell_hessian(ishell, i, j, ipoint) = &
shell_hessian(ishell, i, j, ipoint) + two_a * two_a * xyz(i) * xyz(j) * v
end do
end do
end do
end do
end do
end do
end function qmckl_compute_ao_basis_shell_gaussian_hessian
#+end_src
*** Test
#+begin_src python :results output :exports none
import numpy as np
def f(a,x,y):
return np.sum( [c * np.exp( -b*(np.linalg.norm(x-y))**2) for b,c in a] )
def d2f(a,x,y,n,m):
h0 = 1.e-6
if n == 1: h = np.array([h0,0.,0.])
elif n == 2: h = np.array([0.,h0,0.])
elif n == 3: h = np.array([0.,0.,h0])
if m == 1: k = np.array([h0,0.,0.])
elif m == 2: k = np.array([0.,h0,0.])
elif m == 3: k = np.array([0.,0.,h0])
# return ( f(a,x+h+k,y) - f(a,x+h,y) - f(a,x+k,y) + f(a,x,y) ) / h0**2
return (f(a,x+h+k,y) - f(a,x+h-k,y)-f(a,x-h+k,y) + f(a,x-h-k,y)) / (4.*h0**2)
elec_26_w1 = np.array( [ 1.49050402641, 2.90106987953, -1.05920815468 ] )
elec_15_w2 = np.array( [ -2.20180344582,-1.9113150239, 2.2193744778600002 ] )
nucl_1 = np.array( [ 1.096243353458458e+00, 8.907054016973815e-01, 7.777092280258892e-01 ] )
nucl_2 = np.array( [ 1.168459237342663e+00, 1.125660720053393e+00, 2.833370314829343e+00 ] )
#double prim_vgl[prim_num][5][point_num];
x = elec_26_w1 ; y = nucl_1
a = [( 8.236000E+03, -1.130000E-04 * 6.1616545431994848e+02 ),
( 1.235000E+03, -8.780000E-04 * 1.4847738511079908e+02 ),
( 2.808000E+02, -4.540000E-03 * 4.8888635917437597e+01 ),
( 7.927000E+01, -1.813300E-02 * 1.8933972232608955e+01 ),
( 2.559000E+01, -5.576000E-02 * 8.1089160941724145e+00 ),
( 8.997000E+00, -1.268950E-01 * 3.7024003863155635e+00 ),
( 3.319000E+00, -1.703520E-01 * 1.7525302846177560e+00 ),
( 9.059000E-01, 1.403820E-01 * 6.6179013183966806e-01 ),
( 3.643000E-01, 5.986840E-01 * 3.3419848027174592e-01 ),
( 1.285000E-01, 3.953890E-01 * 1.5296336817449557e-01 )]
print ( "[1][1][1][26] : %25.15e"% d2f(a,x,y,1,1))
print ( "[1][1][2][26] : %25.15e"% d2f(a,x,y,2,1))
print ( "[1][1][3][26] : %25.15e"% d2f(a,x,y,3,1))
print ( "[2][1][1][26] : %25.15e"% d2f(a,x,y,1,2))
print ( "[2][1][2][26] : %25.15e"% d2f(a,x,y,2,2))
print ( "[2][1][3][26] : %25.15e"% d2f(a,x,y,3,2))
print ( "[3][1][1][26] : %25.15e"% d2f(a,x,y,1,3))
print ( "[3][1][2][26] : %25.15e"% d2f(a,x,y,2,3))
print ( "[3][1][3][26] : %25.15e"% d2f(a,x,y,3,3))
#+end_src
#+RESULTS:
: [1][1][1][26] : -1.396105453466134e-02
: [1][1][2][26] : 6.786238238021269e-03
: [1][1][3][26] : -6.205105873569039e-03
: [2][1][1][26] : 6.786238238021269e-03
: [2][1][2][26] : 1.932481952238163e-02
: [2][1][3][26] : -3.163094786096110e-02
: [3][1][1][26] : -6.205105873569039e-03
: [3][1][2][26] : -3.163094786096110e-02
: [3][1][3][26] : 1.360717094556207e-02
#+begin_src c :tangle (eval c_test) :exports none
{
#define shell_num chbrclf_shell_num
double* elec_coord = &(chbrclf_elec_coord[0][0][0]);
assert(qmckl_electron_provided(context));
int64_t point_num = elec_num;
rc = qmckl_set_point(context, 'N', point_num, elec_coord, point_num*3);
assert(rc == QMCKL_SUCCESS);
double shell_hessian[point_num][3][3][shell_num];
rc = qmckl_get_ao_basis_shell_hessian(context, &(shell_hessian[0][0][0][0]),
(int64_t) 3*3*point_num*shell_num);
assert (rc == QMCKL_SUCCESS);
printf(" shell_hessian[26][0][0][1] %25.15e\n", shell_hessian[26][0][0][1]);
printf(" shell_hessian[26][1][0][1] %25.15e\n", shell_hessian[26][1][0][1]);
printf(" shell_hessian[26][2][0][1] %25.15e\n", shell_hessian[26][2][0][1]);
printf(" shell_hessian[26][0][1][1] %25.15e\n", shell_hessian[26][0][1][1]);
printf(" shell_hessian[26][1][1][1] %25.15e\n", shell_hessian[26][1][1][1]);
printf(" shell_hessian[26][2][1][1] %25.15e\n", shell_hessian[26][2][1][1]);
printf(" shell_hessian[26][0][2][1] %25.15e\n", shell_hessian[26][0][2][1]);
printf(" shell_hessian[26][1][2][1] %25.15e\n", shell_hessian[26][1][2][1]);
printf(" shell_hessian[26][2][2][1] %25.15e\n", shell_hessian[26][2][2][1]);
assert( fabs(shell_hessian[26][0][0][1] - ( -1.396360193576081e-02)) < 1.e-14 );
assert( fabs(shell_hessian[26][1][0][1] - ( 6.788393224947506e-03)) < 1.e-14 );
assert( fabs(shell_hessian[26][2][0][1] - ( -6.202714807711193e-03)) < 1.e-14 );
assert( fabs(shell_hessian[26][0][1][1] - ( 6.788393224947506e-03)) < 1.e-14 );
assert( fabs(shell_hessian[26][1][1][1] - ( 1.931962058731147e-02)) < 1.e-14 );
assert( fabs(shell_hessian[26][2][1][1] - ( -3.162810386893850e-02)) < 1.e-14 );
assert( fabs(shell_hessian[26][0][2][1] - ( -6.202714807711193e-03)) < 1.e-14 );
assert( fabs(shell_hessian[26][1][2][1] - ( -3.162810386893850e-02)) < 1.e-14 );
assert( fabs(shell_hessian[26][2][2][1] - ( 1.360444252028902e-02)) < 1.e-14 );
}
#+end_src
* Polynomial part
Going from the atomic basis set to AOs implies a systematic
@ -5367,6 +5772,202 @@ for (int32_t ldl=3 ; ldl<=5 ; ++ldl) {
}
#+end_src
** Hessian
*** Compute
:PROPERTIES:
:Name: qmckl_compute_ao_polynomial_hessian
:CRetType: qmckl_exit_code
:FRetType: qmckl_exit_code
:END:
#+NAME: qmckl_compute_ao_polynomial_hessian_args
| Variable | Type | In/Out | Description |
|-----------+---------------------+--------+------------------------------------------------------|
| ~context~ | ~qmckl_context~ | in | Global state |
| ~X~ | ~double[3]~ | in | Array containing the coordinates of the points |
| ~R~ | ~double[3]~ | in | Array containing the x,y,z coordinates of the center |
| ~lmax~ | ~int32_t~ | in | Maximum angular momentum |
| ~n~ | ~int64_t~ | inout | Number of computed polynomials |
| ~hessian~ | ~double[3][3][ldv]~ | out | Hessian of the polynomials |
|-----------+---------------------+--------+------------------------------------------------------|
#+begin_src c :tangle (eval h_func) :comments org
qmckl_exit_code qmckl_compute_ao_polynomial_hessian_doc (
const qmckl_context context,
const double* X,
const double* R,
const int32_t lmax,
int64_t* n,
double* const hessian);
#+end_src
#+begin_src f90 :tangle (eval f)
function qmckl_compute_ao_polynomial_hessian_doc (context, &
X, R, lmax, n, hessian) &
bind(C) result(info)
use qmckl_constants
implicit none
integer (qmckl_context), intent(in) , value :: context
real (c_double ) , intent(in) :: X(3)
real (c_double ) , intent(in) :: R(3)
integer (c_int32_t) , intent(in) , value :: lmax
integer (c_int64_t) , intent(inout) :: n
real (c_double ) , intent(out) :: hessian(3,3,(lmax+1)*(lmax+2)*(lmax+3)/6)
integer(qmckl_exit_code) :: info
integer :: i,j,m,k
integer :: a,b,c,d
double precision :: Y(3)
double precision :: pows(-2:lmax,3)
double precision :: xy, yz, xz
double precision :: da, db, dc, dd
info = 0
if (context == QMCKL_NULL_CONTEXT) then
info = QMCKL_INVALID_CONTEXT
return
endif
if (lmax < 0) then
info = QMCKL_INVALID_ARG_4
return
endif
! The shift below is such that polynomials will not make the AO equal to zero at the nodes of the orbitals
do i=1,3
Y(i) = (X(i) - R(i)) + 1.d-20
end do
if (lmax == 0) then
do k = 1, 3
do m = 1, 3
hessian(k,m,1) = 0.d0
end do
end do
n=1
else if (lmax > 0) then
pows(-2:0,1:3) = 1.d0
do i=1,lmax
pows(i,1) = pows(i-1,1) * Y(1)
pows(i,2) = pows(i-1,2) * Y(2)
pows(i,3) = pows(i-1,3) * Y(3)
end do
hessian(1:3,1:3,1:4) = 0.d0
n=4
endif
! l>=2
dd = 2.d0
do d=2,lmax
da = dd
do a=d,0,-1
db = dd-da
do b=d-a,0,-1
c = d - a - b
dc = dd - da - db
n = n+1
xy = pows(a,1) * pows(b,2)
yz = pows(b,2) * pows(c,3)
xz = pows(a,1) * pows(c,3)
xy = dc * xy
xz = db * xz
yz = da * yz
hessian(1,1,n) = da * (da-1.d0) * pows(a-2,1) * pows(b,2) * pows(c,3)
hessian(2,2,n) = db * (db-1.d0) * pows(a,1) * pows(b-2,2) * pows(c,3)
hessian(3,3,n) = dc * (dc-1.d0) * pows(a,1) * pows(b,2) * pows(c-2,3)
hessian(1,2,n) = da * db * pows(a-1,1) * pows(b-1,2) * pows(c,3)
hessian(2,1,n) = da * db * pows(a-1,1) * pows(b-1,2) * pows(c,3)
hessian(1,3,n) = da * dc * pows(a-1,1) * pows(b,2) * pows(c-1,3)
hessian(3,1,n) = da * dc * pows(a-1,1) * pows(b,2) * pows(c-1,3)
hessian(2,3,n) = db * dc * pows(a,1) * pows(b-1,2) * pows(c-1,3)
hessian(3,2,n) = db * dc * pows(a,1) * pows(b-1,2) * pows(c-1,3)
db = db - 1.d0
end do
da = da - 1.d0
end do
dd = dd + 1.d0
end do
info = QMCKL_SUCCESS
end function qmckl_compute_ao_polynomial_hessian_doc
#+end_src
#+begin_src c :tangle (eval h_func) :comments org
qmckl_exit_code qmckl_ao_polynomial_hessian (
const qmckl_context context,
const double* X,
const double* R,
const int32_t lmax,
int64_t* n,
double* const hessian );
#+end_src
#+begin_src c :tangle (eval h_func) :comments org
qmckl_exit_code qmckl_compute_ao_polynomial_hessian_doc (
const qmckl_context context,
const double* X,
const double* R,
const int32_t lmax,
int64_t* n,
double* const hessian);
#+end_src
#+begin_src c :tangle (eval c) :comments org
qmckl_exit_code
qmckl_ao_polynomial_hessian (const qmckl_context context,
const double* X,
const double* R,
const int32_t lmax,
int64_t* n,
double* const hessian)
{
#ifdef HAVE_HPC
return qmckl_compute_ao_polynomial_hessian_doc
#else
return qmckl_compute_ao_polynomial_hessian_doc
#endif
(context, X, R, lmax, n, hessian);
}
#+end_src
#+begin_src f90 :tangle (eval fh_func) :comments org :exports none
interface
integer(qmckl_exit_code) function qmckl_ao_polynomial_hessian &
(context, X, R, lmax, n, hessian) &
bind(C)
use qmckl_constants
import
implicit none
integer (qmckl_context), intent(in) , value :: context
real (c_double ) , intent(in) :: X(3)
real (c_double ) , intent(in) :: R(3)
integer (c_int32_t) , intent(in) , value :: lmax
integer (c_int64_t) , intent(inout) :: n
real (c_double ) , intent(out) :: hessian(3,3,(lmax+1)*(lmax+2)*(lmax+3)/6)
end function qmckl_ao_polynomial_hessian
end interface
#+end_src
* Combining radial and polynomial parts
** Determination of nucleus ranges
@ -7316,6 +7917,352 @@ assert( fabs(ao_vgl[26][4][224] - ( 3.153244195820293e-08)) < 1.e-14 );
#+end_src
** AO Hessian
*** Get
#+begin_src c :comments org :tangle (eval h_func) :noweb yes
qmckl_exit_code
qmckl_get_ao_basis_ao_hessian(qmckl_context context,
double* const ao_hessian,
const int64_t size_max);
#+end_src
#+begin_src c :comments org :tangle (eval c) :noweb yes :exports none
qmckl_exit_code
qmckl_get_ao_basis_ao_hessian(qmckl_context context,
double* const ao_hessian,
const int64_t size_max)
{
if (qmckl_context_check(context) == QMCKL_NULL_CONTEXT) {
return QMCKL_NULL_CONTEXT;
}
qmckl_exit_code rc;
rc = qmckl_provide_ao_basis_ao_hessian(context);
if (rc != QMCKL_SUCCESS) return rc;
qmckl_context_struct* const ctx = (qmckl_context_struct*) context;
assert (ctx != NULL);
const int64_t sze = ctx->nucleus.num * ctx->ao_basis.ao_num * 3 * 3 * ctx->point.num;
if (size_max < sze) {
return qmckl_failwith( context,
QMCKL_INVALID_ARG_3,
"qmckl_get_ao_basis_ao_hessian",
"input array too small");
}
memcpy(ao_hessian, ctx->ao_basis.ao_hessian, sze * sizeof(double));
return QMCKL_SUCCESS;
}
#+end_src
*** Provide
#+begin_src c :comments org :tangle (eval h_private_func) :noweb yes :export none
qmckl_exit_code qmckl_provide_ao_basis_ao_hessian(qmckl_context context);
#+end_src
#+begin_src c :comments org :tangle (eval c) :noweb yes :export none
qmckl_exit_code qmckl_provide_ao_basis_ao_hessian(qmckl_context context)
{
qmckl_exit_code rc = QMCKL_SUCCESS;
if (qmckl_context_check(context) == QMCKL_NULL_CONTEXT) {
return qmckl_failwith( context,
QMCKL_INVALID_CONTEXT,
"qmckl_provide_ao_basis_ao_hessian",
NULL);
}
qmckl_context_struct* const ctx = (qmckl_context_struct*) context;
assert (ctx != NULL);
if (!ctx->ao_basis.provided) {
return qmckl_failwith( context,
QMCKL_NOT_PROVIDED,
"qmckl_provide_ao_basis_ao_hessian",
NULL);
}
/* Compute if necessary */
if (ctx->point.date > ctx->ao_basis.ao_hessian_date) {
qmckl_memory_info_struct mem_info = qmckl_memory_info_struct_zero;
mem_info.size = ctx->nucleus.num * ctx->ao_basis.ao_num * 3 * 3 * ctx->point.num * sizeof(double);
if (ctx->ao_basis.ao_hessian != NULL) {
qmckl_memory_info_struct mem_info_test = qmckl_memory_info_struct_zero;
rc = qmckl_get_malloc_info(context, ctx->ao_basis.ao_hessian, &mem_info_test);
/* if rc != QMCKL_SUCCESS, we are maybe in an _inplace function because the
memory was not allocated with qmckl_malloc */
if ((rc == QMCKL_SUCCESS) && (mem_info_test.size != mem_info.size)) {
rc = qmckl_free(context, ctx->ao_basis.ao_hessian);
assert (rc == QMCKL_SUCCESS);
ctx->ao_basis.ao_hessian = NULL;
}
}
/* Allocate array */
if (ctx->ao_basis.ao_hessian == NULL) {
double* ao_hessian = (double*) qmckl_malloc(context, mem_info);
if (ao_hessian == NULL) {
return qmckl_failwith( context,
QMCKL_ALLOCATION_FAILED,
"qmckl_ao_basis_ao_hessian",
NULL);
}
ctx->ao_basis.ao_hessian = ao_hessian;
}
rc = qmckl_provide_ao_basis_shell_vgl(context);
if (rc != QMCKL_SUCCESS) {
return qmckl_failwith( context, rc, "qmckl_provide_ao_basis_shell_vgl", NULL);
}
rc = qmckl_provide_ao_basis_shell_hessian(context);
if (rc != QMCKL_SUCCESS) {
return qmckl_failwith( context, rc, "qmckl_provide_ao_basis_shell_hessian", NULL);
}
rc = qmckl_compute_ao_hessian_doc(context,
ctx->ao_basis.ao_num,
ctx->ao_basis.shell_num,
ctx->point.num,
ctx->nucleus.num,
ctx->point.coord.data,
ctx->nucleus.coord.data,
ctx->ao_basis.nucleus_index,
ctx->ao_basis.nucleus_shell_num,
ctx->ao_basis.nucleus_range,
ctx->ao_basis.nucleus_max_ang_mom,
ctx->ao_basis.shell_ang_mom,
ctx->ao_basis.ao_factor,
ctx->ao_basis.shell_vgl,
ctx->ao_basis.shell_hessian,
ctx->ao_basis.ao_hessian);
if (rc != QMCKL_SUCCESS) {
return rc;
}
ctx->ao_basis.ao_hessian_date = ctx->date;
}
return QMCKL_SUCCESS;
}
#+end_src
*** Compute
:PROPERTIES:
:Name: qmckl_compute_ao_hessian
:CRetType: qmckl_exit_code
:FRetType: qmckl_exit_code
:END:
#+NAME: qmckl_ao_hessian_args_doc
| 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 |
| ~coord~ | ~double[3][point_num]~ | in | Coordinates |
| ~nucl_coord~ | ~double[3][nucl_num]~ | in | Nuclear coordinates |
| ~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 |
| ~nucleus_range~ | ~double[nucl_num]~ | in | Range beyond which all is zero |
| ~nucleus_max_ang_mom~ | ~int32_t[nucl_num]~ | in | Maximum angular momentum 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 |
| ~shell_vgl~ | ~double[point_num][5][shell_num]~ | in | Value, gradients and Laplacian of the shells |
| ~shell_hessian~ | ~double[point_num][3][3][shell_num]~ | in | Value, gradients and Laplacian of the shells |
| ~ao_hessian~ | ~double[nucl_num][3][point_num][3][ao_num]~ | out | Value, gradients and Laplacian of the AOs |
|-----------------------+-----------------------------------+--------+----------------------------------------------|
#+begin_src f90 :comments org :tangle (eval f) :noweb yes
function qmckl_compute_ao_hessian_doc(context, &
ao_num, shell_num, point_num, nucl_num, &
coord, nucl_coord, nucleus_index, nucleus_shell_num, &
nucleus_range, nucleus_max_ang_mom, shell_ang_mom, &
ao_factor, shell_vgl, shell_hessian, ao_hessian) &
bind(C) result(info)
use qmckl_constants
use qmckl, only : qmckl_ao_polynomial_hessian, 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
real (c_double ) , intent(in) :: coord(point_num,3)
real (c_double ) , intent(in) :: nucl_coord(nucl_num,3)
integer (c_int64_t) , intent(in) :: nucleus_index(nucl_num)
integer (c_int64_t) , intent(in) :: nucleus_shell_num(nucl_num)
real (c_double ) , intent(in) :: nucleus_range(nucl_num)
integer (c_int32_t) , intent(in) :: nucleus_max_ang_mom(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) :: shell_vgl(shell_num,5,point_num)
real (c_double ) , intent(in) :: shell_hessian(shell_num,3,3,point_num)
real (c_double ) , intent(out) :: ao_hessian(ao_num,3,point_num,3,nucl_num)
integer(qmckl_exit_code) :: info
double precision :: e_coord(3), n_coord(3)
integer*8 :: n_poly
integer :: l, il, k, i, j
integer*8 :: ipoint, inucl, ishell
integer*8 :: ishell_start, ishell_end
integer :: lstart(0:20)
double precision :: x, y, z, r2
double precision :: cutoff
double precision, allocatable :: poly_hessian(:,:,:), poly_vgl(:,:)
integer , allocatable :: powers(:,:), ao_index(:)
allocate(poly_vgl(5,ao_num), poly_hessian(3,3,ao_num), powers(3,ao_num), ao_index(ao_num))
! 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
e_coord(1) = coord(ipoint,1)
e_coord(2) = coord(ipoint,2)
e_coord(3) = coord(ipoint,3)
ao_hessian(:,:,ipoint,:,:) = 0.d0
do inucl=1,nucl_num
n_coord(1) = nucl_coord(inucl,1)
n_coord(2) = nucl_coord(inucl,2)
n_coord(3) = nucl_coord(inucl,3)
! Test if the point is in the range of the nucleus
x = e_coord(1) - n_coord(1)
y = e_coord(2) - n_coord(2)
z = e_coord(3) - n_coord(3)
r2 = x*x + y*y + z*z
! Compute polynomials
info = qmckl_ao_polynomial_hessian(context, e_coord, n_coord, &
nucleus_max_ang_mom(inucl), n_poly, poly_hessian)
info = qmckl_ao_polynomial_vgl(context, e_coord, n_coord, &
nucleus_max_ang_mom(inucl), n_poly, powers, 3_8, &
poly_vgl, 5_8)
! Loop over shells
ishell_start = nucleus_index(inucl) + 1
ishell_end = nucleus_index(inucl) + nucleus_shell_num(inucl)
do ishell = ishell_start, ishell_end
k = ao_index(ishell)
l = shell_ang_mom(ishell)
do il = lstart(l), lstart(l+1)-1
do i = 1, 3
do j = 1, 3
ao_hessian(k,i,ipoint,j,inucl) = (&
poly_hessian(i,j,il) * shell_vgl(ishell,1,ipoint) + &
poly_vgl(1,il) * shell_hessian(ishell,i,j,ipoint) + &
poly_vgl(i+1,il) * shell_vgl(ishell,j+1,ipoint) + &
poly_vgl(j+1,il) * shell_vgl(ishell,i+1,ipoint) &
) * ao_factor(k)
end do
end do
k = k+1
end do
end do
end do
end do
deallocate(poly_vgl, powers, poly_hessian, ao_index)
end function qmckl_compute_ao_hessian_doc
#+end_src
#+begin_src c :tangle (eval h_private_func) :comments org
qmckl_exit_code qmckl_compute_ao_hessian_doc (
const qmckl_context context,
const int64_t ao_num,
const int64_t shell_num,
const int64_t point_num,
const int64_t nucl_num,
const double* coord,
const double* nucl_coord,
const int64_t* nucleus_index,
const int64_t* nucleus_shell_num,
const double* nucleus_range,
const int32_t* nucleus_max_ang_mom,
const int32_t* shell_ang_mom,
const double* ao_factor,
const double* shell_vgl,
const double* shell_hessian,
double* const ao_hessian );
#+end_src
*** Test
#+begin_src c :tangle (eval c_test) :exports none
{
#define shell_num chbrclf_shell_num
#define ao_num chbrclf_ao_num
double* elec_coord = &(chbrclf_elec_coord[0][0][0]);
assert(qmckl_electron_provided(context));
int64_t point_num = elec_num;
rc = qmckl_set_point(context, 'N', point_num, elec_coord, point_num*3);
assert(rc == QMCKL_SUCCESS);
double ao_vgl[point_num][5][ao_num];
double ao_hessian[nucl_num][3][point_num][3][ao_num];
rc = qmckl_get_ao_basis_ao_vgl(context, &(ao_vgl[0][0][0]),
(int64_t) 5*point_num*ao_num);
assert (rc == QMCKL_SUCCESS);
rc = qmckl_get_ao_basis_ao_hessian(context, &(ao_hessian[0][0][0][0][0]),
(int64_t) nucl_num*3*point_num*3*ao_num);
assert (rc == QMCKL_SUCCESS);
for (int a = 0; a < nucl_num; a++){
printf("%25.15e\n", fabs(ao_vgl[26][4][219] - (ao_hessian[a][0][26][0][219] + ao_hessian[a][1][26][1][219] + ao_hessian[a][2][26][2][219])));
//assert( fabs(ao_vgl[26][4][219] - (ao_hessian[a][0][26][0][219] + ao_hessian[a][1][26][1][219] + ao_hessian[a][2][26][2][219])) < 1.e-14 );
}
}
#+end_src
* End of files :noexport:
#+begin_src c :tangle (eval h_private_type)

View File

@ -102,6 +102,8 @@ typedef struct qmckl_forces_struct{
uint64_t forces_ao_value_date;
double * restrict forces_mo_value;
uint64_t forces_mo_value_date;
double * restrict forces_mo_g;
uint64_t forces_mo_g_date;
} qmckl_forces_struct;
#+end_src
@ -4614,6 +4616,328 @@ printf("OK\n");
#+end_src
* Force of MO value
** Get
#+begin_src c :comments org :tangle (eval h_func) :noweb yes
qmckl_exit_code
qmckl_get_forces_mo_g(qmckl_context context,
double* const forces_mo_g,
const int64_t size_max);
#+end_src
#+begin_src c :comments org :tangle (eval c) :noweb yes :exports none
qmckl_exit_code
qmckl_get_forces_mo_g(qmckl_context context,
double* const forces_mo_g,
const int64_t size_max)
{
if (qmckl_context_check(context) == QMCKL_NULL_CONTEXT) {
return QMCKL_NULL_CONTEXT;
}
qmckl_exit_code rc;
rc = qmckl_provide_forces_mo_g(context);
if (rc != QMCKL_SUCCESS) return rc;
qmckl_context_struct* const ctx = (qmckl_context_struct*) context;
assert (ctx != NULL);
const int64_t sze = ctx->point.num * 3 * 3 * ctx->mo_basis.mo_num * ctx->nucleus.num;
if (size_max < sze) {
return qmckl_failwith( context,
QMCKL_INVALID_ARG_3,
"qmckl_get_forces_mo_g",
"input array too small");
}
memcpy(forces_mo_g, ctx->forces.forces_mo_g, sze * sizeof(double));
return QMCKL_SUCCESS;
}
#+end_src
#+begin_src f90 :tangle (eval fh_func) :comments org :exports none
interface
integer(qmckl_exit_code) function qmckl_get_forces_mo_g (context, &
forces_mo_g, size_max) bind(C)
use, intrinsic :: iso_c_binding
import
implicit none
integer (c_int64_t) , intent(in) , value :: context
real(c_double), intent(out) :: forces_mo_g(*)
integer (c_int64_t) , intent(in) , value :: size_max
end function qmckl_get_forces_mo_g
end interface
#+end_src
** Provide
#+begin_src c :comments org :tangle (eval h_private_func) :noweb yes :exports none
qmckl_exit_code qmckl_provide_forces_mo_g(qmckl_context context);
#+end_src
#+begin_src c :comments org :tangle (eval c) :noweb yes :export none
qmckl_exit_code qmckl_provide_forces_mo_g(qmckl_context context)
{
qmckl_exit_code rc = QMCKL_SUCCESS;
if (qmckl_context_check(context) == QMCKL_NULL_CONTEXT) {
return qmckl_failwith( context,
QMCKL_INVALID_CONTEXT,
"qmckl_provide_forces_mo_g",
NULL);
}
qmckl_context_struct* const ctx = (qmckl_context_struct*) context;
assert (ctx != NULL);
if (!ctx->mo_basis.provided) {
return qmckl_failwith( context,
QMCKL_NOT_PROVIDED,
"qmckl_provide_mo_basis_mo_vgl",
NULL);
}
/* Compute if necessary */
if (ctx->point.date > ctx->forces.forces_mo_g_date) {
qmckl_memory_info_struct mem_info = qmckl_memory_info_struct_zero;
mem_info.size = 3 * 3 * ctx->mo_basis.mo_num * ctx->point.num * ctx->nucleus.num * sizeof(double);
if (ctx->forces.forces_mo_g != NULL) {
qmckl_memory_info_struct mem_info_test = qmckl_memory_info_struct_zero;
rc = qmckl_get_malloc_info(context, ctx->forces.forces_mo_g, &mem_info_test);
/* if rc != QMCKL_SUCCESS, we are maybe in an _inplace function because the
memory was not allocated with qmckl_malloc */
if ((rc == QMCKL_SUCCESS) && (mem_info_test.size != mem_info.size)) {
rc = qmckl_free(context, ctx->forces.forces_mo_value);
assert (rc == QMCKL_SUCCESS);
ctx->forces.forces_mo_value = NULL;
}
}
/* Allocate array */
if (ctx->forces.forces_mo_g == NULL) {
double* forces_mo_g = (double*) qmckl_malloc(context, mem_info);
if (forces_mo_g == NULL) {
return qmckl_failwith( context,
QMCKL_ALLOCATION_FAILED,
"qmckl_forces_mo_g",
NULL);
}
ctx->forces.forces_mo_g = forces_mo_g;
}
rc = qmckl_provide_ao_basis_ao_hessian(context);
if (rc != QMCKL_SUCCESS) {
return qmckl_failwith( context,
QMCKL_NOT_PROVIDED,
"qmckl_ao_basis_ao_hessian",
NULL);
}
rc = qmckl_compute_forces_mo_g_doc(context,
ctx->ao_basis.ao_num,
ctx->mo_basis.mo_num,
ctx->point.num,
ctx->nucleus.num,
ctx->mo_basis.coefficient_t,
ctx->ao_basis.ao_hessian,
ctx->forces.forces_mo_g);
}
}
#+end_src
** Compute
:PROPERTIES:
:Name: qmckl_compute_forces_mo_g
:CRetType: qmckl_exit_code
:FRetType: qmckl_exit_code
:END:
#+NAME: qmckl_compute_forces_mo_g_args
| 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 |
| ~coefficient_t~ | ~double[mo_num][ao_num]~ | in | Transpose of the AO to MO transformation matrix |
| ~ao_hessian~ | ~double[nucl_num][3][point_num][3][ao_num]~ | in | Value, gradients and Laplacian of the AOs |
| ~forces_mo_g~ | ~double[nucl_num][3][point_num][3][mo_num]~ | out | Value, gradients and Laplacian of the MOs |
|-----------------+--------------------------------+--------+-------------------------------------------------|
#+begin_src f90 :comments org :tangle (eval f) :noweb yes
integer function qmckl_compute_forces_mo_g_doc(context, &
ao_num, mo_num, point_num, nucl_num, &
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
real (c_double ) , intent(in) :: coefficient_t(mo_num,ao_num)
real (c_double ) , intent(in) :: ao_hessian(ao_num,3,point_num,3,nucl_num)
real (c_double ) , intent(out) :: forces_mo_g(mo_num,3,point_num,3,nucl_num)
integer*8 :: i,j,k, m, n,a
info = QMCKL_SUCCESS
do j=1,point_num
forces_mo_g(:,:,j,:,:) = 0.d0
do k=1,ao_num
do i=1,mo_num
do a=1, nucl_num
do m = 1, 3
do n = 1, 3
forces_mo_g(i, m, j, n, a) = forces_mo_g(i, m, j, n, a) - coefficient_t(i,k) * ao_hessian(k, m, j, n, a)
end do
end do
end do
end do
end do
end do
end function qmckl_compute_forces_mo_g_doc
#+end_src
#+RESULTS:
#+begin_src c :tangle (eval h_func) :comments org
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 double* coefficient_t,
const double* ao_hessian,
double* const forces_mo_g );
#+end_src
** Test
#+begin_src c :tangle (eval c_test)
printf("Forces MO gradient\n");
rc = qmckl_set_nucleus_coord(context, 'T', &(nucl_coord[0]), 3*nucl_num);
assert(rc == QMCKL_SUCCESS);
double * forces_mo_g = (double*) malloc(nucl_num* 3 * point_num* 3 * mo_num *sizeof(double));
rc = qmckl_get_forces_mo_g(context, &forces_mo_g[0], 3*3*nucl_num*mo_num*point_num);
assert(rc == QMCKL_SUCCESS);
double * finite_difference_force_mo_g = (double*) malloc(nucl_num* 3 * point_num* 3 * mo_num * sizeof(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);
temp_coord = (double*) malloc(3 * nucl_num * sizeof(double));
if (temp_coord == NULL) {
free(nucleus_coord);
return QMCKL_ALLOCATION_FAILED;
}
mo_output = (double*) malloc(5 * point_num * mo_num * sizeof(double));
if (mo_output == NULL) {
free(temp_coord);
free(nucleus_coord);
return QMCKL_ALLOCATION_FAILED;
}
// 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);
// Call the provided function
rc = qmckl_get_mo_basis_mo_vgl(context,&mo_output[0], 5*point_num*mo_num);
assert(rc == QMCKL_SUCCESS);
// Accumulate derivative using finite-difference coefficients
for (int i = 0; i < point_num; i++) {
for (int n = 0; n < 3; n++){
for (int j = 0; j < mo_num; j++) {
if (m == -4) {
finite_difference_force_mo_g[k*3*mo_num*point_num*nucl_num + a*3*mo_num*point_num + i*3*mo_num + n*mo_num + j] = 0.0;
}
finite_difference_force_mo_g[k*3*mo_num*point_num*nucl_num + a*3*mo_num*point_num + i*3*mo_num + n*mo_num + j] += coef[m + 4] * mo_output[i*mo_num*5 + (n+1)*mo_num + j]/delta_x;
}
}
}
}
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);
free(nucleus_coord);
free(temp_coord);
free(mo_output);
for (int j = 0; j < mo_num; j++){
for (int n = 0; n < 3; n++){
for (int i = 0; i < point_num; i++){
for (int a = 0; a < nucl_num; a++) {
for (int k = 0; k < 3; k++){
//printf("k=%i a=%i i=%i n=%i j=%i\n", k, a, i, n, j);
//printf("%.10f\t", finite_difference_force_mo_g[k*3*mo_num*point_num*nucl_num + a*3*mo_num*point_num + i*3*mo_num + n*mo_num + j]);
//printf("%.10f\n", forces_mo_g[a*9*mo_num*point_num + k*3*mo_num*point_num + i*3*mo_num + n*mo_num + j]);
assert(fabs(finite_difference_force_mo_g[k*3*mo_num*point_num*nucl_num + a*3*mo_num*point_num + i*3*mo_num + n*mo_num + j] - forces_mo_g[a*9*mo_num*point_num + k*3*mo_num*point_num + i*3*mo_num + n*mo_num + j]) < 1.e-9);
}
}
}
}
}
free(forces_mo_g);
free(finite_difference_force_mo_g);
printf("OK\n");
#+end_src
* End of files :noexport:

View File

@ -3025,7 +3025,7 @@ for (int elec = 0; elec < elec_num; elec++){
}
#+end_src
** $\delta p$ matrix gradients and Laplacian
** $\delta P$ matrix gradients and Laplacian
*** Get
@ -6684,7 +6684,7 @@ qmckl_exit_code
qmckl_get_jastrow_champ_single_accept(qmckl_context context);
#+end_src
#+begin_src c :comments org :tangle (eval c) :noweb yes :exports none
#+begin_src c :comments org :tangle (eval c) :noweb yes
qmckl_exit_code
qmckl_get_jastrow_champ_single_accept(qmckl_context context)
{