mirror of
https://github.com/TREX-CoE/qmckl.git
synced 2025-01-03 01:56:18 +01:00
Added qmckl_point
This commit is contained in:
parent
527b96e3df
commit
c4635e9296
@ -53,7 +53,7 @@ src_qmckl_f = src/qmckl_f.f90
|
|||||||
src_qmckl_fo = src/qmckl_f.o
|
src_qmckl_fo = src/qmckl_f.o
|
||||||
header_tests = tests/chbrclf.h tests/n2.h
|
header_tests = tests/chbrclf.h tests/n2.h
|
||||||
|
|
||||||
fortrandir = $(datadir)/fortran
|
fortrandir = $(datadir)/qmckl/fortran
|
||||||
fortran_DATA = $(src_qmckl_f)
|
fortran_DATA = $(src_qmckl_f)
|
||||||
|
|
||||||
QMCKL_TEST_DIR = $(abs_srcdir)/share/qmckl/test_data/
|
QMCKL_TEST_DIR = $(abs_srcdir)/share/qmckl/test_data/
|
||||||
|
23
configure.ac
23
configure.ac
@ -176,6 +176,22 @@ AX_BLAS([], [AC_MSG_ERROR([BLAS was not found.])])
|
|||||||
## LAPACK
|
## LAPACK
|
||||||
AX_LAPACK([], [AC_MSG_ERROR([LAPACK was not found.])])
|
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.
|
# Options.
|
||||||
|
|
||||||
AC_ARG_ENABLE(debug, [AS_HELP_STRING([--enable-debug],[compile for debugging])], ok=$enableval, ok=no)
|
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])
|
esac],[vfc_ci=false])
|
||||||
AM_CONDITIONAL([VFC_CI], [test x$vfc_ci = xtrue])
|
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
|
if test "$FC" = "verificarlo-f"; then
|
||||||
AC_MSG_NOTICE(verificarlo-f detected)
|
AC_MSG_NOTICE(verificarlo-f detected)
|
||||||
# Arguments order is important here
|
# Arguments order is important here
|
||||||
|
132
org/qmckl.org
132
org/qmckl.org
@ -3,6 +3,33 @@
|
|||||||
#+SETUPFILE: ../tools/theme.setup
|
#+SETUPFILE: ../tools/theme.setup
|
||||||
# -*- mode: org -*-
|
# -*- 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
|
* Using QMCkl
|
||||||
|
|
||||||
The =qmckl.h= header file installed in the =${prefix}/include= directory
|
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
|
Moreover, within the Emacs text editor the source code blocks can be executed
|
||||||
interactively, in the same spirit as Jupyter notebooks.
|
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
|
** 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]].
|
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
|
** 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
|
Most of the codes of the [[https://trex-coe.eu][TREX CoE]] are written in Fortran with some
|
||||||
Bash and Python. Outside of the CoE, Fortran is also important (Casino, Amolqc),
|
scripts in Bash and Python. Outside of the CoE, Fortran is also
|
||||||
and other important languages used by the community are C and C++ (QMCPack,
|
important in QMC codes (Casino, Amolqc), and other important
|
||||||
QWalk), and Julia is gaining in popularity. The library we design should be
|
languages used by the community are C and C++ (QMCPack, QWalk),
|
||||||
compatible with all of these languages. The QMCkl API has to be compatible
|
Julia and Rust are gaining in popularity. We want QMCkl to be
|
||||||
with the C language since libraries with a C-compatible API can be used in
|
compatible with all of these languages, so the QMCkl API has to be
|
||||||
every other language.
|
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
|
High-performance versions of QMCkl, with the same API, can be
|
||||||
the experts in HPC. These optimized libraries will be tuned for specific
|
rewritten by HPC experts. These optimized libraries will be tuned
|
||||||
architectures, among which we can cite x86 based processors, and GPU
|
for specific architectures, among which we can cite x86 based
|
||||||
accelerators. Nowadays, the most efficient software tools to take advantage of
|
processors, and GPU accelerators. Nowadays, the most efficient
|
||||||
low-level features of the processor (intrinsics) and of GPUs are for C++
|
software tools to take advantage of low-level features
|
||||||
developers. It is highly probable that the optimized implementations will be
|
(intrinsics, prefetching, aligned or pinned memory allocation,
|
||||||
written in C++, and this is agreement with our choice to make the API
|
...) are for C++ developers. It is highly probable that optimized
|
||||||
C-compatible.
|
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
|
Fortran is one of the most common languages used by the community,
|
||||||
enough to make the algorithms readable both by experts in QMC, and experts in
|
and is simple enough to make the algorithms readable both by
|
||||||
HPC. Hence we propose in this pedagogical implementation of QMCkl to use Fortran
|
experts in QMC, and experts in HPC. Hence we propose in this
|
||||||
to express the QMC algorithms. As the main languages of the library is C, this
|
pedagogical implementation of QMCkl to use Fortran to express the
|
||||||
implies that the exposed C functions call the Fortran routine. However, for
|
QMC algorithms. However, for internal functions related to system
|
||||||
internal functions related to system programming, the C language is more natural
|
programming, the C language is more natural than Fortran.
|
||||||
than Fortran.
|
|
||||||
|
|
||||||
The Fortran source files should provide a C interface using the
|
As QMCkl appears like a C library, for each Fortran function there
|
||||||
~iso_c_binding~ module. The name of the Fortran source files should end with
|
is an ~iso_c_binding~ interface to make the Fortran function
|
||||||
=_f.f90= to be properly handled by the =Makefile=. The names of the functions
|
callable from C. It is this C interface which is exposed to the
|
||||||
defined in Fortran should be the same as those exposed in the API suffixed by
|
user. As a consequence, the Fortran users of the library never
|
||||||
=_f=.
|
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
|
For more guidelines on using Fortran to generate a C interface, see
|
||||||
[[http://fortranwiki.org/fortran/show/Generating+C+Interfaces][this link]].
|
[[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
|
#+begin_src bash
|
||||||
cppcheck --addon=cert --enable=all *.c &> cppcheck.out
|
cppcheck --addon=cert --enable=all *.c &> cppcheck.out
|
||||||
|
# or
|
||||||
|
make cppcheck ; cat cppcheck.out
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
** Design of the library
|
** 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 C files should be =xxx.c= and =xxx.h= and the name of the
|
||||||
produced Fortran file should be =xxx.f90=.
|
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
|
In the names of the variables and functions, only the singular
|
||||||
form is allowed.
|
form is allowed.
|
||||||
|
|
||||||
@ -240,33 +284,25 @@ cppcheck --addon=cert --enable=all *.c &> cppcheck.out
|
|||||||
conversions. These functions are also responsible for allocating
|
conversions. These functions are also responsible for allocating
|
||||||
temporary storage, to simplify the use of accelerators.
|
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
|
** Numerical precision
|
||||||
|
|
||||||
The number of bits of precision required for a function should be
|
The minimal number of bits of precision required for a function
|
||||||
given as an input of low-level computational functions. This input
|
should be given as an input of low-level computational
|
||||||
will be used to define the values of the different thresholds that
|
functions. This input will be used to define the values of the
|
||||||
might be used to avoid computing unnecessary noise. High-level
|
different thresholds that might be used to avoid computing
|
||||||
functions will use the precision specified in the =context=
|
unnecessary noise. High-level functions will use the precision
|
||||||
variable.
|
specified in the =context= variable.
|
||||||
|
|
||||||
In order to automatize numerical accuracy tests, QMCkl uses
|
In order to automatize numerical accuracy tests, QMCkl uses
|
||||||
[[https://github.com/verificarlo/verificarlo][Verificarlo]] and
|
[[https://github.com/verificarlo/verificarlo][Verificarlo]] and its CI functionality. You can read Verificarlo CI's
|
||||||
its CI functionality. You can read Verificarlo CI's documentation
|
documentation at the [[https://github.com/verificarlo/verificarlo/blob/master/doc/06-Postprocessing.md#verificarlo-ci][following link]]. Reading it is advised to
|
||||||
at the [[https://github.com/verificarlo/verificarlo/blob/master/doc/06-Postprocessing.md#verificarlo-ci][following link]].
|
understand the remainder of this section.
|
||||||
Reading it is advised to understand the remainder of this section.
|
|
||||||
|
|
||||||
To enable support for Verificarlo CI tests when building the
|
To enable support for Verificarlo CI tests when building the
|
||||||
library, use the following configure command :
|
library, use the following configure command :
|
||||||
|
|
||||||
#+begin_src bash
|
#+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
|
#+end_src
|
||||||
|
|
||||||
Note that this does require an install of Verificarlo *with
|
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).
|
- ~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.
|
interfaces, have a look at the ~tools/qmckl_probes~ files.
|
||||||
|
|
||||||
Finally, if you need to add a QMCkl kernel to the CI tests
|
Finally, if you need to add a QMCkl kernel to the CI tests
|
||||||
|
@ -4843,6 +4843,5 @@ assert( fabs(ao_vgl[1][26][224] - (-3.843864637762753e-09)) < 1.e-14 );
|
|||||||
# vim: syntax=c
|
# vim: syntax=c
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
* TODO [0/1] Missing features :noexport:
|
* TODO [0/1] Missing features :noexport:
|
||||||
- [ ] Error messages to tell what is missing when initializing
|
- [ ] Error messages to tell what is missing when initializing
|
||||||
|
@ -28,6 +28,7 @@ int main() {
|
|||||||
#include "qmckl_error_private_type.h"
|
#include "qmckl_error_private_type.h"
|
||||||
#include "qmckl_memory_private_type.h"
|
#include "qmckl_memory_private_type.h"
|
||||||
#include "qmckl_numprec_private_type.h"
|
#include "qmckl_numprec_private_type.h"
|
||||||
|
#include "qmckl_point_private_type.h"
|
||||||
#include "qmckl_nucleus_private_type.h"
|
#include "qmckl_nucleus_private_type.h"
|
||||||
#include "qmckl_electron_private_type.h"
|
#include "qmckl_electron_private_type.h"
|
||||||
#include "qmckl_ao_private_type.h"
|
#include "qmckl_ao_private_type.h"
|
||||||
@ -35,6 +36,7 @@ int main() {
|
|||||||
#include "qmckl_jastrow_private_type.h"
|
#include "qmckl_jastrow_private_type.h"
|
||||||
#include "qmckl_determinant_private_type.h"
|
#include "qmckl_determinant_private_type.h"
|
||||||
#include "qmckl_local_energy_private_type.h"
|
#include "qmckl_local_energy_private_type.h"
|
||||||
|
#include "qmckl_point_private_func.h"
|
||||||
#include "qmckl_nucleus_private_func.h"
|
#include "qmckl_nucleus_private_func.h"
|
||||||
#include "qmckl_electron_private_func.h"
|
#include "qmckl_electron_private_func.h"
|
||||||
#include "qmckl_ao_private_func.h"
|
#include "qmckl_ao_private_func.h"
|
||||||
@ -121,6 +123,9 @@ typedef struct qmckl_context_struct {
|
|||||||
/* Current date */
|
/* Current date */
|
||||||
uint64_t date;
|
uint64_t date;
|
||||||
|
|
||||||
|
/* Points */
|
||||||
|
qmckl_point_struct *point;
|
||||||
|
|
||||||
/* -- Molecular system -- */
|
/* -- Molecular system -- */
|
||||||
qmckl_nucleus_struct nucleus;
|
qmckl_nucleus_struct nucleus;
|
||||||
qmckl_electron_struct electron;
|
qmckl_electron_struct electron;
|
||||||
@ -236,6 +241,9 @@ qmckl_context qmckl_context_create() {
|
|||||||
ctx->numprec.precision = QMCKL_DEFAULT_PRECISION;
|
ctx->numprec.precision = QMCKL_DEFAULT_PRECISION;
|
||||||
ctx->numprec.range = QMCKL_DEFAULT_RANGE;
|
ctx->numprec.range = QMCKL_DEFAULT_RANGE;
|
||||||
|
|
||||||
|
rc = qmckl_init_point(context);
|
||||||
|
assert (rc == QMCKL_SUCCESS);
|
||||||
|
|
||||||
rc = qmckl_init_electron(context);
|
rc = qmckl_init_electron(context);
|
||||||
assert (rc == QMCKL_SUCCESS);
|
assert (rc == QMCKL_SUCCESS);
|
||||||
|
|
||||||
|
591
org/qmckl_point.org
Normal file
591
org/qmckl_point.org
Normal file
@ -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 <stdbool.h>
|
||||||
|
#+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 <assert.h>
|
||||||
|
#include <math.h>
|
||||||
|
#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 <stdint.h>
|
||||||
|
#elif HAVE_INTTYPES_H
|
||||||
|
#include <inttypes.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#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 ; i<point_num ; ++i) {
|
||||||
|
,*ptr = ctx->point->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)
|
||||||
|
{
|
||||||
|
|
||||||
|
<<check_alloc>>
|
||||||
|
|
||||||
|
for (int64_t i=0 ; i<num ; ++i) {
|
||||||
|
ctx->point->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)
|
||||||
|
{
|
||||||
|
|
||||||
|
<<check_alloc>>
|
||||||
|
|
||||||
|
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<point_num ; ++i) {
|
||||||
|
assert( coord[3*i+0] == coord_x[i] );
|
||||||
|
assert( coord[3*i+1] == coord_y[i] );
|
||||||
|
assert( coord[3*i+2] == coord_z[i] );
|
||||||
|
}
|
||||||
|
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
* End of files :noexport:
|
||||||
|
|
||||||
|
#+begin_src c :tangle (eval h_private_type)
|
||||||
|
#endif
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
#+begin_src c :tangle (eval h_private_func)
|
||||||
|
#endif
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
*** Test
|
||||||
|
#+begin_src c :tangle (eval c_test)
|
||||||
|
if (qmckl_context_destroy(context) != QMCKL_SUCCESS)
|
||||||
|
return QMCKL_FAILURE;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
*** Compute file names
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
; The following is required to compute the file names
|
||||||
|
|
||||||
|
(setq pwd (file-name-directory buffer-file-name))
|
||||||
|
(setq name (file-name-nondirectory (substring buffer-file-name 0 -4)))
|
||||||
|
(setq f (concat pwd name "_f.f90"))
|
||||||
|
(setq fh (concat pwd name "_fh.f90"))
|
||||||
|
(setq c (concat pwd name ".c"))
|
||||||
|
(setq h (concat name ".h"))
|
||||||
|
(setq h_private (concat name "_private.h"))
|
||||||
|
(setq c_test (concat pwd "test_" name ".c"))
|
||||||
|
(setq f_test (concat pwd "test_" name "_f.f90"))
|
||||||
|
|
||||||
|
; Minted
|
||||||
|
(require 'ox-latex)
|
||||||
|
(setq org-latex-listings 'minted)
|
||||||
|
(add-to-list 'org-latex-packages-alist '("" "listings"))
|
||||||
|
(add-to-list 'org-latex-packages-alist '("" "color"))
|
||||||
|
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
#+RESULTS:
|
||||||
|
| | color |
|
||||||
|
| | listings |
|
||||||
|
|
||||||
|
|
||||||
|
# -*- mode: org -*-
|
||||||
|
# vim: syntax=c
|
||||||
|
|
||||||
|
|
@ -1,19 +1,20 @@
|
|||||||
qmckl.org
|
qmckl.org
|
||||||
qmckl_ao.org
|
|
||||||
qmckl_blas.org
|
|
||||||
qmckl_context.org
|
qmckl_context.org
|
||||||
qmckl_determinant.org
|
|
||||||
qmckl_distance.org
|
|
||||||
qmckl_electron.org
|
|
||||||
qmckl_error.org
|
qmckl_error.org
|
||||||
|
qmckl_blas.org
|
||||||
|
qmckl_memory.org
|
||||||
|
qmckl_numprec.org
|
||||||
|
qmckl_point.org
|
||||||
|
qmckl_nucleus.org
|
||||||
|
qmckl_electron.org
|
||||||
|
qmckl_distance.org
|
||||||
|
qmckl_ao.org
|
||||||
|
qmckl_mo.org
|
||||||
|
qmckl_determinant.org
|
||||||
|
qmckl_sherman_morrison_woodbury.org
|
||||||
qmckl_jastrow.org
|
qmckl_jastrow.org
|
||||||
qmckl_local_energy.org
|
qmckl_local_energy.org
|
||||||
qmckl_memory.org
|
|
||||||
qmckl_mo.org
|
|
||||||
qmckl_numprec.org
|
|
||||||
qmckl_nucleus.org
|
|
||||||
qmckl_sherman_morrison_woodbury.org
|
|
||||||
qmckl_utils.org
|
qmckl_utils.org
|
||||||
qmckl_trexio.org
|
qmckl_trexio.org
|
||||||
qmckl_verificarlo.org
|
|
||||||
qmckl_tests.org
|
qmckl_tests.org
|
||||||
|
qmckl_verificarlo.org
|
||||||
|
Loading…
Reference in New Issue
Block a user