Merge pull request #449 from rbberger/python_refactoring
Add Python 3 compatibility and expand Python interface availability
This commit is contained in:
@ -118,11 +118,6 @@ check which version of Python you have installed, by simply typing
|
||||
|
||||
11.2 Overview of using Python from a LAMMPS script :link(py_2),h4
|
||||
|
||||
NOTE: It is not currently possible to use the "python"_python.html
|
||||
command described in this section with Python 3, only with Python 2.
|
||||
The C API changed from Python 2 to 3 and the LAMMPS code is not
|
||||
compatible with both.
|
||||
|
||||
LAMMPS has a "python"_python.html command which can be used in an
|
||||
input script to define and execute a Python function that you write
|
||||
the code for. The Python function can also be assigned to a LAMMPS
|
||||
|
||||
@ -50,7 +50,7 @@ def factorial(n):
|
||||
return n * factorial(n-1)
|
||||
""" :pre
|
||||
|
||||
python loop input 1 SELF return v_value format -f here """
|
||||
python loop input 1 SELF return v_value format pf here """
|
||||
def loop(lmpptr,N,cut0):
|
||||
from lammps import lammps
|
||||
lmp = lammps(ptr=lmpptr) :pre
|
||||
@ -59,7 +59,7 @@ def loop(lmpptr,N,cut0):
|
||||
|
||||
for i in range(N):
|
||||
cut = cut0 + i*0.1
|
||||
lmp.set_variable("cut",cut) # set a variable in LAMMPS
|
||||
lmp.set_variable("cut",cut) # set a variable in LAMMPS
|
||||
lmp.command("pair_style lj/cut $\{cut\}") # LAMMPS commands
|
||||
lmp.command("pair_coeff * * 1.0 1.0")
|
||||
lmp.command("run 100")
|
||||
@ -67,11 +67,6 @@ def loop(lmpptr,N,cut0):
|
||||
|
||||
[Description:]
|
||||
|
||||
NOTE: It is not currently possible to use the "python"_python.html
|
||||
command described in this section with Python 3, only with Python 2.
|
||||
The C API changed from Python 2 to 3 and the LAMMPS code is not
|
||||
compatible with both.
|
||||
|
||||
Define a Python function or execute a previously defined function.
|
||||
Arguments, including LAMMPS variables, can be passed to the function
|
||||
from the LAMMPS input script and a value returned by the Python
|
||||
@ -477,16 +472,7 @@ python"_Section_python.html. Note that it is important that the
|
||||
stand-alone LAMMPS executable and the LAMMPS shared library be
|
||||
consistent (built from the same source code files) in order for this
|
||||
to work. If the two have been built at different times using
|
||||
different source files, problems may occur.
|
||||
|
||||
As described above, you can use the python command to invoke a Python
|
||||
function which calls back to LAMMPS through its Python-wrapped library
|
||||
interface. However you cannot do the opposite. I.e. you cannot call
|
||||
LAMMPS from Python and invoke the python command to "callback" to
|
||||
Python and execute a Python function. LAMMPS will generate an error
|
||||
if you try to do that. Note that we think there actually should be a
|
||||
way to do that, but haven't yet been able to figure out how to do it
|
||||
successfully.
|
||||
different source files, problems may occur.
|
||||
|
||||
[Related commands:]
|
||||
|
||||
|
||||
@ -55,7 +55,7 @@ using the generated {auto} Makefile.
|
||||
cd $LAMMPS_DIR/src :pre
|
||||
|
||||
# generate custom Makefile
|
||||
python2 Make.py -jpg -png -s ffmpeg exceptions -m mpi -a file :pre
|
||||
python Make.py -jpg -png -s ffmpeg exceptions -m mpi -a file :pre
|
||||
|
||||
# add packages if necessary
|
||||
make yes-MOLECULE :pre
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
# Python function that implements a loop of short runs
|
||||
# calls back to LAMMPS via "lmp" instance
|
||||
# lammps() must be called with ptr=lmpptr for this to work
|
||||
from __future__ import print_function
|
||||
|
||||
def loop(N,cut0,thresh,lmpptr):
|
||||
print "LOOP ARGS",N,cut0,thresh,lmpptr
|
||||
print("LOOP ARGS",N,cut0,thresh,lmpptr)
|
||||
from lammps import lammps
|
||||
lmp = lammps(ptr=lmpptr)
|
||||
natoms = lmp.get_natoms()
|
||||
@ -12,11 +13,12 @@ def loop(N,cut0,thresh,lmpptr):
|
||||
cut = cut0 + i*0.1
|
||||
|
||||
lmp.set_variable("cut",cut) # set a variable in LAMMPS
|
||||
|
||||
lmp.command("pair_style lj/cut ${cut}") # LAMMPS command
|
||||
#lmp.command("pair_style lj/cut %d" % cut) # LAMMPS command option
|
||||
|
||||
lmp.command("pair_coeff * * 1.0 1.0") # ditto
|
||||
lmp.command("run 10") # ditto
|
||||
pe = lmp.extract_compute("thermo_pe",0,0) # extract total PE from LAMMPS
|
||||
print "PE",pe/natoms,thresh
|
||||
print("PE",pe/natoms,thresh)
|
||||
if pe/natoms < thresh: return
|
||||
|
||||
@ -25,13 +25,14 @@ run 10
|
||||
# example of catching a syntax error
|
||||
|
||||
python simple here """
|
||||
from __future__ import print_function
|
||||
|
||||
def simple():
|
||||
import exceptions
|
||||
print "Inside simple function"
|
||||
print("Inside simple function")
|
||||
try:
|
||||
foo += 1
|
||||
except Exception, e:
|
||||
print "FOO error:",e
|
||||
except Exception as e:
|
||||
print("FOO error:", e)
|
||||
"""
|
||||
|
||||
python simple invoke
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
# Settings that the LAMMPS build will import when this package library is used
|
||||
# See the README file for more explanation
|
||||
|
||||
python_SYSINC = $(shell which python2-config > /dev/null 2>&1 && python2-config --includes || python-config --includes )
|
||||
python_SYSLIB = $(shell which python2-config > /dev/null 2>&1 && python2-config --ldflags || python-config --ldflags)
|
||||
python_SYSINC = $(shell which python-config > /dev/null 2>&1 && python-config --includes || :)
|
||||
python_SYSLIB = $(shell which python-config > /dev/null 2>&1 && python-config --ldflags || :)
|
||||
python_SYSPATH =
|
||||
PYTHON=python
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
# Settings that the LAMMPS build will import when this package library is used
|
||||
# See the README file for more explanation
|
||||
|
||||
python_SYSINC = $(shell which python2-config > /dev/null 2>&1 && python2-config --includes || python-config --includes )
|
||||
python_SYSLIB = $(shell which python2-config > /dev/null 2>&1 && python2-config --ldflags || python-config --ldflags)
|
||||
python_SYSINC = $(shell which python2-config > /dev/null 2>&1 && python2-config --includes || (which python-config > /dev/null 2>&1 && python-config --includes || :))
|
||||
python_SYSLIB = $(shell which python2-config > /dev/null 2>&1 && python2-config --ldflags || (which python-config > /dev/null 2>&1 && python-config --ldflags || :))
|
||||
python_SYSPATH =
|
||||
PYTHON=$(shell which python2 > /dev/null 2>&1 && echo python2 || echo python)
|
||||
|
||||
@ -4,3 +4,4 @@
|
||||
python_SYSINC = -I/usr/local/include/python2.7
|
||||
python_SYSLIB = -lpython2.7 -lnsl -ldl -lreadline -ltermcap -lpthread -lutil -lm -Xlinker -export-dynamic
|
||||
python_SYSPATH =
|
||||
PYTHON=python2.7
|
||||
|
||||
7
lib/python/Makefile.lammps.python3
Normal file
7
lib/python/Makefile.lammps.python3
Normal file
@ -0,0 +1,7 @@
|
||||
# Settings that the LAMMPS build will import when this package library is used
|
||||
# See the README file for more explanation
|
||||
|
||||
python_SYSINC = $(shell which python3-config > /dev/null 2>&1 && python3-config --includes || (which python-config > /dev/null 2>&1 && python-config --includes || :))
|
||||
python_SYSLIB = $(shell which python3-config > /dev/null 2>&1 && python3-config --ldflags || (which python-config > /dev/null 2>&1 && python-config --ldflags || :))
|
||||
python_SYSPATH =
|
||||
PYTHON=$(shell which python3 > /dev/null 2>&1 && echo python3 || echo python)
|
||||
@ -1,26 +1,26 @@
|
||||
The Makefile.lammps file in this directory is used when building
|
||||
LAMMPS with its PYTHON package installed. The file has several
|
||||
settings needed to compile and link LAMMPS with the Python library.
|
||||
You should choose a Makefile.lammps.* file compatible with your system
|
||||
and your version of Python, and copy it to Makefile.lammps before
|
||||
building LAMMPS itself. You may need to edit one of the provided
|
||||
files to match your system.
|
||||
|
||||
Note that is not currently possible to use the PYTHON package with
|
||||
Python 3, only with Python 2. The C API changed from Python 2 to 3
|
||||
and the LAMMPS code is not compatible with both.
|
||||
The default Makefile.lammps will automatically choose the default
|
||||
python interpreter of your system and will infer the flags from
|
||||
the python-config utility, that is usually bundled with the python
|
||||
installation. If needed, you can copy one of the other provided
|
||||
Makefile.lammps.* files to to Makefile.lammps before building
|
||||
LAMMPS itself.
|
||||
|
||||
If you create a new Makefile.lammps file suitable for some version of
|
||||
Python on some system, that is not a match to one of the provided
|
||||
Makefile.lammps.* files, you can send it to the developers, and we can
|
||||
include it in the distribution for others to use.
|
||||
|
||||
To illustrate, these are example settings from the
|
||||
Makefile.lammps.python2.7 file:
|
||||
The files Makefile.lammps.python2 and Makefile.lammps.python3 are
|
||||
similar to the default file, but meant for the case that both,
|
||||
python 2 and python 3, are installed simultaneously and you want
|
||||
to prefer one over the other. If neither of these files work, you
|
||||
may have to create a custom Makefile.lammps file suitable for
|
||||
the version of Python on your system. To illustrate, these are
|
||||
example settings from the Makefile.lammps.python2.7 file:
|
||||
|
||||
python_SYSINC = -I/usr/local/include/python2.7
|
||||
python_SYSLIB = -lpython2.7 -lnsl -ldl -lreadline -ltermcap -lpthread -lutil -lm
|
||||
python_SYSPATH =
|
||||
python_SYSPATH =
|
||||
PYTHON=python2.7
|
||||
|
||||
python_SYSINC refers to the directory where Python's Python.h file is
|
||||
found. LAMMPS includes this file.
|
||||
@ -30,10 +30,13 @@ application (LAMMPS in this case) to "embed" Python in the
|
||||
application. The Python library itself is listed (-lpython2.7) are
|
||||
are several system libraries needed by Python.
|
||||
|
||||
python_SYSPATH = refers to the path (e.g. -L/usr/local/lib) where the
|
||||
python_SYSPATH refers to the path (e.g. -L/usr/local/lib) where the
|
||||
Python library can be found. You may not need this setting if the
|
||||
path is already included in your LD_LIBRARY_PATH environment variable.
|
||||
|
||||
PYTHON is the name of the python interpreter. It is used for
|
||||
installing the LAMMPS python module with "make install-python"
|
||||
|
||||
-------------------------
|
||||
|
||||
Note that the trickiest issue to figure out for inclusion in
|
||||
|
||||
@ -30,7 +30,7 @@ from collections import namedtuple
|
||||
import os
|
||||
import select
|
||||
import re
|
||||
|
||||
import sys
|
||||
|
||||
class MPIAbortException(Exception):
|
||||
def __init__(self, message):
|
||||
@ -151,9 +151,16 @@ class lammps(object):
|
||||
|
||||
else:
|
||||
# magic to convert ptr to ctypes ptr
|
||||
pythonapi.PyCObject_AsVoidPtr.restype = c_void_p
|
||||
pythonapi.PyCObject_AsVoidPtr.argtypes = [py_object]
|
||||
self.lmp = c_void_p(pythonapi.PyCObject_AsVoidPtr(ptr))
|
||||
if sys.version_info >= (3, 0):
|
||||
# Python 3 (uses PyCapsule API)
|
||||
pythonapi.PyCapsule_GetPointer.restype = c_void_p
|
||||
pythonapi.PyCapsule_GetPointer.argtypes = [py_object, c_char_p]
|
||||
self.lmp = c_void_p(pythonapi.PyCapsule_GetPointer(ptr, None))
|
||||
else:
|
||||
# Python 2 (uses PyCObject API)
|
||||
pythonapi.PyCObject_AsVoidPtr.restype = c_void_p
|
||||
pythonapi.PyCObject_AsVoidPtr.argtypes = [py_object]
|
||||
self.lmp = c_void_p(pythonapi.PyCObject_AsVoidPtr(ptr))
|
||||
|
||||
def __del__(self):
|
||||
if self.lmp and self.opened:
|
||||
@ -305,7 +312,7 @@ class lammps(object):
|
||||
def set_variable(self,name,value):
|
||||
if name: name = name.encode()
|
||||
if value: value = str(value).encode()
|
||||
return self.lib.lammps_set_variable(self.lmp,name,str(value))
|
||||
return self.lib.lammps_set_variable(self.lmp,name,value)
|
||||
|
||||
# return current value of thermo keyword
|
||||
|
||||
|
||||
2
src/.gitignore
vendored
2
src/.gitignore
vendored
@ -848,8 +848,6 @@
|
||||
/pppm_tip4p_cg.h
|
||||
/prd.cpp
|
||||
/prd.h
|
||||
/python.cpp
|
||||
/python.h
|
||||
/python_impl.cpp
|
||||
/python_impl.h
|
||||
/reader_molfile.cpp
|
||||
|
||||
@ -223,7 +223,8 @@ mpi-stubs:
|
||||
@cd STUBS; $(MAKE) clean; $(MAKE)
|
||||
|
||||
# install LAMMPS shared lib and Python wrapper for Python usage
|
||||
|
||||
# include python package settings to automatically adapt name of python interpreter
|
||||
sinclude ../lib/python/Makefile.lammps
|
||||
install-python:
|
||||
@$(PYTHON) ../python/install.py
|
||||
|
||||
|
||||
@ -26,11 +26,9 @@ action () {
|
||||
fi
|
||||
}
|
||||
|
||||
# force rebuild of files with LMP_KOKKOS switch
|
||||
# also variable so its *.d dependence on changed python_wrapper.h is rebuilt
|
||||
# force rebuild of files using python header
|
||||
|
||||
touch ../python_wrapper.h
|
||||
touch ../variable.cpp
|
||||
touch ../python.h
|
||||
|
||||
# all package files with no dependencies
|
||||
|
||||
|
||||
@ -25,25 +25,51 @@ enum{NONE,INT,DOUBLE,STRING,PTR};
|
||||
|
||||
#define VALUELENGTH 64 // also in variable.cpp
|
||||
|
||||
// Wrap API changes between Python 2 and 3 using macros
|
||||
#if PY_MAJOR_VERSION == 2
|
||||
#define PY_INT_FROM_LONG(X) PyInt_FromLong(X)
|
||||
#define PY_INT_AS_LONG(X) PyInt_AsLong(X)
|
||||
#define PY_STRING_FROM_STRING(X) PyString_FromString(X)
|
||||
#define PY_VOID_POINTER(X) PyCObject_FromVoidPtr((void *) X, NULL)
|
||||
#define PY_STRING_AS_STRING(X) PyString_AsString(X)
|
||||
|
||||
#elif PY_MAJOR_VERSION == 3
|
||||
#define PY_INT_FROM_LONG(X) PyLong_FromLong(X)
|
||||
#define PY_INT_AS_LONG(X) PyLong_AsLong(X)
|
||||
#define PY_STRING_FROM_STRING(X) PyUnicode_FromString(X)
|
||||
#define PY_VOID_POINTER(X) PyCapsule_New((void *) X, NULL, NULL)
|
||||
#define PY_STRING_AS_STRING(X) PyUnicode_AsUTF8(X)
|
||||
#endif
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
Python::Python(LAMMPS *lmp) : Pointers(lmp)
|
||||
PythonImpl::PythonImpl(LAMMPS *lmp) : Pointers(lmp)
|
||||
{
|
||||
python_exists = 1;
|
||||
|
||||
pyMain = NULL;
|
||||
|
||||
// pfuncs stores interface info for each Python function
|
||||
|
||||
nfunc = 0;
|
||||
pfuncs = NULL;
|
||||
|
||||
external_interpreter = false;
|
||||
// one-time initialization of Python interpreter
|
||||
// pymain stores pointer to main module
|
||||
external_interpreter = Py_IsInitialized();
|
||||
|
||||
Py_Initialize();
|
||||
PyEval_InitThreads();
|
||||
|
||||
PyGILState_STATE gstate = PyGILState_Ensure();
|
||||
|
||||
PyObject *pModule = PyImport_AddModule("__main__");
|
||||
if (!pModule) error->all(FLERR,"Could not initialize embedded Python");
|
||||
|
||||
pyMain = (void *) pModule;
|
||||
|
||||
PyGILState_Release(gstate);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
Python::~Python()
|
||||
PythonImpl::~PythonImpl()
|
||||
{
|
||||
if(pyMain) {
|
||||
// clean up
|
||||
@ -71,7 +97,7 @@ Python::~Python()
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
void Python::command(int narg, char **arg)
|
||||
void PythonImpl::command(int narg, char **arg)
|
||||
{
|
||||
if (narg < 2) error->all(FLERR,"Invalid python command");
|
||||
|
||||
@ -156,22 +182,7 @@ void Python::command(int narg, char **arg)
|
||||
|
||||
int ifunc = create_entry(arg[0]);
|
||||
|
||||
// one-time initialization of Python interpreter
|
||||
// pymain stores pointer to main module
|
||||
PyGILState_STATE gstate;
|
||||
|
||||
if (pyMain == NULL) {
|
||||
external_interpreter = Py_IsInitialized();
|
||||
Py_Initialize();
|
||||
PyEval_InitThreads();
|
||||
gstate = PyGILState_Ensure();
|
||||
|
||||
PyObject *pModule = PyImport_AddModule("__main__");
|
||||
if (!pModule) error->all(FLERR,"Could not initialize embedded Python");
|
||||
pyMain = (void *) pModule;
|
||||
} else {
|
||||
gstate = PyGILState_Ensure();
|
||||
}
|
||||
PyGILState_STATE gstate = PyGILState_Ensure();
|
||||
|
||||
// send Python code to Python interpreter
|
||||
// file: read the file via PyRun_SimpleFile()
|
||||
@ -230,7 +241,7 @@ void Python::command(int narg, char **arg)
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
void Python::invoke_function(int ifunc, char *result)
|
||||
void PythonImpl::invoke_function(int ifunc, char *result)
|
||||
{
|
||||
PyGILState_STATE gstate = PyGILState_Ensure();
|
||||
PyObject *pValue;
|
||||
@ -259,8 +270,10 @@ void Python::invoke_function(int ifunc, char *result)
|
||||
error->all(FLERR,"Could not evaluate Python function input variable");
|
||||
}
|
||||
|
||||
pValue = PyInt_FromLong(atoi(str));
|
||||
} else pValue = PyInt_FromLong(pfuncs[ifunc].ivalue[i]);
|
||||
pValue = PY_INT_FROM_LONG(atoi(str));
|
||||
} else {
|
||||
pValue = PY_INT_FROM_LONG(pfuncs[ifunc].ivalue[i]);
|
||||
}
|
||||
} else if (itype == DOUBLE) {
|
||||
if (pfuncs[ifunc].ivarflag[i]) {
|
||||
str = input->variable->retrieve(pfuncs[ifunc].svalue[i]);
|
||||
@ -271,7 +284,9 @@ void Python::invoke_function(int ifunc, char *result)
|
||||
}
|
||||
|
||||
pValue = PyFloat_FromDouble(atof(str));
|
||||
} else pValue = PyFloat_FromDouble(pfuncs[ifunc].dvalue[i]);
|
||||
} else {
|
||||
pValue = PyFloat_FromDouble(pfuncs[ifunc].dvalue[i]);
|
||||
}
|
||||
} else if (itype == STRING) {
|
||||
if (pfuncs[ifunc].ivarflag[i]) {
|
||||
str = input->variable->retrieve(pfuncs[ifunc].svalue[i]);
|
||||
@ -279,10 +294,13 @@ void Python::invoke_function(int ifunc, char *result)
|
||||
PyGILState_Release(gstate);
|
||||
error->all(FLERR,"Could not evaluate Python function input variable");
|
||||
}
|
||||
pValue = PyString_FromString(str);
|
||||
} else pValue = PyString_FromString(pfuncs[ifunc].svalue[i]);
|
||||
|
||||
pValue = PY_STRING_FROM_STRING(str);
|
||||
} else {
|
||||
pValue = PY_STRING_FROM_STRING(pfuncs[ifunc].svalue[i]);
|
||||
}
|
||||
} else if (itype == PTR) {
|
||||
pValue = PyCObject_FromVoidPtr((void *) lmp,NULL);
|
||||
pValue = PY_VOID_POINTER(lmp);
|
||||
}
|
||||
PyTuple_SetItem(pArgs,i,pValue);
|
||||
}
|
||||
@ -306,11 +324,11 @@ void Python::invoke_function(int ifunc, char *result)
|
||||
if (pfuncs[ifunc].noutput) {
|
||||
int otype = pfuncs[ifunc].otype;
|
||||
if (otype == INT) {
|
||||
sprintf(result,"%ld",PyInt_AsLong(pValue));
|
||||
sprintf(result,"%ld",PY_INT_AS_LONG(pValue));
|
||||
} else if (otype == DOUBLE) {
|
||||
sprintf(result,"%.15g",PyFloat_AsDouble(pValue));
|
||||
} else if (otype == STRING) {
|
||||
char *pystr = PyString_AsString(pValue);
|
||||
char *pystr = PY_STRING_AS_STRING(pValue);
|
||||
if (pfuncs[ifunc].longstr)
|
||||
strncpy(pfuncs[ifunc].longstr,pystr,pfuncs[ifunc].length_longstr);
|
||||
else strncpy(result,pystr,VALUELENGTH-1);
|
||||
@ -323,7 +341,7 @@ void Python::invoke_function(int ifunc, char *result)
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
int Python::find(char *name)
|
||||
int PythonImpl::find(char *name)
|
||||
{
|
||||
for (int i = 0; i < nfunc; i++)
|
||||
if (strcmp(name,pfuncs[i].name) == 0) return i;
|
||||
@ -332,7 +350,7 @@ int Python::find(char *name)
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
int Python::variable_match(char *name, char *varname, int numeric)
|
||||
int PythonImpl::variable_match(char *name, char *varname, int numeric)
|
||||
{
|
||||
int ifunc = find(name);
|
||||
if (ifunc < 0) return -1;
|
||||
@ -344,14 +362,14 @@ int Python::variable_match(char *name, char *varname, int numeric)
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
char *Python::long_string(int ifunc)
|
||||
char *PythonImpl::long_string(int ifunc)
|
||||
{
|
||||
return pfuncs[ifunc].longstr;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
int Python::create_entry(char *name)
|
||||
int PythonImpl::create_entry(char *name)
|
||||
{
|
||||
// ifunc = index to entry by name in pfuncs vector, can be old or new
|
||||
// free old vectors if overwriting old pfunc
|
||||
@ -461,7 +479,7 @@ int Python::create_entry(char *name)
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
void Python::deallocate(int i)
|
||||
void PythonImpl::deallocate(int i)
|
||||
{
|
||||
delete [] pfuncs[i].itype;
|
||||
delete [] pfuncs[i].ivarflag;
|
||||
130
src/PYTHON/python_impl.h
Normal file
130
src/PYTHON/python_impl.h
Normal file
@ -0,0 +1,130 @@
|
||||
/* -*- c++ -*- ----------------------------------------------------------
|
||||
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
|
||||
http://lammps.sandia.gov, Sandia National Laboratories
|
||||
Steve Plimpton, sjplimp@sandia.gov
|
||||
|
||||
Copyright (2003) Sandia Corporation. Under the terms of Contract
|
||||
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
|
||||
certain rights in this software. This software is distributed under
|
||||
the GNU General Public License.
|
||||
|
||||
See the README file in the top-level LAMMPS directory.
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
#ifndef LMP_PYTHON_IMPL_H
|
||||
#define LMP_PYTHON_IMPL_H
|
||||
|
||||
#include "pointers.h"
|
||||
|
||||
namespace LAMMPS_NS {
|
||||
|
||||
class PythonImpl : protected Pointers, public PythonInterface {
|
||||
public:
|
||||
bool external_interpreter;
|
||||
|
||||
PythonImpl(class LAMMPS *);
|
||||
~PythonImpl();
|
||||
void command(int, char **);
|
||||
void invoke_function(int, char *);
|
||||
int find(char *);
|
||||
int variable_match(char *, char *, int);
|
||||
char *long_string(int);
|
||||
|
||||
private:
|
||||
int ninput,noutput,length_longstr;
|
||||
char **istr;
|
||||
char *ostr,*format;
|
||||
void *pyMain;
|
||||
|
||||
struct PyFunc {
|
||||
char *name;
|
||||
int ninput,noutput;
|
||||
int *itype,*ivarflag;
|
||||
int *ivalue;
|
||||
double *dvalue;
|
||||
char **svalue;
|
||||
int otype;
|
||||
char *ovarname;
|
||||
char *longstr;
|
||||
int length_longstr;
|
||||
void *pFunc;
|
||||
};
|
||||
|
||||
PyFunc *pfuncs;
|
||||
int nfunc;
|
||||
|
||||
int create_entry(char *);
|
||||
void deallocate(int);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* ERROR/WARNING messages:
|
||||
|
||||
E: Invalid python command
|
||||
|
||||
Self-explanatory. Check the input script syntax and compare to the
|
||||
documentation for the command. You can use -echo screen as a
|
||||
command-line option when running LAMMPS to see the offending line.
|
||||
|
||||
E: Python invoke of undefined function
|
||||
|
||||
Cannot invoke a function that has not been previously defined.
|
||||
|
||||
E: Python variable does not match Python function
|
||||
|
||||
This matching is defined by the python-style variable and the python
|
||||
command.
|
||||
|
||||
E: Cannot embed Python when also extending Python with LAMMPS
|
||||
|
||||
When running LAMMPS via Python through the LAMMPS library interface
|
||||
you cannot also user the input script python command.
|
||||
|
||||
E: Could not initialize embedded Python
|
||||
|
||||
The main module in Python was not accessible.
|
||||
|
||||
E: Could not open Python file
|
||||
|
||||
The specified file of Python code cannot be opened. Check that the
|
||||
path and name are correct.
|
||||
|
||||
E: Could not process Python file
|
||||
|
||||
The Python code in the specified file was not run successfully by
|
||||
Python, probably due to errors in the Python code.
|
||||
|
||||
E: Could not process Python string
|
||||
|
||||
The Python code in the here string was not run successfully by Python,
|
||||
probably due to errors in the Python code.
|
||||
|
||||
E: Could not find Python function
|
||||
|
||||
The provided Python code was run successfully, but it not
|
||||
define a callable function with the required name.
|
||||
|
||||
E: Python function is not callable
|
||||
|
||||
The provided Python code was run successfully, but it not
|
||||
define a callable function with the required name.
|
||||
|
||||
E: Could not create Python function arguments
|
||||
|
||||
This is an internal Python error, possibly because the number
|
||||
of inputs to the function is too large.
|
||||
|
||||
E: Could not evaluate Python function input variable
|
||||
|
||||
Self-explanatory.
|
||||
|
||||
E: Python function evaluation failed
|
||||
|
||||
The Python function did not run successfully and/or did not return a
|
||||
value (if it is supposed to return a value). This is probably due to
|
||||
some error condition in the function.
|
||||
|
||||
*/
|
||||
@ -45,6 +45,7 @@
|
||||
#include "accelerator_kokkos.h"
|
||||
#include "accelerator_omp.h"
|
||||
#include "timer.h"
|
||||
#include "python.h"
|
||||
#include "memory.h"
|
||||
#include "version.h"
|
||||
#include "error.h"
|
||||
@ -67,6 +68,7 @@ LAMMPS::LAMMPS(int narg, char **arg, MPI_Comm communicator)
|
||||
error = new Error(this);
|
||||
universe = new Universe(this,communicator);
|
||||
output = NULL;
|
||||
python = NULL;
|
||||
|
||||
screen = NULL;
|
||||
logfile = NULL;
|
||||
@ -585,6 +587,7 @@ LAMMPS::~LAMMPS()
|
||||
|
||||
if (world != universe->uworld) MPI_Comm_free(&world);
|
||||
|
||||
delete python;
|
||||
delete kokkos;
|
||||
delete [] suffix;
|
||||
delete [] suffix2;
|
||||
@ -639,6 +642,8 @@ void LAMMPS::create()
|
||||
// must be after modify so can create Computes
|
||||
update = new Update(this); // must be after output, force, neighbor
|
||||
timer = new Timer(this);
|
||||
|
||||
python = new Python(this);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
@ -759,6 +764,9 @@ void LAMMPS::destroy()
|
||||
|
||||
delete timer;
|
||||
timer = NULL;
|
||||
|
||||
delete python;
|
||||
python = NULL;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
|
||||
@ -54,6 +54,8 @@ class LAMMPS {
|
||||
class KokkosLMP *kokkos; // KOKKOS accelerator class
|
||||
class AtomKokkos *atomKK; // KOKKOS version of Atom class
|
||||
|
||||
class Python * python; // Python interface
|
||||
|
||||
class CiteMe *citeme; // citation info
|
||||
|
||||
LAMMPS(int, char **, MPI_Comm);
|
||||
|
||||
@ -56,7 +56,8 @@ class Pointers {
|
||||
infile(ptr->infile),
|
||||
screen(ptr->screen),
|
||||
logfile(ptr->logfile),
|
||||
atomKK(ptr->atomKK) {}
|
||||
atomKK(ptr->atomKK),
|
||||
python(ptr->python) {}
|
||||
virtual ~Pointers() {}
|
||||
|
||||
protected:
|
||||
@ -83,6 +84,7 @@ class Pointers {
|
||||
FILE *&logfile;
|
||||
|
||||
class AtomKokkos *&atomKK;
|
||||
class Python *&python;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
99
src/python.cpp
Normal file
99
src/python.cpp
Normal file
@ -0,0 +1,99 @@
|
||||
/* ----------------------------------------------------------------------
|
||||
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
|
||||
http://lammps.sandia.gov, Sandia National Laboratories
|
||||
Steve Plimpton, sjplimp@sandia.gov
|
||||
|
||||
Copyright (2003) Sandia Corporation. Under the terms of Contract
|
||||
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
|
||||
certain rights in this software. This software is distributed under
|
||||
the GNU General Public License.
|
||||
|
||||
See the README file in the top-level LAMMPS directory.
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
#include "python.h"
|
||||
#include "error.h"
|
||||
|
||||
using namespace LAMMPS_NS;
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
Python::Python(LAMMPS *lmp) : Pointers(lmp)
|
||||
{
|
||||
// implementation of Python interface is only loaded on demand
|
||||
// and only if PYTHON package has been installed and compiled into binary
|
||||
impl = NULL;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
Python::~Python()
|
||||
{
|
||||
delete impl;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
PythonInterface::~PythonInterface()
|
||||
{
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
void Python::init()
|
||||
{
|
||||
#if LMP_PYTHON
|
||||
if (!impl) impl = new PythonImpl(lmp);
|
||||
#else
|
||||
error->all(FLERR,"Python support missing! Compile with PYTHON package installed!");
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
bool Python::is_enabled() const {
|
||||
#if LMP_PYTHON
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
void Python::command(int narg, char **arg)
|
||||
{
|
||||
init();
|
||||
impl->command(narg, arg);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
void Python::invoke_function(int ifunc, char *result)
|
||||
{
|
||||
init();
|
||||
impl->invoke_function(ifunc, result);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
int Python::find(char *name)
|
||||
{
|
||||
init();
|
||||
return impl->find(name);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
int Python::variable_match(char *name, char *varname, int numeric)
|
||||
{
|
||||
init();
|
||||
return impl->variable_match(name, varname, numeric);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
char * Python::long_string(int ifunc)
|
||||
{
|
||||
init();
|
||||
return impl->long_string(ifunc);
|
||||
}
|
||||
@ -18,50 +18,42 @@
|
||||
|
||||
namespace LAMMPS_NS {
|
||||
|
||||
class Python : protected Pointers {
|
||||
public:
|
||||
int python_exists;
|
||||
bool external_interpreter;
|
||||
class PythonInterface {
|
||||
public:
|
||||
virtual ~PythonInterface();
|
||||
virtual void command(int, char **) = 0;
|
||||
virtual void invoke_function(int, char *) = 0;
|
||||
virtual int find(char *) = 0;
|
||||
virtual int variable_match(char *, char *, int) = 0;
|
||||
virtual char * long_string(int ifunc) = 0;
|
||||
};
|
||||
|
||||
class Python : protected Pointers {
|
||||
public:
|
||||
Python(class LAMMPS *);
|
||||
~Python();
|
||||
|
||||
void command(int, char **);
|
||||
void invoke_function(int, char *);
|
||||
int find(char *);
|
||||
int variable_match(char *, char *, int);
|
||||
char *long_string(int);
|
||||
char * long_string(int ifunc);
|
||||
|
||||
private:
|
||||
int ninput,noutput,length_longstr;
|
||||
char **istr;
|
||||
char *ostr,*format;
|
||||
void *pyMain;
|
||||
bool is_enabled() const;
|
||||
void init();
|
||||
|
||||
struct PyFunc {
|
||||
char *name;
|
||||
int ninput,noutput;
|
||||
int *itype,*ivarflag;
|
||||
int *ivalue;
|
||||
double *dvalue;
|
||||
char **svalue;
|
||||
int otype;
|
||||
char *ovarname;
|
||||
char *longstr;
|
||||
int length_longstr;
|
||||
void *pFunc;
|
||||
};
|
||||
|
||||
PyFunc *pfuncs;
|
||||
int nfunc;
|
||||
|
||||
int create_entry(char *);
|
||||
void deallocate(int);
|
||||
private:
|
||||
PythonInterface * impl;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if LMP_PYTHON
|
||||
#include "python_impl.h"
|
||||
#endif
|
||||
|
||||
/* ERROR/WARNING messages:
|
||||
|
||||
E: Invalid python command
|
||||
@ -1,47 +0,0 @@
|
||||
/* -*- c++ -*- ----------------------------------------------------------
|
||||
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
|
||||
http://lammps.sandia.gov, Sandia National Laboratories
|
||||
Steve Plimpton, sjplimp@sandia.gov
|
||||
|
||||
Copyright (2003) Sandia Corporation. Under the terms of Contract
|
||||
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
|
||||
certain rights in this software. This software is distributed under
|
||||
the GNU General Public License.
|
||||
|
||||
See the README file in the top-level LAMMPS directory.
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
#ifndef LMP_PYTHON_WRAPPER_H
|
||||
#define LMP_PYTHON_WRAPPER_H
|
||||
|
||||
// true interface to embedded Python
|
||||
// used when PYTHON package is installed
|
||||
|
||||
#ifdef LMP_PYTHON
|
||||
|
||||
#include "python.h"
|
||||
|
||||
#else
|
||||
|
||||
// dummy interface to PYTHON
|
||||
// needed for compiling when PYTHON is not installed
|
||||
|
||||
namespace LAMMPS_NS {
|
||||
|
||||
class Python {
|
||||
public:
|
||||
int python_exists;
|
||||
|
||||
Python(class LAMMPS *) {python_exists = 0;}
|
||||
~Python() {}
|
||||
void command(int, char **) {}
|
||||
void invoke_function(int, char *) {}
|
||||
int find(char *) {return -1;}
|
||||
int variable_match(char *, char *, int) {return -1;}
|
||||
char *long_string(int) {return NULL;}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
@ -34,7 +34,7 @@
|
||||
#include "random_mars.h"
|
||||
#include "math_const.h"
|
||||
#include "atom_masks.h"
|
||||
#include "python_wrapper.h"
|
||||
#include "python.h"
|
||||
#include "memory.h"
|
||||
#include "info.h"
|
||||
#include "error.h"
|
||||
@ -111,10 +111,6 @@ Variable::Variable(LAMMPS *lmp) : Pointers(lmp)
|
||||
precedence[MULTIPLY] = precedence[DIVIDE] = precedence[MODULO] = 6;
|
||||
precedence[CARAT] = 7;
|
||||
precedence[UNARY] = precedence[NOT] = 8;
|
||||
|
||||
// Python wrapper, real or dummy
|
||||
|
||||
python = new Python(lmp);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
@ -144,7 +140,6 @@ Variable::~Variable()
|
||||
delete randomequal;
|
||||
delete randomatom;
|
||||
|
||||
delete python;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
@ -464,7 +459,7 @@ void Variable::set(int narg, char **arg)
|
||||
|
||||
} else if (strcmp(arg[1],"python") == 0) {
|
||||
if (narg != 3) error->all(FLERR,"Illegal variable command");
|
||||
if (!python->python_exists)
|
||||
if (!python->is_enabled())
|
||||
error->all(FLERR,"LAMMPS is not built with Python embedded");
|
||||
int ivar = find(arg[0]);
|
||||
if (ivar >= 0) {
|
||||
@ -735,7 +730,7 @@ void Variable::set_arrays(int i)
|
||||
|
||||
void Variable::python_command(int narg, char **arg)
|
||||
{
|
||||
if (!python->python_exists)
|
||||
if (!python->is_enabled())
|
||||
error->all(FLERR,"LAMMPS is not built with Python embedded");
|
||||
python->command(narg,arg);
|
||||
}
|
||||
|
||||
@ -78,8 +78,6 @@ class Variable : protected Pointers {
|
||||
int precedence[18]; // precedence level of math operators
|
||||
// set length to include up to XOR in enum
|
||||
|
||||
class Python *python; // ptr to embedded Python interpreter
|
||||
|
||||
struct Tree { // parse tree for atom-style or vector-style vars
|
||||
double value; // single scalar
|
||||
double *array; // per-atom or per-type list of doubles
|
||||
|
||||
Reference in New Issue
Block a user