Unverified Commit 741a7fe6 authored by Axel Kohlmeyer's avatar Axel Kohlmeyer
Browse files

final touches to support compiling with libcurl transparently

parent 7a8bb5ba
Loading
Loading
Loading
Loading

examples/kim/in.query

0 → 100644
+11 −0
Original line number Diff line number Diff line

# 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}
+34 −0
Original line number Diff line number Diff line
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
+6 −1
Original line number Diff line number Diff line
@@ -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.)
+6 −0
Original line number Diff line number Diff line
@@ -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:
+134 −22
Original line number Diff line number Diff line
@@ -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 < 2) error->all(FLERR,"Illegal kim_query command");

  if (narg != 3) error->all(FLERR,"Illegal kim_query command");
  varname = arg[0];
  function = arg[1];

  model = arg[0];
  property = arg[1];
  varname = arg[2];
#if defined(LMP_KIM_CURL)

  value = do_query(model, property, comm->me, world);
  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)

// 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 *model, char *property, int rank, MPI_Comm comm)
char *do_query(char *qfunction, int narg, char **arg, int rank, MPI_Comm comm)
{
  char value[512], *retval;

  // only run query from rank 0
  // run the web query from rank 0 only

  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];
      }

    // fake query
    strcpy(value,(const char*)"4.25");
#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.

  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