Commit 7caf6cf4 authored by Richard Berger's avatar Richard Berger
Browse files

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.
parent a6f0d700
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -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
+3 −3
Original line number Diff line number Diff line
@@ -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
+0 −3
Original line number Diff line number Diff line
@@ -32,6 +32,3 @@ class LAMMPSLJCutPotential(object):
        lj3 = coeff[4]
        lj4 = coeff[5]
        return (r6inv * (lj3*r6inv - lj4))

lammps_pair_style = LAMMPSLJCutPotential()
+48 −12
Original line number Diff line number Diff line
@@ -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, '.');

  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;

  FILE *fp = fopen(arg[2],"r");
  if (fp == NULL)
    error->all(FLERR,"Cannot open python pair potential class file");
  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'");
  }

  delete [] module_name;
  delete [] cls_name;

  PyObject *py_pair_instance = PyObject_GetAttrString(pModule,"lammps_pair_style");
  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) {