Change how a Python pair style is loaded

Implements a class loader which takes a fully qualified Python class
name, loads the module and creates an object instance.

To add flexibility, the current working directory and the
directory specified by the LAMMPS_POTENTIALS environment variable are
added to the module search path.
This commit is contained in:
Richard Berger 2017-05-16 23:29:48 -04:00
parent a6f0d700f1
commit 7caf6cf459
4 changed files with 54 additions and 21 deletions

View File

@ -12,7 +12,7 @@ mass * 1.0
velocity all create 3.0 87287
pair_style hybrid lj/cut 2.5 python 2.5
pair_coeff * * python lj-melt-potential.py lj NULL
pair_coeff * * python potentials.LAMMPSLJCutPotential lj NULL
pair_coeff * 2 lj/cut 1.0 1.0
neighbor 0.3 bin
@ -31,7 +31,7 @@ clear
read_restart hybrid.restart
pair_style hybrid lj/cut 2.5 python 2.5
pair_coeff * * python lj-melt-potential.py lj NULL
pair_coeff * * python potentials.LAMMPSLJCutPotential lj NULL
pair_coeff * 2 lj/cut 1.0 1.0
fix 1 all nve
@ -47,7 +47,7 @@ atom_style atomic
read_data hybrid.data
pair_style hybrid lj/cut 2.5 python 2.5
pair_coeff * * python lj-melt-potential.py lj NULL
pair_coeff * * python potentials.LAMMPSLJCutPotential lj NULL
pair_coeff * 2 lj/cut 1.0 1.0
neighbor 0.3 bin

View File

@ -12,7 +12,7 @@ mass * 1.0
velocity all create 3.0 87287
pair_style python 2.5
pair_coeff * * lj-melt-potential.py lj
pair_coeff * * potentials.LAMMPSLJCutPotential lj
neighbor 0.3 bin
neigh_modify every 20 delay 0 check no
@ -30,7 +30,7 @@ clear
read_restart melt.restart
pair_style python 2.5
pair_coeff * * lj-melt-potential.py lj
pair_coeff * * potentials.LAMMPSLJCutPotential lj
fix 1 all nve
@ -45,7 +45,7 @@ atom_style atomic
read_data melt.data
pair_style python 2.5
pair_coeff * * lj-melt-potential.py lj
pair_coeff * * potentials.LAMMPSLJCutPotential lj
neighbor 0.3 bin
neigh_modify every 20 delay 0 check no

View File

@ -32,6 +32,3 @@ class LAMMPSLJCutPotential(object):
lj3 = coeff[4]
lj4 = coeff[5]
return (r6inv * (lj3*r6inv - lj4))
lammps_pair_style = LAMMPSLJCutPotential()

View File

@ -42,12 +42,26 @@ PairPython::PairPython(LAMMPS *lmp) : Pair(lmp) {
reinitflag = 0;
python->init();
py_potential = NULL;
// add current directory to PYTHONPATH
PyObject * py_path = PySys_GetObject("path");
PyList_Append(py_path, PY_STRING_FROM_STRING("."));
// if LAMMPS_POTENTIALS environment variable is set, add it to PYTHONPATH as well
const char * potentials_path = getenv("LAMMPS_POTENTIALS");
if (potentials_path != NULL) {
PyList_Append(py_path, PY_STRING_FROM_STRING(potentials_path));
}
}
/* ---------------------------------------------------------------------- */
PairPython::~PairPython()
{
if(py_potential) Py_DECREF((PyObject*) py_potential);
if (allocated) {
memory->destroy(setflag);
memory->destroy(cutsq);
@ -234,34 +248,56 @@ void PairPython::coeff(int narg, char **arg)
error->all(FLERR,"Incorrect args for pair coefficients");
// check if python potential file exists and source it
char * full_cls_name = arg[2];
char * lastpos = strrchr(full_cls_name, '.');
FILE *fp = fopen(arg[2],"r");
if (fp == NULL)
error->all(FLERR,"Cannot open python pair potential class file");
if (lastpos == NULL) {
error->all(FLERR,"Python pair style requires fully qualified class name");
}
size_t module_name_length = strlen(full_cls_name) - strlen(lastpos);
size_t cls_name_length = strlen(lastpos)-1;
char * module_name = new char[module_name_length+1];
char * cls_name = new char[cls_name_length+1];
strncpy(module_name, full_cls_name, module_name_length);
module_name[module_name_length] = 0;
strcpy(cls_name, lastpos+1);
PyGILState_STATE gstate = PyGILState_Ensure();
int err = PyRun_SimpleFile(fp,arg[2]);
if (err) {
PyObject * pModule = PyImport_ImportModule(module_name);
if (!pModule) {
PyErr_Print();
PyErr_Clear();
PyGILState_Release(gstate);
error->all(FLERR,"Loading python pair style class failure");
error->all(FLERR,"Loading python pair style module failure");
}
fclose(fp);
// create LAMMPS atom type to potential file type mapping in python class
// by calling 'lammps_pair_style.map_coeff(name,type)'
PyObject *pModule = PyImport_AddModule("__main__");
if (!pModule) error->all(FLERR,"Could not initialize embedded Python");
PyObject *py_pair_type = PyObject_GetAttrString(pModule, cls_name);
if (!py_pair_type) {
PyErr_Print();
PyErr_Clear();
PyGILState_Release(gstate);
error->all(FLERR,"Could not find pair style class in module'");
}
PyObject *py_pair_instance = PyObject_GetAttrString(pModule,"lammps_pair_style");
delete [] module_name;
delete [] cls_name;
PyObject * py_pair_instance = PyObject_CallObject(py_pair_type, NULL);
if (!py_pair_instance) {
PyErr_Print();
PyErr_Clear();
PyGILState_Release(gstate);
error->all(FLERR,"Could not find 'lammps_pair_style instance'");
error->all(FLERR,"Could not instantiate instance of pair style class'");
}
py_potential = (void *) py_pair_instance; // XXX do we need to increment reference counter?
py_potential = (void *) py_pair_instance;
PyObject *py_map_coeff = PyObject_GetAttrString(py_pair_instance,"map_coeff");
if (!py_map_coeff) {