updates and bugfixes for liblammpsplugin plugin loader for LAMMPS shared lib

This commit is contained in:
Axel Kohlmeyer
2023-01-11 06:11:46 -05:00
parent f8de1b1a75
commit 8e494aa771
6 changed files with 246 additions and 41 deletions

1
examples/COUPLE/plugin/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/build

View File

@ -0,0 +1,47 @@
##########################################
# CMake build system for coupling to the LAMMPS library
# where the library is loaded dynamically at runtime.
##########################################
cmake_minimum_required(VERSION 3.10)
# enforce out-of-source build
if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR})
message(FATAL_ERROR "In-source builds are not allowed. You must create and use a build directory. "
"Please remove CMakeCache.txt and CMakeFiles first.")
endif()
project(liblammpsplugin VERSION 1.0 LANGUAGES C)
# by default, install into $HOME/.local (not /usr/local),
# so that no root access (and sudo) is needed
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
set(CMAKE_INSTALL_PREFIX "$ENV{HOME}/.local" CACHE PATH "Default install path" FORCE)
endif()
# ugly hacks for MSVC which by default always reports an old C++ standard in the __cplusplus macro
# and prints lots of pointless warnings about "unsafe" functions
if(MSVC)
if(CMAKE_C_COMPILER_ID STREQUAL "MSVC")
if(LAMMPS_EXCEPTIONS)
add_compile_options(/EHsc)
endif()
endif()
add_compile_definitions(_CRT_SECURE_NO_WARNINGS)
endif()
find_package(MPI REQUIRED)
# do not include the (obsolete) MPI C++ bindings which makes
# for leaner object files and avoids namespace conflicts
set(MPI_CXX_SKIP_MPICXX TRUE)
##########################
add_executable(simple-plugin simple.c liblammpsplugin.c)
target_link_libraries(simple-plugin PRIVATE MPI::MPI_C)
target_compile_definitions(simple-plugin PRIVATE LAMMPS_LIB_MPI)
# link with -ldl or equivalent for plugin loading; except on Windows
if(NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
target_link_libraries(simple-plugin PRIVATE ${CMAKE_DL_LIBS})
endif()

View File

@ -11,9 +11,16 @@ liblammpsplugin.c is the LAMMPS library plugin loader
You can then build the driver executable codes with a compile line You can then build the driver executable codes with a compile line
like below. like below.
mpicc -c -O -Wall -g -I$HOME/lammps/src liblammpsplugin.c mpicc -c -O -DLAMMPS_LIB_MPI -Wall -g liblammpsplugin.c
mpicc -c -O -Wall -g simple.c mpicc -c -O -DLAMMPS_LIB_MPI -Wall -g simple.c
mpicc simple.o liblammpsplugin.o -ldl -o simpleC mpicc simple.o liblammpsplugin.o -ldl -o simple-plugin
or using the provided CMake file with:
mkdir build
cd build
cmake ../
cmake --build .
You also need to build LAMMPS as a shared library You also need to build LAMMPS as a shared library
(see examples/COUPLE/README), e.g. (see examples/COUPLE/README), e.g.
@ -26,17 +33,17 @@ or
cd $HOME/lammps cd $HOME/lammps
mkdir build-shared mkdir build-shared
cd build-shared cd build-shared
cmake -D BUILD_LIB=on -D BUILD_SHARED_LIBS=on ../cmake cmake -D BUILD_MPI=on -D BUILD_SHARED_LIBS=on ../cmake
make make
You then run simpleC on a parallel machine You then run simple-plugin on a parallel machine
on some number of processors Q with 3 arguments: on some number of processors Q with 3 arguments:
% mpirun -np Q simpleC P in.lj $HOME/lammps/src/liblammps.so % mpirun -np Q simple-plugin P in.lj $HOME/lammps/src/liblammps.so
or or
% mpirun -np Q simpleC P in.lj $HOME/lammps/build-shared/liblammps.so % mpirun -np Q simple-plugin P in.lj $HOME/lammps/build-shared/liblammps.so
P is the number of procs you want LAMMPS to run on (must be <= Q) and P is the number of procs you want LAMMPS to run on (must be <= Q) and
in.lj is a LAMMPS input script and the last argument is the path to in.lj is a LAMMPS input script and the last argument is the path to

View File

@ -1,7 +1,7 @@
/* -*- c++ -*- ---------------------------------------------------------- /* -*- c++ -*- ----------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
https://www.lammps.org/ Sandia National Laboratories https://www.lammps.org/, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov LAMMPS development team: developers@lammps.org
Copyright (2003) Sandia Corporation. Under the terms of Contract Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
@ -18,10 +18,29 @@
a LAMMPS plugin to some other software. a LAMMPS plugin to some other software.
*/ */
#include "library.h"
#include "liblammpsplugin.h" #include "liblammpsplugin.h"
#include <stdlib.h>
#if defined(_WIN32)
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#if defined(_WIN32_WINNT)
#undef _WIN32_WINNT
#endif
// target Windows version is windows 7 and later
#define _WIN32_WINNT _WIN32_WINNT_WIN7
#define PSAPI_VERSION 2
#include <windows.h>
#else
#include <dlfcn.h> #include <dlfcn.h>
#endif
#include <stdlib.h>
liblammpsplugin_t *liblammpsplugin_load(const char *lib) liblammpsplugin_t *liblammpsplugin_load(const char *lib)
{ {
@ -29,14 +48,29 @@ liblammpsplugin_t *liblammpsplugin_load(const char *lib)
void *handle; void *handle;
if (lib == NULL) return NULL; if (lib == NULL) return NULL;
#ifdef _WIN32
handle = (void *) LoadLibrary(lib);
#else
handle = dlopen(lib,RTLD_NOW|RTLD_GLOBAL); handle = dlopen(lib,RTLD_NOW|RTLD_GLOBAL);
#endif
if (handle == NULL) return NULL; if (handle == NULL) return NULL;
lmp = (liblammpsplugin_t *) malloc(sizeof(liblammpsplugin_t)); lmp = (liblammpsplugin_t *) malloc(sizeof(liblammpsplugin_t));
lmp->handle = handle; lmp->handle = handle;
#define ADDSYM(symbol) lmp->symbol = dlsym(handle,"lammps_" #symbol) #ifdef _WIN32
#define ADDSYM(symbol) *(void **) (&lmp->symbol) = (void *) GetProcAddress((HINSTANCE) handle, "lammps_" #symbol)
#else
#define ADDSYM(symbol) *(void **) (&lmp->symbol) = dlsym(handle,"lammps_" #symbol)
#endif
#if defined(LAMMPS_LIB_MPI)
ADDSYM(open); ADDSYM(open);
#else
lmp->open = NULL;
#endif
ADDSYM(open_no_mpi); ADDSYM(open_no_mpi);
ADDSYM(open_fortran); ADDSYM(open_fortran);
ADDSYM(close); ADDSYM(close);
@ -46,6 +80,8 @@ liblammpsplugin_t *liblammpsplugin_load(const char *lib)
ADDSYM(kokkos_finalize); ADDSYM(kokkos_finalize);
ADDSYM(python_finalize); ADDSYM(python_finalize);
ADDSYM(error);
ADDSYM(file); ADDSYM(file);
ADDSYM(command); ADDSYM(command);
ADDSYM(commands_list); ADDSYM(commands_list);
@ -70,6 +106,7 @@ liblammpsplugin_t *liblammpsplugin_load(const char *lib)
ADDSYM(extract_compute); ADDSYM(extract_compute);
ADDSYM(extract_fix); ADDSYM(extract_fix);
ADDSYM(extract_variable); ADDSYM(extract_variable);
ADDSYM(extract_variable_datatype);
ADDSYM(set_variable); ADDSYM(set_variable);
ADDSYM(gather_atoms); ADDSYM(gather_atoms);
@ -77,8 +114,15 @@ liblammpsplugin_t *liblammpsplugin_load(const char *lib)
ADDSYM(gather_atoms_subset); ADDSYM(gather_atoms_subset);
ADDSYM(scatter_atoms); ADDSYM(scatter_atoms);
ADDSYM(scatter_atoms_subset); ADDSYM(scatter_atoms_subset);
ADDSYM(gather_bonds); ADDSYM(gather_bonds);
ADDSYM(gather);
ADDSYM(gather_concat);
ADDSYM(gather_subset);
ADDSYM(scatter);
ADDSYM(scatter_subset);
ADDSYM(create_atoms); ADDSYM(create_atoms);
ADDSYM(find_pair_neighlist); ADDSYM(find_pair_neighlist);
@ -116,6 +160,9 @@ liblammpsplugin_t *liblammpsplugin_load(const char *lib)
ADDSYM(plugin_count); ADDSYM(plugin_count);
ADDSYM(plugin_name); ADDSYM(plugin_name);
ADDSYM(encode_image_flags);
ADDSYM(decode_image_flags);
ADDSYM(set_fix_external_callback); ADDSYM(set_fix_external_callback);
ADDSYM(fix_external_get_force); ADDSYM(fix_external_get_force);
ADDSYM(fix_external_set_energy_global); ADDSYM(fix_external_set_energy_global);
@ -125,6 +172,8 @@ liblammpsplugin_t *liblammpsplugin_load(const char *lib)
ADDSYM(fix_external_set_vector_length); ADDSYM(fix_external_set_vector_length);
ADDSYM(fix_external_set_vector); ADDSYM(fix_external_set_vector);
ADDSYM(flush_buffers);
ADDSYM(free); ADDSYM(free);
ADDSYM(is_running); ADDSYM(is_running);
@ -139,6 +188,8 @@ liblammpsplugin_t *liblammpsplugin_load(const char *lib)
lmp->has_error = NULL; lmp->has_error = NULL;
lmp->get_last_error_message = NULL; lmp->get_last_error_message = NULL;
#endif #endif
ADDSYM(python_api_version);
return lmp; return lmp;
} }
@ -147,7 +198,11 @@ int liblammpsplugin_release(liblammpsplugin_t *lmp)
if (lmp == NULL) return 1; if (lmp == NULL) return 1;
if (lmp->handle == NULL) return 2; if (lmp->handle == NULL) return 2;
#ifdef _WIN32
FreeLibrary((HINSTANCE) lmp->handle);
#else
dlclose(lmp->handle); dlclose(lmp->handle);
#endif
free((void *)lmp); free((void *)lmp);
return 0; return 0;
} }

View File

@ -1,7 +1,7 @@
/* -*- c++ -*- ---------------------------------------------------------- /* -*- c++ -*- ----------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
https://www.lammps.org/ Sandia National Laboratories https://www.lammps.org/, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov LAMMPS development team: developers@lammps.org
Copyright (2003) Sandia Corporation. Under the terms of Contract Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
@ -28,11 +28,71 @@
#define LAMMPS_SMALLBIG #define LAMMPS_SMALLBIG
#endif #endif
#if defined(LAMMPS_LIB_MPI)
#include <mpi.h> #include <mpi.h>
#if defined(LAMMPS_BIGBIG) || defined(LAMMPS_SMALLBIG)
#include <inttypes.h> /* for int64_t */
#endif #endif
#if defined(LAMMPS_BIGBIG) || defined(LAMMPS_SMALLBIG)
#include <stdint.h> /* for int64_t */
#endif
/* The following enums must be kept in sync with the equivalent enums
* or constants in python/lammps/constants.py, fortran/lammps.f90,
* tools/swig/lammps.i, and examples/COUPLE/plugin/liblammpsplugin.h */
/* Data type constants for extracting data from atoms, computes and fixes */
enum _LMP_DATATYPE_CONST {
LAMMPS_INT = 0, /*!< 32-bit integer (array) */
LAMMPS_INT_2D = 1, /*!< two-dimensional 32-bit integer array */
LAMMPS_DOUBLE = 2, /*!< 64-bit double (array) */
LAMMPS_DOUBLE_2D = 3, /*!< two-dimensional 64-bit double array */
LAMMPS_INT64 = 4, /*!< 64-bit integer (array) */
LAMMPS_INT64_2D = 5, /*!< two-dimensional 64-bit integer array */
LAMMPS_STRING = 6 /*!< C-String */
};
/* Style constants for extracting data from computes and fixes. */
enum _LMP_STYLE_CONST {
LMP_STYLE_GLOBAL = 0, /*!< return global data */
LMP_STYLE_ATOM = 1, /*!< return per-atom data */
LMP_STYLE_LOCAL = 2 /*!< return local data */
};
/* Type and size constants for extracting data from computes and fixes. */
enum _LMP_TYPE_CONST {
LMP_TYPE_SCALAR = 0, /*!< return scalar */
LMP_TYPE_VECTOR = 1, /*!< return vector */
LMP_TYPE_ARRAY = 2, /*!< return array */
LMP_SIZE_VECTOR = 3, /*!< return length of vector */
LMP_SIZE_ROWS = 4, /*!< return number of rows */
LMP_SIZE_COLS = 5 /*!< return number of columns */
};
/* Error codes to select the suitable function in the Error class */
enum _LMP_ERROR_CONST {
LMP_ERROR_WARNING = 0, /*!< call Error::warning() */
LMP_ERROR_ONE = 1, /*!< called from one MPI rank */
LMP_ERROR_ALL = 2, /*!< called from all MPI ranks */
LMP_ERROR_WORLD = 4, /*!< error on Comm::world */
LMP_ERROR_UNIVERSE = 8 /*!< error on Comm::universe */
};
/** Variable style constants for extracting data from variables.
*
* Must be kept in sync with the equivalent constants in python/lammps/constants.py,
* fortran/lammps.f90, and tools/swig/lammps.i */
enum _LMP_VAR_CONST {
LMP_VAR_EQUAL = 0, /*!< compatible with equal-style variables */
LMP_VAR_ATOM = 1, /*!< compatible with atom-style variables */
LMP_VAR_VECTOR = 2, /*!< compatible with vector-style variables */
LMP_VAR_STRING = 3 /*!< return value will be a string (catch-all) */
};
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
@ -49,7 +109,11 @@ struct _liblammpsplugin {
int abiversion; int abiversion;
int has_exceptions; int has_exceptions;
void *handle; void *handle;
#if defined(LAMMPS_LIB_MPI)
void *(*open)(int, char **, MPI_Comm, void **); void *(*open)(int, char **, MPI_Comm, void **);
#else
void *open;
#endif
void *(*open_no_mpi)(int, char **, void **); void *(*open_no_mpi)(int, char **, void **);
void *(*open_fortran)(int, char **, void **, int); void *(*open_fortran)(int, char **, void **, int);
void (*close)(void *); void (*close)(void *);
@ -59,13 +123,15 @@ struct _liblammpsplugin {
void (*kokkos_finalize)(); void (*kokkos_finalize)();
void (*python_finalize)(); void (*python_finalize)();
void (*error)(void *, int, const char *);
void (*file)(void *, char *); void (*file)(void *, char *);
char *(*command)(void *, const char *); char *(*command)(void *, const char *);
void (*commands_list)(void *, int, const char **); void (*commands_list)(void *, int, const char **);
void (*commands_string)(void *, const char *); void (*commands_string)(void *, const char *);
double (*get_natoms)(void *); double (*get_natoms)(void *);
double (*get_thermo)(void *, char *); double (*get_thermo)(void *, const char *);
void (*extract_box)(void *, double *, double *, void (*extract_box)(void *, double *, double *,
double *, double *, double *, int *, int *); double *, double *, double *, int *, int *);
@ -78,12 +144,13 @@ struct _liblammpsplugin {
int *(*extract_global_datatype)(void *, const char *); int *(*extract_global_datatype)(void *, const char *);
void *(*extract_global)(void *, const char *); void *(*extract_global)(void *, const char *);
void *(*extract_atom_datatype)(void *, const char *); int *(*extract_atom_datatype)(void *, const char *);
void *(*extract_atom)(void *, const char *); void *(*extract_atom)(void *, const char *);
void *(*extract_compute)(void *, const char *, int, int); void *(*extract_compute)(void *, const char *, int, int);
void *(*extract_fix)(void *, const char *, int, int, int, int); void *(*extract_fix)(void *, const char *, int, int, int, int);
void *(*extract_variable)(void *, const char *, char *); void *(*extract_variable)(void *, const char *, char *);
int (*extract_variable_datatype)(void *, const char *);
int (*set_variable)(void *, char *, char *); int (*set_variable)(void *, char *, char *);
void (*gather_atoms)(void *, char *, int, int, void *); void (*gather_atoms)(void *, char *, int, int, void *);
@ -94,21 +161,25 @@ struct _liblammpsplugin {
void (*gather_bonds)(void *, void *); void (*gather_bonds)(void *, void *);
// lammps_create_atoms() takes tagint and imageint as args void (*gather)(void *, char *, int, int, void *);
// ifdef insures they are compatible with rest of LAMMPS void (*gather_concat)(void *, char *, int, int, void *);
// caller must match to how LAMMPS library is built void (*gather_subset)(void *, char *, int, int, int, int *,void *);
void (*scatter)(void *, char *, int, int, void *);
void (*scatter_subset)(void *, char *, int, int, int, int *, void *);
/* lammps_create_atoms() takes tagint and imageint as args
* the ifdef insures they are compatible with rest of LAMMPS
* caller must match to how LAMMPS library is built */
#ifndef LAMMPS_BIGBIG #ifndef LAMMPS_BIGBIG
void (*create_atoms)(void *, int, int *, int *, double *, void (*create_atoms)(void *, int, int *, int *, double *, double *, int *, int);
double *, int *, int);
#else #else
void (*create_atoms)(void *, int, int64_t *, int *, double *, void (*create_atoms)(void *, int, int64_t *, int *, double *, double *, int64_t *, int);
double *, int64_t *, int);
#endif #endif
int (*find_pair_neighlist)(void *, const char *, int, int, int); int (*find_pair_neighlist)(void *, const char *, int, int, int);
int (*find_fix_neighlist)(void *, const char *, int); int (*find_fix_neighlist)(void *, const char *, int);
int (*find_compute_neighlist)(void *, char *, int); int (*find_compute_neighlist)(void *, const char *, int);
int (*neighlist_num_elements)(void *, int); int (*neighlist_num_elements)(void *, int);
void (*neighlist_element_neighbors)(void *, int, int, int *, int *, int **); void (*neighlist_element_neighbors)(void *, int, int, int *, int *, int **);
@ -141,8 +212,16 @@ struct _liblammpsplugin {
int (*plugin_count)(); int (*plugin_count)();
int (*plugin_name)(int, char *, char *, int); int (*plugin_name)(int, char *, char *, int);
void (*set_fix_external_callback)(void *, const char *, FixExternalFnPtr, void*); #if !defined(LAMMPS_BIGBIG)
void (*fix_external_get_force)(void *, const char *); int (*encode_image_flags)(int, int, int);
void (*decode_image_flags)(int, int *);
#else
int64_t (*encode_image_flags)(int, int, int);
void (*decode_image_flags)(int64_t, int *);
#endif
void (*set_fix_external_callback)(void *, const char *, FixExternalFnPtr, void *);
double **(*fix_external_get_force)(void *, const char *);
void (*fix_external_set_energy_global)(void *, const char *, double); void (*fix_external_set_energy_global)(void *, const char *, double);
void (*fix_external_set_energy_peratom)(void *, const char *, double *); void (*fix_external_set_energy_peratom)(void *, const char *, double *);
void (*fix_external_set_virial_global)(void *, const char *, double *); void (*fix_external_set_virial_global)(void *, const char *, double *);
@ -150,6 +229,8 @@ struct _liblammpsplugin {
void (*fix_external_set_vector_length)(void *, const char *, int); void (*fix_external_set_vector_length)(void *, const char *, int);
void (*fix_external_set_vector)(void *, const char *, int, double); void (*fix_external_set_vector)(void *, const char *, int, double);
void (*flush_buffers)(void *);
void (*free)(void *); void (*free)(void *);
void (*is_running)(void *); void (*is_running)(void *);
@ -157,6 +238,8 @@ struct _liblammpsplugin {
int (*has_error)(void *); int (*has_error)(void *);
int (*get_last_error_message)(void *, char *, int); int (*get_last_error_message)(void *, char *, int);
int (*python_api_version)();
}; };
typedef struct _liblammpsplugin liblammpsplugin_t; typedef struct _liblammpsplugin liblammpsplugin_t;

View File

@ -1,7 +1,7 @@
/* ---------------------------------------------------------------------- /* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
www.cs.sandia.gov/~sjplimp/lammps.html https://www.lammps.org, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov, Sandia National Laboratories LAMMPS development team: developers@lammps.org
Copyright (2003) Sandia Corporation. Under the terms of Contract Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
@ -19,10 +19,16 @@
in.lammps = LAMMPS input script in.lammps = LAMMPS input script
See README for compilation instructions */ See README for compilation instructions */
#include <mpi.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <mpi.h>
/* define so interface to lammps_open() is available,
since we will run on split communicator */
#define LAMMPS_LIB_MPI 1
#include "liblammpsplugin.h" /* this is the include for the plugin loader */ #include "liblammpsplugin.h" /* this is the include for the plugin loader */
int main(int narg, char **arg) int main(int narg, char **arg)
@ -87,7 +93,13 @@ int main(int narg, char **arg)
MPI_Abort(MPI_COMM_WORLD,1); MPI_Abort(MPI_COMM_WORLD,1);
} }
} }
if (lammps == 1) lmp = plugin->open(0,NULL,comm_lammps,NULL); if (lammps == 1) {
if (plugin->open == NULL) {
printf("ERROR: liblammpsmpi.c must be compiled with -DLAMMPS_LIB_MPI=1 for this program\n");
MPI_Abort(MPI_COMM_WORLD,2);
}
lmp = plugin->open(0,NULL,comm_lammps,NULL);
}
while (1) { while (1) {
if (me == 0) { if (me == 0) {
@ -112,23 +124,23 @@ int main(int narg, char **arg)
int natoms = plugin->get_natoms(lmp); int natoms = plugin->get_natoms(lmp);
x = (double *) malloc(3*natoms*sizeof(double)); x = (double *) malloc(3*natoms*sizeof(double));
plugin->gather_atoms(lmp,"x",1,3,x); plugin->gather_atoms(lmp,(char *)"x",1,3,x);
v = (double *) malloc(3*natoms*sizeof(double)); v = (double *) malloc(3*natoms*sizeof(double));
plugin->gather_atoms(lmp,"v",1,3,v); plugin->gather_atoms(lmp,(char *)"v",1,3,v);
double epsilon = 0.1; double epsilon = 0.1;
x[0] += epsilon; x[0] += epsilon;
plugin->scatter_atoms(lmp,"x",1,3,x); plugin->scatter_atoms(lmp,(char *)"x",1,3,x);
plugin->command(lmp,"run 1"); plugin->command(lmp,"run 1");
} }
// extract force on single atom two different ways /* extract force on single atom two different ways */
if (lammps == 1) { if (lammps == 1) {
double **f = (double **) plugin->extract_atom(lmp,"f"); double **f = (double **) plugin->extract_atom(lmp,"f");
printf("Force on 1 atom via extract_atom: %g\n",f[0][0]); printf("Force on 1 atom via extract_atom: %g\n",f[0][0]);
double *fx = (double *) plugin->extract_variable(lmp,"fx","all"); double *fx = (double *) plugin->extract_variable(lmp,"fx",(char *)"all");
printf("Force on 1 atom via extract_variable: %g\n",fx[0]); printf("Force on 1 atom via extract_variable: %g\n",fx[0]);
} }
@ -160,7 +172,7 @@ int main(int narg, char **arg)
if (v) free(v); if (v) free(v);
if (type) free(type); if (type) free(type);
// close down LAMMPS /* close down LAMMPS */
if (lammps == 1) { if (lammps == 1) {
plugin->close(lmp); plugin->close(lmp);