diff --git a/include/gcp.h b/include/gcp.h new file mode 100644 index 0000000..aab41df --- /dev/null +++ b/include/gcp.h @@ -0,0 +1,48 @@ +/* This file is part of mctc-gcp. +* SPDX-Identifier: LGPL-3.0-or-later +* +* mctc-gcp is free software: you can redistribute it and/or modify it under +* the terms of the Lesser GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* mctc-gcp is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* Lesser GNU General Public License for more details. +* +* You should have received a copy of the Lesser GNU General Public License +* along with mctc-gcp. If not, see . +**/ + +#ifndef GCP_H +#define GCP_H + +#ifdef __cplusplus +#define GCP_API_ENTRY extern "C" +#else +#define GCP_API_ENTRY extern +#endif + +GCP_API_ENTRY void c_gcp_call(int* n, // No. of atoms + double* xyz, // coordinates (3,n) in Bohr + double* lat, // lattice matrix + int* iz, // element numbers + double* gcp_e, // gcp energy + double* gcp_g, // gcp gradient + double* gcp_glat, // gcp lattice gradient + bool* dograd, // flag: evaluate gradient + bool* dohess, // flag: evaluate hessian (file: gcp_hessian) + bool* pbc, // flag: periodic boundary conditions + const char* method, // method name + bool* echo, // flag: verbose output + bool* parfile // flag: print extended parameter file (gcp.param) + ); + +GCP_API_ENTRY void setr0ab(int* max_elem, // max element number + double* autoang, // a.u. to Angstrom (0.52917726) + double* r // vector of size max_elem x max_elem + ); + +#endif + diff --git a/meson.build b/meson.build index 6203927..a0fea82 100644 --- a/meson.build +++ b/meson.build @@ -64,6 +64,10 @@ gcp_lic = files( 'COPYING.LESSER', ) +gcp_header = files( + 'include/gcp.h', +) + if install # Distribute the license files in share/licenses/ install_data( @@ -71,6 +75,10 @@ if install install_dir: get_option('datadir')/'licenses'/meson.project_name() ) + install_headers( + gcp_header + ) + pkg = import('pkgconfig') pkg.generate( gcp_lib, diff --git a/src/gcp.f90 b/src/gcp.f90 index 9fb1b60..3039337 100644 --- a/src/gcp.f90 +++ b/src/gcp.f90 @@ -407,6 +407,38 @@ subroutine gcp_call(n,xyz,lat,iz,gcp_e,gcp_g,gcp_glat,dograd,dohess,pbc,method,e end subroutine gcp_call +!*************************************************** +!* C/C++-interface * +!*************************************************** +subroutine c_gcp_call(n,xyz,lat,iz,gcp_e,gcp_g,gcp_glat,i_dograd,i_dohess,i_pbc,i_method,i_echo,i_parfile) bind(c, name='c_gcp_call') +!implicit none +use, intrinsic :: iso_c_binding, only: c_char +integer n !number of atoms +real*8 xyz(3,n) !xyzcoordinates +real*8 lat(3,3) !lattice matrix +integer iz(n) !element number +real*8 gcp_g(3,n) !xyz gradient +real*8 gcp_glat(3,3) +real*8 gcp_e + +! C-input +logical*1 i_dograd,i_dohess,i_echo,i_pbc,i_parfile +character(len=1,kind=c_char), intent(in) :: i_method(20) + +! F-input +logical dograd,dohess,echo,pbc,parfile +character*20 method + +dograd = i_dograd +dohess = i_dohess +pbc = i_pbc +echo = i_echo +parfile = i_parfile + +method = transfer(i_method(1:20), method) +call gcp_call(n,xyz,lat,iz,gcp_e,gcp_g,gcp_glat,dograd,dohess,pbc,method,echo,parfile) + +end subroutine c_gcp_call !*************************************************** @@ -3900,7 +3932,7 @@ end subroutine set_criteria_gcp !C in parts due to INTEL compiler bug !CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC -subroutine setr0ab(max_elem,autoang,r) +subroutine setr0ab(max_elem,autoang,r) bind(c, name='setr0ab') implicit none integer max_elem,i,j,k real*8 r(max_elem,max_elem),autoang diff --git a/test/c_api/test_gcp_cxx_api.cpp b/test/c_api/test_gcp_cxx_api.cpp new file mode 100644 index 0000000..c87c8c2 --- /dev/null +++ b/test/c_api/test_gcp_cxx_api.cpp @@ -0,0 +1,158 @@ +/* This file is part of mctc-gcp. + * SPDX-Identifier: LGPL-3.0-or-later + * + * mctc-gcp is free software: you can redistribute it and/or modify it under + * the terms of the Lesser GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * mctc-gcp is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Lesser GNU General Public License for more details. + * + * You should have received a copy of the Lesser GNU General Public License + * along with mctc-gcp. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct { + std::vector iz; + std::vector coords; + std::vector lattice; + bool pbc; +} Molecule; + +bool test_generic(const std::string& title, Molecule& mol, const std::string& method, const double energy_ref){ + + char method_f[20]; + strcpy(method_f,method.c_str()); + for(size_t ii=method.size();ii<20;ii++) method_f[ii] = ' '; + + bool dograd = false; + bool dohess = false; + bool echo = false; + bool parfile = false; + bool pbc = mol.pbc; + + auto& lat = mol.lattice; + auto& xyz = mol.coords; + auto& iz = mol.iz; + int nat = (int)(xyz.size()/3); + + + double energy = 0.e0; + std::vector gradient(3*nat,0.e0); + std::vector gradlat(9,0.e0); + + c_gcp_call(&nat,&xyz[0],&lat[0],&iz[0],&energy,&gradient[0],&gradlat[0],&dograd,&dohess,&pbc,method_f,&echo,&parfile); + + double de = energy - energy_ref; + + std::string stat = "\x1B[32m [OK]\x1B[0m"; + + bool is_ok = true; + if (fabs(de) > 1e-9){ + stat = "\x1B[31m [FAILED]\x1B[0m"; + is_ok = false; + } + printf("E: %30.20f %20s %s\n",energy,stat.c_str(),title.c_str()); + + return is_ok; + +} + +int main(int argc, char* argv[]){ + + std::vector > test_systems = { + { + "Alanine@HF3c", + { + {1,7,6,6,8,6,1,7,6,6,8,6,8,1,1,1,1,1,1,1,1,1,1}, + {-1.93145285444792,+3.69743396003490,+5.07672663197993, + -2.38225794234874,+1.87122793226519,+5.47939866438837, + -2.38363826594372,+0.46945474235908,+3.10066131453095, + +0.05491295406579,+0.84981606018213,+1.57533328139901, + +1.15553526565357,+2.88302479323393,+1.49584893725220, + -4.60525415514495,+1.33546037841295,+1.46093111812950, + -0.94935967135323,+1.23895283176357,+6.59006017993275, + +0.90719609031382,-1.21518242048549,+0.28080129333493, + +2.94491704712175,-0.96790880864505,-1.53990197241268, + +2.33465737391659,+0.79844258337069,-3.73912178828922, + +3.92673604793746,+1.81703260886247,-5.01158300414526, + +3.66032988644352,-3.56018817506558,-2.59948629629987, + -0.17835566103986,+0.97841613903525,-4.20105316431806, + -0.35820586681744,+2.10507058522216,-5.63692062300423, + -0.23557408796486,-2.73553018128516,+0.13945189803826, + -2.61502607287587,-1.54956844388107,+3.54379863895688, + -4.40788990832190,+3.34964157223239,+1.02628696163526, + -6.37737290628970,+1.04790338926862,+2.48347133798594, + -4.67147573464799,+0.30228459708274,-0.33039253201856, + +4.58101416587973,-0.11358970578901,-0.60029127792819, + +2.05572744486357,-4.42625244199752,-3.58274737172425, + +4.26057887986804,-4.81176728720273,-1.06753470682591, + +5.21404372180499,-3.36409206395890,-3.94412805049104}, + {0.,0.,0.,0.,0.,0.,0.,0.,0.}, + false + }, + "hf3c", + -0.12313247650779590714e0 + }, + { + "Alanine@R2SCAN-3c", + { + {1,7,6,6,8,6,1,7,6,6,8,6,8,1,1,1,1,1,1,1,1,1,1}, + {-1.93145285444792,+3.69743396003490,+5.07672663197993, + -2.38225794234874,+1.87122793226519,+5.47939866438837, + -2.38363826594372,+0.46945474235908,+3.10066131453095, + +0.05491295406579,+0.84981606018213,+1.57533328139901, + +1.15553526565357,+2.88302479323393,+1.49584893725220, + -4.60525415514495,+1.33546037841295,+1.46093111812950, + -0.94935967135323,+1.23895283176357,+6.59006017993275, + +0.90719609031382,-1.21518242048549,+0.28080129333493, + +2.94491704712175,-0.96790880864505,-1.53990197241268, + +2.33465737391659,+0.79844258337069,-3.73912178828922, + +3.92673604793746,+1.81703260886247,-5.01158300414526, + +3.66032988644352,-3.56018817506558,-2.59948629629987, + -0.17835566103986,+0.97841613903525,-4.20105316431806, + -0.35820586681744,+2.10507058522216,-5.63692062300423, + -0.23557408796486,-2.73553018128516,+0.13945189803826, + -2.61502607287587,-1.54956844388107,+3.54379863895688, + -4.40788990832190,+3.34964157223239,+1.02628696163526, + -6.37737290628970,+1.04790338926862,+2.48347133798594, + -4.67147573464799,+0.30228459708274,-0.33039253201856, + +4.58101416587973,-0.11358970578901,-0.60029127792819, + +2.05572744486357,-4.42625244199752,-3.58274737172425, + +4.26057887986804,-4.81176728720273,-1.06753470682591, + +5.21404372180499,-3.36409206395890,-3.94412805049104}, + {0.,0.,0.,0.,0.,0.,0.,0.,0.}, + false + }, + "r2scan3c", + 0.01836274475757706734e0 + }, + }; + + printf("Run C-API tests...\n"); + size_t nok = 0; + for(auto& mol : test_systems){ + if (test_generic(std::get<0>(mol),std::get<1>(mol),std::get<2>(mol),std::get<3>(mol))) nok++; + } + + if (nok == test_systems.size()) + printf("All tests passed!\n"); + else + printf("%li out of %li tests failed!\n",test_systems.size()-nok,test_systems.size()); + + return 0; + +} +