diff --git a/.github/workflows/test-build.yml b/.github/workflows/test-build.yml index 41b59e0..c7af73f 100644 --- a/.github/workflows/test-build.yml +++ b/.github/workflows/test-build.yml @@ -47,6 +47,7 @@ jobs: - name: Run test run: make -j 4 check + working-directory: _build - name: Archive test log file if: failure() @@ -57,13 +58,7 @@ jobs: - name: Dist test run: make distcheck - - - name: Archive test log file - if: failure() - uses: actions/upload-artifact@v2 - with: - name: dist-report-ubuntu - path: test-suite.log + working-directory: _build x86_macos: @@ -91,37 +86,26 @@ jobs: git clone https://github.com/TREX-CoE/trexio.git cd trexio ./autogen.sh - mkdir _build - cd _build - ../configure --enable-silent-rules - make -j 4 - - - name: Run test - run: make -j 4 check - - - name: Archive test log file - if: failure() - uses: actions/upload-artifact@v2 - with: - name: test-report-ubuntu - path: test-suite.log - - - name: Dist test - run: make distcheck - - - name: Archive test log file - if: failure() - uses: actions/upload-artifact@v2 - with: ./configure --prefix=${PWD}/_install --enable-silent-rules make -j 4 make install + - name: Test TREXIO + run: make -j 4 check + working-directory: trexio + + - name: Archive TREXIO test log file + if: failure() + uses: actions/upload-artifact@v2 + with: + name: test-report-trexio-macos + path: trexio/test-suite.log + - name: Build QMCkl run: | export PKG_CONFIG_PATH=${PWD}/trexio/_install/lib/pkgconfig:$PKG_CONFIG_PATH ./autogen.sh - ./configure --enable-silent-rules --enable-debug + ./configure CC=gcc-10 FC=gfortran-10 --enable-silent-rules --enable-debug make -j 4 - name: Run test diff --git a/README.md b/README.md index 4ab5bae..703bfee 100644 --- a/README.md +++ b/README.md @@ -73,6 +73,24 @@ sudo make install sudo make installcheck ``` + +## Linking to your program + +The `make install` command takes care of installing the QMCkl shared library on the user machine. +Once installed, add `-lqmckl` to the list of compiler options. + +In some cases (e.g. when using custom `prefix` during configuration), the QMCkl library might end up installed in a directory, which is absent in the default `$LIBRARY_PATH`. +In order to link the program against QMCkl, the search paths can be modified as follows: + +`export LIBRARY_PATH=$LIBRARY_PATH:/lib` + +(same holds for `$LD_LIBRARY_PATH`). The `` has to be replaced with the prefix used during the installation. + +If your project relies on the CMake build system, feel free to use the +[FindQMCKL.cmake](https://github.com/TREX-CoE/qmckl/blob/master/cmake/FindQMCKL.cmake) +module to find and link the QMCkl library automatically. + + ## Verificarlo CI Since Verificarlo should not be a dependency of QMCkl, all Verificarlo diff --git a/cmake/FindQMCKL.cmake b/cmake/FindQMCKL.cmake new file mode 100644 index 0000000..89b0b11 --- /dev/null +++ b/cmake/FindQMCKL.cmake @@ -0,0 +1,77 @@ +#=========================================== + +# Try to find the QMCkl library; +# If found, it will define the following variables (note the plural form): +# QMCKL_FOUND - System has libqmckl; +# QMCKL_INCLUDE_DIRS - The QMCKL include directories; +# QMCKL_LIBRARIES - The libraries needed to use QMCKL; + +# If QMCKL has been installed in a non-standard location, one can set an +# environment variable $QMCKL_DIR in the current shell: +# $ export QMCKL_DIR= +# to indicate the prefix used during the QMCKL installation +# (typically `./configure prefix= ..` or `cmake -DCMAKE_INSTALL_DIR= ..`) + +# This file should be located WITHIN your project source tree. +# (e.g. in cmake/FindQMCKL.cmake) +# How to use it in your project CMakeLists.txt: + +# This is needed to locate FindQMCKL.cmake file, modify it according to your source tree. +# list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/") + +# find_package(QMCKL) +# if (QMCKL_FOUND) +# include_directories(${QMCKL_INCLUDE_DIRS}) +# target_link_libraries(your_target ${QMCKL_LIBRARIES}) +# endif() + +#=========================================== + +# This file is distirbuted under the BSD 3-Clause License. +# Copyright (c) 2021, TREX Center of Excellence + +#=========================================== + +message("") + +set(QMCKL_SEARCH_PATHS + ~/Library/Frameworks + /Library/Frameworks + /usr/local + /usr + /sw # Fink + /opt/local # DarwinPorts + /opt/csw # Blastwave + /opt +) + +find_path(QMCKL_INCLUDE_DIR + NAMES qmckl.h + HINTS $ENV{QMCKL_DIR} + PATH_SUFFIXES include/qmckl include + PATHS ${QMCKL_SEARCH_PATHS} + ) + + +# No need to specify platform-specific prefix (e.g. libqmckl on Unix) or +# suffix (e.g. .so on Unix or .dylib on MacOS) in NAMES. CMake takes care of that. +find_library(QMCKL_LIBRARY + NAMES qmckl + HINTS $ENV{QMCKL_DIR} + PATH_SUFFIXES lib64 lib + PATHS ${QMCKL_SEARCH_PATHS} + ) + +message("") + +# Handle the QUIETLY and REQUIRED arguments and set QMCKL_FOUND to TRUE if +# all listed variables are TRUE. +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(QMCKL DEFAULT_MSG QMCKL_LIBRARY QMCKL_INCLUDE_DIR ) +MARK_AS_ADVANCED(QMCKL_INCLUDE_DIR QMCKL_LIBRARY) + +# Mot setting _INCLUDE_DIR and _LIBRARIES is considered a bug, +# see https://gitlab.kitware.com/cmake/community/-/wikis/doc/tutorials/How-To-Find-Libraries +set(QMCKL_LIBRARIES ${QMCKL_LIBRARY}) +set(QMCKL_INCLUDE_DIRS ${QMCKL_INCLUDE_DIR}) + diff --git a/configure.ac b/configure.ac index fcc1dc5..968fbf8 100644 --- a/configure.ac +++ b/configure.ac @@ -49,12 +49,12 @@ AS_IF([test -d ${srcdir}/.git], AC_ARG_WITH(ifort, [AS_HELP_STRING([--with-ifort],[Use Intel Fortran compiler])], with_ifort=$withval, with_ifort=no) AS_IF([test "$with_ifort" == "yes"], [ FC=ifort - FCFLAGS="-xHost -ip -O2 -ftz -finline -g -mkl=sequential" ]) + FCFLAGS="-xHost -ip -Ofast -ftz -finline -g -mkl=sequential" ]) AC_ARG_WITH(icc, [AS_HELP_STRING([--with-icc],[Use Intel C compiler])], with_icc=$withval, with_icc=no) AS_IF([test "$with_icc" == "yes"], [ CC=icc - CFLAGS="-xHost -ip -O2 -ftz -finline -g -mkl=sequential" ]) + CFLAGS="-xHost -ip -Ofast -ftz -finline -g -mkl=sequential" ]) AS_IF([test "$with_icc"."$with_ifort" == "yes.yes"], [ ax_blas_ok="yes" diff --git a/org/qmckl_ao.org b/org/qmckl_ao.org index 55057bd..7cc7eef 100644 --- a/org/qmckl_ao.org +++ b/org/qmckl_ao.org @@ -1,3 +1,4 @@ +B #+TITLE: Atomic Orbitals #+SETUPFILE: ../tools/theme.setup #+INCLUDE: ../tools/lib.org @@ -268,7 +269,7 @@ end interface *** Data structure :noexport: - #+begin_src c :comments org :tangle (eval h_private_type) + #+begin_src c :comments org :tangle (eval h_private_type) :noweb yes typedef struct qmckl_ao_basis_struct { int64_t shell_num; int64_t prim_num; @@ -299,6 +300,9 @@ typedef struct qmckl_ao_basis_struct { bool provided; bool ao_cartesian; char type; +#ifdef HAVE_HPC + <> +#endif } qmckl_ao_basis_struct; #+end_src @@ -770,14 +774,14 @@ qmckl_set_ao_basis_shell_prim_num (qmckl_context context, } #+end_src - + #+begin_src c :comments org :tangle (eval h_func) qmckl_exit_code qmckl_set_ao_basis_shell_prim_index (qmckl_context context, const int64_t* shell_prim_index, const int64_t size_max); #+end_src - + #+begin_src c :comments org :tangle (eval c) :noweb yes :exports none qmckl_exit_code qmckl_set_ao_basis_shell_prim_index (qmckl_context context, @@ -831,15 +835,15 @@ qmckl_set_ao_basis_shell_prim_index (qmckl_context context, <> } #+end_src - - + + #+begin_src c :comments org :tangle (eval h_func) qmckl_exit_code qmckl_set_ao_basis_shell_factor (qmckl_context context, const double* shell_factor, const int64_t size_max); #+end_src - + #+begin_src c :comments org :tangle (eval c) :noweb yes :exports none qmckl_exit_code qmckl_set_ao_basis_shell_factor (qmckl_context context, @@ -893,15 +897,15 @@ qmckl_set_ao_basis_shell_factor (qmckl_context context, <> } #+end_src - - + + #+begin_src c :comments org :tangle (eval h_func) qmckl_exit_code qmckl_set_ao_basis_exponent (qmckl_context context, const double* exponent, const int64_t size_max); #+end_src - + #+begin_src c :comments org :tangle (eval c) :noweb yes :exports none qmckl_exit_code qmckl_set_ao_basis_exponent (qmckl_context context, @@ -2485,7 +2489,6 @@ free(ao_factor_test); | ~ao_vgl~ | ~double[point_num][5][ao_num]~ | Value, gradients, Laplacian of the primitives at current positions | | ~ao_vgl_date~ | ~uint64_t~ | Last modification date of Value, gradients, Laplacian of the AOs at current positions | - *** After initialization When the basis set is completely entered, extra data structures may be @@ -2625,11 +2628,114 @@ qmckl_exit_code qmckl_finalize_basis(qmckl_context context) { } } } - /* TODO : sort the basis set here */ - return QMCKL_SUCCESS; + + rc = QMCKL_SUCCESS; +#ifdef HAVE_HPC + rc = qmckl_finalize_basis_hpc(context); +#endif + + return rc; } #+end_src +*** HPC-specific data structures + + For faster access, we provide extra arrays for the shell information as: + - $C_{psa}$ = =coef_per_nucleus (iprim, ishell, inucl)= + - $\gamma_{pa}$ =expo_per_nucleus (iprim, inucl)= + + such that the computation of the radial parts can be vectorized. + + Exponents are sorted in increasing order to exit loops quickly, + and only unique exponents are kept. This also allows to pack the + exponents to enable vectorization of exponentials. + + The computation of the radial part is made as + \[ + R_{sa} = \sum_p C_{psa} \gamma_{pa} + \] + which is a matrix-vector product. + + #+NAME:HPC_struct + #+begin_src c :comments org :exports none + /* HPC specific data structures */ + qmckl_tensor coef_per_nucleus; + qmckl_matrix expo_per_nucleus; + #+end_src + + #+begin_src c :comments org :tangle (eval h_private_func) :exports none +#ifdef HAVE_HPC +qmckl_exit_code qmckl_finalize_basis_hpc (qmckl_context context); +#endif + #+end_src + + #+begin_src c :comments org :tangle (eval c) :exports none +#ifdef HAVE_HPC +qmckl_exit_code qmckl_finalize_basis_hpc (qmckl_context context) +{ + qmckl_context_struct* const ctx = (qmckl_context_struct* const) context; + + int64_t shell_max = 0; + int64_t prim_max = 0; + int64_t nucl_num = ctx->nucleus.num; + for (int inucl=0 ; inucl < nucl_num ; ++inucl) { + shell_max = ctx->ao_basis.nucleus_shell_num[inucl] > shell_max ? + ctx->ao_basis.nucleus_shell_num[inucl] : shell_max; + + int64_t prim_num = 0; + const int64_t ishell_start = ctx->ao_basis.nucleus_index[inucl]; + const int64_t ishell_end = ctx->ao_basis.nucleus_index[inucl] + ctx->ao_basis.nucleus_shell_num[inucl]; + for (int64_t ishell = ishell_start ; ishell < ishell_end ; ++ishell) { + prim_num += ctx->ao_basis.shell_prim_num[ishell]; + } + prim_max = prim_num > prim_max ? + prim_num : prim_max; + } + + int64_t size[3] = { prim_max, shell_max, nucl_num }; + ctx->ao_basis.coef_per_nucleus = qmckl_tensor_alloc( context, 3, size ); + ctx->ao_basis.coef_per_nucleus = qmckl_tensor_set(ctx->ao_basis.coef_per_nucleus, 0.); + + ctx->ao_basis.expo_per_nucleus = qmckl_matrix_alloc( context, prim_max, nucl_num ); + ctx->ao_basis.expo_per_nucleus = qmckl_matrix_set(ctx->ao_basis.expo_per_nucleus, 0.); + + double expo[prim_max]; + double coef[shell_max][prim_max]; + for (int inucl=0 ; inucl < nucl_num ; ++inucl) { + memset(expo, 0, sizeof(expo)); + memset(coef, 0, sizeof(expo)); + + int64_t idx = 0; + const int64_t ishell_start = ctx->ao_basis.nucleus_index[inucl]; + const int64_t ishell_end = ctx->ao_basis.nucleus_index[inucl] + ctx->ao_basis.nucleus_shell_num[inucl]; + for (int64_t ishell = ishell_start ; ishell < ishell_end ; ++ishell) { + + const int64_t iprim_start = ctx->ao_basis.shell_prim_index[ishell]; + const int64_t iprim_end = ctx->ao_basis.shell_prim_index[ishell] + ctx->ao_basis.shell_prim_num[ishell]; + for (int64_t iprim = iprim_start ; iprim < iprim_end ; ++iprim) { + expo[idx] = ctx->ao_basis.coefficient_normalized[iprim]; + coef[ishell - ishell_start][idx] = ctx->ao_basis.coefficient_normalized[iprim]; + idx += 1; + } + } + + for (int64_t i=0 ; iao_basis.expo_per_nucleus, i, inucl ) = expo[i]; + } + + for (int64_t j=0 ; jao_basis.coef_per_nucleus, i, j, inucl ) = coef[j][i]; + } + } + + } + return QMCKL_SUCCESS; +} +#endif + + #+end_src + *** Access functions #+begin_src c :comments org :tangle (eval h_func) :noweb yes @@ -3040,11 +3146,11 @@ integer(c_int32_t) function test_qmckl_ao_gaussian_vgl(context) bind(C) integer(c_int64_t), intent(in), value :: context integer*8 :: n, ldv, j, i - double precision :: X(3), R(3), Y(3), r2 + double precision :: X(3), R(3), Y(3), r2, z double precision, allocatable :: VGL(:,:), A(:) double precision :: epsilon - epsilon = qmckl_get_numprec_epsilon(context) + epsilon = 3.d0 * qmckl_get_numprec_epsilon(context) X = (/ 1.1 , 2.2 , 3.3 /) R = (/ 0.1 , 1.2 , -2.3 /) @@ -3068,29 +3174,43 @@ integer(c_int32_t) function test_qmckl_ao_gaussian_vgl(context) bind(C) do i=1,n test_qmckl_ao_gaussian_vgl = -11 - if (dabs(1.d0 - VGL(i,1) / (& - dexp(-A(i) * r2) & - )) > epsilon ) return + z = dabs(1.d0 - VGL(i,1) / (dexp(-A(i) * r2)) ) + if ( z > epsilon ) then + print *, z, epsilon + return + end if test_qmckl_ao_gaussian_vgl = -12 - if (dabs(1.d0 - VGL(i,2) / (& - -2.d0 * A(i) * Y(1) * dexp(-A(i) * r2) & - )) > epsilon ) return + z = dabs(1.d0 - VGL(i,2) / (& + -2.d0 * A(i) * Y(1) * dexp(-A(i) * r2) )) + if ( z > epsilon ) then + print *, z, epsilon + return + end if test_qmckl_ao_gaussian_vgl = -13 - if (dabs(1.d0 - VGL(i,3) / (& - -2.d0 * A(i) * Y(2) * dexp(-A(i) * r2) & - )) > epsilon ) return + z = dabs(1.d0 - VGL(i,3) / (& + -2.d0 * A(i) * Y(2) * dexp(-A(i) * r2) )) + if ( z > epsilon ) then + print *, z, epsilon + return + end if test_qmckl_ao_gaussian_vgl = -14 - if (dabs(1.d0 - VGL(i,4) / (& - -2.d0 * A(i) * Y(3) * dexp(-A(i) * r2) & - )) > epsilon ) return + z = dabs(1.d0 - VGL(i,4) / (& + -2.d0 * A(i) * Y(3) * dexp(-A(i) * r2) )) + if ( z > epsilon ) then + print *, z, epsilon + return + end if test_qmckl_ao_gaussian_vgl = -15 - if (dabs(1.d0 - VGL(i,5) / (& - A(i) * (4.d0*r2*A(i) - 6.d0) * dexp(-A(i) * r2) & - )) > epsilon ) return + z = dabs(1.d0 - VGL(i,5) / (& + A(i) * (4.d0*r2*A(i) - 6.d0) * dexp(-A(i) * r2) )) + if ( z > epsilon ) then + print *, z, epsilon + return + end if end do test_qmckl_ao_gaussian_vgl = 0 @@ -5062,8 +5182,8 @@ for (int32_t ldl=3 ; ldl<=5 ; ++ldl) { for (int32_t k=0 ; k<5 ; ++k) { for (int32_t l=0 ; l 0) { - const double* f = &(ao_factor[k]); + const double* __restrict__ f = ao_factor + k; const int64_t idx = lstart[l]; switch (nucleus_max_ang_mom[inucl]) { case 0: - ao_vgl_1[0] = s1 * f[0]; - ao_vgl_2[0] = s2 * f[0]; - ao_vgl_3[0] = s3 * f[0]; - ao_vgl_4[0] = s4 * f[0]; - ao_vgl_5[0] = s5; break; case 1: poly_vgl_1 = &(poly_vgl_l1[0][idx]); poly_vgl_2 = &(poly_vgl_l1[1][idx]); poly_vgl_3 = &(poly_vgl_l1[2][idx]); poly_vgl_4 = &(poly_vgl_l1[3][idx]); - for (int64_t il=0 ; il +#include #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -60,8 +61,20 @@ int main() { #+end_src -* Data types +* - +:PROPERTIES: +:UNNUMBERED: t +:END: + +Basic linear algebra data types and operations are described in this file. +The data types are private, so that HPC implementations can use +whatever data structures they prefer. + +These data types are expected to be used internally in QMCkl. They +are not intended to be passed to external codes. +* Data types + ** Vector | Variable | Type | Description | @@ -69,7 +82,7 @@ int main() { | ~size~ | ~int64_t~ | Dimension of the vector | | ~data~ | ~double*~ | Elements | - #+begin_src c :comments org :tangle (eval h_private_type) + #+begin_src c :comments org :tangle (eval h_private_type) :exports none typedef struct qmckl_vector { int64_t size; double* data; @@ -85,7 +98,7 @@ qmckl_vector_alloc( qmckl_context context, Allocates a new vector. If the allocation failed the size is zero. - #+begin_src c :comments org :tangle (eval c) + #+begin_src c :comments org :tangle (eval c) :exports none qmckl_vector qmckl_vector_alloc( qmckl_context context, const int64_t size) @@ -114,7 +127,7 @@ qmckl_vector_free( qmckl_context context, qmckl_vector* vector); #+end_src - #+begin_src c :comments org :tangle (eval c) + #+begin_src c :comments org :tangle (eval c) :exports none qmckl_exit_code qmckl_vector_free( qmckl_context context, qmckl_vector* vector) @@ -145,7 +158,7 @@ qmckl_vector_free( qmckl_context context, The dimensions use Fortran ordering: two elements differing by one in the first dimension are consecutive in memory. - #+begin_src c :comments org :tangle (eval h_private_type) + #+begin_src c :comments org :tangle (eval h_private_type) :exports none typedef struct qmckl_matrix { int64_t size[2]; double* data; @@ -162,7 +175,7 @@ qmckl_matrix_alloc( qmckl_context context, Allocates a new matrix. If the allocation failed the sizes are zero. - #+begin_src c :comments org :tangle (eval c) + #+begin_src c :comments org :tangle (eval c) :exports none qmckl_matrix qmckl_matrix_alloc( qmckl_context context, const int64_t size1, @@ -195,7 +208,7 @@ qmckl_matrix_free( qmckl_context context, qmckl_matrix* matrix); #+end_src - #+begin_src c :comments org :tangle (eval c) + #+begin_src c :comments org :tangle (eval c) :exports none qmckl_exit_code qmckl_matrix_free( qmckl_context context, qmckl_matrix* matrix) @@ -228,7 +241,7 @@ qmckl_matrix_free( qmckl_context context, The dimensions use Fortran ordering: two elements differing by one in the first dimension are consecutive in memory. - #+begin_src c :comments org :tangle (eval h_private_type) + #+begin_src c :comments org :tangle (eval h_private_type) :exports none #define QMCKL_TENSOR_ORDER_MAX 16 typedef struct qmckl_tensor { @@ -249,7 +262,7 @@ qmckl_tensor_alloc( qmckl_context context, Allocates memory for a tensor. If the allocation failed, the size is zero. - #+begin_src c :comments org :tangle (eval c) + #+begin_src c :comments org :tangle (eval c) :exports none qmckl_tensor qmckl_tensor_alloc( qmckl_context context, const int64_t order, @@ -285,11 +298,11 @@ qmckl_tensor_alloc( qmckl_context context, #+begin_src c :comments org :tangle (eval h_private_func) qmckl_exit_code -qmckl_tensor_free( qmckl_context context, +qmckl_tensor_free (qmckl_context context, qmckl_tensor* tensor); #+end_src - #+begin_src c :comments org :tangle (eval c) + #+begin_src c :comments org :tangle (eval c) :exports none qmckl_exit_code qmckl_tensor_free( qmckl_context context, qmckl_tensor* tensor) @@ -325,7 +338,7 @@ qmckl_matrix_of_vector(const qmckl_vector vector, Reshapes a vector into a matrix. - #+begin_src c :comments org :tangle (eval c) + #+begin_src c :comments org :tangle (eval c) :exports none qmckl_matrix qmckl_matrix_of_vector(const qmckl_vector vector, const int64_t size1, @@ -355,7 +368,7 @@ qmckl_tensor_of_vector(const qmckl_vector vector, Reshapes a vector into a tensor. - #+begin_src c :comments org :tangle (eval c) + #+begin_src c :comments org :tangle (eval c) :exports none qmckl_tensor qmckl_tensor_of_vector(const qmckl_vector vector, const int64_t order, @@ -385,7 +398,7 @@ qmckl_vector_of_matrix(const qmckl_matrix matrix); Reshapes a matrix into a vector. - #+begin_src c :comments org :tangle (eval c) + #+begin_src c :comments org :tangle (eval c) :exports none qmckl_vector qmckl_vector_of_matrix(const qmckl_matrix matrix) { @@ -409,7 +422,7 @@ qmckl_tensor_of_matrix(const qmckl_matrix matrix, Reshapes a matrix into a tensor. - #+begin_src c :comments org :tangle (eval c) + #+begin_src c :comments org :tangle (eval c) :exports none qmckl_tensor qmckl_tensor_of_matrix(const qmckl_matrix matrix, const int64_t order, @@ -439,7 +452,7 @@ qmckl_vector_of_tensor(const qmckl_tensor tensor); Reshapes a tensor into a vector. - #+begin_src c :comments org :tangle (eval c) + #+begin_src c :comments org :tangle (eval c) :exports none qmckl_vector qmckl_vector_of_tensor(const qmckl_tensor tensor) { @@ -468,7 +481,7 @@ qmckl_matrix_of_tensor(const qmckl_tensor tensor, Reshapes a tensor into a vector. - #+begin_src c :comments org :tangle (eval c) + #+begin_src c :comments org :tangle (eval c) :exports none qmckl_matrix qmckl_matrix_of_tensor(const qmckl_tensor tensor, const int64_t size1, @@ -493,15 +506,88 @@ qmckl_matrix_of_tensor(const qmckl_tensor tensor, ** Access macros - #+begin_src c :comments org :tangle (eval h_private_func) + Macros are provided to ease the access to vectors, matrices and + tensors. Matrices use column-major ordering, as in Fortran. + + #+begin_src c :tangle no +double qmckl_vec (qmckl_vector v, int64_t i); // v[i] +double qmckl_mat (qmckl_matrix m, int64_t i, int64_t j) // m[j][i] + +double qmckl_ten3(qmckl_tensor t, int64_t i, int64_t j, int64_t k); // t[k][j][i] +double qmckl_ten4(qmckl_tensor t, int64_t i, int64_t j, int64_t k, int64_t l); +double qmckl_ten5(qmckl_tensor t, int64_t i, int64_t j, int64_t k, int64_t l, int64_t m); +... + #+end_src + + #+begin_src c :comments org :tangle (eval h_private_func) :exports none #define qmckl_vec(v, i) v.data[i] #define qmckl_mat(m, i, j) m.data[(i) + (j)*m.size[0]] -#define qmckl_ten3(t, i, j, k) t.data[(i) + m.size[0]*((j) + size[1]*(k))] -#define qmckl_ten4(t, i, j, k, l) t.data[(i) + m.size[0]*((j) + size[1]*((k) + size[2]*(l)))] -#define qmckl_ten5(t, i, j, k, l, m) t.data[(i) + m.size[0]*((j) + size[1]*((k) + size[2]*((l) + size[3]*(m))))] +#define qmckl_ten3(t, i, j, k) t.data[(i) + t.size[0]*((j) + t.size[1]*(k))] +#define qmckl_ten4(t, i, j, k, l) t.data[(i) + t.size[0]*((j) + t.size[1]*((k) + t.size[2]*(l)))] +#define qmckl_ten5(t, i, j, k, l, m) t.data[(i) + t.size[0]*((j) + t.size[1]*((k) + t.size[2]*((l) + t.size[3]*(m))))] #+end_src + For example: + +** Set all elements + +*** Vector + + #+begin_src c :comments org :tangle (eval h_private_func) +qmckl_vector +qmckl_vector_set(qmckl_vector vector, double value); + #+end_src + + #+begin_src c :comments org :tangle (eval c) :exports none +qmckl_vector +qmckl_vector_set(qmckl_vector vector, double value) +{ + for (int64_t i=0 ; i #include #include +#include #include "qmckl.h" #include "qmckl_context_private_type.h" @@ -69,6 +70,8 @@ int main() { #+end_src + + * Context handling The context variable is a handle for the state of the library, @@ -146,7 +149,7 @@ typedef struct qmckl_context_struct { the pointer associated with a context is non-null, we can still verify that it points to the expected data structure. - #+begin_src c :comments org :tangle (eval h_private_type) :noweb yes + #+begin_src c :comments org :tangle (eval h_private_type) :noweb yes :exports none #define VALID_TAG 0xBEEFFACE #define INVALID_TAG 0xDEADBEEF #+end_src @@ -156,10 +159,11 @@ typedef struct qmckl_context_struct { if the context is valid, ~QMCKL_NULL_CONTEXT~ otherwise. #+begin_src c :comments org :tangle (eval h_func) :noexport -qmckl_context qmckl_context_check(const qmckl_context context) ; +qmckl_context +qmckl_context_check (const qmckl_context context) ; #+end_src - #+begin_src c :tangle (eval c) + #+begin_src c :tangle (eval c) :exports none qmckl_context qmckl_context_check(const qmckl_context context) { if (context == QMCKL_NULL_CONTEXT) @@ -176,19 +180,27 @@ qmckl_context qmckl_context_check(const qmckl_context context) { } #+end_src - The context keeps a ``date'' that allows to check which data needs + The context keeps a /date/ that allows to check which data needs to be recomputed. The date is incremented when the context is touched. When a new element is added to the context, the functions - [[Creation][qmckl_context_create]], [[Destroy][qmckl_context_destroy]] and [[Copy][qmckl_context_copy]] + [[Creation][=qmckl_context_create=]] [[Destroy][=qmckl_context_destroy=]] and [[Copy][=qmckl_context_copy=]] should be updated in order to make deep copies. - #+begin_src c :comments org :tangle (eval h_func) :noexport -qmckl_exit_code qmckl_context_touch(const qmckl_context context) ; + When the electron coordinates have changed, the context is touched + using the following function. + + #+begin_src c :comments org :tangle (eval h_func) +qmckl_exit_code +qmckl_context_touch (const qmckl_context context); #+end_src - #+begin_src c :tangle (eval c) -qmckl_exit_code qmckl_context_touch(const qmckl_context context) { + This has the effect to increment the date of the context. + + #+begin_src c :tangle (eval c) :exports none +qmckl_exit_code +qmckl_context_touch(const qmckl_context context) +{ if (qmckl_context_check(context) == QMCKL_NULL_CONTEXT) { return qmckl_failwith( context, @@ -213,12 +225,12 @@ qmckl_exit_code qmckl_context_touch(const qmckl_context context) { - A new context always has all its members initialized with a NULL value # Header - #+begin_src c :comments org :tangle (eval h_func) :exports none + #+begin_src c :comments org :tangle (eval h_func) qmckl_context qmckl_context_create(); #+end_src # Source - #+begin_src c :tangle (eval c) + #+begin_src c :tangle (eval c) :exports none qmckl_context qmckl_context_create() { qmckl_context_struct* const ctx = @@ -241,7 +253,9 @@ qmckl_context qmckl_context_create() { rc = pthread_mutexattr_init(&attr); assert (rc == 0); +#ifdef PTHREAD_MUTEX_RECURSIVE (void) pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); +#endif rc = pthread_mutex_init ( &(ctx->mutex), &attr); assert (rc == 0); @@ -252,30 +266,30 @@ qmckl_context qmckl_context_create() { /* Initialize data */ { ctx->tag = VALID_TAG; - + const qmckl_context context = (const qmckl_context) ctx; assert ( qmckl_context_check(context) != QMCKL_NULL_CONTEXT ); - + qmckl_exit_code rc; - + ctx->numprec.precision = QMCKL_DEFAULT_PRECISION; ctx->numprec.range = QMCKL_DEFAULT_RANGE; rc = qmckl_init_point(context); assert (rc == QMCKL_SUCCESS); - + rc = qmckl_init_electron(context); assert (rc == QMCKL_SUCCESS); - + rc = qmckl_init_nucleus(context); assert (rc == QMCKL_SUCCESS); - + rc = qmckl_init_ao_basis(context); assert (rc == QMCKL_SUCCESS); - + rc = qmckl_init_mo_basis(context); assert (rc == QMCKL_SUCCESS); - + rc = qmckl_init_determinant(context); assert (rc == QMCKL_SUCCESS); } @@ -326,13 +340,13 @@ assert( qmckl_context_check(context) == context ); ~lock_count~ attribute. # Header - #+begin_src c :comments org :tangle (eval h_func) :exports none + #+begin_src c :comments org :tangle (eval h_func) void qmckl_lock (qmckl_context context); void qmckl_unlock(qmckl_context context); #+end_src # Source - #+begin_src c :tangle (eval c) + #+begin_src c :tangle (eval c) :exports none void qmckl_lock(qmckl_context context) { if (context == QMCKL_NULL_CONTEXT) return ; @@ -345,9 +359,6 @@ void qmckl_lock(qmckl_context context) { } assert (rc == 0); ctx->lock_count += 1; -/* - printf(" lock : %d\n", ctx->lock_count); -,*/ } void qmckl_unlock(const qmckl_context context) { @@ -359,9 +370,6 @@ void qmckl_unlock(const qmckl_context context) { } assert (rc == 0); ctx->lock_count -= 1; -/* - printf("unlock : %d\n", ctx->lock_count); -,*/ } #+end_src @@ -372,12 +380,14 @@ void qmckl_unlock(const qmckl_context context) { # Header #+begin_src c :comments org :tangle (eval h_func) :exports none +/* qmckl_context qmckl_context_copy(const qmckl_context context); +*/ #+end_src # Source - #+begin_src c :tangle (eval c) + #+begin_src c :tangle (eval c) :exports none qmckl_context qmckl_context_copy(const qmckl_context context) { const qmckl_context checked_context = qmckl_context_check(context); @@ -418,13 +428,13 @@ qmckl_context qmckl_context_copy(const qmckl_context context) { # Fortran interface #+begin_src f90 :tangle (eval fh_func) :exports none - interface - integer (qmckl_context) function qmckl_context_copy(context) bind(C) - use, intrinsic :: iso_c_binding - import - integer (qmckl_context), intent(in), value :: context - end function qmckl_context_copy - end interface +! interface +! integer (qmckl_context) function qmckl_context_copy(context) bind(C) +! use, intrinsic :: iso_c_binding +! import +! integer (qmckl_context), intent(in), value :: context +! end function qmckl_context_copy +! end interface #+end_src # Test @@ -443,13 +453,16 @@ munit_assert_int64(qmckl_context_check(new_context), ==, new_context); It frees the context, and returns the previous context. # Header - #+begin_src c :comments org :tangle (eval h_func) :exports none -qmckl_exit_code qmckl_context_destroy(const qmckl_context context); + #+begin_src c :comments org :tangle (eval h_func) +qmckl_exit_code +qmckl_context_destroy (const qmckl_context context); #+end_src # Source - #+begin_src c :tangle (eval c) -qmckl_exit_code qmckl_context_destroy(const qmckl_context context) { + #+begin_src c :tangle (eval c) :exports none +qmckl_exit_code +qmckl_context_destroy (const qmckl_context context) +{ const qmckl_context checked_context = qmckl_context_check(context); if (checked_context == QMCKL_NULL_CONTEXT) return QMCKL_INVALID_CONTEXT; diff --git a/org/qmckl_error.org b/org/qmckl_error.org index cecd42d..97cc7cc 100644 --- a/org/qmckl_error.org +++ b/org/qmckl_error.org @@ -46,7 +46,7 @@ int main() { #+end_src -* +* - :PROPERTIES: :UNNUMBERED: t :END: @@ -204,18 +204,25 @@ return '\n'.join(result) string is assumed to be large enough to contain the error message (typically 128 characters). +* hidden :noexport: + + #+NAME: MAX_STRING_LENGTH + : 128 + * Decoding errors To decode the error messages, ~qmckl_string_of_error~ converts an error code into a string. - #+NAME: MAX_STRING_LENGTH - : 128 + #+begin_src c :comments org :tangle (eval h_func) :noweb yes +const char* +qmckl_string_of_error (const qmckl_exit_code error); + #+end_src - #+begin_src c :comments org :tangle (eval h_func) :exports none :noweb yes -const char* qmckl_string_of_error(const qmckl_exit_code error); -void qmckl_string_of_error_f(const qmckl_exit_code error, - char result[<>]); + #+begin_src c :comments org :tangle (eval h_private_func) :exports none :noweb yes +void +qmckl_string_of_error_f(const qmckl_exit_code error, + char result[<>]); #+end_src The text strings are extracted from the previous table. @@ -326,7 +333,7 @@ return '\n'.join(result) #+end_example # Source - #+begin_src c :comments org :tangle (eval c) :noweb yes + #+begin_src c :comments org :tangle (eval c) :noweb yes :exports none const char* qmckl_string_of_error(const qmckl_exit_code error) { switch (error) { <> @@ -340,7 +347,7 @@ void qmckl_string_of_error_f(const qmckl_exit_code error, char result[< 0); assert (exit_code < QMCKL_INVALID_EXIT_CODE); assert (function != NULL); @@ -544,8 +553,6 @@ if (x < 0) { #endif #+end_src - -** Test #+begin_src c :comments link :tangle (eval c_test) /* Initialize the variables */ char function_name[QMCKL_MAX_FUN_LEN]=""; diff --git a/org/qmckl_nucleus.org b/org/qmckl_nucleus.org index 0191afe..319d5d1 100644 --- a/org/qmckl_nucleus.org +++ b/org/qmckl_nucleus.org @@ -187,6 +187,19 @@ qmckl_get_nucleus_num (const qmckl_context context, int64_t* const num) { } #+end_src + #+begin_src f90 :tangle (eval fh_func) :comments org :exports none +interface + integer(c_int32_t) function qmckl_get_nucleus_num(context, num) & + bind(C) + use, intrinsic :: iso_c_binding + import + implicit none + integer (c_int64_t) , intent(in) , value :: context + integer (c_int64_t) , intent(out) :: num + end function qmckl_get_nucleus_num +end interface + #+end_src + #+begin_src c :comments org :tangle (eval h_func) :exports none qmckl_exit_code @@ -242,6 +255,20 @@ qmckl_get_nucleus_charge (const qmckl_context context, #+end_src + #+begin_src f90 :tangle (eval fh_func) :comments org :exports none +interface + integer(c_int32_t) function qmckl_get_nucleus_charge(context, charge, 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) :: charge(*) + integer (c_int64_t) , intent(in) , value :: size_max + end function qmckl_get_nucleus_charge +end interface + #+end_src + #+begin_src c :comments org :tangle (eval h_func) :exports none qmckl_exit_code @@ -277,6 +304,18 @@ qmckl_get_nucleus_rescale_factor (const qmckl_context context, } #+end_src + #+begin_src f90 :tangle (eval fh_func) :comments org :exports none +interface + integer(c_int32_t) function qmckl_get_nucleus_rescale_factor(context, kappa) & + bind(C) + use, intrinsic :: iso_c_binding + import + implicit none + integer (c_int64_t) , intent(in) , value :: context + real (c_double) , intent(out) :: kappa + end function qmckl_get_nucleus_rescale_factor +end interface + #+end_src #+begin_src c :comments org :tangle (eval h_func) :exports none qmckl_exit_code @@ -342,6 +381,21 @@ qmckl_get_nucleus_coord (const qmckl_context context, } #+end_src + #+begin_src f90 :tangle (eval fh_func) :comments org :exports none +interface + integer(c_int32_t) function qmckl_get_nucleus_coord(context, transp, coord, size_max) & + bind(C) + use, intrinsic :: iso_c_binding + import + implicit none + integer (c_int64_t) , intent(in) , value :: context + character(c_char) , intent(in) , value :: transp + real (c_double) , intent(out) :: coord(*) + integer (c_int64_t) , intent(in) , value :: size_max + end function qmckl_get_nucleus_coord +end interface + #+end_src + When all the data relative to nuclei have been set, the following function returns ~true~. @@ -424,7 +478,7 @@ interface implicit none integer (c_int64_t) , intent(in) , value :: context integer (c_int64_t) , intent(in) , value :: num - end function + end function qmckl_set_nucleus_num end interface #+end_src @@ -570,7 +624,7 @@ interface character(c_char) , intent(in) , value :: transp real (c_double) , intent(in) :: coord(*) integer (c_int64_t) , intent(in) , value :: size_max - end function + end function qmckl_set_nucleus_coord end interface #+end_src @@ -604,14 +658,14 @@ qmckl_set_nucleus_rescale_factor(qmckl_context context, #+begin_src f90 :tangle (eval fh_func) :comments org :exports none interface - integer(c_int32_t) function qmckl_set_rescale_factor(context, kappa) & + integer(c_int32_t) function qmckl_set_nucleus_rescale_factor(context, kappa) & bind(C) use, intrinsic :: iso_c_binding import implicit none integer (c_int64_t) , intent(in) , value :: context real (c_double) , intent(in) , value :: kappa - end function + end function qmckl_set_nucleus_rescale_factor end interface #+end_src