final touches to support compiling with libcurl transparently

This commit is contained in:
Axel Kohlmeyer 2018-08-20 18:56:40 -04:00
parent 7a8bb5baaf
commit 741a7fe630
No known key found for this signature in database
GPG Key ID: D9B44E93BF0C375A
5 changed files with 190 additions and 22 deletions

11
examples/kim/in.query Normal file
View File

@ -0,0 +1,11 @@
# example for performing a query to the OpenKIM test database to retrieve
# a parameter to be used in the input. here it requests the aluminium
# lattice constant for a specific test used for a specific model and then
# assigns it to the variable 'latconst'
units metal
info variables out log
kim_query latconst get_test_result test=TE_156715955670_004 species=["Al"] model=MO_800509458712_001 prop=structure-cubic-crystal-npt keys=["a"] units=["angstrom"]
info variables out log
lattice fcc ${latconst}

View File

@ -0,0 +1,34 @@
LAMMPS (16 Aug 2018)
# example for performing a query to the OpenKIM test database to retrieve
# a parameter to be used in the input. here it requests the aluminium
# lattice constant for a specific test used for a specific model and then
# assigns it to the variable 'latconst'
units metal
info variables out log
Info-Info-Info-Info-Info-Info-Info-Info-Info-Info-Info
Printed on Mon Aug 20 18:44:24 2018
Variable information:
Info-Info-Info-Info-Info-Info-Info-Info-Info-Info-Info
kim_query latconst get_test_result test=TE_156715955670_004 species=["Al"] model=MO_800509458712_001 prop=structure-cubic-crystal-npt keys=["a"] units=["angstrom"]
info variables out log
Info-Info-Info-Info-Info-Info-Info-Info-Info-Info-Info
Printed on Mon Aug 20 18:44:24 2018
Variable information:
Variable[ 0]: latconst , style = string , def = 4.0320827961
Info-Info-Info-Info-Info-Info-Info-Info-Info-Info-Info
lattice fcc ${latconst}
lattice fcc 4.0320827961
Lattice spacing in x,y,z = 4.03208 4.03208 4.03208
Total wall time: 0:00:00

View File

@ -17,13 +17,18 @@
ifeq ($(strip $(shell pkg-config --version)),)
$(error 'pkg-config' not found, but is required to configure the KIM API)
endif
kim_PREFIX := $(shell cat ../../lib/kim/kim-prefix.txt 2> /dev/null)
kim_PREFIX := $(if $(kim_PREFIX),$(kim_PREFIX)/lib/pkgconfig,)
kim_PREFIX := $(if $(shell printf -- "$${PKG_CONFIG_PATH}"),$(kim_PREFIX):$(shell printf -- "$${PKG_CONFIG_PATH}"),$(kim_PREFIX))
# there is no usable libcurl installation
ifeq ($(shell curl-config --version 2> /dev/null),)
kim_SYSINC := $(shell export PKG_CONFIG_PATH="$(kim_PREFIX)"; pkg-config --cflags libkim-api-v2 2> /dev/null)
kim_SYSLIB := $(shell export PKG_CONFIG_PATH="$(kim_PREFIX)"; pkg-config --libs libkim-api-v2 2> /dev/null)
else
kim_SYSINC := $(shell export PKG_CONFIG_PATH="$(kim_PREFIX)"; pkg-config --cflags libkim-api-v2 2> /dev/null) $(shell curl-config --cflags) -DLMP_KIM_CURL
kim_SYSLIB := $(shell export PKG_CONFIG_PATH="$(kim_PREFIX)"; pkg-config --libs libkim-api-v2 2> /dev/null) $(shell curl-config --libs)
endif
ifeq ($(strip $(kim_SYSINC)),)
$(error 'pkg-config' could not find an installed KIM API library.)

View File

@ -13,6 +13,12 @@ do the same thing by typing "python Install.py" from within this
directory, or you can do it manually by following the instructions
below.
As of KIM API version 2, the KIM package also provides a LAMMPS command
to perform queries through the OpenKIM web API. This feature requires
that the CURL library (libcurl) development package and its configuration
query tool, curl-config, are installed. The provided Makefile.lammps
is set up to automatically detect this.
-----------------
Instructions:

View File

@ -57,36 +57,55 @@
#include <mpi.h>
#include <cstring>
#include <string>
#include "kim_query.h"
#include "comm.h"
#include "error.h"
#include "input.h"
#include "variable.h"
#include <sys/types.h>
#include <curl/curl.h>
using namespace LAMMPS_NS;
static char *do_query(char *, char *, int, MPI_Comm);
#if defined(LMP_KIM_CURL)
struct WriteBuf {
char *dataptr;
size_t sizeleft;
};
static char *do_query(char *, int, char **, int, MPI_Comm);
static size_t write_callback(void *, size_t, size_t, void *);
#endif
/* ---------------------------------------------------------------------- */
void KimQuery::command(int narg, char **arg)
{
char *model, *property, *varname, *value;
char *varname, *function, *value;
if (narg != 3) error->all(FLERR,"Illegal kim_query command");
if (narg < 2) error->all(FLERR,"Illegal kim_query command");
model = arg[0];
property = arg[1];
varname = arg[2];
varname = arg[0];
function = arg[1];
value = do_query(model, property, comm->me, world);
#if defined(LMP_KIM_CURL)
value = do_query(function, narg-2, arg+2, comm->me, world);
// check for valid result
// on error the content of "value" is a '\0' byte
// as the first element, and then the error message
// that was returned by the web server
int len = strlen(value) + 1;
if (len == 1) {
// TODO: store more detailed error message after \0 byte.
error->all(FLERR,"Query of OpenKIM database failed");
if (0 == strlen(value)) {
char errmsg[512];
sprintf(errmsg,"OpenKIM query failed: %s",value+1);
error->all(FLERR,errmsg);
}
char **varcmd = new char*[3];
@ -98,26 +117,119 @@ void KimQuery::command(int narg, char **arg)
delete[] varcmd;
delete[] value;
#else
error->all(FLERR,"Cannot use 'kim_query' command when KIM package "
"is compiled without support for libcurl");
#endif
}
#if defined(LMP_KIM_CURL)
char *do_query(char *model, char *property, int rank, MPI_Comm comm)
// copy data to the user provided data structure, optionally in increments
size_t write_callback(void *data, size_t size, size_t nmemb, void *userp)
{
struct WriteBuf *buf = (struct WriteBuf *)userp;
size_t buffer_size = size*nmemb;
// copy chunks into the buffer for as long as there is space left
if (buf->sizeleft) {
size_t copy_this_much = buf->sizeleft;
if (copy_this_much > buffer_size)
copy_this_much = buffer_size;
memcpy(buf->dataptr, data, copy_this_much);
buf->dataptr += copy_this_much;
buf->sizeleft -= copy_this_much;
return copy_this_much;
}
return 0; // done
}
char *do_query(char *qfunction, int narg, char **arg, int rank, MPI_Comm comm)
{
char value[512], *retval;
// only run query from rank 0
if (rank == 0) {
// run the web query from rank 0 only
// fake query
strcpy(value,(const char*)"4.25");
if (rank == 0) {
CURL *handle;
CURLcode res;
// set up and clear receive buffer
struct WriteBuf buf;
buf.dataptr = value;
buf.sizeleft = 511;
memset(value,0,512);
// create curl web query instance
curl_global_init(CURL_GLOBAL_DEFAULT);
handle = curl_easy_init();
if (handle) {
std::string url("https://query.openkim.org/api/");
url += qfunction;
std::string query(arg[0]);
for (int i=1; i < narg; ++i) {
query += '&';
query += arg[i];
}
#if LMP_DEBUG_CURL
curl_easy_setopt(handle, CURLOPT_VERBOSE, 1L);
#endif
#if defined(LMP_NO_SSL_CHECK)
// disable verifying SSL certificate and host name
curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(handle, CURLOPT_SSL_VERIFYHOST, 0L);
#endif
curl_easy_setopt(handle, CURLOPT_URL, url.c_str());
curl_easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(handle, CURLOPT_POSTFIELDS, query.c_str());
curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION,write_callback);
curl_easy_setopt(handle, CURLOPT_WRITEDATA,&buf);
// perform OpenKIM query and check for errors
res = curl_easy_perform(handle);
if (res != CURLE_OK) {
// on error we return an "empty" string but add error message after it
value[0]= '\0';
strcpy(value+1,curl_easy_strerror(res));
}
curl_easy_cleanup(handle);
}
curl_global_cleanup();
}
MPI_Bcast(value, 512, MPI_CHAR, 0, comm);
// must make a proper copy of the query, as the stack allocation
// will go out of scope
// we must make a proper copy of the query, as the stack allocation
// for "value" will go out of scope. a valid query has a '[' as
// the first character. skip over it (and the last character ']', too)
// an error messages starts with a '\0' character. copy that and
// the remaining string, as that is the error message.
int len = strlen(value) + 1;
retval = new char[len];
strcpy(retval,value);
if (value[0] == '[') {
int len = strlen(value)-1;
retval = new char[len];
value[len] = '\0';
strcpy(retval,value+1);
} else if (value[0] == '\0') {
int len = strlen(value+1)+2;
retval = new char[len];
retval[0] = '\0';
strcpy(retval+1,value+1);
} else {
// unknown response type. we should not get here.
// copy response without modifications.
int len = strlen(value)+1;
retval = new char[len];
strcpy(retval,value);
}
return retval;
}
#endif