diff --git a/index.html b/index.html index dc07312..dd7d4f8 100644 --- a/index.html +++ b/index.html @@ -3,7 +3,7 @@ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
- +The ultimate goal of QMCkl is to provide a high-performance @@ -333,7 +333,7 @@ optimized libraries.
-Literate programming is particularly adapted in this context. +Literate programming is particularly adapted in this context. Source files are written in org-mode format, to provide useful comments and LaTex formulas close to the code. There exists multiple possibilities to convert org-mode files into different formats such @@ -348,21 +348,21 @@ compiled.
-Fortran is one of the most common languages used by the community, +Fortran is one of the most common languages used by the community, and is simple enough to make the algorithms readable. Hence we -propose in this pedagogical implementation of QMCkl to use Fortran +propose in this pedagogical implementation of QMCkl to use Fortran to express the algorithms. For specific internal functions where -the C language is more natural, C is used. +the C language is more natural, C is used.
-As Fortran modules generate compiler-dependent files, the use of +As Fortran modules generate compiler-dependent files, the use of modules is restricted to the internal use of the library, otherwise -the compliance with C is violated. +the compliance with C is violated.
@@ -373,8 +373,8 @@ justified.
Any text editor can be used to edit org-mode files. For a better @@ -409,27 +409,27 @@ And pandoc can convert multiple markdown formats into org-mode.
-The Fortran source files should provide a C interface using
-iso_c_binding
. The name of the Fortran source files should end
+The Fortran source files should provide a C interface using
+iso_c_binding
. 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
. Fortran interface files
+the functions defined in fortran should be the same as those
+exposed in the API suffixed by _f
. Fortran interface files
should also be written in the qmckl_f.f90
file.
-For more guidelines on using Fortran to generate a C interface, see +For more guidelines on using Fortran to generate a C interface, see this link.
To improve readability, we maintain a consistent coding style in @@ -437,8 +437,8 @@ the library.
The proposed API should allow the library to: @@ -465,8 +465,8 @@ functions (see below).
Use qmckl_
as a prefix for all exported functions and variables.
@@ -476,8 +476,8 @@ All exported header files should have a filename with the prefix
If the name of the org-mode file is xxx.org
, the name of the
-produced C files should be xxx.c
and xxx.h
and the name of the
-produced Fortran files should be xxx.f90
+produced C files should be xxx.c
and xxx.h
and the name of the
+produced Fortran files should be xxx.f90
@@ -491,12 +491,12 @@ form is allowed.
The application programming interface (API) is designed to be -compatible with the C programming language (not C++), to ensure +compatible with the C programming language (not C++), to ensure that the library will be easily usable in any language. This implies that only the following data types are allowed in the API:
@@ -507,7 +507,7 @@ implies that only the following data types are allowed in the API:@@ -515,14 +515,14 @@ Complex numbers can be represented by an array of 2 floats.
-To facilitate the use in other languages than C, we provide some +To facilitate the use in other languages than C, we provide some bindings in other languages in other repositories.
Global variables should be avoided in the library, because it is @@ -535,22 +535,22 @@ QMCkl functions.
-The internal structure of the context is not specified, to give a
+The internal structure of the context is not specified, to give a
maximum of freedom to the different implementations. Modifying
the state is done by setters and getters, prefixed by
-qmckl_context_set_
an qmckl_context_get_
. When a context
+qmckl_context_set_
an qmckl_context_get_
. When a context
variable is modified by a setter, a copy of the old data structure
is made and updated, and the pointer to the new data structure is
returned, such that the old contexts can still be accessed. It is
also possible to modify the state in an impure fashion, using the
-qmckl_context_update_
functions. The context and its old
+qmckl_context_update_
functions. The context and its old
versions can be destroyed with qmckl_context_destroy
.
Low-level functions are very simple functions which are leaves of @@ -565,8 +565,8 @@ if they need temporary memory it should be provided in input.
High-level functions are at the top of the function call tree.
@@ -584,8 +584,8 @@ the context
variable.
The number of bits of precision required for a function should be @@ -599,8 +599,8 @@ variable.
Reducing the scaling of an algorithm usually implies also reducing @@ -613,8 +613,8 @@ implemented adapted to different problem sizes.
stdint
should be used for integers (int32_t
, int64_t
)qmckl.h
header fileqmckl.h
header file
-This file produces the qmckl.h
header file, which is to be included
-when qmckl functions are used.
+The qmckl.h
header file has to be included in C codes when
+QMCkl functions are used:
+#+BEGINSRC C :tangle none
+#include "qmckl.h"
+#+ENDSRC f90
-We also create here the qmckl_f.f90
which is the Fortran interface file.
+In Fortran programs, the qmckl_f.f90
interface file should be
+included in the source code using the library, and the Fortran codes
+should use the qmckl
module as
+#+BEGINSRC f90 :tangle none
+use qmckl
+#+ENDSRC f90
-These are the codes returned by the functions to indicate success
-or failure. All such functions should have as a return type qmckl_exit_code
.
-
#define QMCKL_SUCCESS 0 -#define QMCKL_FAILURE 1 - -typedef int32_t qmckl_exit_code; -typedef int64_t qmckl_context ; - -
integer, parameter :: QMCKL_SUCCESS = 0 -integer, parameter :: QMCKL_FAILURE = 0 --
-Controlling numerical precision enables optimizations. Here, the -default parameters determining the target numerical precision and -range are defined. -
- -#define QMCKL_DEFAULT_PRECISION 53 -#define QMCKL_DEFAULT_RANGE 11 --
integer, parameter :: QMCKL_DEFAULT_PRECISION = 53 -integer, parameter :: QMCKL_DEFAULT_RANGE = 11 --
-We override the allocation functions to enable the possibility of -optimized libraries to fine-tune the memory allocation. -
- --2 files are produced: -
-qmckl_memory.c
test_qmckl_memory.c
qmckl_malloc
-Memory allocation function, letting the library choose how the -memory will be allocated, and a pointer is returned to the user. -The context is passed to let the library store data related to the -allocation inside the context. -
- -void* qmckl_malloc(const qmckl_context ctx, const size_t size); --
interface - type (c_ptr) function qmckl_malloc (context, size) bind(C) - use, intrinsic :: iso_c_binding - integer (c_int64_t), intent(in), value :: context - integer (c_int64_t), intent(in), value :: size - end function qmckl_malloc -end interface --
qmckl_free
void* qmckl_free(void *ptr); --
interface - type (c_ptr) function qmckl_free (ptr) bind(C) - use, intrinsic :: iso_c_binding - type (c_ptr), intent(in), value :: ptr - end function qmckl_free -end interface --
-This file is written in C because it is more natural to express the -context in C than in Fortran. +This file is written in C because it is more natural to express the +context in C than in Fortran.
@@ -811,27 +670,51 @@ context in C than in Fortran.
-The context variable is a handle for the state of the library, and
+The context variable is a handle for the state of the library, and
is stored in the following data structure, which can't be seen
outside of the library. To simplify compatibility with other
languages, the pointer to the internal data structure is converted
into a 64-bit signed integer, defined in the qmckl_context
type.
-A value of 0 for the context is equivalent to a NULL
pointer.
+A value of 0
for the context is equivalent to a NULL
pointer.
+typedef int64_t qmckl_context ;
+We define here the the data structure containing the strings +necessary for error handling. +
+ +#define QMCKL_MAX_FUN_LEN 256 +#define QMCKL_MAX_MSG_LEN 1024 + +typedef struct qmckl_error_struct { + + qmckl_exit_code exit_code; + char function[QMCKL_MAX_FUN_LEN]; + char message [QMCKL_MAX_MSG_LEN]; + +} qmckl_error_struct; ++
Data structure for the info related to the atomic orbitals basis set. @@ -840,27 +723,27 @@ basis set.
typedef struct qmckl_ao_basis_struct { - int64_t shell_num; - int64_t prim_num; - int64_t * shell_center; - int32_t * shell_ang_mom; - double * shell_factor; - double * exponent ; - double * coefficient ; + int64_t shell_num; + int64_t prim_num; + int64_t * shell_center; + int32_t * shell_ang_mom; + double * shell_factor; + double * exponent ; + double * coefficient ; int64_t * shell_prim_num; - char type; + char type; } qmckl_ao_basis_struct;
The tag is used internally to check if the memory domain pointed -by a pointer is a valid context. +by a pointer is a valid context.
qmckl_context_check
qmckl_context_update_error
qmckl_exit_code +qmckl_context_update_error(qmckl_context context, const qmckl_exit_code exit_code, const char* function, const char* message); ++
qmckl_exit_code +qmckl_context_update_error(qmckl_context context, const qmckl_exit_code exit_code, const char* function, const char* message) +{ + assert (context != 0); + assert (function != NULL); + assert (message != NULL); + assert (exit_code > 0); + assert (exit_code < QMCKL_INVALID_EXIT_CODE); + + qmckl_context_struct* ctx = (qmckl_context_struct*) context; + if (ctx == NULL) return QMCKL_FAILURE; + + if (ctx->error != NULL) { + free(ctx->error); + ctx->error = NULL; + } + + qmckl_error_struct* error = (qmckl_error_struct*) qmckl_malloc (context, sizeof(qmckl_error_struct)); + error->exit_code = exit_code; + strcpy(error->function, function); + strcpy(error->message, message); + + ctx->error = error; + + return QMCKL_SUCCESS; +} ++
qmckl_context_set_error
qmckl_context +qmckl_context_set_error(qmckl_context context, const qmckl_exit_code exit_code, const char* function, const char* message); ++
qmckl_context +qmckl_context_set_error(qmckl_context context, const qmckl_exit_code exit_code, const char* function, const char* message) +{ + assert (context != 0); + assert (function != NULL); + assert (message != NULL); + assert (exit_code > 0); + assert (exit_code < QMCKL_INVALID_EXIT_CODE); + + qmckl_context new_context = qmckl_context_copy(context); + if (new_context == 0) return context; + + if (qmckl_context_update_error(new_context, exit_code, + function, message) != QMCKL_SUCCESS) { + return context; + } + + return new_context; +} ++
qmckl_context_check
-Checks if the domain pointed by the pointer is a valid context.
-Returns the input qmckl_context
if the context is valid, 0
+Checks if the domain pointed by the pointer is a valid context.
+Returns the input qmckl_context
if the context is valid, 0
otherwise.
qmckl_context qmckl_context_check(const qmckl_context context) { @@ -924,13 +902,13 @@ otherwise. -
qmckl_context_create
qmckl_context_create
-To create a new context, use qmckl_context_create()
.
+To create a new context, use qmckl_context_create()
.
qmckl_context
typeqmckl_context
type
Returns 0
upon failure to allocate the internal data structure
0
upon failure to allocate the internal data structure
qmckl_context qmckl_context_create() { @@ -959,6 +937,7 @@ Returns0
upon failure to allocate the internal data structure context->precision = QMCKL_DEFAULT_PRECISION; context->range = QMCKL_DEFAULT_RANGE; context->tag = VALID_TAG; + context->error = NULL; return (qmckl_context) context; } @@ -967,8 +946,8 @@ Returns0
upon failure to allocate the internal data structure
interface
integer (c_int64_t) function qmckl_context_create() bind(C)
@@ -982,17 +961,17 @@ Returns 0
upon failure to allocate the internal data structure
-
qmckl_context_copy
qmckl_context_copy
-This function makes a shallow copy of the current context. +This function makes a shallow copy of the current context.
qmckl_context
typeqmckl_context
typeReturns 0 upon failure to allocate the internal data structure -for the new context +for the new context
qmckl_context qmckl_context_copy(const qmckl_context context) { @@ -1016,7 +995,7 @@ for the new context qmckl_context_struct* old_context = (qmckl_context_struct*) checked_context; - qmckl_context_struct* new_context = + qmckl_context_struct* new_context = (qmckl_context_struct*) qmckl_malloc (context, sizeof(qmckl_context_struct)); if (new_context == NULL) { return (qmckl_context) 0; @@ -1027,6 +1006,7 @@ for the new context new_context->precision = old_context->precision; new_context->range = old_context->range; new_context->tag = VALID_TAG; + new_context->error = old_context->error; return (qmckl_context) new_context; } @@ -1036,8 +1016,8 @@ for the new context
interface integer (c_int64_t) function qmckl_context_copy(context) bind(C) @@ -1052,16 +1032,16 @@ for the new context -
qmckl_context_previous
qmckl_context_previous
-Returns the previous context +Returns the previous context
-Returns 0 for the 0-valued context +Returns 0 for the 0-valued context
qmckl_context qmckl_context_previous(const qmckl_context context) { @@ -1090,8 +1070,8 @@ Returns 0 for the 0-valued context
interface integer (c_int64_t) function qmckl_context_previous(context) bind(C) @@ -1106,16 +1086,16 @@ Returns 0 for the 0-valued context -
qmckl_context_destroy
qmckl_context_destroy
-Destroys the current context, leaving the ancestors untouched. +Destroys the current context, leaving the ancestors untouched.
qmckl_exit_code qmckl_context_destroy(const qmckl_context context) { @@ -1137,16 +1117,15 @@ Destroys the current context, leaving the ancestors untouched. if (ctx == NULL) return QMCKL_FAILURE; ctx->tag = INVALID_TAG; - qmckl_free(ctx); - return QMCKL_SUCCESS; + return qmckl_free(context,ctx); }
interface integer (c_int32_t) function qmckl_context_destroy(context) bind(C) @@ -1160,14 +1139,11 @@ Destroys the current context, leaving the ancestors untouched. - -
-For H2 with the following basis set, +For H2 with the following basis set,
@@ -1175,7 +1151,7 @@ HYDROGEN S 5 1 3.387000E+01 6.068000E-03 2 5.095000E+00 4.530800E-02 -3 1.159000E+00 2.028220E-01 +3 1.159000E+00 2.028220E-01 4 3.258000E-01 5.039030E-01 5 1.027000E-01 3.834210E-01 S 1 @@ -1210,12 +1186,12 @@ COEFFICIENT = [ 0.006068, 0.045308, 0.202822, 0.503903, 0.383421, 0.503903, 0.383421, 1.0, 1.0, 1.0, 1.0, 1.0]
qmckl_context_update_ao_basis
qmckl_context_update_ao_basis
-Updates the data describing the AO basis set into the context. +Updates the data describing the AO basis set into the context.
QMCKL_SUCCESS |
+0 | +
QMCKL_INVALID_ARG_1 |
+1 | +
QMCKL_INVALID_ARG_2 |
+2 | +
QMCKL_INVALID_ARG_3 |
+3 | +
QMCKL_INVALID_ARG_4 |
+4 | +
QMCKL_INVALID_ARG_5 |
+5 | +
QMCKL_INVALID_ARG_6 |
+6 | +
QMCKL_INVALID_ARG_7 |
+7 | +
QMCKL_INVALID_ARG_8 |
+8 | +
QMCKL_INVALID_ARG_9 |
+9 | +
QMCKL_INVALID_ARG_10 |
+10 | +
QMCKL_NULL_CONTEXT |
+101 | +
QMCKL_FAILURE |
+102 | +
QMCKL_ERRNO |
+103 | +
QMCKL_INVALID_EXIT_CODE |
+104 | +
""" This script generates the C and Fortran constants for the error + codes from the org-mode table. +""" + +result = [ "#+BEGIN_SRC C :comments org :tangle qmckl.h" ] +for (text, code) in table: + text=text.replace("~","") + result += [ f"#define {text:30s} {code:d}" ] +result += [ "#+END_SRC" ] + +result += [ "" ] + +result += [ "#+BEGIN_SRC f90 :comments org :tangle qmckl_f.f90" ] +for (text, code) in table: + text=text.replace("~","") + result += [ f" integer, parameter :: {text:30s} = {code:d}" ] +result += [ "#+END_SRC" ] + +return '\n'.join(result) + ++
#define QMCKL_SUCCESS 0 +#define QMCKL_INVALID_ARG_1 1 +#define QMCKL_INVALID_ARG_2 2 +#define QMCKL_INVALID_ARG_3 3 +#define QMCKL_INVALID_ARG_4 4 +#define QMCKL_INVALID_ARG_5 5 +#define QMCKL_INVALID_ARG_6 6 +#define QMCKL_INVALID_ARG_7 7 +#define QMCKL_INVALID_ARG_8 8 +#define QMCKL_INVALID_ARG_9 9 +#define QMCKL_INVALID_ARG_10 10 +#define QMCKL_NULL_CONTEXT 101 +#define QMCKL_FAILURE 102 +#define QMCKL_ERRNO 103 +#define QMCKL_INVALID_EXIT_CODE 104 ++
integer, parameter :: QMCKL_SUCCESS = 0 +integer, parameter :: QMCKL_INVALID_ARG_1 = 1 +integer, parameter :: QMCKL_INVALID_ARG_2 = 2 +integer, parameter :: QMCKL_INVALID_ARG_3 = 3 +integer, parameter :: QMCKL_INVALID_ARG_4 = 4 +integer, parameter :: QMCKL_INVALID_ARG_5 = 5 +integer, parameter :: QMCKL_INVALID_ARG_6 = 6 +integer, parameter :: QMCKL_INVALID_ARG_7 = 7 +integer, parameter :: QMCKL_INVALID_ARG_8 = 8 +integer, parameter :: QMCKL_INVALID_ARG_9 = 9 +integer, parameter :: QMCKL_INVALID_ARG_10 = 10 +integer, parameter :: QMCKL_NULL_CONTEXT = 101 +integer, parameter :: QMCKL_FAILURE = 102 +integer, parameter :: QMCKL_ERRNO = 103 +integer, parameter :: QMCKL_INVALID_EXIT_CODE = 104 ++
+To make a function fail, the qmckl_failwith
function should be
+called, such that information about the failure is stored in
+the context. The desired exit code is given as an argument, as
+well as the name of the function and an error message. The return
+code of the function is the desired return code.
+
qmckl_exit_code qmckl_failwith(qmckl_context context, + const qmckl_exit_code exit_code, + const char* function, + const char* message) ; ++
qmckl_exit_code qmckl_failwith(qmckl_context context, + const qmckl_exit_code exit_code, + const char* function, + const char* message) { + if (context == 0) return QMCKL_NULL_CONTEXT; + assert (exit_code > 0); + assert (exit_code < QMCKL_INVALID_EXIT_CODE); + assert (function != NULL); + assert (message != NULL); + assert (strlen(function) < QMCKL_MAX_FUN_LEN); + assert (strlen(message) < QMCKL_MAX_MSG_LEN); + + context = qmckl_context_set_error(context, exit_code, function, message); + return exit_code; +} + ++
+For example, this function can be used as +
+if (x < 0) { + return qmckl_failwith(context, + QMCKL_INVALID_ARG_2, + "qmckl_function", + "Expected x >= 0"); + } ++
+Controlling numerical precision enables optimizations. Here, the +default parameters determining the target numerical precision and +range are defined. +
+ +#define QMCKL_DEFAULT_PRECISION 53 +#define QMCKL_DEFAULT_RANGE 11 ++
integer, parameter :: QMCKL_DEFAULT_PRECISION = 53 +integer, parameter :: QMCKL_DEFAULT_RANGE = 11 ++
+We override the allocation functions to enable the possibility of +optimized libraries to fine-tune the memory allocation. +
+ ++2 files are produced: +
+qmckl_memory.c
test_qmckl_memory.c
qmckl_malloc
+Memory allocation function, letting the library choose how the +memory will be allocated, and a pointer is returned to the user. +The context is passed to let the library store data related to the +allocation inside the context. +
+ +void* qmckl_malloc(const qmckl_context ctx, const size_t size); ++
interface + type (c_ptr) function qmckl_malloc (context, size) bind(C) + use, intrinsic :: iso_c_binding + integer (c_int64_t), intent(in), value :: context + integer (c_int64_t), intent(in), value :: size + end function qmckl_malloc +end interface ++
qmckl_free
+The context is passed, in case some important information has been +stored related to memory allocation and needs to be updated. +
+ +qmckl_exit_code qmckl_free(qmckl_context context, void *ptr); ++
interface + integer (c_int32_t) function qmckl_free (context, ptr) bind(C) + use, intrinsic :: iso_c_binding + integer (c_int64_t), intent(in), value :: context + type (c_ptr), intent(in), value :: ptr + end function qmckl_free +end interface ++
Function for the computation of distances between particles.
@@ -1916,18 +2261,18 @@ Function for the computation of distances between particles.qmckl_distance_sq
qmckl_distance_sq
Computes the matrix of the squared distances between all pairs of points in two sets, one point within each set: @@ -1938,8 +2283,8 @@ points in two sets, one point within each set: