diff --git a/org/qmckl_ao.org b/org/qmckl_ao.org index 47877b7..aa6a648 100644 --- a/org/qmckl_ao.org +++ b/org/qmckl_ao.org @@ -367,7 +367,7 @@ if (qmckl_context_check(context) == QMCKL_NULL_CONTEXT) { qmckl_context_struct* const ctx = (qmckl_context_struct*) context; -if (!(ctx->ao_basis.uninitialized & mask)) { +if (mask != 0 && !(ctx->ao_basis.uninitialized & mask)) { return qmckl_failwith( context, QMCKL_ALREADY_SET, "qmckl_set_ao_*", @@ -3141,7 +3141,7 @@ qmckl_get_ao_basis_ao_value (qmckl_context context, qmckl_exit_code rc; - rc = qmckl_provide_ao_value(context); + rc = qmckl_provide_ao_basis_ao_value(context); if (rc != QMCKL_SUCCESS) return rc; qmckl_context_struct* const ctx = (qmckl_context_struct*) context; @@ -3217,7 +3217,7 @@ qmckl_get_ao_basis_ao_value_inplace (qmckl_context context, ctx->ao_basis.ao_value = ao_value; - rc = qmckl_provide_ao_value(context); + rc = qmckl_provide_ao_basis_ao_value(context); if (rc != QMCKL_SUCCESS) return rc; ctx->ao_basis.ao_value = old_array; @@ -3625,18 +3625,26 @@ end function qmckl_compute_ao_basis_primitive_gaussian_vgl_f *** Provide :noexport: - #+begin_src c :comments org :tangle (eval h_private_func) :noweb yes :exports none -qmckl_exit_code qmckl_provide_ao_basis_primitive_vgl(qmckl_context context); - #+end_src +#+CALL: write_provider_header( group="ao_basis", data="primitive_vgl" ) - #+begin_src c :comments org :tangle (eval c) :noweb yes :exports none +#+RESULTS: +#+begin_src c :comments org :tangle (eval h_private_func) :noweb yes :export none +qmckl_exit_code qmckl_provide_ao_basis_primitive_vgl(qmckl_context context); +#+end_src + +#+CALL: write_provider_pre( group="ao_basis", data="primitive_vgl", dimension="ctx->ao_basis.prim_num * 5 * ctx->point.num") + +#+RESULTS: +#+begin_src c :comments org :tangle (eval c) :noweb yes :export none qmckl_exit_code qmckl_provide_ao_basis_primitive_vgl(qmckl_context context) { + qmckl_exit_code rc; + if (qmckl_context_check(context) == QMCKL_NULL_CONTEXT) { return qmckl_failwith( context, QMCKL_INVALID_CONTEXT, - "qmckl_provide_get_ao_basis_primitive_vgl", + "qmckl_provide_ao_basis_primitive_vgl", NULL); } @@ -3646,19 +3654,26 @@ qmckl_exit_code qmckl_provide_ao_basis_primitive_vgl(qmckl_context context) if (!ctx->ao_basis.provided) { return qmckl_failwith( context, QMCKL_NOT_PROVIDED, - "qmckl_ao_basis_primitive_vgl", + "qmckl_provide_ao_basis_primitive_vgl", NULL); } /* Compute if necessary */ if (ctx->point.date > ctx->ao_basis.primitive_vgl_date) { + if (ctx->point.alloc_date > ctx->ao_basis.primitive_vgl_date) { + if (ctx->ao_basis.primitive_vgl != NULL) { + rc = qmckl_free(context, ctx->ao_basis.primitive_vgl); + assert (rc == QMCKL_SUCCESS); + ctx->ao_basis.primitive_vgl = NULL; + } + } + /* Allocate array */ if (ctx->ao_basis.primitive_vgl == NULL) { qmckl_memory_info_struct mem_info = qmckl_memory_info_struct_zero; - mem_info.size = ctx->ao_basis.prim_num * 5 * ctx->point.num * - sizeof(double); + mem_info.size = ctx->ao_basis.prim_num * 5 * ctx->point.num * sizeof(double); double* primitive_vgl = (double*) qmckl_malloc(context, mem_info); if (primitive_vgl == NULL) { @@ -3670,7 +3685,9 @@ qmckl_exit_code qmckl_provide_ao_basis_primitive_vgl(qmckl_context context) ctx->ao_basis.primitive_vgl = primitive_vgl; } - qmckl_exit_code rc; +#+end_src + + #+begin_src c :comments org :tangle (eval c) :noweb yes :exports none if (ctx->ao_basis.type == 'G') { rc = qmckl_compute_ao_basis_primitive_gaussian_vgl(context, ctx->ao_basis.prim_num, @@ -3687,16 +3704,22 @@ qmckl_exit_code qmckl_provide_ao_basis_primitive_vgl(qmckl_context context) "compute_ao_basis_primitive_vgl", "Not yet implemented"); } + #+end_src + +#+CALL: write_provider_post( group="ao_basis", data="shell_vgl" ) + +#+RESULTS: +#+begin_src c :comments org :tangle (eval c) :noweb yes :export none if (rc != QMCKL_SUCCESS) { return rc; } - ctx->ao_basis.primitive_vgl_date = ctx->date; + ctx->ao_basis.shell_vgl_date = ctx->date; } return QMCKL_SUCCESS; } - #+end_src +#+end_src *** Test :noexport: @@ -4031,14 +4054,22 @@ end function qmckl_compute_ao_basis_shell_gaussian_vgl_f *** Provide :noexport: - #+begin_src c :comments org :tangle (eval h_private_func) :noweb yes :exports none -qmckl_exit_code qmckl_provide_ao_basis_shell_vgl(qmckl_context context); - #+end_src +#+CALL: write_provider_header( group="ao_basis", data="shell_vgl" ) - #+begin_src c :comments org :tangle (eval c) :noweb yes :exports none +#+RESULTS: +#+begin_src c :comments org :tangle (eval h_private_func) :noweb yes :export none +qmckl_exit_code qmckl_provide_ao_basis_shell_vgl(qmckl_context context); +#+end_src + +#+CALL: write_provider_pre( group="ao_basis", data="shell_vgl", dimension="ctx->ao_basis.shell_num * 5 * ctx->point.num") + +#+RESULTS: +#+begin_src c :comments org :tangle (eval c) :noweb yes :export none qmckl_exit_code qmckl_provide_ao_basis_shell_vgl(qmckl_context context) { + qmckl_exit_code rc; + if (qmckl_context_check(context) == QMCKL_NULL_CONTEXT) { return qmckl_failwith( context, QMCKL_INVALID_CONTEXT, @@ -4059,6 +4090,14 @@ qmckl_exit_code qmckl_provide_ao_basis_shell_vgl(qmckl_context context) /* Compute if necessary */ if (ctx->point.date > ctx->ao_basis.shell_vgl_date) { + if (ctx->point.alloc_date > ctx->ao_basis.shell_vgl_date) { + if (ctx->ao_basis.shell_vgl != NULL) { + rc = qmckl_free(context, ctx->ao_basis.shell_vgl); + assert (rc == QMCKL_SUCCESS); + ctx->ao_basis.shell_vgl = NULL; + } + } + /* Allocate array */ if (ctx->ao_basis.shell_vgl == NULL) { @@ -4075,7 +4114,9 @@ qmckl_exit_code qmckl_provide_ao_basis_shell_vgl(qmckl_context context) ctx->ao_basis.shell_vgl = shell_vgl; } - qmckl_exit_code rc; +#+end_src + +#+begin_src c :comments org :tangle (eval c) :noweb yes :exports none if (ctx->ao_basis.type == 'G') { rc = qmckl_compute_ao_basis_shell_gaussian_vgl(context, ctx->ao_basis.prim_num, @@ -4098,6 +4139,11 @@ qmckl_exit_code qmckl_provide_ao_basis_shell_vgl(qmckl_context context) "compute_ao_basis_shell_vgl", "Not yet implemented"); } +#+end_src +#+CALL: write_provider_post( group="ao_basis", data="shell_vgl" ) + +#+RESULTS: +#+begin_src c :comments org :tangle (eval c) :noweb yes :export none if (rc != QMCKL_SUCCESS) { return rc; } @@ -4107,7 +4153,7 @@ qmckl_exit_code qmckl_provide_ao_basis_shell_vgl(qmckl_context context) return QMCKL_SUCCESS; } - #+end_src +#+end_src *** Test :noexport: @@ -5920,18 +5966,26 @@ qmckl_compute_ao_value_hpc_gaussian (const qmckl_context context, **** Provide :noexport: - #+begin_src c :comments org :tangle (eval h_private_func) :noweb yes :exports none -qmckl_exit_code qmckl_provide_ao_value(qmckl_context context); - #+end_src +#+CALL: write_provider_header( group="ao_basis", data="ao_value" ) - #+begin_src c :comments org :tangle (eval c) :noweb yes :exports none -qmckl_exit_code qmckl_provide_ao_value(qmckl_context context) +#+RESULTS: +#+begin_src c :comments org :tangle (eval h_private_func) :noweb yes :export none +qmckl_exit_code qmckl_provide_ao_basis_ao_value(qmckl_context context); +#+end_src + +#+CALL: write_provider_pre( group="ao_basis", data="ao_value", dimension="ctx->ao_basis.ao_num * ctx->point.num") + +#+RESULTS: +#+begin_src c :comments org :tangle (eval c) :noweb yes :export none +qmckl_exit_code qmckl_provide_ao_basis_ao_value(qmckl_context context) { + qmckl_exit_code rc; + if (qmckl_context_check(context) == QMCKL_NULL_CONTEXT) { return qmckl_failwith( context, QMCKL_INVALID_CONTEXT, - "qmckl_provide_ao_value", + "qmckl_provide_ao_basis_ao_value", NULL); } @@ -5941,28 +5995,26 @@ qmckl_exit_code qmckl_provide_ao_value(qmckl_context context) if (!ctx->ao_basis.provided) { return qmckl_failwith( context, QMCKL_NOT_PROVIDED, - "qmckl_ao_value", + "qmckl_provide_ao_basis_ao_value", NULL); } /* Compute if necessary */ if (ctx->point.date > ctx->ao_basis.ao_value_date) { - qmckl_exit_code rc; - - /* Provide required data */ -#ifndef HAVE_HPC - rc = qmckl_provide_ao_basis_shell_vgl(context); - if (rc != QMCKL_SUCCESS) { - return qmckl_failwith( context, rc, "qmckl_provide_ao_basis_shell_vgl", NULL); + if (ctx->point.alloc_date > ctx->ao_basis.ao_value_date) { + if (ctx->ao_basis.ao_value != NULL) { + rc = qmckl_free(context, ctx->ao_basis.ao_value); + assert (rc == QMCKL_SUCCESS); + ctx->ao_basis.ao_value = NULL; + } } -#endif /* Allocate array */ if (ctx->ao_basis.ao_value == NULL) { qmckl_memory_info_struct mem_info = qmckl_memory_info_struct_zero; - mem_info.size = ctx->ao_basis.ao_num * 5 * ctx->point.num * sizeof(double); + mem_info.size = ctx->ao_basis.ao_num * ctx->point.num * sizeof(double); double* ao_value = (double*) qmckl_malloc(context, mem_info); if (ao_value == NULL) { @@ -5974,6 +6026,9 @@ qmckl_exit_code qmckl_provide_ao_value(qmckl_context context) ctx->ao_basis.ao_value = ao_value; } +#+end_src + + #+begin_src c :comments org :tangle (eval c) :noweb yes :exports none if (ctx->ao_basis.ao_vgl_date == ctx->point.date) { // ao_vgl has been computed at this step: Just copy the data. @@ -6032,6 +6087,12 @@ qmckl_exit_code qmckl_provide_ao_value(qmckl_context context) ctx->ao_basis.ao_value); ,*/ } else { + /* Provide required data */ + rc = qmckl_provide_ao_basis_shell_vgl(context); + if (rc != QMCKL_SUCCESS) { + return qmckl_failwith( context, rc, "qmckl_provide_ao_basis_shell_vgl", NULL); + } + rc = qmckl_compute_ao_value_doc(context, ctx->ao_basis.ao_num, ctx->ao_basis.shell_num, @@ -6049,6 +6110,12 @@ qmckl_exit_code qmckl_provide_ao_value(qmckl_context context) ctx->ao_basis.ao_value); } #else + /* Provide required data */ + rc = qmckl_provide_ao_basis_shell_vgl(context); + if (rc != QMCKL_SUCCESS) { + return qmckl_failwith( context, rc, "qmckl_provide_ao_basis_shell_vgl", NULL); + } + rc = qmckl_compute_ao_value_doc(context, ctx->ao_basis.ao_num, ctx->ao_basis.shell_num, @@ -6065,10 +6132,15 @@ qmckl_exit_code qmckl_provide_ao_value(qmckl_context context) ctx->ao_basis.shell_vgl, ctx->ao_basis.ao_value); #endif - if (rc != QMCKL_SUCCESS) { - return rc; - } + } + #+end_src +#+CALL: write_provider_post( group="ao_basis", data="ao_value" ) + +#+RESULTS: +#+begin_src c :comments org :tangle (eval c) :noweb yes :export none + if (rc != QMCKL_SUCCESS) { + return rc; } ctx->ao_basis.ao_value_date = ctx->date; @@ -6076,7 +6148,7 @@ qmckl_exit_code qmckl_provide_ao_value(qmckl_context context) return QMCKL_SUCCESS; } - #+end_src +#+end_src **** Test :noexport: diff --git a/org/qmckl_jastrow.org b/org/qmckl_jastrow.org index 5fe060a..ca94399 100644 --- a/org/qmckl_jastrow.org +++ b/org/qmckl_jastrow.org @@ -407,7 +407,7 @@ qmckl_exit_code qmckl_init_jastrow(qmckl_context context) { qmckl_context_struct* const ctx = (qmckl_context_struct*) context; assert (ctx != NULL); - ctx->jastrow.uninitialized = (1 << 5) - 1; + ctx->jastrow.uninitialized = (1 << 6) - 1; /* Default values */ @@ -746,6 +746,14 @@ if (qmckl_context_check(context) == QMCKL_NULL_CONTEXT) { } qmckl_context_struct* const ctx = (qmckl_context_struct*) context; + +if (mask != 0 && !(ctx->jastrow.uninitialized & mask)) { + printf("%d %d\n", mask, ctx->jastrow.uninitialized ); + return qmckl_failwith( context, + QMCKL_ALREADY_SET, + "qmckl_set_jastrow_*", + NULL); + } #+end_src #+NAME:post2 @@ -768,6 +776,9 @@ qmckl_set_jastrow_ord_num(qmckl_context context, const int64_t bord_num, const int64_t cord_num) { + + int32_t mask = 1 << 0; + <> if (aord_num <= 0) { @@ -791,7 +802,6 @@ qmckl_set_jastrow_ord_num(qmckl_context context, "cord_num <= 0"); } - int32_t mask = 1 << 0; ctx->jastrow.aord_num = aord_num; ctx->jastrow.bord_num = bord_num; ctx->jastrow.cord_num = cord_num; @@ -803,6 +813,8 @@ qmckl_set_jastrow_ord_num(qmckl_context context, qmckl_exit_code qmckl_set_jastrow_type_nucl_num(qmckl_context context, const int64_t type_nucl_num) { + int32_t mask = 1 << 1; + <> if (type_nucl_num <= 0) { @@ -812,7 +824,6 @@ qmckl_set_jastrow_type_nucl_num(qmckl_context context, const int64_t type_nucl_n "type_nucl_num < 0"); } - int32_t mask = 1 << 1; ctx->jastrow.type_nucl_num = type_nucl_num; <> @@ -824,10 +835,11 @@ qmckl_set_jastrow_type_nucl_vector(qmckl_context context, int64_t const * type_nucl_vector, const int64_t nucl_num) { -<> int32_t mask = 1 << 2; +<> + int64_t type_nucl_num; qmckl_exit_code rc = qmckl_get_jastrow_type_nucl_num(context, &type_nucl_num); if (rc != QMCKL_SUCCESS) return rc; @@ -879,10 +891,10 @@ qmckl_set_jastrow_aord_vector(qmckl_context context, double const * aord_vector, const int64_t size_max) { -<> - int32_t mask = 1 << 3; +<> + int64_t aord_num; qmckl_exit_code rc = qmckl_get_jastrow_aord_num(context, &aord_num); if (rc != QMCKL_SUCCESS) return rc; @@ -946,10 +958,10 @@ qmckl_set_jastrow_bord_vector(qmckl_context context, double const * bord_vector, const int64_t size_max) { -<> - int32_t mask = 1 << 4; +<> + int64_t bord_num; qmckl_exit_code rc = qmckl_get_jastrow_bord_num(context, &bord_num); if (rc != QMCKL_SUCCESS) return rc; @@ -1009,10 +1021,10 @@ qmckl_set_jastrow_cord_vector(qmckl_context context, double const * cord_vector, const int64_t size_max) { -<> - int32_t mask = 1 << 5; +<> + qmckl_exit_code rc = qmckl_provide_dim_cord_vect(context); if (rc != QMCKL_SUCCESS) return rc; @@ -1042,7 +1054,7 @@ qmckl_set_jastrow_cord_vector(qmckl_context context, rc = qmckl_free(context, ctx->jastrow.cord_vector); if (rc != QMCKL_SUCCESS) { return qmckl_failwith( context, rc, - "qmckl_set_ord_vector", + "qmckl_set_cord_vector", NULL); } } diff --git a/org/qmckl_mo.org b/org/qmckl_mo.org index 3e21623..6d23bf0 100644 --- a/org/qmckl_mo.org +++ b/org/qmckl_mo.org @@ -305,6 +305,13 @@ if (qmckl_context_check(context) == QMCKL_NULL_CONTEXT) { } qmckl_context_struct* const ctx = (qmckl_context_struct*) context; + +if (mask != 0 && !(ctx->mo_basis.uninitialized & mask)) { + return qmckl_failwith( context, + QMCKL_ALREADY_SET, + "qmckl_set_mo_*", + NULL); + } #+end_src #+NAME:post @@ -320,6 +327,9 @@ return QMCKL_SUCCESS; #+begin_src c :comments org :tangle (eval c) :noweb yes :exports none qmckl_exit_code qmckl_set_mo_basis_mo_num(qmckl_context context, const int64_t mo_num) { + + int32_t mask = 1 ; + <
>
 
   if (mo_num <= 0) {
@@ -329,17 +339,17 @@ qmckl_exit_code qmckl_set_mo_basis_mo_num(qmckl_context context, const int64_t m
                            "mo_num <= 0");
   }
 
-  int32_t mask = 1 ;
   ctx->mo_basis.mo_num = mo_num;
 
   <>
 }
 
 qmckl_exit_code  qmckl_set_mo_basis_coefficient(qmckl_context context, const double* coefficient) {
-  <
>
-
+  
   int32_t mask = 1 << 1;
 
+  <
>
+
   if (ctx->mo_basis.coefficient != NULL) {
     qmckl_exit_code rc = qmckl_free(context, ctx->mo_basis.coefficient);
     if (rc != QMCKL_SUCCESS) {
@@ -447,7 +457,7 @@ qmckl_get_mo_basis_mo_value(qmckl_context context,
 
   qmckl_exit_code rc;
 
-  rc = qmckl_provide_ao_value(context);
+  rc = qmckl_provide_ao_basis_ao_value(context);
   if (rc != QMCKL_SUCCESS) return rc;
 
   rc = qmckl_provide_mo_value(context);
@@ -575,7 +585,7 @@ qmckl_exit_code qmckl_provide_mo_value(qmckl_context context)
                            NULL);
   }
 
-  rc = qmckl_provide_ao_value(context);
+  rc = qmckl_provide_ao_basis_ao_value(context);
   if (rc != QMCKL_SUCCESS) {
     return qmckl_failwith( context,
                            QMCKL_NOT_PROVIDED,
diff --git a/org/qmckl_point.org b/org/qmckl_point.org
index 20fabbf..6344975 100644
--- a/org/qmckl_point.org
+++ b/org/qmckl_point.org
@@ -77,11 +77,13 @@ int main() {
 
   The following data stored in the context:
 
-  | Variable | Type           | Description                               |
-  |----------+----------------+-------------------------------------------|
-  | ~num~    | ~int64_t~      | Total number of points                    |
-  | ~date~   | ~uint64_t~     | Last modification date of the coordinates |
-  | ~coord~  | ~qmckl_matrix~ | ~num~ \times 3 matrix                     |
+  | Variable     | Type           | Description                               |
+  |--------------+----------------+-------------------------------------------|
+  | ~num~        | ~int64_t~      | Total number of points                    |
+  | ~alloc_num~ | ~int64_t~      | Numer of allocated number of points       |
+  | ~date~       | ~uint64_t~     | Last modification date of the coordinates |
+  | ~alloc_date~ | ~uint64_t~     | Last modification date of the allocation  |
+  | ~coord~      | ~qmckl_matrix~ | ~num~ \times 3 matrix                     |
 
   We consider that the matrix is stored 'transposed' and 'normal'
   corresponds to the 3 \times ~num~ matrix.
@@ -91,7 +93,9 @@ int main() {
    #+begin_src c :comments org :tangle (eval h_private_type)
 typedef struct qmckl_point_struct {
   int64_t      num;
+  int64_t      alloc_num;
   uint64_t     date;
+  uint64_t     alloc_date;
   qmckl_matrix coord;
 } qmckl_point_struct;
 
@@ -308,7 +312,7 @@ qmckl_set_point (qmckl_context context,
   assert (ctx != NULL);
 
   qmckl_exit_code rc;
-  if (ctx->point.num != num) {
+  if (num > ctx->point.alloc_num) {
 
     if (ctx->point.coord.data != NULL) {
       rc = qmckl_matrix_free(context, &(ctx->point.coord));
@@ -322,7 +326,6 @@ qmckl_set_point (qmckl_context context,
                              "qmckl_set_point",
                              NULL);
     }
-
   };
 
   ctx->point.num = num;
@@ -350,6 +353,11 @@ qmckl_set_point (qmckl_context context,
   rc = qmckl_context_touch(context);
   assert (rc == QMCKL_SUCCESS);
 
+  if (num > ctx->point.alloc_num) {
+    ctx->point.alloc_num = num;
+    ctx->point.alloc_date = ctx->point.date;
+  };
+
   return QMCKL_SUCCESS;
 
 }
diff --git a/tools/lib.org b/tools/lib.org
index fd198a9..5e3d78d 100644
--- a/tools/lib.org
+++ b/tools/lib.org
@@ -4,10 +4,10 @@
 ** Defines the name of the current file
 
    #+NAME: filename
-   #+begin_src elisp :tangle no 
+   #+begin_src elisp :tangle no
 (file-name-nondirectory (substring buffer-file-name 0 -4))
    #+end_src
-  
+
 ** Function to get the value of a property.
  #+NAME: get_value
  #+begin_src elisp :var key="Type"
@@ -15,7 +15,6 @@
   (org-entry-get nil key t))
  #+end_src
 
-
 ** Table of function arguments
 
    #+NAME: test
@@ -32,7 +31,7 @@
      | ~ldb~     | ~int64_t~        | in     | Leading dimension of array ~B~                |
      | ~C~       | ~double[n][ldc]~ | out    | Array containing the $m \times n$ matrix $C$  |
      | ~ldc~     | ~int64_t~        | in     | Leading dimension of array ~C~                |
-   
+
 
 *** Fortran-C type conversions
 
@@ -124,7 +123,7 @@ for d in parse_table(table):
         const = "const "
     else:
         const = ""
-        
+
     results += [ f"      {const}{c_type} {name}" ]
 
 results=',\n'.join(results)
@@ -146,10 +145,9 @@ return template
           const double* B,
           const int64_t ldb,
           double* const C,
-          const int64_t ldc ); 
+          const int64_t ldc );
     #+end_src
 
-
 *** Generates a C interface to the Fortran function
 
     #+NAME: generate_c_interface
@@ -258,4 +256,161 @@ return results
     #+END_SRC
 
 
-    
+
+** Creating provide functions
+
+    #+NAME: write_provider_header
+    #+BEGIN_SRC python :var group="GROUP" :var data="DATA" :results drawer :noweb yes :wrap "src c :comments org :tangle (eval h_private_func) :noweb yes :export none"
+template = "qmckl_exit_code qmckl_provide_{{ group }}_{{ data }}(qmckl_context context);"
+
+msg = template.replace("{{ group }}", group) \
+              .replace("{{ data }}", data)
+return msg
+    #+END_SRC
+
+    #+RESULTS: write_provider_header
+    #+begin_src c :comments org :tangle (eval h_private_func) :noweb yes :export none
+    qmckl_exit_code qmckl_provide_GROUP_DATA(qmckl_context context);
+    #+end_src
+
+    #+NAME: write_provider_pre
+    #+BEGIN_SRC python :var group="GROUP" :var data="DATA" :var dimension="DIMENSION" :results drawer :noweb yes :wrap "src c :comments org :tangle (eval c) :noweb yes :export none"
+template = """qmckl_exit_code qmckl_provide_{{ group }}_{{ data }}(qmckl_context context)
+{
+
+  qmckl_exit_code rc;
+
+  if (qmckl_context_check(context) == QMCKL_NULL_CONTEXT) {
+    return qmckl_failwith( context,
+                           QMCKL_INVALID_CONTEXT,
+                           "qmckl_provide_{{ group }}_{{ data }}",
+                           NULL);
+  }
+
+  qmckl_context_struct* const ctx = (qmckl_context_struct*) context;
+  assert (ctx != NULL);
+
+  if (!ctx->{{ group }}.provided) {
+    return qmckl_failwith( context,
+                           QMCKL_NOT_PROVIDED,
+                           "qmckl_provide_{{ group }}_{{ data }}",
+                           NULL);
+  }
+
+  /* Compute if necessary */
+  if (ctx->point.date > ctx->{{ group }}.{{ data }}_date) {
+
+    if (ctx->point.alloc_date > ctx->{{ group }}.{{ data }}_date) {
+      if (ctx->{{ group }}.{{ data }} != NULL) {
+        rc = qmckl_free(context, ctx->{{ group }}.{{ data }});
+        assert (rc == QMCKL_SUCCESS);
+        ctx->{{ group }}.{{ data }} = NULL;
+      }
+    }
+
+    /* Allocate array */
+    if (ctx->{{ group }}.{{ data }} == NULL) {
+
+      qmckl_memory_info_struct mem_info = qmckl_memory_info_struct_zero;
+      mem_info.size = {{ dimension }} * sizeof(double);
+      double* {{ data }} = (double*) qmckl_malloc(context, mem_info);
+
+      if ({{ data }} == NULL) {
+        return qmckl_failwith( context,
+                               QMCKL_ALLOCATION_FAILED,
+                               "qmckl_{{ group }}_{{ data }}",
+                               NULL);
+      }
+      ctx->{{ group }}.{{ data }} = {{ data }};
+    }
+
+"""
+
+msg = template.replace("{{ group }}", group) \
+              .replace("{{ data }}", data) \
+              .replace("{{ dimension }}", dimension)
+return msg
+    #+END_SRC
+
+    #+RESULTS: write_provider_pre
+    #+begin_src c :comments org :tangle (eval c) :noweb yes :export none
+    qmckl_exit_code qmckl_provide_GROUP_DATA(qmckl_context context)
+    {
+
+      qmckl_exit_code rc;
+
+      if (qmckl_context_check(context) == QMCKL_NULL_CONTEXT) {
+        return qmckl_failwith( context,
+                               QMCKL_INVALID_CONTEXT,
+                               "qmckl_provide_GROUP_DATA",
+                               NULL);
+      }
+
+      qmckl_context_struct* const ctx = (qmckl_context_struct*) context;
+      assert (ctx != NULL);
+
+      if (!ctx->GROUP.provided) {
+        return qmckl_failwith( context,
+                               QMCKL_NOT_PROVIDED,
+                               "qmckl_provide_GROUP_DATA",
+                               NULL);
+      }
+
+      /* Compute if necessary */
+      if (ctx->point.date > ctx->GROUP.DATA_date) {
+
+        if (ctx->point.alloc_date > ctx->GROUP.DATA_date) {
+          rc = qmckl_free(context, ctx->GROUP.DATA);
+          assert (rc == QMCKL_SUCCESS);
+          ctx->GROUP.DATA = NULL;
+        }
+
+        /* Allocate array */
+        if (ctx->GROUP.DATA == NULL) {
+
+          qmckl_memory_info_struct mem_info = qmckl_memory_info_struct_zero;
+          mem_info.size = DIMENSION * sizeof(double);
+          double* DATA = (double*) qmckl_malloc(context, mem_info);
+
+          if (DATA == NULL) {
+            return qmckl_failwith( context,
+                                   QMCKL_ALLOCATION_FAILED,
+                                   "qmckl_GROUP_DATA",
+                                   NULL);
+          }
+          ctx->GROUP.DATA = DATA;
+        }
+
+    #+end_src
+
+    #+NAME: write_provider_post
+    #+BEGIN_SRC python :var group="BASIS" :var data="DATA" :results drawer :noweb yes :wrap "src c :comments org :tangle (eval c) :noweb yes :export none"
+template = """    if (rc != QMCKL_SUCCESS) {
+      return rc;
+    }
+
+    ctx->{{ group }}.{{ data }}_date = ctx->date;
+  }
+
+  return QMCKL_SUCCESS;
+}
+"""
+
+msg = template.replace("{{ group }}", group) \
+              .replace("{{ data }}", data)
+
+return msg
+    #+END_SRC
+
+    #+RESULTS: write_provider_post
+    #+begin_src c :comments org :tangle (eval c) :noweb yes :export none
+        if (rc != QMCKL_SUCCESS) {
+          return rc;
+        }
+
+        ctx->BASIS.DATA_date = ctx->date;
+      }
+
+      return QMCKL_SUCCESS;
+    }
+    #+end_src