The qmckl.h header file has to be included in C codes when
@@ -385,12 +385,12 @@ Both files are located in the include/ directory.
-
-
2 Developing in QMCkl
+
+
2 Developing in QMCkl
-
-
2.1 Literate programming
+
+
2.1 Literate programming
In a traditional source code, most of the lines of source files of a program
@@ -435,9 +435,8 @@ interactively, in the same spirit as Jupyter notebooks.
-
-
-
2.2 Source code editing
+
+
2.2 Source code editing
For a tutorial on literate programming with org-mode, follow this link.
@@ -468,9 +467,8 @@ org-mode.
-
-
-
2.3 Choice of the programming language
+
+
2.3 Choice of the programming language
Most of the codes of the TREX CoE are written in Fortran with some scripts in
@@ -508,7 +506,7 @@ 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. Fortran interfaces should also be written in the qmckl_f.f90 file.
+_f.
@@ -518,25 +516,27 @@ For more guidelines on using Fortran to generate a C interface, see
The proposed API should allow the library to: deal with memory transfers
@@ -547,8 +547,8 @@ functions (see below).
-
-
2.6 Naming conventions
+
+
2.6 Naming conventions
To avoid namespace collisions, we use qmckl_ as a prefix for all exported
@@ -573,8 +573,8 @@ form is allowed.
-
-
2.7 Application programming interface
+
+
2.7 Application programming interface
In the C language, the number of bits used by the integer types can change
@@ -595,8 +595,7 @@ than C, we restrict the data types in the interfaces to the following:
and terminated by a '\0' character (C convention).
Complex numbers can be represented by an array of 2 floats.
Boolean variables are stored as integers, 1 for true and 0 for false
-
Floating point variables should be by default
-
double unless explicitly mentioned
+
Floating point variables should be by default double unless explicitly mentioned
integers used for counting should always be int64_t
@@ -607,15 +606,15 @@ bindings in other languages in other repositories.
-
-
2.8 Global state
+
+
2.8 Global state
Global variables should be avoided in the library, because it is
possible that one single program needs to use multiple instances
of the library. To solve this problem we propose to use a pointer
to a context variable, built by the library with the
-qmckl_context_create function. The =context= contains the global
+qmckl_context_create function. The =context= contains the global
state of the library, and is used as the first argument of many
QMCkl functions.
@@ -624,36 +623,119 @@ QMCkl functions.
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
-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
-versions can be destroyed with qmckl_context_destroy.
+qmckl_set_ an qmckl_get_.
-
-
2.9 Low-level functions
+
+
2.9 Headers
+A single qmckl.h header to be distributed by the library
+is built by concatenating some of the produced header files.
+To facilitate building the qmckl.h file, we separate types from
+function declarations in headers. Types should be defined in header
+files suffixed by _type.h, and functions in files suffixed by
+_func.h.
+As these files will be concatenated in a single file, they should
+not be guarded by #ifndef *_H, and they should not include other
+produced headers.
+
+
+
+Some particular types that are not exported need to be known by the
+context, and there are some functions to update instances of these
+types contained inside the context. For example, a
+qmckl_numprec_struct is present in the context, and the function
+qmckl_set_numprec_range takes a context as a parameter, and set a
+value in the qmckl_numprec_struct contained in the context.
+Because of these intricate dependencies, a private header is
+created, containing the qmckl_numprec_struct. This header is
+included in the private header which defines the type of the
+context. Headers for private types are suffixed by _private_type.h
+and headers for private functions, _private_func.h.
+Fortran interfaces should also be written in the *_f_func.f90 file,
+and the types definitions should be written in the *_f_type.f90 file.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
File
+
Scope
+
Description
+
+
+
+
+
*_type.h
+
Public
+
Type definitions
+
+
+
+
*_func.h
+
Public
+
Function definitions
+
+
+
+
*_private_type.h
+
Private
+
Type definitions
+
+
+
+
*_private_func.h
+
Private
+
Function definitions
+
+
+
+
*fh_type.f90
+
Public
+
Fortran type definitions
+
+
+
+
*fh_func.f90
+
Public
+
Fortran function definitions
+
+
+
+
+
+
+
+
2.10 Low-level functions
+
+
Low-level functions are very simple functions which are leaves of
the function call tree (they don't call any other QMCkl function).
These functions are pure, and unaware of the QMCkl
-context. They are not allowed to allocate/deallocate memory, and
+context. They are not allowed to allocate/deallocate memory, and
if they need temporary memory it should be provided in input.
-
-
2.10 High-level functions
-
+
+
2.11 High-level functions
+
High-level functions are at the top of the function call tree.
They are able to choose which lower-level function to call
@@ -665,28 +747,28 @@ 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.
+the context variable.
-
-
2.11 Numerical precision
-
+
+
2.12 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
+functions will use the precision specified in the context
variable.
-
-
2.12 Algorithms
-
+
+
2.13 Algorithms
+
Reducing the scaling of an algorithm usually implies also reducing
its arithmetic complexity (number of flops per byte). Therefore,
@@ -697,23 +779,11 @@ implemented adapted to different problem sizes.
-
-
-
2.13 Rules for the API
-
-
-
stdint should be used for integers (int32_t, int64_t)
-
integers used for counting should always be int64_t
-
floats should be by default double, unless explicitly mentioned
-
pointers are converted to int64_t to increase portability
-The atomic basis set is defined as a list of shells. Each shell \(s\) is
-centered on a nucleus \(A\), possesses a given angular momentum \(l\) and a
-radial function \(R_s\). The radial function is a linear combination of
-\emph{primitive} functions that can be of type Slater (\(p=1\)) or
-Gaussian (\(p=2\)):
-
-In the case of Gaussian functions, \(n_s\) is always zero.
-The normalization factor \(\mathcal{N}_s\) ensures that all the functions
-of the shell are normalized to unity. As this normalization requires
-the ability to compute overlap integrals, it should be written in the
-file to ensure that the file is self-contained and does not require
-the client program to have the ability to compute such integrals.
-
-where \(\theta(i)\) returns the shell on which the AO is expanded,
-and \(\eta(i)\) denotes which angular function is chosen.
-
-
-
-In this section we describe the kernels used to compute the values,
-gradients and Laplacian of the atomic basis functions.
-
-
-
-
1 Polynomial part
+
+
1 Context
-
-
-
1.1 Powers of \(x-X_i\)
-
-The qmckl_ao_power function computes all the powers of the n
-input data up to the given maximum value given in input for each of
-the \(n\) points:
-
-
-
-\[ P_{ik} = X_i^k \]
+The following arrays are stored in the context:
@@ -418,47 +397,1122 @@ the \(n\) points:
-
context
-
input
-
Global state
+
type
+
+
Gaussian ('G') or Slater ('S')
-
n
-
input
-
Number of values
+
shell_num
+
+
Number of shells
-
X(n)
-
input
-
Array containing the input values
+
prim_num
+
+
Total number of primitives
-
LMAX(n)
-
input
-
Array containing the maximum power for each value
+
shell_center
+
[shell_num]
+
Id of the nucleus on which each shell is centered
-
P(LDP,n)
-
output
-
Array containing all the powers of X
+
shell_ang_mom
+
[shell_num]
+
Angular momentum of each shell
-
LDP
-
input
-
Leading dimension of array P
+
shell_prim_num
+
[shell_num]
+
Number of primitives in each shell
+
+
+
+
shell_prim_index
+
[shell_num]
+
Address of the first primitive of each shell in the EXPONENT array
+
+
+
+
shell_factor
+
[shell_num]
+
Normalization factor for each shell
+
+
+
+
exponent
+
[prim_num]
+
Array of exponents
+
+
+
+
coefficient
+
[prim_num]
+
Array of coefficients
-Requirements:
+For H2 with the following basis set,
+The uninitialized integer contains one bit set to one for each
+initialization function which has not bee called. It becomes equal
+to zero after all initialization functions have been called. The
+struct is then initialized and provided == 1.
+
+
+
+
+
+
1.2 Access functions
+
+
+Access to scalars copies the values at the passed address, and
+for array values a pointer to the array is returned.
+
+The qmckl_ao_power function computes all the powers of the n
+input data up to the given maximum value given in input for each of
+the \(n\) points:
+
+
+
+\[ P_{ik} = X_i^k \]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
qmcklcontext
+
context
+
in
+
Global state
+
+
+
+
int64t
+
n
+
in
+
Number of values
+
+
+
+
double
+
X[n]
+
in
+
Array containing the input values
+
+
+
+
int32t
+
LMAX[n]
+
in
+
Array containing the maximum power for each value
+
+
+
+
double
+
P[n][ldp]
+
out
+
Array containing all the powers of X
+
+
+
+
int64t
+
ldp
+
in
+
Leading dimension of array P
+
+
+
+
+
+
+
2.1.1 Requirements:
+
context is not QMCKL_NULL_CONTEXT
n > 0
@@ -467,18 +1521,28 @@ Requirements:
P is allocated with at least \(n \times \max_i \text{LMAX}_i \times 8\) bytes
integer functionqmckl_ao_polynomial_vgl_f(context, X, R, lmax, n, L, ldl, VGL, ldv) result(info)useqmckl
@@ -856,8 +1954,20 @@ For example, with a=0, b=2 and c=1 the string is "yyz"
end functionqmckl_ao_polynomial_vgl_f
+
+
+
+
2.2.4 C interface
+
+
+
2.2.5 Fortran interface
+
+
+
+
2.2.6 Test
+
integer(c_int32_t) functiontest_qmckl_ao_polynomial_vgl(context) bind(C)
useqmckl
@@ -873,7 +1983,7 @@ For example, with a=0, b=2 and c=1 the string is "yyz"
double precision :: wdouble precision :: epsilon
- epsilon = qmckl_context_get_epsilon(context)
+ epsilon = qmckl_get_numprec_epsilon(context)
X = (/ 1.1 , 2.2 , 3.3 /)
R = (/ 0.1 , 1.2 , -2.3 /)
@@ -959,10 +2069,15 @@ munit_assert_int(0, ==, test_qmckl_ao_polynomial_vgl(context));
+
-
-
2 Gaussian basis functions
-
+
+
3 Radial part
+
+
+
+
3.1 Gaussian basis functions
+
qmckl_ao_gaussian_vgl computes the values, gradients and
Laplacians at a given point of n Gaussian functions centered at
@@ -1135,7 +2250,7 @@ Requirements :
double precision, allocatable :: VGL(:,:), A(:)double precision :: epsilon
- epsilon = qmckl_context_get_epsilon(context)
+ epsilon = qmckl_get_numprec_epsilon(context)
X = (/ 1.1 , 2.2 , 3.3 /)
R = (/ 0.1 , 1.2 , -2.3 /)
@@ -1193,13 +2308,21 @@ Requirements :
The context variable is a handle for the state of the library,
and is stored in a data structure which can't be seen outside of
-the library. To simplify compatibility with other languages, the
+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 QMCKL_NULL_CONTEXT for the context is equivalent to a
@@ -396,21 +338,16 @@ A value of QMCKL_NULL_CONTEXT for the context is equivalent to a
-The context appears as an immutable data structure: modifying a
-context returns a new context with the modifications. Therefore, it
-is necessary to store a pointer to the old version of context so
-that it can be freed when necessary.
-Note that we also provide a possibility to mutate the context, but
-this should be done with caution, only when it is justified.
+An immutable context would have required to implement a garbage
+collector. To keep the library simple, we have chosen to implement
+the context as a mutable data structure, so it has to be handled
+with care.
@@ -419,52 +356,15 @@ and ctx is a qmckl_context_struct* pointer.
-
-
1.1 Data structure
+
+
1.1 Data structure
-The main data structure contains pointers to other data structures,
-containing the data specific to each given domain, such that the
-modified contexts don't need to duplicate the data but only the
-pointers.
+When a new element is added to the context, the functions
+qmcklcontextcreate, qmcklcontextdestroy and qmcklcontextcopy
+should be updated inorder to make deep copies.
A tag is used internally to check if the memory domain pointed
@@ -496,7 +396,7 @@ if the context is valid, QMCKL_NULL_CONTEXT otherwise.
if (context == QMCKL_NULL_CONTEXT)
return QMCKL_NULL_CONTEXT;
- constqmckl_context_struct* ctx = (qmckl_context_struct*) context;
+ constqmckl_context_struct* constctx = (constqmckl_context_struct* const) context;
/* Try to access memory */
if (ctx->tag != VALID_TAG) {
@@ -510,8 +410,8 @@ if the context is valid, QMCKL_NULL_CONTEXT otherwise.
-
-
1.2 Creation
+
+
1.2 Creation
To create a new context, qmckl_context_create() should be used.
@@ -524,57 +424,69 @@ To create a new context, qmckl_context_create() should be used.
For thread safety, the context may be locked/unlocked. The lock is
initialized with the PTHREAD_MUTEX_RECURSIVE attribute, and the
@@ -583,47 +495,32 @@ number of times the thread has locked it is saved in the
-qmckl_context_copy makes a shallow copy of a context. It returns
+qmckl_context_copy makes a deep copy of a context. It returns
QMCKL_NULL_CONTEXT upon failure.
qmckl_contextqmckl_context_copy(constqmckl_contextcontext) {
- qmckl_lock(context);
-
constqmckl_contextchecked_context = qmckl_context_check(context);
if (checked_context == QMCKL_NULL_CONTEXT) {
- qmckl_unlock(context);
return QMCKL_NULL_CONTEXT;
}
+ /*
+ qmckl_lock(context);
+ {
- qmckl_context_struct* old_ctx =
- (qmckl_context_struct*) checked_context;
+ const qmckl_context_struct* const old_ctx =
+ (qmckl_context_struct* const) checked_context;
- qmckl_context_struct* new_ctx =
- (qmckl_context_struct*) qmckl_malloc (context, sizeof(qmckl_context_struct));
+ qmckl_context_struct* const new_ctx =
+ (qmckl_context_struct* const) malloc (context, sizeof(qmckl_context_struct));
- if (new_ctx == NULL) {
- qmckl_unlock(context);
+ if (new_ctx == NULL) {
+ qmckl_unlock(context);
+ return QMCKL_NULL_CONTEXT;
+ }
+
+ * Copy the old context on the new one *
+ * TODO Deep copies should be done here *
+ memcpy(new_ctx, old_ctx, sizeof(qmckl_context_struct));
+
+ qmckl_unlock( (qmckl_context) new_ctx );
+
+ return (qmckl_context) new_ctx;
+ }
+ qmckl_unlock(context);
+*/
return QMCKL_NULL_CONTEXT;
- }
-
- /* Copy the old context on the new one */
- memcpy(new_ctx, old_ctx, sizeof(qmckl_context_struct));
-
- new_ctx->prev = old_ctx;
-
- qmckl_unlock( (qmckl_context) new_ctx );
- qmckl_unlock( (qmckl_context) old_ctx );
-
- return (qmckl_context) new_ctx;
}
-
-
1.6 Destroy
-
+
+
1.5 Destroy
+
The context is destroyed with qmckl_context_destroy, leaving the ancestors untouched.
It frees the context, and returns the previous context.
qmckl_exit_codeqmckl_context_destroy(constqmckl_contextcontext) {
constqmckl_contextchecked_context = qmckl_context_check(context);
- if (checked_context == QMCKL_NULL_CONTEXT) return QMCKL_NULL_CONTEXT;
+ if (checked_context == QMCKL_NULL_CONTEXT) return QMCKL_INVALID_CONTEXT;
+
+ qmckl_context_struct* constctx = (qmckl_context_struct* const) context;
+ assert (ctx != NULL); /* Shouldn't be possible because the context is valid */
qmckl_lock(context);
-
- qmckl_context_struct* ctx = (qmckl_context_struct*) context;
- assert (ctx != NULL); /* Shouldn't be true because the context is valid */
-
- qmckl_unlock(context);
-
- constqmckl_contextprev_context = (qmckl_context) ctx->prev;
- if (prev_context == QMCKL_NULL_CONTEXT) {
- /* This is the first context, free all memory. */
- structqmckl_memory_struct* new = NULL;
- while (ctx->alloc != NULL) {
- new = ctx->alloc->next;
- free(ctx->alloc->pointer);
- ctx->alloc->pointer = NULL;
- free(ctx->alloc);
- ctx->alloc = new;
+ {
+ /* Memory: Remove all allocated data */
+ for (size_tpos = (size_t) 0 ; pos < ctx->memory.array_size ; ++pos) {
+ if (ctx->memory.element[pos].pointer != NULL) {
+ free(ctx->memory.element[pos].pointer);
+ memset( &(ctx->memory.element[pos]), 0, sizeof(qmckl_memory_info_struct) );
+ ctx->memory.n_allocated -= 1;
+ }
}
+ assert (ctx->memory.n_allocated == (size_t) 0);
+ free(ctx->memory.element);
+ ctx->memory.element = NULL;
+ ctx->memory.array_size = (size_t) 0;
}
-
- qmckl_exit_coderc;
- rc = qmckl_context_remove_memory(context,ctx);
- assert (rc == QMCKL_SUCCESS);
+ qmckl_unlock(context);
ctx->tag = INVALID_TAG;
constintrc_destroy = pthread_mutex_destroy( &(ctx->mutex) );
if (rc_destroy != 0) {
+/* DEBUG */
fprintf(stderr, "qmckl_context_destroy: %s (count = %d)\n", strerror(rc_destroy), ctx->lock_count);
abort();
}
- rc = qmckl_free(context,ctx);
- assert (rc == QMCKL_SUCCESS);
-
- return prev_context;
-}
-
-
-
-
-
-
-
2 Memory allocation handling
-
-
-
-
2.1 Data structure
-
-
-Pointers to all allocated memory domains are stored in the context,
-in a linked list. The size is also stored, to enable the
-computation of the amount of currently used memory by the library.
-
-The following function, called in qmckl_memory.c, appends a new
-pair (pointer, size) to the data structure.
-It is forbidden to pass the NULL pointer, or a zero size.
-If the context is QMCKL_NULL_CONTEXT, the function returns
-immediately with QMCKL_SUCCESS.
-
-The following function, called in qmckl_memory.c, removes a
-pointer from the data structure.
-It is forbidden to pass the NULL pointer.
-If the context is QMCKL_NULL_CONTEXT, the function returns
-immediately with QMCKL_SUCCESS.
-
-The error is updated in the context using
-qmckl_context_update_error, although it is recommended to use
-qmckl_context_set_error for the immutable variant.
-When the error is set in the context, it is mandatory to specify
-from which function the error is triggered, and a message
-explaining the error. The exit code can't be QMCKL_SUCCESS.
-
-The qmckl_context_set_error function returns a new context with
-the error domain updated.
-
-
-
-
qmckl_context
-qmckl_context_set_error(qmckl_contextcontext,
- constqmckl_exit_codeexit_code,
- constchar* function_name,
- constchar* message)
-{
- /* Passing a function name and a message is mandatory. */
- assert (function_name != NULL);
- assert (message != NULL);
-
- /* Exit codes are assumed valid. */
- assert (exit_code >= 0);
- assert (exit_code != QMCKL_SUCCESS);
- assert (exit_code < QMCKL_INVALID_EXIT_CODE);
-
- /* The context is assumed to be valid */
- if (qmckl_context_check(context) == QMCKL_NULL_CONTEXT)
- return QMCKL_NULL_CONTEXT;
-
- qmckl_contextnew_context = qmckl_context_copy(context);
-
- /* Should be impossible because the context is valid */
- assert (new_context != QMCKL_NULL_CONTEXT);
-
- if (qmckl_context_update_error(new_context,
- exit_code,
- function_name,
- message) != QMCKL_SUCCESS) {
- return context;
- }
-
- return new_context;
-}
-
-
-
-
-
-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.
-
if (x < 0) {
- return qmckl_failwith(context,
- QMCKL_INVALID_ARG_2,
- "qmckl_function",
- "Expected x >= 0");
- }
-
-
-
-
-
-
-
-
4 Control of the numerical precision
-
-
-Controlling numerical precision enables optimizations. Here, the
-default parameters determining the target numerical precision and
-range are defined.
-
-
-
-
-
-
-
-
-
-
-
-
-
QMCKL_DEFAULT_PRECISION
-
53
-
-
-
-
QMCKL_DEFAULT_RANGE
-
11
-
-
-
-
-
-
""" This script generates the C and Fortran constants from the org-mode table.
-"""
-
-result = [ "#+begin_src c :comments org :tangle (eval 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 (eval fh) :exports none" ]
-for (text, code) in table:
- text=text.replace("~","")
- result += [ f" integer, parameter :: {text:30s} = {code:d}" ]
-result += [ "#+end_src" ]
-
-return'\n'.join(result)
-
-
-The following functions set and get the required precision and
-range. precision is an integer between 2 and 53, and range is an
-integer between 2 and 11.
-
-
-
-The setter functions functions return a new context as a 64-bit
-integer. The getter functions return the value, as a 32-bit
-integer. The update functions return QMCKL_SUCCESS or
-QMCKL_FAILURE.
-
-
-
-
-
4.1 Precision
-
-
-qmckl_context_update_precision modifies the parameter for the
-numerical precision in a context. If the context doesn't have any
-precision set yet, the default values are used.
-
@@ -348,16 +348,13 @@ for the JavaScript code in this tag.
-
-Functions for the computation of distances between particles.
-
-
-
1 Squared distance
+
+
1 Squared distance
-
-
1.1qmckl_distance_sq
+
+
1.1qmckl_distance_sq
qmckl_distance_sq computes the matrix of the squared distances
@@ -370,7 +367,7 @@ between all pairs of points in two sets, one point within each set:
\]
-
+
@@ -420,7 +417,7 @@ between all pairs of points in two sets, one point within each set:
double
-
A[3][lda]
+
A[][lda]
in
Array containing the \(m \times 3\) matrix \(A\)
@@ -434,7 +431,7 @@ between all pairs of points in two sets, one point within each set:
double
-
B[3][ldb]
+
B[][ldb]
in
Array containing the \(n \times 3\) matrix \(B\)
@@ -463,8 +460,8 @@ between all pairs of points in two sets, one point within each set:
-
-
1.1.1 Requirements
+
+
1.1.1 Requirements
context is not QMCKL_NULL_CONTEXT
@@ -482,8 +479,8 @@ between all pairs of points in two sets, one point within each set:
-
-
1.1.2 C header
+
+
1.1.2 C header
qmckl_exit_codeqmckl_distance_sq (
@@ -496,21 +493,21 @@ between all pairs of points in two sets, one point within each set:
constint64_tlda,
constdouble* B,
constint64_tldb,
- double* C,
+ double* constC,
constint64_tldc );
-
-
1.1.3 Source
+
+
1.1.3 Source
integer functionqmckl_distance_sq_f(context, transa, transb, m, n, A, LDA, B, LDB, C, LDC) result(info)useqmcklimplicitnone
- integer*8 , intent(in) :: context
+ integer(qmckl_context) , intent(in) :: contextcharacter , intent(in) :: transa, transbinteger*8 , intent(in) :: m, ninteger*8 , intent(in) :: lda
@@ -637,8 +634,8 @@ between all pairs of points in two sets, one point within each set:
-
-
1.1.4 Performance
+
+
1.1.4 Performance
This function might be more efficient when A and B are
@@ -651,7 +648,7 @@ transposed.
The library should never make the calling programs abort, nor
perform any input/output operations. This decision has to be taken
@@ -329,10 +333,11 @@ by the developer of the code calling the library.
All the functions return with an exit code, defined as
-
typedefint32_tqmckl_exit_code;
+
typedefint32_tqmckl_exit_code;
+
The exit code returns the completion status of the function to the
calling program. When a function call completed successfully,
@@ -345,7 +350,7 @@ error code is returned to the program.
Here is the complete list of exit codes.
-
+
@@ -468,10 +473,20 @@ Here is the complete list of exit codes.
-The qmckl_strerror converts an exit code into a string. The
+The qmckl_string_of_error converts an exit code into a string. The
string is assumed to be large enough to contain the error message
(typically 128 characters).
+
+
+
+
+
1 Decoding errors
+
+
+To decode the error messages, qmckl_string_of_error converts an
+error code into a string.
+
128
@@ -550,7 +565,8 @@ The text strings are extracted from the previous table.
interfacesubroutineqmckl_string_of_error (error, string) bind(C, name='qmckl_string_of_error_f')
use, intrinsic :: iso_c_binding
- integer (c_int32_t), intent(in), value :: error
+ import
+ integer (qmckl_exit_code), intent(in), value :: errorcharacter, intent(out) :: string(128)end subroutineqmckl_string_of_errorend interface
@@ -558,10 +574,143 @@ The text strings are extracted from the previous table.
+
+
+
2 Data structure in context
+
+
+The strings are declared with a maximum fixed size to avoid
+dynamic memory allocation.
+
+The error is updated in the context using qmckl_set_error.
+When the error is set in the context, it is mandatory to specify
+from which function the error is triggered, and a message
+explaining the error. The exit code can't be QMCKL_SUCCESS.
+
+
+
+
qmckl_exit_code
+qmckl_set_error(qmckl_contextcontext,
+ constqmckl_exit_codeexit_code,
+ constchar* function_name,
+ constchar* message)
+{
+ /* Passing a function name and a message is mandatory. */
+ assert (function_name != NULL);
+ assert (message != NULL);
+
+ /* Exit codes are assumed valid. */
+ assert (exit_code >= 0);
+ assert (exit_code != QMCKL_SUCCESS);
+ assert (exit_code < QMCKL_INVALID_EXIT_CODE);
+
+ /* The context is assumed to exist. */
+ assert (qmckl_context_check(context) != QMCKL_NULL_CONTEXT);
+
+ qmckl_lock(context);
+ {
+ qmckl_context_struct* constctx = (qmckl_context_struct* const) context;
+ assert (ctx != NULL); /* Impossible because the context is valid. */
+
+ ctx->error.exit_code = exit_code;
+ strncpy(ctx->error.function, function_name, QMCKL_MAX_FUN_LEN);
+ strncpy(ctx->error.message, message, QMCKL_MAX_MSG_LEN);
+ }
+ qmckl_unlock(context);
+
+ return QMCKL_SUCCESS;
+}
+
+
+
+
+
+
+
4 Failing
+
+
+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. If the
+message is NULL, then the default message obtained by
+qmckl_string_of_error is used. The return code of the function is
+the desired return code.
+Upon failure, a QMCKL_NULL_CONTEXT is returned.
+
-We override the allocation functions to enable the possibility of
-optimized libraries to fine-tune the memory allocation.
+Every time a new block of memory is allocated, the information
+relative to the allocation is stored in a new qmckl_memory_info_struct.
+A qmckl_memory_info_struct contains the pointer to the memory block,
+its size in bytes, and extra implementation-specific information such as
+alignment, pinning, if the memory should be allocated on CPU or GPU
+etc.
+The memory element of the context is a data structure which
+contains an array of qmckl_memory_info_struct, the size of the
+array, and the number of allocated blocks.
+
+Passing information to the allocation routine should be done by
+passing an instance of a qmckl_memory_info_struct.
+
+
+
+
+
+
3 Allocation/deallocation functions
+
Memory allocation inside the library should be done with
qmckl_malloc. It lets the library choose how the memory will be
@@ -337,51 +387,87 @@ If the allocation failed, the NULL pointer is returned.
+Controlling numerical precision enables optimizations. Here, the
+default parameters determining the target numerical precision and
+range are defined. Following the IEEE Standard for Floating-Point
+Arithmetic (IEEE 754),
+precision refers to the number of significand bits and range
+refers to the number of exponent bits.
+
+The following functions set and get the required precision and
+range. precision is an integer between 2 and 53, and range is an
+integer between 2 and 11.
+
+
+
+The setter functions functions return a new context as a 64-bit
+integer. The getter functions return the value, as a 32-bit
+integer. The update functions return QMCKL_SUCCESS or
+QMCKL_FAILURE.
+
+
+
+
+
+
2 Precision
+
+
+qmckl_context_set_numprec_precision modifies the parameter for the
+numerical precision in the context.
+