From c4635e9296e520449fd942b29df204d83b1d2eca Mon Sep 17 00:00:00 2001 From: Anthony Scemama Date: Thu, 20 Jan 2022 01:50:54 +0100 Subject: [PATCH] Added qmckl_point --- Makefile.am | 2 +- configure.ac | 23 +- org/qmckl.org | 132 ++++++---- org/qmckl_ao.org | 1 - org/qmckl_context.org | 8 + org/qmckl_point.org | 591 ++++++++++++++++++++++++++++++++++++++++++ org/table_of_contents | 23 +- 7 files changed, 712 insertions(+), 68 deletions(-) create mode 100644 org/qmckl_point.org diff --git a/Makefile.am b/Makefile.am index c04b90a..8fae847 100644 --- a/Makefile.am +++ b/Makefile.am @@ -53,7 +53,7 @@ src_qmckl_f = src/qmckl_f.f90 src_qmckl_fo = src/qmckl_f.o header_tests = tests/chbrclf.h tests/n2.h -fortrandir = $(datadir)/fortran +fortrandir = $(datadir)/qmckl/fortran fortran_DATA = $(src_qmckl_f) QMCKL_TEST_DIR = $(abs_srcdir)/share/qmckl/test_data/ diff --git a/configure.ac b/configure.ac index 52bfdac..3e0b83e 100644 --- a/configure.ac +++ b/configure.ac @@ -176,6 +176,22 @@ AX_BLAS([], [AC_MSG_ERROR([BLAS was not found.])]) ## LAPACK AX_LAPACK([], [AC_MSG_ERROR([LAPACK was not found.])]) + +# Specific options required with some compilers +case $FC in + + ifort*) + FCFLAGS="$FCFLAGS -nofor-main" + ;; + + gfortran*) + # Order is important here + FCFLAGS="-cpp $FCFLAGS" + ;; +esac + + + # Options. AC_ARG_ENABLE(debug, [AS_HELP_STRING([--enable-debug],[compile for debugging])], ok=$enableval, ok=no) @@ -282,13 +298,6 @@ AC_ARG_ENABLE([vfc_ci], esac],[vfc_ci=false]) AM_CONDITIONAL([VFC_CI], [test x$vfc_ci = xtrue]) -# Enable Fortran preprocessor -if test "$FC" = "gfortran"; then - AC_MSG_NOTICE(gfortran detected) - # Arguments order is important here - FCFLAGS="-cpp $FCFLAGS" -fi - if test "$FC" = "verificarlo-f"; then AC_MSG_NOTICE(verificarlo-f detected) # Arguments order is important here diff --git a/org/qmckl.org b/org/qmckl.org index e46b2bd..5434a54 100644 --- a/org/qmckl.org +++ b/org/qmckl.org @@ -3,6 +3,33 @@ #+SETUPFILE: ../tools/theme.setup # -*- mode: org -*- +* Installing QMCkl + + The latest version fo QMCkl can be downloaded + [[https://github.com/TREX-CoE/qmckl/releases/latest][here]], and the source code is accessible on the + [[https://github.com/TREX-CoE/qmckl][GitHub repository]]. + +** Installing from the released tarball (for end users) + + QMCkl is built with GNU Autotools, so the usual + =configure ; make ; make check ; make install= scheme will be used. + + As usual, the C compiler can be specified with the ~CC~ variable + and the Fortran compiler with the ~FC~ variable. The compiler + options are defined using ~CFLAGS~ and ~FCFLAGS~. + +** Installing from the source repository (for developers) + + To compile from the source repository, additional dependencies are + required to generated the source files: + - Emacs >= 26 + - Autotools + - Python3 + + When the repository is downloaded, the Makefile is not yet + generated, as well as the configure script. =./autogen.sh= has + to be executed first. + * Using QMCkl The =qmckl.h= header file installed in the =${prefix}/include= directory @@ -59,6 +86,9 @@ Both files are located in the =include/= directory. Moreover, within the Emacs text editor the source code blocks can be executed interactively, in the same spirit as Jupyter notebooks. + Note that Emacs is not needed for end users because the distributed + tarball contains the generated source code. + ** Source code editing For a tutorial on literate programming with org-mode, follow [[http://www.howardism.org/Technical/Emacs/literate-programming-tutorial.html][this link]]. @@ -80,36 +110,50 @@ Both files are located in the =include/= directory. ** Choice of the programming language - Most of the codes of the [[https://trex-coe.eu][TREX CoE]] are written in Fortran with some scripts in - Bash and Python. Outside of the CoE, Fortran is also important (Casino, Amolqc), - and other important languages used by the community are C and C++ (QMCPack, - QWalk), and Julia is gaining in popularity. The library we design should be - compatible with all of these languages. The QMCkl API has to be compatible - with the C language since libraries with a C-compatible API can be used in - every other language. + Most of the codes of the [[https://trex-coe.eu][TREX CoE]] are written in Fortran with some + scripts in Bash and Python. Outside of the CoE, Fortran is also + important in QMC codes (Casino, Amolqc), and other important + languages used by the community are C and C++ (QMCPack, QWalk), + Julia and Rust are gaining in popularity. We want QMCkl to be + compatible with all of these languages, so the QMCkl API has to be + compatible with the C language since libraries with a C-compatible + API can be used in every other language. - High-performance versions of the QMCkl, with the same API, will be rewritten by - the experts in HPC. These optimized libraries will be tuned for specific - architectures, among which we can cite x86 based processors, and GPU - accelerators. Nowadays, the most efficient software tools to take advantage of - low-level features of the processor (intrinsics) and of GPUs are for C++ - developers. It is highly probable that the optimized implementations will be - written in C++, and this is agreement with our choice to make the API - C-compatible. + High-performance versions of QMCkl, with the same API, can be + rewritten by HPC experts. These optimized libraries will be tuned + for specific architectures, among which we can cite x86 based + processors, and GPU accelerators. Nowadays, the most efficient + software tools to take advantage of low-level features + (intrinsics, prefetching, aligned or pinned memory allocation, + ...) are for C++ developers. It is highly probable that optimized + implementations will be written in C++, but as the API is + C-compatible this doesn't pose any problem for linking the library + in other languages. - Fortran is one of the most common languages used by the community, and is simple - enough to make the algorithms readable both by experts in QMC, and experts in - HPC. Hence we propose in this pedagogical implementation of QMCkl to use Fortran - to express the QMC algorithms. As the main languages of the library is C, this - implies that the exposed C functions call the Fortran routine. However, for - internal functions related to system programming, the C language is more natural - than Fortran. + Fortran is one of the most common languages used by the community, + and is simple enough to make the algorithms readable both by + experts in QMC, and experts in HPC. Hence we propose in this + pedagogical implementation of QMCkl to use Fortran to express the + QMC algorithms. However, for internal functions related to system + programming, the C language is more natural than Fortran. - The Fortran source files should provide a C interface using the - ~iso_c_binding~ module. The name of the Fortran source files should end with - =_f.f90= to be properly handled by the =Makefile=. The names of the functions - defined in Fortran should be the same as those exposed in the API suffixed by - =_f=. + As QMCkl appears like a C library, for each Fortran function there + is an ~iso_c_binding~ interface to make the Fortran function + callable from C. It is this C interface which is exposed to the + user. As a consequence, the Fortran users of the library never + call directly the Fortran routines, but call instead the C binding + function and an ~iso_c_binding~ is still required: + + #+begin_example + ISO_C_BINDING ISO_C_BINDING + Fortran ---------------> C ---------------> Fortran + #+end_example + + The name of the Fortran source files should end with =_f.f90= to + be properly handled by the =Makefile= and to avoid collision of + object files (=*.o=) with the compiled C source files. The names + of the functions defined in Fortran should be the same as those + exposed in the API suffixed by =_f=. For more guidelines on using Fortran to generate a C interface, see [[http://fortranwiki.org/fortran/show/Generating+C+Interfaces][this link]]. @@ -123,6 +167,8 @@ Both files are located in the =include/= directory. #+begin_src bash cppcheck --addon=cert --enable=all *.c &> cppcheck.out +# or +make cppcheck ; cat cppcheck.out #+end_src ** Design of the library @@ -142,8 +188,6 @@ cppcheck --addon=cert --enable=all *.c &> cppcheck.out produced C files should be =xxx.c= and =xxx.h= and the name of the produced Fortran file should be =xxx.f90=. - Arrays are in uppercase and scalars are in lowercase. - In the names of the variables and functions, only the singular form is allowed. @@ -240,33 +284,25 @@ cppcheck --addon=cert --enable=all *.c &> cppcheck.out conversions. These functions are also responsible for allocating temporary storage, to simplify the use of accelerators. - The high-level functions should be pure, unless the introduction - of non-purity is justified. All the side effects should be made in - the =context= variable. - - # TODO : We need an identifier for impure functions - # Suggestion (VJ): using *_unsafe_* for impure functions ? - ** Numerical precision - The number of bits of precision required for a function should be - given as an input of low-level computational functions. This input - will be used to define the values of the different thresholds that - might be used to avoid computing unnecessary noise. High-level - functions will use the precision specified in the =context= - variable. + The minimal number of bits of precision required for a function + should be given as an input of low-level computational + functions. This input will be used to define the values of the + different thresholds that might be used to avoid computing + unnecessary noise. High-level functions will use the precision + specified in the =context= variable. In order to automatize numerical accuracy tests, QMCkl uses - [[https://github.com/verificarlo/verificarlo][Verificarlo]] and - its CI functionality. You can read Verificarlo CI's documentation - at the [[https://github.com/verificarlo/verificarlo/blob/master/doc/06-Postprocessing.md#verificarlo-ci][following link]]. - Reading it is advised to understand the remainder of this section. + [[https://github.com/verificarlo/verificarlo][Verificarlo]] and its CI functionality. You can read Verificarlo CI's + documentation at the [[https://github.com/verificarlo/verificarlo/blob/master/doc/06-Postprocessing.md#verificarlo-ci][following link]]. Reading it is advised to + understand the remainder of this section. To enable support for Verificarlo CI tests when building the library, use the following configure command : #+begin_src bash - QMCKL_DEVEL=1 ./configure --prefix=$PWD/_install --enable-silent-rules --enable-maintainer-mode CC=verificarlo-f FC=verificarlo-f --host=x86_64 --enable-vfc_ci + ./configure CC=verificarlo-f FC=verificarlo-f --host=x86_64 --enable-vfc_ci #+end_src Note that this does require an install of Verificarlo *with @@ -290,7 +326,7 @@ cppcheck --addon=cert --enable=all *.c &> cppcheck.out - ~qmckl_probe_check_relative~ : place a probe with a relative check. If ~vfc_ci~ is disabled, this will return the result of a relative check (|val - ref| / ref < accuracy target?). If the check fails, true is returned (false otherwise). - If you need more details on these functions or their Fortran + If you need more detail on these functions or their Fortran interfaces, have a look at the ~tools/qmckl_probes~ files. Finally, if you need to add a QMCkl kernel to the CI tests diff --git a/org/qmckl_ao.org b/org/qmckl_ao.org index 2fd2ed3..5ba081b 100644 --- a/org/qmckl_ao.org +++ b/org/qmckl_ao.org @@ -4843,6 +4843,5 @@ assert( fabs(ao_vgl[1][26][224] - (-3.843864637762753e-09)) < 1.e-14 ); # vim: syntax=c - * TODO [0/1] Missing features :noexport: - [ ] Error messages to tell what is missing when initializing diff --git a/org/qmckl_context.org b/org/qmckl_context.org index 7b26a7f..5dadf94 100644 --- a/org/qmckl_context.org +++ b/org/qmckl_context.org @@ -28,6 +28,7 @@ int main() { #include "qmckl_error_private_type.h" #include "qmckl_memory_private_type.h" #include "qmckl_numprec_private_type.h" +#include "qmckl_point_private_type.h" #include "qmckl_nucleus_private_type.h" #include "qmckl_electron_private_type.h" #include "qmckl_ao_private_type.h" @@ -35,6 +36,7 @@ int main() { #include "qmckl_jastrow_private_type.h" #include "qmckl_determinant_private_type.h" #include "qmckl_local_energy_private_type.h" +#include "qmckl_point_private_func.h" #include "qmckl_nucleus_private_func.h" #include "qmckl_electron_private_func.h" #include "qmckl_ao_private_func.h" @@ -121,6 +123,9 @@ typedef struct qmckl_context_struct { /* Current date */ uint64_t date; + /* Points */ + qmckl_point_struct *point; + /* -- Molecular system -- */ qmckl_nucleus_struct nucleus; qmckl_electron_struct electron; @@ -236,6 +241,9 @@ qmckl_context qmckl_context_create() { 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); diff --git a/org/qmckl_point.org b/org/qmckl_point.org new file mode 100644 index 0000000..5593299 --- /dev/null +++ b/org/qmckl_point.org @@ -0,0 +1,591 @@ +#+TITLE: Point +#+SETUPFILE: ../tools/theme.setup +#+INCLUDE: ../tools/lib.org + +This data structure contains cartesian coordinates where the functions +will be evaluated. For DFT codes these may be the integration grid +points. For QMC codes, these are the electron coordinates of all the +walkers. + +* Headers :noexport: + #+begin_src elisp :noexport :results none +(org-babel-lob-ingest "../tools/lib.org") +#+end_src + + + #+begin_src c :tangle (eval h_private_type) +#ifndef QMCKL_POINT_HPT +#define QMCKL_POINT_HPT +#include + #+end_src + + #+begin_src c :tangle (eval h_private_func) +#ifndef QMCKL_POINT_HPF +#define QMCKL_POINT_HPF + #+end_src + + #+begin_src c :tangle (eval c_test) :noweb yes +#include "qmckl.h" +#include +#include +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "chbrclf.h" + +int main() { + qmckl_context context; + context = qmckl_context_create(); + #+end_src + + #+begin_src c :tangle (eval c) +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_STDINT_H +#include +#elif HAVE_INTTYPES_H +#include +#endif + +#include +#include +#include +#include +#include + +#include + +#include "qmckl.h" +#include "qmckl_context_private_type.h" +#include "qmckl_memory_private_type.h" +#include "qmckl_memory_private_func.h" +#include "qmckl_point_private_func.h" + #+end_src + +* Context + + The following data stored in the context: + + | Variable | Type | Description | + |-----------+---------------+------------------------| + | ~num~ | ~int64_t~ | Total number of points | + | ~coord_x~ | ~double[num]~ | X coordinates | + | ~coord_y~ | ~double[num]~ | Y coordinates | + | ~coord_z~ | ~double[num]~ | Z coordinates | + + We consider that 'transposed' and 'normal' storage follows the convention: + + | | Normal | Transposed | + |---------+------------------+------------------| + | C | ~[point_num][3]~ | ~[3][point_num]~ | + | Fortran | ~(3,point_num)~ | ~(point_num,3)~ | + +** Data structure + + #+begin_src c :comments org :tangle (eval h_private_type) +typedef struct qmckl_point_struct { + double* coord_x; + double* coord_y; + double* coord_z; + int64_t num; +} qmckl_point_struct; + + #+end_src + + #+begin_src c :comments org :tangle (eval h_private_func) +qmckl_exit_code qmckl_init_point(qmckl_context context); + #+end_src + + #+begin_src c :comments org :tangle (eval c) +qmckl_exit_code qmckl_init_point(qmckl_context context) { + + if (qmckl_context_check(context) == QMCKL_NULL_CONTEXT) { + return false; + } + + qmckl_context_struct* const ctx = (qmckl_context_struct* const) context; + assert (ctx != NULL); + + qmckl_memory_info_struct mem_info = qmckl_memory_info_struct_zero; + mem_info.size = sizeof(qmckl_point_struct); + ctx->point = (qmckl_point_struct*) qmckl_malloc(context, mem_info); + if (ctx->point == NULL) { + return qmckl_failwith( context, + QMCKL_ALLOCATION_FAILED, + "qmckl_init_point", + NULL); + } + memset(ctx->point, 0, sizeof(qmckl_point_struct)); + + return QMCKL_SUCCESS; +} + #+end_src + +** Access functions + + Access functions return ~QMCKL_SUCCESS~ when the data has been + successfully retrieved. They return ~QMCKL_INVALID_CONTEXT~ when + the context is not a valid context. If the function returns + successfully, the variable pointed by the pointer given in argument + contains the requested data. Otherwise, this variable is untouched. + +*** Number of points + + #+begin_src c :comments org :tangle (eval h_func) :exports none +qmckl_exit_code qmckl_get_point_num (const qmckl_context context, int64_t* const num); + #+end_src + + Returns the number of points stored in the context. + + #+begin_src c :comments org :tangle (eval c) :noweb yes :exports none +qmckl_exit_code +qmckl_get_point_num (const qmckl_context context, int64_t* const num) { + + if (qmckl_context_check(context) == QMCKL_NULL_CONTEXT) { + return QMCKL_INVALID_CONTEXT; + } + + if (num == NULL) { + return qmckl_failwith( context, + QMCKL_INVALID_ARG_2, + "qmckl_get_point_num", + "num is a null pointer"); + } + + qmckl_context_struct* const ctx = (qmckl_context_struct* const) context; + assert (ctx != NULL); + assert (ctx->point != NULL); + + assert (ctx->point->num > (int64_t) 0); + ,*num = ctx->point->num; + return QMCKL_SUCCESS; +} + #+end_src + + #+begin_src f90 :comments org :tangle (eval fh_func) :noweb yes +interface + integer(c_int32_t) function qmckl_get_point_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 +end interface + #+end_src + +*** Point coordinates + + #+begin_src c :comments org :tangle (eval h_func) :exports none +qmckl_exit_code qmckl_get_point(const qmckl_context context, + double* const coord, + const int64_t size_max); + #+end_src + + Returns the point coordinates as sequences of (x,y,z). + The pointer is assumed to point on a memory block of size + ~size_max~ \ge ~3 * point_num~. + + #+begin_src c :comments org :tangle (eval c) :noweb yes :exports none +qmckl_exit_code +qmckl_get_point(const qmckl_context context, + double* const coord, + const int64_t size_max) +{ + + if (qmckl_context_check(context) == QMCKL_NULL_CONTEXT) { + return QMCKL_INVALID_CONTEXT; + } + + if (coord == NULL) { + return qmckl_failwith( context, + QMCKL_INVALID_ARG_2, + "qmckl_get_point_coord", + "coord is a null pointer"); + } + + qmckl_context_struct* const ctx = (qmckl_context_struct* const) context; + assert (ctx != NULL); + assert (ctx->point != NULL); + + int64_t point_num = ctx->point->num; + + assert (ctx->point->coord_x != NULL); + assert (ctx->point->coord_y != NULL); + assert (ctx->point->coord_z != NULL); + + if (size_max < 3*point_num) { + return qmckl_failwith( context, + QMCKL_INVALID_ARG_3, + "qmckl_get_point_coord", + "size_max too small"); + } + + + double * ptr = coord; + for (int64_t i=0 ; ipoint->coord_x[i]; ++ptr; + ,*ptr = ctx->point->coord_y[i]; ++ptr; + ,*ptr = ctx->point->coord_z[i]; ++ptr; + } + + return QMCKL_SUCCESS; +} + + #+end_src + + #+begin_src f90 :comments org :tangle (eval fh_func) :noweb yes +interface + integer(c_int32_t) function qmckl_get_point(context, coord, 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) :: coord(*) + integer (c_int64_t) , intent(in) :: size_max + end function +end interface + #+end_src + + + #+begin_src c :comments org :tangle (eval h_func) :exports none +qmckl_exit_code qmckl_get_point_xyz (const qmckl_context context, + double* const coord_x, + double* const coord_y, + double* const coord_z, + const int64_t size_max); + #+end_src + + Returns the point coordinates in three different arrays, one for + each component x,y,z. + The pointers are assumed to point on a memory block of size + ~size_max~ \ge ~point_num~. + + #+begin_src c :comments org :tangle (eval c) :noweb yes :exports none +qmckl_exit_code +qmckl_get_point_xyz (const qmckl_context context, + double* const coord_x, + double* const coord_y, + double* const coord_z, + const int64_t size_max) +{ + + if (qmckl_context_check(context) == QMCKL_NULL_CONTEXT) { + return QMCKL_INVALID_CONTEXT; + } + + if (coord_x == NULL) { + return qmckl_failwith( context, + QMCKL_INVALID_ARG_2, + "qmckl_get_point_coord_xyz", + "coord_x is a null pointer"); + } + + if (coord_y == NULL) { + return qmckl_failwith( context, + QMCKL_INVALID_ARG_3, + "qmckl_get_point_coord_xyz", + "coord_y is a null pointer"); + } + + if (coord_z == NULL) { + return qmckl_failwith( context, + QMCKL_INVALID_ARG_4, + "qmckl_get_point_coord_xyz", + "coord_z is a null pointer"); + } + + qmckl_context_struct* const ctx = (qmckl_context_struct* const) context; + assert (ctx != NULL); + assert (ctx->point != NULL); + + int64_t point_num = ctx->point->num; + + assert (ctx->point->coord_x != NULL); + assert (ctx->point->coord_y != NULL); + assert (ctx->point->coord_z != NULL); + + if (size_max < point_num) { + return qmckl_failwith( context, + QMCKL_INVALID_ARG_5, + "qmckl_get_point_coord_xyz", + "size_max too small"); + } + + memcpy(coord_x, ctx->point->coord_x, point_num*sizeof(double)); + memcpy(coord_y, ctx->point->coord_y, point_num*sizeof(double)); + memcpy(coord_z, ctx->point->coord_z, point_num*sizeof(double)); + + return QMCKL_SUCCESS; +} + #+end_src + + #+begin_src f90 :comments org :tangle (eval fh_func) :noweb yes +interface + integer(c_int32_t) function qmckl_get_point_xyz(context, & + coord_x, coord_y, coord_z, 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) :: coord_x(*) + real (c_double ) , intent(out) :: coord_y(*) + real (c_double ) , intent(out) :: coord_z(*) + integer (c_int64_t) , intent(in) :: size_max + end function +end interface + #+end_src + +** Initialization functions + + When the data is set in the context, if the arrays are large + enough, we overwrite the data contained in them. + + #+NAME: check_alloc + #+begin_src c :exports none + if (qmckl_context_check(context) == QMCKL_NULL_CONTEXT) { + return QMCKL_NULL_CONTEXT; + } + + qmckl_context_struct* const ctx = (qmckl_context_struct* const) context; + assert (ctx != NULL); + assert (ctx->point != NULL); + + if (ctx->point->num < num) { + + if (ctx->point->coord_x != NULL) { + qmckl_free(context, ctx->point->coord_x); + ctx->point->coord_x = NULL; + } + + if (ctx->point->coord_y != NULL) { + qmckl_free(context, ctx->point->coord_y); + ctx->point->coord_y = NULL; + } + + if (ctx->point->coord_z != NULL) { + qmckl_free(context, ctx->point->coord_z); + ctx->point->coord_z = NULL; + } + + qmckl_memory_info_struct mem_info = qmckl_memory_info_struct_zero; + mem_info.size = num*sizeof(double); + + ctx->point->coord_x = (double*) qmckl_malloc(context, mem_info); + if (ctx->point->coord_x == NULL) { + return qmckl_failwith( context, + QMCKL_ALLOCATION_FAILED, + "qmckl_set_point", + NULL); + } + + ctx->point->coord_y = (double*) qmckl_malloc(context, mem_info); + if (ctx->point->coord_y == NULL) { + return qmckl_failwith( context, + QMCKL_ALLOCATION_FAILED, + "qmckl_set_point", + NULL); + } + + ctx->point->coord_z = (double*) qmckl_malloc(context, mem_info); + if (ctx->point->coord_z == NULL) { + return qmckl_failwith( context, + QMCKL_ALLOCATION_FAILED, + "qmckl_set_point", + NULL); + } + }; + + ctx->point->num = num; + #+end_src + + To set the data relative to the points in the context, one of the + following functions need to be called. + + #+begin_src c :comments org :tangle (eval h_func) +qmckl_exit_code qmckl_set_point (qmckl_context context, + const double* coord, + const int64_t num); + #+end_src + + Copy a sequence of (x,y,z) into the context. + + #+begin_src c :comments org :tangle (eval c) :noweb yes +qmckl_exit_code +qmckl_set_point (qmckl_context context, + const double* coord, + const int64_t num) +{ + + <> + + for (int64_t i=0 ; ipoint->coord_x[i] = coord[3*i ]; + ctx->point->coord_y[i] = coord[3*i+1]; + ctx->point->coord_z[i] = coord[3*i+2]; + } + + return QMCKL_SUCCESS; + +} + #+end_src + + #+begin_src f90 :comments org :tangle (eval fh_func) :noweb yes +interface + integer(c_int32_t) function qmckl_set_point(context, & + coord_x, coord_y, coord_z, size_max) bind(C) + use, intrinsic :: iso_c_binding + import + implicit none + + integer (c_int64_t) , intent(in) , value :: context + real (c_double ) , intent(in) :: coord_x(*) + real (c_double ) , intent(in) :: coord_y(*) + real (c_double ) , intent(in) :: coord_z(*) + integer (c_int64_t) , intent(in) , value :: size_max + end function +end interface + #+end_src + + #+begin_src c :comments org :tangle (eval h_func) +qmckl_exit_code qmckl_set_point_xyz (qmckl_context context, + const double* coord_x, + const double* coord_y, + const double* coord_z, + const int64_t num); + #+end_src + + #+begin_src c :comments org :tangle (eval c) :noweb yes +qmckl_exit_code +qmckl_set_point_xyz (qmckl_context context, + const double* coord_x, + const double* coord_y, + const double* coord_z, + const int64_t num) +{ + + <> + + memcpy(ctx->point->coord_x, coord_x, num*sizeof(double)); + memcpy(ctx->point->coord_y, coord_y, num*sizeof(double)); + memcpy(ctx->point->coord_z, coord_z, num*sizeof(double)); + + return QMCKL_SUCCESS; +} + #+end_src + + #+begin_src f90 :comments org :tangle (eval fh_func) :noweb yes +interface + integer(c_int32_t) function qmckl_set_point_xyz(context, & + coord_x, coord_y, coord_z, size_max) bind(C) + use, intrinsic :: iso_c_binding + import + implicit none + + integer (c_int64_t) , intent(in) , value :: context + real (c_double ) , intent(in) :: coord_x(*) + real (c_double ) , intent(in) :: coord_y(*) + real (c_double ) , intent(in) :: coord_z(*) + integer (c_int64_t) , intent(in) , value :: size_max + end function +end interface + #+end_src + + +** Test + + #+begin_src c :tangle (eval c_test) +/* Reference input data */ +int64_t point_num = chbrclf_elec_num; +double* coord = &(chbrclf_elec_coord[0][0][0]); + +/* --- */ + +qmckl_exit_code rc; + +rc = qmckl_set_point (context, coord, point_num); +assert(rc == QMCKL_SUCCESS); + +int64_t n; +rc = qmckl_get_point_num (context, &n); +assert(rc == QMCKL_SUCCESS); +assert(n == point_num); + +double coord2[point_num*3]; +double coord_x[point_num]; +double coord_y[point_num]; +double coord_z[point_num]; + +rc = qmckl_get_point_xyz (context, coord_x, coord_y, coord_z, point_num); +assert(rc == QMCKL_SUCCESS); + +rc = qmckl_get_point (context, coord2, (point_num*3)); +assert(rc == QMCKL_SUCCESS); + +for (int64_t i=0 ; i<3*point_num ; ++i) { + assert( coord[i] == coord2[i] ); +} + +for (int64_t i=0 ; i