Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F90450421
python.cpp
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Fri, Nov 1, 19:21
Size
12 KB
Mime Type
text/x-c
Expires
Sun, Nov 3, 19:21 (1 d, 23 h)
Engine
blob
Format
Raw Data
Handle
22077759
Attached To
rLAMMPS lammps
python.cpp
View Options
/* ----------------------------------------------------------------------
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 "python.h"
#include "force.h"
#include "input.h"
#include "variable.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
enum{NONE,INT,DOUBLE,STRING,PTR};
#define VALUELENGTH 64 // also in variable.cpp
/* ---------------------------------------------------------------------- */
Python::Python(LAMMPS *lmp) : Pointers(lmp)
{
python_exists = 1;
pyMain = NULL;
// pfuncs stores interface info for each Python function
nfunc = 0;
pfuncs = NULL;
}
/* ---------------------------------------------------------------------- */
Python::~Python()
{
// clean up
for (int i = 0; i < nfunc; i++) {
delete [] pfuncs[i].name;
deallocate(i);
PyObject *pFunc = (PyObject *) pfuncs[i].pFunc;
Py_XDECREF(pFunc);
}
// shutdown Python interpreter
if (pyMain) Py_Finalize();
memory->sfree(pfuncs);
}
/* ---------------------------------------------------------------------- */
void Python::command(int narg, char **arg)
{
if (narg < 2) error->all(FLERR,"Invalid python command");
// if invoke is only keyword, invoke the previously defined function
if (narg == 2 && strcmp(arg[1],"invoke") == 0) {
int ifunc = find(arg[0]);
if (ifunc < 0) error->all(FLERR,"Python invoke of undefined function");
char *str = NULL;
if (noutput) {
str = input->variable->pythonstyle(pfuncs[ifunc].ovarname,
pfuncs[ifunc].name);
if (!str)
error->all(FLERR,"Python variable does not match Python function");
}
invoke_function(ifunc,str);
return;
}
// parse optional args, invoke is not allowed in this mode
ninput = noutput = 0;
istr = NULL;
ostr = NULL;
format = NULL;
char *pyfile = NULL;
char *herestr = NULL;
int existflag = 0;
int iarg = 1;
while (iarg < narg) {
if (strcmp(arg[iarg],"input") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Invalid python command");
ninput = force->inumeric(FLERR,arg[iarg+1]);
if (ninput < 0) error->all(FLERR,"Invalid python command");
iarg += 2;
istr = new char*[ninput];
if (iarg+ninput > narg) error->all(FLERR,"Invalid python command");
for (int i = 0; i < ninput; i++) istr[i] = arg[iarg+i];
iarg += ninput;
} else if (strcmp(arg[iarg],"return") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Invalid python command");
noutput = 1;
ostr = arg[iarg+1];
iarg += 2;
} else if (strcmp(arg[iarg],"format") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Invalid python command");
int n = strlen(arg[iarg+1]) + 1;
format = new char[n];
strcpy(format,arg[iarg+1]);
iarg += 2;
} else if (strcmp(arg[iarg],"file") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Invalid python command");
delete[] pyfile;
int n = strlen(arg[iarg+1]) + 1;
pyfile = new char[n];
strcpy(pyfile,arg[iarg+1]);
iarg += 2;
} else if (strcmp(arg[iarg],"here") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Invalid python command");
herestr = arg[iarg+1];
iarg += 2;
} else if (strcmp(arg[iarg],"exists") == 0) {
existflag = 1;
iarg++;
} else error->all(FLERR,"Invalid python command");
}
if (pyfile && herestr) error->all(FLERR,"Invalid python command");
if (pyfile && existflag) error->all(FLERR,"Invalid python command");
if (herestr && existflag) error->all(FLERR,"Invalid python command");
// create or overwrite entry in pfuncs vector with name = arg[0]
int ifunc = create_entry(arg[0]);
// one-time intitialization of Python interpreter
// Py_SetArgv() enables finding of *.py module files in current dir
// only needed for module load, not for direct file read into __main__
// pymain stores pointer to main module
if (pyMain == NULL) {
if (Py_IsInitialized())
error->all(FLERR,"Cannot embed Python when also "
"extending Python with LAMMPS");
Py_Initialize();
//char *arg = (char *) "./lmp";
//PySys_SetArgv(1,&arg);
//PyObject *pName = PyString_FromString("__main__");
//if (!pName) errorX->all(FLERR,"Bad pName");
//PyObject *pModule = PyImport_Import(pName);
//Py_DECREF(pName);
PyObject *pModule = PyImport_AddModule("__main__");
if (!pModule) error->all(FLERR,"Could not initialize embedded Python");
pyMain = (void *) pModule;
}
// send Python code to Python interpreter
// file: read the file via PyRun_SimpleFile()
// here: process the here string directly
// exist: do nothing, assume code has already been run
if (pyfile) {
FILE *fp = fopen(pyfile,"r");
if (fp == NULL) error->all(FLERR,"Could not open Python file");
int err = PyRun_SimpleFile(fp,pyfile);
if (err) error->all(FLERR,"Could not process Python file");
fclose(fp);
} else if (herestr) {
int err = PyRun_SimpleString(herestr);
if (err) error->all(FLERR,"Could not process Python string");
}
// pFunc = function object for requested function
PyObject *pModule = (PyObject *) pyMain;
PyObject *pFunc = PyObject_GetAttrString(pModule,pfuncs[ifunc].name);
if (!pFunc) error->all(FLERR,"Could not find Python function");
if (!PyCallable_Check(pFunc))
error->all(FLERR,"Python function is not callable");
pfuncs[ifunc].pFunc = (void *) pFunc;
// clean-up input storage
delete [] istr;
delete [] format;
delete [] pyfile;
}
/* ------------------------------------------------------------------ */
void Python::invoke_function(int ifunc, char *result)
{
PyObject *pValue;
char *str;
PyObject *pFunc = (PyObject *) pfuncs[ifunc].pFunc;
// create Python tuple of input arguments
int ninput = pfuncs[ifunc].ninput;
PyObject *pArgs = PyTuple_New(ninput);
if (!pArgs) error->all(FLERR,"Could not create Python function arguments");
for (int i = 0; i < ninput; i++) {
int itype = pfuncs[ifunc].itype[i];
if (itype == INT) {
if (pfuncs[ifunc].ivarflag[i]) {
str = input->variable->retrieve(pfuncs[ifunc].svalue[i]);
if (!str)
error->all(FLERR,"Could not evaluate Python function input variable");
pValue = PyInt_FromLong(atoi(str));
} else pValue = PyInt_FromLong(pfuncs[ifunc].ivalue[i]);
} else if (itype == DOUBLE) {
if (pfuncs[ifunc].ivarflag[i]) {
str = input->variable->retrieve(pfuncs[ifunc].svalue[i]);
if (!str)
error->all(FLERR,"Could not evaluate Python function input variable");
pValue = PyFloat_FromDouble(atof(str));
} 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]);
if (!str)
error->all(FLERR,"Could not evaluate Python function input variable");
pValue = PyString_FromString(str);
} else pValue = PyString_FromString(pfuncs[ifunc].svalue[i]);
} else if (itype == PTR) {
pValue = PyCObject_FromVoidPtr((void *) lmp,NULL);
}
PyTuple_SetItem(pArgs,i,pValue);
}
// call the Python function
// error check with one() since only some procs may fail
pValue = PyObject_CallObject(pFunc,pArgs);
if (!pValue) error->one(FLERR,"Python function evaluation failed");
Py_DECREF(pArgs);
// function returned a value
// assign it to result string stored by python-style variable
if (pfuncs[ifunc].noutput) {
int otype = pfuncs[ifunc].otype;
if (otype == INT) {
sprintf(result,"%ld",PyInt_AsLong(pValue));
} else if (otype == DOUBLE) {
sprintf(result,"%.15g",PyFloat_AsDouble(pValue));
} else if (otype == STRING) {
char *pystr = PyString_AsString(pValue);
strncpy(result,pystr,VALUELENGTH-1);
}
Py_DECREF(pValue);
}
}
/* ------------------------------------------------------------------ */
int Python::find(char *name)
{
for (int i = 0; i < nfunc; i++)
if (strcmp(name,pfuncs[i].name) == 0) return i;
return -1;
}
/* ------------------------------------------------------------------ */
int Python::variable_match(char *name, char *varname, int numeric)
{
int ifunc = find(name);
if (ifunc < 0) return -1;
if (pfuncs[ifunc].noutput == 0) return -1;
if (strcmp(pfuncs[ifunc].ovarname,varname) != 0) return -1;
if (numeric && pfuncs[ifunc].otype == STRING) return -1;
return ifunc;
}
/* ------------------------------------------------------------------ */
int Python::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
int ifunc = find(name);
if (ifunc < 0) {
ifunc = nfunc;
nfunc++;
pfuncs = (PyFunc *)
memory->srealloc(pfuncs,nfunc*sizeof(struct PyFunc),"python:pfuncs");
int n = strlen(name) + 1;
pfuncs[ifunc].name = new char[n];
strcpy(pfuncs[ifunc].name,name);
} else deallocate(ifunc);
pfuncs[ifunc].ninput = ninput;
pfuncs[ifunc].noutput = noutput;
if (!format && ninput+noutput)
error->all(FLERR,"Invalid python command");
else if (format && strlen(format) != ninput+noutput)
error->all(FLERR,"Invalid python command");
// process inputs as values or variables
pfuncs[ifunc].itype = new int[ninput];
pfuncs[ifunc].ivarflag = new int[ninput];
pfuncs[ifunc].ivalue = new int[ninput];
pfuncs[ifunc].dvalue = new double[ninput];
pfuncs[ifunc].svalue = new char*[ninput];
for (int i = 0; i < ninput; i++) {
pfuncs[ifunc].svalue[i] = NULL;
char type = format[i];
if (type == 'i') {
pfuncs[ifunc].itype[i] = INT;
if (strstr(istr[i],"v_") == istr[i]) {
pfuncs[ifunc].ivarflag[i] = 1;
int n = strlen(&istr[i][2]) + 1;
pfuncs[ifunc].svalue[i] = new char[n];
strcpy(pfuncs[ifunc].svalue[i],&istr[i][2]);
} else {
pfuncs[ifunc].ivarflag[i] = 0;
pfuncs[ifunc].ivalue[i] = force->inumeric(FLERR,istr[i]);
}
} else if (type == 'f') {
pfuncs[ifunc].itype[i] = DOUBLE;
if (strstr(istr[i],"v_") == istr[i]) {
pfuncs[ifunc].ivarflag[i] = 1;
int n = strlen(&istr[i][2]) + 1;
pfuncs[ifunc].svalue[i] = new char[n];
strcpy(pfuncs[ifunc].svalue[i],&istr[i][2]);
} else {
pfuncs[ifunc].ivarflag[i] = 0;
pfuncs[ifunc].dvalue[i] = force->numeric(FLERR,istr[i]);
}
} else if (type == 's') {
pfuncs[ifunc].itype[i] = STRING;
if (strstr(istr[i],"v_") == istr[i]) {
pfuncs[ifunc].ivarflag[i] = 1;
int n = strlen(&istr[i][2]) + 1;
pfuncs[ifunc].svalue[i] = new char[n];
strcpy(pfuncs[ifunc].svalue[i],&istr[i][2]);
} else {
pfuncs[ifunc].ivarflag[i] = 0;
int n = strlen(istr[i]) + 1;
pfuncs[ifunc].svalue[i] = new char[n];
strcpy(pfuncs[ifunc].svalue[i],istr[i]);
}
} else if (type == 'p') {
pfuncs[ifunc].ivarflag[i] = 0;
pfuncs[ifunc].itype[i] = PTR;
if (strcmp(istr[i],"SELF") != 0)
error->all(FLERR,"Invalid python command");
} else error->all(FLERR,"Invalid python command");
}
// process output as value or variable
pfuncs[ifunc].ovarname = NULL;
if (!noutput) return ifunc;
char type = format[ninput];
if (type == 'i') pfuncs[ifunc].otype = INT;
else if (type == 'f') pfuncs[ifunc].otype = DOUBLE;
else if (type == 's') pfuncs[ifunc].otype = STRING;
else error->all(FLERR,"Invalid python command");
if (strstr(ostr,"v_") != ostr) error->all(FLERR,"Invalid python command");
int n = strlen(&ostr[2]) + 1;
pfuncs[ifunc].ovarname = new char[n];
strcpy(pfuncs[ifunc].ovarname,&ostr[2]);
return ifunc;
}
/* ------------------------------------------------------------------ */
void Python::deallocate(int i)
{
delete [] pfuncs[i].itype;
delete [] pfuncs[i].ivarflag;
delete [] pfuncs[i].ivalue;
delete [] pfuncs[i].dvalue;
for (int j = 0; j < pfuncs[i].ninput; j++)
delete [] pfuncs[i].svalue[j];
delete [] pfuncs[i].svalue;
delete [] pfuncs[i].ovarname;
}
Event Timeline
Log In to Comment