1
0
mirror of https://github.com/TREX-CoE/qmckl.git synced 2025-05-01 04:44:49 +02:00

Merge pull request #114 from EmielSlootman/master

Added Single-electron move Jastrow
This commit is contained in:
Anthony Scemama 2025-04-29 10:43:26 +02:00 committed by GitHub
commit f7f97dfc84
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 18189 additions and 87 deletions

View File

@ -188,7 +188,7 @@ $(htmlize_el):
tests/chbrclf.h: $(qmckl_h)
tests/n2.h: $(qmckl_h)
include/n2.h: $(qmckl_h)
cppcheck: cppcheck.out

View File

@ -31,6 +31,7 @@ grep TITLE $(cat table_of_contents) | tr ':' ' '
| qmckl_determinant.org | #+TITLE | Slater | Determinant | |
| qmckl_sherman_morrison_woodbury.org | #+TITLE | Sherman-Morrison-Woodbury | | |
| qmckl_jastrow_champ.org | #+TITLE | CHAMP | Jastrow | Factor |
| qmckl_jastrow_champ_single.org | #+TITLE | CHAMP | Jastrow | Single |
| qmckl_local_energy.org | #+TITLE | Local | Energy | |
| qmckl_trexio.org | #+TITLE | TREXIO | I/O | library |
| qmckl_tests.org | #+TITLE | Data | for | Tests |
@ -62,6 +63,7 @@ return '\n'.join(result)
- [[./qmckl_determinant.html][Slater Determinant]]
- [[./qmckl_sherman_morrison_woodbury.html][Sherman-Morrison-Woodbury]]
- [[./qmckl_jastrow_champ.html][CHAMP Jastrow Factor]]
- [[./qmckl_jastrow_champ_single.html][CHAMP Jastrow Factor Single]]
- [[./qmckl_local_energy.html][Local Energy]]
- [[./qmckl_trexio.html][TREXIO I/O library]]
- [[./qmckl_tests.html][Data for Tests]]

File diff suppressed because it is too large Load Diff

View File

@ -34,6 +34,8 @@ int main() {
#include "qmckl_ao_private_type.h"
#include "qmckl_mo_private_type.h"
#include "qmckl_jastrow_champ_private_type.h"
#include "qmckl_jastrow_champ_single_private_type.h"
#include "qmckl_forces_private_type.h"
#include "qmckl_determinant_private_type.h"
#include "qmckl_local_energy_private_type.h"
#include "qmckl_point_private_func.h"
@ -42,6 +44,8 @@ int main() {
#include "qmckl_ao_private_func.h"
#include "qmckl_mo_private_func.h"
#include "qmckl_jastrow_champ_private_func.h"
#include "qmckl_jastrow_champ_single_private_func.h"
#include "qmckl_forces_private_func.h"
#include "qmckl_determinant_private_func.h"
#include "qmckl_local_energy_private_func.h"
#+end_src
@ -129,6 +133,7 @@ typedef struct qmckl_context_struct {
/* Points */
qmckl_point_struct point;
qmckl_jastrow_champ_single_struct single_point;
/* -- Molecular system -- */
qmckl_nucleus_struct nucleus;
@ -136,6 +141,7 @@ typedef struct qmckl_context_struct {
qmckl_ao_basis_struct ao_basis;
qmckl_mo_basis_struct mo_basis;
qmckl_jastrow_champ_struct jastrow_champ;
qmckl_forces_struct forces;
qmckl_determinant_struct det;
qmckl_local_energy_struct local_energy;
@ -224,10 +230,24 @@ qmckl_context_touch(const qmckl_context context)
ctx->date += 1UL;
ctx->point.date = ctx-> date;
ctx->electron.walker.point.date = ctx-> date;
return QMCKL_SUCCESS;
}
#+end_src
*** Fortran binding
#+begin_src f90 :tangle (eval fh_func) :exports none
interface
integer (qmckl_context) function qmckl_context_touch(context) bind(C)
use, intrinsic :: iso_c_binding
import
integer (qmckl_context), intent(in), value :: context
end function qmckl_context_touch
end interface
#+end_src
** Creation
To create a new context, ~qmckl_context_create()~ should be used.

View File

@ -1153,24 +1153,31 @@ qmckl_check(context, rc);
*** Get
#+begin_src c :comments org :tangle (eval h_func) :noweb yes
qmckl_exit_code qmckl_get_electron_en_distance(qmckl_context context, double* distance);
qmckl_exit_code
qmckl_get_electron_en_distance(qmckl_context context,
double* const distance,
const int64_t size_max);
#+end_src
#+begin_src f90 :tangle (eval fh_func) :comments org :exports none
interface
integer(c_int32_t) function qmckl_get_electron_en_distance(context, distance) &
integer(c_int32_t) function qmckl_get_electron_en_distance(context, distance, 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) :: distance(*)
integer (c_int64_t) , intent(in) :: size_max
end function
end interface
#+end_src
#+begin_src c :comments org :tangle (eval c) :noweb yes :exports none
qmckl_exit_code qmckl_get_electron_en_distance(qmckl_context context, double* distance)
qmckl_exit_code
qmckl_get_electron_en_distance(qmckl_context context,
double* const distance,
const int64_t size_max)
{
if (qmckl_context_check(context) == QMCKL_NULL_CONTEXT) {
@ -1185,7 +1192,20 @@ qmckl_exit_code qmckl_get_electron_en_distance(qmckl_context context, double* di
qmckl_context_struct* const ctx = (qmckl_context_struct*) context;
assert (ctx != NULL);
size_t sze = ctx->point.num * ctx->nucleus.num;
if (distance == NULL) {
return qmckl_failwith( context,
QMCKL_INVALID_ARG_2,
"qmckl_get_electron_en_distance",
"distance is a null pointer");
}
int64_t sze = ctx->point.num * ctx->nucleus.num;
if (size_max < sze) {
return qmckl_failwith( context,
QMCKL_INVALID_ARG_3,
"qmckl_get_electron_en_distance",
"size_max < num*nucl_num");
}
memcpy(distance, ctx->electron.en_distance, sze * sizeof(double));
return QMCKL_SUCCESS;
@ -1405,7 +1425,7 @@ assert(qmckl_nucleus_provided(context));
double en_distance[walk_num][elec_num][nucl_num];
rc = qmckl_get_electron_en_distance(context, &(en_distance[0][0][0]));
rc = qmckl_get_electron_en_distance(context, &(en_distance[0][0][0]), walk_num * elec_num * nucl_num);
qmckl_check(context, rc);
// (e,n,w) in Fortran notation

View File

@ -472,18 +472,15 @@ qmckl_get_error(qmckl_context context,
qmckl_context_struct* const ctx = (qmckl_context_struct*) context;
assert (ctx != NULL); /* Impossible because the context is valid. */
/* Turn off annoying GCC warning */
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstringop-truncation"
#endif
size_t sizeCp;
strncpy(function_name, ctx->error.function, QMCKL_MAX_FUN_LEN-1);
strncpy(message , ctx->error.message , QMCKL_MAX_MSG_LEN-1);
sizeCp = strlen(ctx->error.function);
sizeCp = sizeCp > QMCKL_MAX_FUN_LEN ? QMCKL_MAX_FUN_LEN : sizeCp;
memcpy(function_name, ctx->error.function, sizeCp);
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
sizeCp = strlen(ctx->error.message);
sizeCp = sizeCp > QMCKL_MAX_MSG_LEN ? QMCKL_MAX_MSG_LEN : sizeCp;
memcpy(message, ctx->error.message, sizeCp);
(*exit_code) = ctx->error.exit_code;
}

7432
org/qmckl_forces.org Normal file

File diff suppressed because it is too large Load Diff

View File

@ -2304,7 +2304,7 @@ qmckl_exit_code qmckl_get_jastrow_champ_ee_distance_rescaled(qmckl_context conte
if (distance_rescaled == NULL) {
return qmckl_failwith( context,
QMCKL_INVALID_ARG_2,
"qmckl_provide_jastrow_champ_factor_ee_gl",
"qmckl_get_jastrow_champ_ee_distance_rescaled",
"Null pointer");
}
@ -2313,7 +2313,7 @@ qmckl_exit_code qmckl_get_jastrow_champ_ee_distance_rescaled(qmckl_context conte
if (size_max < sze) {
return qmckl_failwith( context,
QMCKL_INVALID_ARG_2,
"qmckl_provide_jastrow_champ_factor_ee_gl",
"qmckl_get_jastrow_champ_ee_distance_rescaled",
"Array too small. Expected elec_num*elec_num*walk_num.");
}
memcpy(distance_rescaled, ctx->jastrow_champ.ee_distance_rescaled, sze * sizeof(double));
@ -6801,14 +6801,14 @@ for p in range(0, cord_num+1):
#+begin_src c :comments org :tangle (eval h_func) :noweb yes
qmckl_exit_code
qmckl_get_jastrow_champ_een_distance_rescaled_e(qmckl_context context,
qmckl_get_jastrow_champ_een_rescaled_e(qmckl_context context,
double* const een_rescaled_e,
const int64_t size_max);
#+end_src
#+begin_src c :comments org :tangle (eval c) :noweb yes :exports none
qmckl_exit_code
qmckl_get_jastrow_champ_een_distance_rescaled_e(qmckl_context context,
qmckl_get_jastrow_champ_een_rescaled_e(qmckl_context context,
double* const een_rescaled_e,
const int64_t size_max)
{
@ -6827,7 +6827,7 @@ qmckl_get_jastrow_champ_een_distance_rescaled_e(qmckl_context context,
if (een_rescaled_e == NULL) {
return qmckl_failwith( context,
QMCKL_INVALID_ARG_2,
"qmckl_get_jastrow_champ_een_distance_rescaled_e",
"qmckl_get_jastrow_champ_een_rescaled_e",
"Null pointer");
}
@ -6836,7 +6836,7 @@ qmckl_get_jastrow_champ_een_distance_rescaled_e(qmckl_context context,
if (size_max < sze) {
return qmckl_failwith( context,
QMCKL_INVALID_ARG_3,
"qmckl_get_jastrow_champ_een_distance_rescaled_e",
"qmckl_get_jastrow_champ_een_rescaled_e",
"Array too small. Expected elec_num*elec_num*walk_num*(cord_num + 1)");
}
@ -7295,6 +7295,50 @@ print("#+end_src")
assert( fabs(een_rescaled_e[0][5][2][2] - (0.0)) < 1.e-10 );
#+end_src
#+begin_src c :tangle (eval c_test) :noweb yes
assert(qmckl_electron_provided(context));
{
double een_rescaled_e[walk_num][(cord_num + 1)][elec_num][elec_num];
rc = qmckl_get_jastrow_champ_een_rescaled_e(context, &(een_rescaled_e[0][0][0][0]),elec_num*elec_num*(cord_num+1)*walk_num);
<<test_ee>>
}
{
printf("een_rescaled_e_hpc\n");
double ee_distance[walk_num * elec_num * elec_num];
rc = qmckl_get_electron_ee_distance(context, &(ee_distance[0]), walk_num*elec_num*elec_num);
assert(rc == QMCKL_SUCCESS);
double een_rescaled_e_doc[walk_num][cord_num+1][elec_num][elec_num];
memset(&(een_rescaled_e_doc[0][0][0][0]), 0, sizeof(een_rescaled_e_doc));
rc = qmckl_compute_een_rescaled_e(context, walk_num, elec_num, cord_num,
rescale_factor_ee, &(ee_distance[0]), &(een_rescaled_e_doc[0][0][0][0]));
assert(rc == QMCKL_SUCCESS);
double een_rescaled_e_hpc[walk_num][cord_num+1][elec_num][elec_num];
memset(&(een_rescaled_e_hpc[0][0][0][0]), 0, sizeof(een_rescaled_e_hpc));
rc = qmckl_compute_een_rescaled_e_hpc(context, walk_num, elec_num, cord_num,
rescale_factor_ee, &(ee_distance[0]), &(een_rescaled_e_hpc[0][0][0][0]));
assert(rc == QMCKL_SUCCESS);
for (int64_t i = 0; i < walk_num; i++) {
for (int64_t j = 0; j < cord_num+1; j++) {
for (int64_t k = 0; k < elec_num; k++) {
for (int64_t l = 0; l < elec_num; l++) {
if (fabs(een_rescaled_e_doc[i][j][k][l] - een_rescaled_e_hpc[i][j][k][l]) > 1.e-12) {
printf("i=%ld j=%ld k=%ld l=%ld doc=%f hpc=%f\n", i, j, k, l, een_rescaled_e_doc[i][j][k][l], een_rescaled_e_hpc[i][j][k][l]);
fflush(stdout);
}
assert(fabs(een_rescaled_e_doc[i][j][k][l] - een_rescaled_e_hpc[i][j][k][l]) < 1.e-8);
}
}
}
}
}
#+end_src
*** Electron-electron rescaled distances derivatives in $J_\text{eeN}$
~een_rescaled_e_gl~ stores the table of the derivatives of the
@ -7315,16 +7359,16 @@ print("#+end_src")
#+begin_src c :comments org :tangle (eval h_func) :noweb yes
qmckl_exit_code
qmckl_get_jastrow_champ_een_distance_rescaled_e_gl(qmckl_context context,
double* const een_rescaled_e_gl,
const int64_t size_max);
qmckl_get_jastrow_champ_een_rescaled_e_gl(qmckl_context context,
double* const een_rescaled_e_gl,
const int64_t size_max);
#+end_src
#+begin_src c :comments org :tangle (eval c) :noweb yes :exports none
qmckl_exit_code
qmckl_get_jastrow_champ_een_distance_rescaled_e_gl(qmckl_context context,
double* const een_rescaled_e_gl,
const int64_t size_max)
qmckl_get_jastrow_champ_een_rescaled_e_gl(qmckl_context context,
double* const een_rescaled_e_gl,
const int64_t size_max)
{
if (qmckl_context_check(context) == QMCKL_NULL_CONTEXT) {
return QMCKL_NULL_CONTEXT;
@ -7341,7 +7385,7 @@ qmckl_get_jastrow_champ_een_distance_rescaled_e_gl(qmckl_context context,
if (een_rescaled_e_gl == NULL) {
return qmckl_failwith( context,
QMCKL_INVALID_ARG_2,
"qmckl_get_jastrow_champ_een_distance_rescaled_e_gl",
"qmckl_get_jastrow_champ_een_rescaled_e_gl",
"Null pointer");
}
@ -7351,7 +7395,7 @@ qmckl_get_jastrow_champ_een_distance_rescaled_e_gl(qmckl_context context,
if (size_max < sze) {
return qmckl_failwith( context,
QMCKL_INVALID_ARG_3,
"qmckl_get_jastrow_champ_een_distance_rescaled_e_gl",
"qmckl_get_jastrow_champ_een_rescaled_e_gl",
"Array too small. Expected elec_num*4*elec_num*walk_num*(cord_num + 1)");
}
@ -7455,7 +7499,7 @@ qmckl_exit_code qmckl_provide_een_rescaled_e_gl(qmckl_context context)
| ~elec_num~ | ~int64_t~ | in | Number of electrons |
| ~cord_num~ | ~int64_t~ | in | Order of polynomials |
| ~rescale_factor_ee~ | ~double~ | in | Factor to rescale ee distances |
| ~coord_ee~ | ~double[walk_num][3][elec_num]~ | in | Electron coordinates |
| ~coord_ee~ | ~double[3][walk_num][elec_num]~ | in | Electron coordinates |
| ~ee_distance~ | ~double[walk_num][elec_num][elec_num]~ | in | Electron-electron distances |
| ~een_rescaled_e~ | ~double[walk_num][0:cord_num][elec_num][elec_num]~ | in | Electron-electron distances |
| ~een_rescaled_e_gl~ | ~double[walk_num][0:cord_num][elec_num][4][elec_num]~ | out | Electron-electron rescaled distances |
@ -8216,7 +8260,7 @@ assert(qmckl_electron_provided(context));
{
double een_rescaled_e_gl[walk_num][(cord_num + 1)][elec_num][4][elec_num];
size_max=walk_num*(cord_num + 1)*elec_num*4*elec_num;
rc = qmckl_get_jastrow_champ_een_distance_rescaled_e_gl(context,
rc = qmckl_get_jastrow_champ_een_rescaled_e_gl(context,
&(een_rescaled_e_gl[0][0][0][0][0]),size_max);
<<test_ee_gl>>
}
@ -8271,7 +8315,7 @@ assert(qmckl_electron_provided(context));
{
/* Finite difference test fails and I can't understand why... */
printf("een_distance_rescaled_e_gl\n");
printf("een_rescaled_e_gl\n");
double fd[walk_num][cord_num+1][elec_num][4][elec_num];
@ -8311,9 +8355,9 @@ assert(qmckl_electron_provided(context));
assert(rc == QMCKL_SUCCESS);
// Call the provided function
rc = qmckl_get_jastrow_champ_een_distance_rescaled_e(context,
&(function_values[0][0][0][0]),
walk_num*(cord_num+1)*elec_num*elec_num);
rc = qmckl_get_jastrow_champ_een_rescaled_e(context,
&(function_values[0][0][0][0]),
walk_num*(cord_num+1)*elec_num*elec_num);
assert(rc == QMCKL_SUCCESS);
// Accumulate derivative using finite-difference coefficients
@ -8353,10 +8397,10 @@ assert(qmckl_electron_provided(context));
}
double een_distance_rescaled_e_gl[walk_num][cord_num+1][elec_num][4][elec_num];
double een_rescaled_e_gl[walk_num][cord_num+1][elec_num][4][elec_num];
rc = qmckl_check(context,
qmckl_get_jastrow_champ_een_distance_rescaled_e_gl(context,
&(een_distance_rescaled_e_gl[0][0][0][0][0]),
qmckl_get_jastrow_champ_een_rescaled_e_gl(context,
&(een_rescaled_e_gl[0][0][0][0][0]),
walk_num*(cord_num+1)*elec_num*4*elec_num)
);
@ -8368,23 +8412,23 @@ assert(qmckl_electron_provided(context));
for (int i = 0; i < elec_num; i++) {
for (int j = 0; j < elec_num; j++) {
for (int k = 0; k < 3; k++){
if (fabs(fd[nw][c][i][k][j] - een_distance_rescaled_e_gl[nw][c][i][k][j]) > 1.e-10) {
if (fabs(fd[nw][c][i][k][j] - een_rescaled_e_gl[nw][c][i][k][j]) > 1.e-10) {
printf("%2d %2d %2d %2d %2d\t", nw, c, i, k, j);
printf("%.10e\t", fd[nw][c][i][k][j]);
printf("%.10e\n", een_distance_rescaled_e_gl[nw][c][i][k][j]);
printf("%.10e\n", een_rescaled_e_gl[nw][c][i][k][j]);
fflush(stdout);
}
assert(fabs(fd[nw][c][i][k][j] - een_distance_rescaled_e_gl[nw][c][i][k][j]) < 1.e-8);
assert(fabs(fd[nw][c][i][k][j] - een_rescaled_e_gl[nw][c][i][k][j]) < 1.e-8);
}
int k=3;
if (i != j) {
if (fabs(fd[nw][c][i][k][j] - een_distance_rescaled_e_gl[nw][c][i][k][j]) > 1.e-8) {
if (fabs(fd[nw][c][i][k][j] - een_rescaled_e_gl[nw][c][i][k][j]) > 1.e-8) {
printf("%2d %2d %2d %2d %2d\t", nw, c, i, k, j);
printf("%.10e\t", fd[nw][c][i][k][j]);
printf("%.10e\n", een_distance_rescaled_e_gl[nw][c][i][k][j]);
printf("%.10e\n", een_rescaled_e_gl[nw][c][i][k][j]);
fflush(stdout);
}
assert(fabs(fd[nw][c][i][k][j] - een_distance_rescaled_e_gl[nw][c][i][k][j]) < 1.e-6);
assert(fabs(fd[nw][c][i][k][j] - een_rescaled_e_gl[nw][c][i][k][j]) < 1.e-6);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -5,6 +5,18 @@
We override the allocation functions to enable the possibility of
optimized libraries to fine-tune the memory allocation.
Example of usage:
#+begin_src c
info_struct mem_info = qmckl_memory_info_struct_zero;
mem_info.size = size * sizeof(double);
data = (double*) qmckl_malloc (context, mem_info);
if (data == NULL) {
return QMCKL_ALLOCATION_FAILED;
}
// ...
qmckl_free(data);
#+end_src
* Headers :noexport:

View File

@ -266,7 +266,11 @@ qmckl_exit_code qmckl_set_mo_basis_coefficient(qmckl_context context,
{
int32_t mask = 1 << 1;
<<pre>>
if (qmckl_context_check(context) == QMCKL_NULL_CONTEXT) {
return QMCKL_NULL_CONTEXT;
}
qmckl_context_struct* const ctx = (qmckl_context_struct*) context;
if (ctx->mo_basis.coefficient != NULL) {
qmckl_exit_code rc = qmckl_free(context, ctx->mo_basis.coefficient);
@ -301,6 +305,20 @@ qmckl_exit_code qmckl_set_mo_basis_coefficient(qmckl_context context,
}
#+end_src
#+begin_src f90 :tangle (eval fh_func) :comments org :exports none
interface
integer(qmckl_exit_code) function qmckl_set_mo_basis_coefficient (context, &
coefficient, 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) :: coefficient(*)
integer (c_int64_t) , intent(in), value :: size_max
end function qmckl_set_mo_basis_coefficient
end interface
#+end_src
When the basis set is completely entered, other data structures are
computed to accelerate the calculations.
@ -369,6 +387,7 @@ qmckl_exit_code qmckl_finalize_mo_basis(qmckl_context context) {
}
#+end_src
** Cusp adjsutment functions
To activate the cusp adjustment, the user must enter the radius of
@ -972,8 +991,7 @@ qmckl_get_mo_basis_mo_value_inplace (qmckl_context context,
"input array too small");
}
rc = qmckl_context_touch(context);
if (rc != QMCKL_SUCCESS) return rc;
ctx->mo_basis.mo_value_date = ctx->point.date - 1UL;
double* old_array = ctx->mo_basis.mo_value;
@ -984,6 +1002,8 @@ qmckl_get_mo_basis_mo_value_inplace (qmckl_context context,
ctx->mo_basis.mo_value = old_array;
ctx->mo_basis.mo_value_date = ctx->point.date - 1UL;
return QMCKL_SUCCESS;
}
#+end_src
@ -1626,8 +1646,7 @@ qmckl_get_mo_basis_mo_vgl_inplace (qmckl_context context,
"input array too small");
}
rc = qmckl_context_touch(context);
if (rc != QMCKL_SUCCESS) return rc;
ctx->mo_basis.mo_vgl_date = ctx->point.date - 1UL;
double* old_array = ctx->mo_basis.mo_vgl;
@ -1638,6 +1657,8 @@ qmckl_get_mo_basis_mo_vgl_inplace (qmckl_context context,
ctx->mo_basis.mo_vgl = old_array;
ctx->mo_basis.mo_vgl_date = ctx->point.date - 1UL;
return QMCKL_SUCCESS;
}
#+end_src

View File

@ -520,7 +520,14 @@ qmckl_set_nucleus_coord(qmckl_context context,
{
int32_t mask = 1 << 2;
<<pre2>>
if (qmckl_context_check(context) == QMCKL_NULL_CONTEXT) {
return qmckl_failwith( context,
QMCKL_NULL_CONTEXT,
"qmckl_set_nucleus_*",
NULL);
}
qmckl_context_struct* const ctx = (qmckl_context_struct*) context;
qmckl_exit_code rc;

View File

@ -13,7 +13,10 @@ qmckl_mo.org
qmckl_determinant.org
qmckl_sherman_morrison_woodbury.org
qmckl_jastrow_champ.org
qmckl_jastrow_champ_single.org
qmckl_jastrow_champ_quad.org
qmckl_local_energy.org
qmckl_forces.org
qmckl_utils.org
qmckl_trexio.org
qmckl_tests.org

View File

@ -38,6 +38,7 @@
(setq src (concat top_builddir "/src/"))
(setq tests (concat top_builddir "/tests/"))
(setq include (concat top_builddir "/include/"))
(setq name (file-name-nondirectory (substring buffer-file-name 0 -4)))
(setq f (concat src name "_f.F90"))
(setq fh_func (concat src name "_fh_func.F90"))