Merge remote-tracking branch 'origin/mliappy2' into mliappy3

This commit is contained in:
Aidan Thompson
2020-12-03 17:37:26 -07:00
35 changed files with 947 additions and 46 deletions

1
.gitignore vendored
View File

@ -46,3 +46,4 @@ Thumbs.db
/Makefile /Makefile
/cmake_install.cmake /cmake_install.cmake
/lmp /lmp

View File

@ -105,7 +105,7 @@ install(TARGETS lmp EXPORT LAMMPS_Targets DESTINATION ${CMAKE_INSTALL_BINDIR})
option(CMAKE_VERBOSE_MAKEFILE "Generate verbose Makefiles" OFF) option(CMAKE_VERBOSE_MAKEFILE "Generate verbose Makefiles" OFF)
set(STANDARD_PACKAGES ASPHERE BODY CLASS2 COLLOID COMPRESS DIPOLE set(STANDARD_PACKAGES ASPHERE BODY CLASS2 COLLOID COMPRESS DIPOLE
GRANULAR KSPACE LATTE MANYBODY MC MESSAGE MISC MLIAP MOLECULE PERI POEMS GRANULAR KSPACE LATTE MANYBODY MC MESSAGE MISC MLIAP MLIAPPY MOLECULE PERI POEMS
QEQ REPLICA RIGID SHOCK SPIN SNAP SRD KIM PYTHON MSCG MPIIO VORONOI QEQ REPLICA RIGID SHOCK SPIN SNAP SRD KIM PYTHON MSCG MPIIO VORONOI
USER-ATC USER-AWPMD USER-BOCS USER-CGDNA USER-MESODPD USER-CGSDK USER-COLVARS USER-ATC USER-AWPMD USER-BOCS USER-CGDNA USER-MESODPD USER-CGSDK USER-COLVARS
USER-DIFFRACTION USER-DPD USER-DRUDE USER-EFF USER-FEP USER-H5MD USER-LB USER-DIFFRACTION USER-DPD USER-DRUDE USER-EFF USER-FEP USER-H5MD USER-LB
@ -194,6 +194,8 @@ endif()
# "hard" dependencies between packages resulting # "hard" dependencies between packages resulting
# in an error instead of skipping over files # in an error instead of skipping over files
pkg_depends(MLIAP SNAP) pkg_depends(MLIAP SNAP)
pkg_depends(MLIAPPY MLIAP)
pkg_depends(MLIAPPY PYTHON)
pkg_depends(MPIIO MPI) pkg_depends(MPIIO MPI)
pkg_depends(USER-ATC MANYBODY) pkg_depends(USER-ATC MANYBODY)
pkg_depends(USER-LB MPI) pkg_depends(USER-LB MPI)
@ -372,7 +374,7 @@ else()
set(CUDA_REQUEST_PIC) set(CUDA_REQUEST_PIC)
endif() endif()
foreach(PKG_WITH_INCL KSPACE PYTHON VORONOI USER-COLVARS USER-MOLFILE USER-NETCDF USER-PLUMED USER-QMMM foreach(PKG_WITH_INCL KSPACE PYTHON MLIAPPY VORONOI USER-COLVARS USER-MOLFILE USER-NETCDF USER-PLUMED USER-QMMM
USER-QUIP USER-SCAFACOS USER-SMD USER-VTK KIM LATTE MESSAGE MSCG COMPRESS) USER-QUIP USER-SCAFACOS USER-SMD USER-VTK KIM LATTE MESSAGE MSCG COMPRESS)
if(PKG_${PKG_WITH_INCL}) if(PKG_${PKG_WITH_INCL})
include(Packages/${PKG_WITH_INCL}) include(Packages/${PKG_WITH_INCL})

View File

@ -0,0 +1,3 @@
execute_process(COMMAND cythonize mliap_model_python_couple.pyx WORKING_DIRECTORY ../src/MLIAPPY)
target_compile_definitions(lammps PRIVATE -DLMP_MLIAPPY)

View File

@ -3,7 +3,8 @@ if(CMAKE_VERSION VERSION_LESS 3.12)
target_include_directories(lammps PRIVATE ${PYTHON_INCLUDE_DIRS}) target_include_directories(lammps PRIVATE ${PYTHON_INCLUDE_DIRS})
target_link_libraries(lammps PRIVATE ${PYTHON_LIBRARIES}) target_link_libraries(lammps PRIVATE ${PYTHON_LIBRARIES})
else() else()
find_package(Python REQUIRED COMPONENTS Development) find_package(Python REQUIRED COMPONENTS Development Interpreter)
target_include_directories(lammps PRIVATE ${Python_INCLUDE_DIRS})
target_link_libraries(lammps PRIVATE Python::Python) target_link_libraries(lammps PRIVATE Python::Python)
endif() endif()
target_compile_definitions(lammps PRIVATE -DLMP_PYTHON) target_compile_definitions(lammps PRIVATE -DLMP_PYTHON)

View File

@ -45,6 +45,7 @@ page gives those details.
* :ref:`MESSAGE <PKG-MESSAGE>` * :ref:`MESSAGE <PKG-MESSAGE>`
* :ref:`MISC <PKG-MISC>` * :ref:`MISC <PKG-MISC>`
* :ref:`MLIAP <PKG-MLIAP>` * :ref:`MLIAP <PKG-MLIAP>`
* :ref:`MLIAPPY <PKG-MLIAPPY>`
* :ref:`MOLECULE <PKG-MOLECULE>` * :ref:`MOLECULE <PKG-MOLECULE>`
* :ref:`MPIIO <PKG-MPIIO>` * :ref:`MPIIO <PKG-MPIIO>`
* :ref:`MSCG <PKG-MSCG>` * :ref:`MSCG <PKG-MSCG>`
@ -678,6 +679,36 @@ To use this package, also the :ref:`SNAP package <PKG-SNAP>` needs to be install
---------- ----------
.. _PKG-MLIAPPY:
MLIAPPY package
-------------
**Contents:**
Extension to the MLIAP package for coupling with python models.
**Install:**
To use this package, also the :ref:`MLIAP package <PKG-MLIAP>` needs to be installed.
To use this package, also the :ref:`PYTHON package <PKG-PYTHON>` needs to be installed.
The version of python must be >3.5.
The python interpreter linked to LAMMPS will need cython and numpy installed.
The examples build models with pytorch, which would thus need to be installed.
This package includes more options for the mliap compute and pair style.
**Author:** Nicholas Lubbers (LANL).
**Supporting info:**
* src/MLIAPPY: filenames -> commands
* src/MLIAPPY/README
* :doc:`pair_style mliap <pair_mliap>`
* examples/mliappy (see README)
----------
.. _PKG-MOLECULE: .. _PKG-MOLECULE:
MOLECULE package MOLECULE package

View File

@ -61,6 +61,8 @@ package:
+----------------------------------+--------------------------------------+----------------------------------------------------+------------------------------------------------------+---------+ +----------------------------------+--------------------------------------+----------------------------------------------------+------------------------------------------------------+---------+
| :ref:`MLIAP <PKG-MLIAP>` | multiple machine learning potentials | :doc:`pair_style mliap <pair_mliap>` | mliap | no | | :ref:`MLIAP <PKG-MLIAP>` | multiple machine learning potentials | :doc:`pair_style mliap <pair_mliap>` | mliap | no |
+----------------------------------+--------------------------------------+----------------------------------------------------+------------------------------------------------------+---------+ +----------------------------------+--------------------------------------+----------------------------------------------------+------------------------------------------------------+---------+
| :ref:`MLIAPPY <PKG-MLIAPPY>` | enable python ML models for mliap | :doc:`pair_style mliap <pair_mliap>` | mliap | no |
+----------------------------------+--------------------------------------+----------------------------------------------------+------------------------------------------------------+---------+
| :ref:`MOLECULE <PKG-MOLECULE>` | molecular system force fields | :doc:`Howto bioFF <Howto_bioFF>` | peptide | no | | :ref:`MOLECULE <PKG-MOLECULE>` | molecular system force fields | :doc:`Howto bioFF <Howto_bioFF>` | peptide | no |
+----------------------------------+--------------------------------------+----------------------------------------------------+------------------------------------------------------+---------+ +----------------------------------+--------------------------------------+----------------------------------------------------+------------------------------------------------------+---------+
| :ref:`MPIIO <PKG-MPIIO>` | MPI parallel I/O dump and restart | :doc:`dump <dump>` | n/a | no | | :ref:`MPIIO <PKG-MPIIO>` | MPI parallel I/O dump and restart | :doc:`dump <dump>` | n/a | no |

View File

@ -18,7 +18,7 @@ Syntax
.. parsed-literal:: .. parsed-literal::
*model* values = style *model* values = style
style = *linear* or *quadratic* style = *linear* or *quadratic* or *mliappy*
*descriptor* values = style filename *descriptor* values = style filename
style = *sna* style = *sna*
filename = name of file containing descriptor definitions filename = name of file containing descriptor definitions
@ -57,7 +57,8 @@ The compute *mliap* command must be followed by two keywords
*model* and *descriptor* in either order. *model* and *descriptor* in either order.
The *model* keyword is followed by a model style, currently limited to The *model* keyword is followed by a model style, currently limited to
either *linear* or *quadratic*. either *linear* or *quadratic*. The *mliappy* model is only available
if lammps is built with MLIAPPY package.
The *descriptor* keyword is followed by a descriptor style, and additional arguments. The *descriptor* keyword is followed by a descriptor style, and additional arguments.
Currently the only descriptor style is *sna*, indicating the bispectrum component Currently the only descriptor style is *sna*, indicating the bispectrum component
@ -167,6 +168,8 @@ LAMMPS was built with that package. In addition, building LAMMPS with the MLIAP
requires building LAMMPS with the SNAP package. requires building LAMMPS with the SNAP package.
See the :doc:`Build package <Build_package>` doc page for more info. See the :doc:`Build package <Build_package>` doc page for more info.
Python models such as neural networks can be used if the MLIAPPY package is built.
Related commands Related commands
"""""""""""""""" """"""""""""""""

View File

@ -16,7 +16,7 @@ Syntax
.. parsed-literal:: .. parsed-literal::
*model* values = style filename *model* values = style filename
style = *linear* or *quadratic* style = *linear* or *quadratic* or *mliappy*
filename = name of file containing model definitions filename = name of file containing model definitions
*descriptor* values = style filename *descriptor* values = style filename
style = *sna* style = *sna*
@ -43,9 +43,10 @@ it is possible to use many different models with a given descriptor,
or many different descriptors with a given model. Currently, the pair_style or many different descriptors with a given model. Currently, the pair_style
supports just two models, *linear* and *quadratic*, supports just two models, *linear* and *quadratic*,
and one descriptor, *sna*, the SNAP descriptor used by :doc:`pair_style snap <pair_snap>`, including the linear, quadratic, and one descriptor, *sna*, the SNAP descriptor used by :doc:`pair_style snap <pair_snap>`, including the linear, quadratic,
and chem variants. Work is currently underway to extend and chem variants. With the MLIAPPY package installed, the *mliappy* model
the interface to handle neural network energy models, is available which can be used to couple python models such as neural network
and it is also straightforward to add new descriptor styles. energy models.
It is also straightforward to add new descriptor styles.
In order to train a model, it is useful to know the gradient or derivative In order to train a model, it is useful to know the gradient or derivative
of energy, force, and stress w.r.t. model parameters. This information of energy, force, and stress w.r.t. model parameters. This information
can be accessed using the related :doc:`compute mliap <compute_mliap>` command. can be accessed using the related :doc:`compute mliap <compute_mliap>` command.
@ -143,6 +144,9 @@ was built with that package. In addition, building LAMMPS with the MLIAP package
requires building LAMMPS with the SNAP package. requires building LAMMPS with the SNAP package.
See the :doc:`Build package <Build_package>` doc page for more info. See the :doc:`Build package <Build_package>` doc page for more info.
Python models such as neural networks can be used if the MLIAPPY package is built.
Related commands Related commands
"""""""""""""""" """"""""""""""""

26
examples/mliappy/README Normal file
View File

@ -0,0 +1,26 @@
README for MLIAPPY Example
These examples run the Ta06 example from the MLIAP package, but using the python coupling.
1: Running models using LAMMPS executable: in.mliap.snap.Ta06A.
To run this, first run convert_mliap_Ta06A.py, which will convert the Ta06 potential into a pytorch model.
It will be saved as "Ta06A.mliap.pytorch.model.pkl".
It will also copy the "mliappy_pytorch.py" file into the current working directory. mliappy_pytorch.py contains
class definitions suitable for wrapping an arbitrary energy model MLIAPPY. It must be available to python when
creating or unpicking a pytorch model for MLIAPPY.
From that point you can run the example lmp -in in.mliap.snap.Ta06A -echo both
2: Running models from python with LAMMPS in library mode: load_external.py
Before testing this, ensure that the first example (using LAMMPS executable) works.
Not all python installations support this mode of operation.
Too test if your interpreter supports this, run:
`python test_pylibs.py`
and examine the output.
If this succeeds, you should be able to run:
`python load_external.py`

View File

@ -0,0 +1,21 @@
# DATE: 2014-09-05 UNITS: metal CONTRIBUTOR: Aidan Thompson athomps@sandia.gov CITATION: Thompson, Swiler, Trott, Foiles and Tucker, arxiv.org, 1409.3880 (2014)
# LAMMPS SNAP parameters for Ta_Cand06A
# required
rcutfac 4.67637
twojmax 6
# elements
nelems 1
elems Ta
radelems 0.5
welems 1
# optional
rfac0 0.99363
rmin0 0
bzeroflag 0

View File

@ -0,0 +1,18 @@
# DATE: 2014-09-05 UNITS: metal CONTRIBUTOR: Aidan Thompson athomps@sandia.gov CITATION: Thompson, Swiler, Trott, Foiles and Tucker, arxiv.org, 1409.3880 (2014)
# Definition of SNAP potential Ta_Cand06A
# Assumes 1 LAMMPS atom type
variable zblcutinner equal 4
variable zblcutouter equal 4.8
variable zblz equal 73
# Specify hybrid with SNAP, ZBL
pair_style hybrid/overlay &
zbl ${zblcutinner} ${zblcutouter} &
mliap model mliappy Ta06A.mliap.pytorch.model.pkl &
descriptor sna Ta06A.mliap.descriptor
pair_coeff 1 1 zbl ${zblz} ${zblz}
pair_coeff * * mliap Ta

View File

@ -0,0 +1,33 @@
import sys
import numpy as np
import torch
import pickle
import os
import shutil
shutil.copyfile('../../src/MLIAPPY/mliappy_pytorch.py','./mliappy_pytorch.py')
import mliappy_pytorch
# Read coefficients
coeffs = np.genfromtxt("../mliap/Ta06A.mliap.model",skip_header=6)
# Write coefficiets to a pytorch linear model
bias = coeffs[0]
weights = coeffs[1:]
lin = torch.nn.Linear(weights.shape[0],1)
lin.to(torch.float64)
with torch.autograd.no_grad():
lin.weight.set_(torch.from_numpy(weights).unsqueeze(0))
lin.bias.set_(torch.as_tensor(bias,dtype=torch.float64).unsqueeze(0))
# Wrap the pytorch model for usage with MLIAPPY
model = mliappy_pytorch.IgnoreElems(lin)
n_descriptors = lin.weight.shape[1]
n_params = mliappy_pytorch.calc_n_params(model)
n_types = 1
linked_model = mliappy_pytorch.TorchWrapper64(model,n_descriptors=n_descriptors,n_elements=n_types)
# Save the result.
with open("Ta06A.mliap.pytorch.model.pkl",'wb') as pfile:
pickle.dump(linked_model,pfile)

View File

@ -0,0 +1,53 @@
# Demonstrate MLIAP interface to linear SNAP potential
# Initialize simulation
variable nsteps index 100
variable nrep equal 4
variable a equal 3.316
units metal
# generate the box and atom positions using a BCC lattice
variable nx equal ${nrep}
variable ny equal ${nrep}
variable nz equal ${nrep}
boundary p p p
lattice bcc $a
region box block 0 ${nx} 0 ${ny} 0 ${nz}
create_box 1 box
create_atoms 1 box
mass 1 180.88
# choose potential
include Ta06A.mliap.pytorch
# Setup output
compute eatom all pe/atom
compute energy all reduce sum c_eatom
compute satom all stress/atom NULL
compute str all reduce sum c_satom[1] c_satom[2] c_satom[3]
variable press equal (c_str[1]+c_str[2]+c_str[3])/(3*vol)
thermo_style custom step temp epair c_energy etotal press v_press
thermo 10
thermo_modify norm yes
# Set up NVE run
timestep 0.5e-3
neighbor 1.0 bin
neigh_modify once no every 1 delay 0 check yes
# Run MD
velocity all create 300.0 4928459 loop geom
fix 1 all nve
run ${nsteps}

View File

@ -0,0 +1,104 @@
# Demonstrate how to load a model from the python side.
# This is essentially the same as in.mliap.pytorch.Ta06A--
# except that python is the driving program, and lammps
# is in library mode.
before_loading =\
"""
# Demonstrate MLIAP interface to linear SNAP potential
# Initialize simulation
variable nsteps index 100
variable nrep equal 4
variable a equal 3.316
units metal
# generate the box and atom positions using a BCC lattice
variable nx equal ${nrep}
variable ny equal ${nrep}
variable nz equal ${nrep}
boundary p p p
lattice bcc $a
region box block 0 ${nx} 0 ${ny} 0 ${nz}
create_box 1 box
create_atoms 1 box
mass 1 180.88
# choose potential
# DATE: 2014-09-05 UNITS: metal CONTRIBUTOR: Aidan Thompson athomps@sandia.gov CITATION: Thompson, Swiler, Trott, Foiles and Tucker, arxiv.org, 1409.3880 (2014)
# Definition of SNAP potential Ta_Cand06A
# Assumes 1 LAMMPS atom type
variable zblcutinner equal 4
variable zblcutouter equal 4.8
variable zblz equal 73
# Specify hybrid with SNAP, ZBL
pair_style hybrid/overlay &
zbl ${zblcutinner} ${zblcutouter} &
mliap model mliappy LATER &
descriptor sna Ta06A.mliap.descriptor
pair_coeff 1 1 zbl ${zblz} ${zblz}
pair_coeff * * mliap Ta
"""
after_loading =\
"""
# Setup output
compute eatom all pe/atom
compute energy all reduce sum c_eatom
compute satom all stress/atom NULL
compute str all reduce sum c_satom[1] c_satom[2] c_satom[3]
variable press equal (c_str[1]+c_str[2]+c_str[3])/(3*vol)
thermo_style custom step temp epair c_energy etotal press v_press
thermo 10
thermo_modify norm yes
# Set up NVE run
timestep 0.5e-3
neighbor 1.0 bin
neigh_modify once no every 1 delay 0 check yes
# Run MD
velocity all create 300.0 4928459 loop geom
fix 1 all nve
run ${nsteps}
"""
import lammps
lmp = lammps.lammps(cmdargs=['-echo','both'])
# This commmand must be run before the MLIAP object is declared in lammps.
lmp.mliappy.activate()
lmp.commands_string(before_loading)
# Now the model is declared, but empty -- because the model filename
# was given as "LATER".
# Load the python module, construct on the fly, do whatever, here:
import pickle
with open('Ta06A.mliap.pytorch.model.pkl','rb') as pfile:
model = pickle.load(pfile)
# Now that you have a model, connect it to the pairstyle
lmp.mliappy.load_model(model)
# Proceed with whatever calculations you like.
lmp.commands_string(after_loading)

View File

@ -0,0 +1,12 @@
import sysconfig, os,ctypes
library = sysconfig.get_config_vars('INSTSONAME')[0]
pylib = ctypes.CDLL(library)
connected = pylib.Py_IsInitialized()
if not connected:
print("FAILURE: This interpreter is not compatible with python-driven mliappy.")
else:
print("SUCCESS: This interpreter is compatible with python-driven MLIAPPY")

View File

@ -506,6 +506,8 @@ class lammps(object):
self.lib.lammps_set_fix_external_callback.argtypes = [c_void_p, c_char_p, self.FIX_EXTERNAL_CALLBACK_FUNC, py_object] self.lib.lammps_set_fix_external_callback.argtypes = [c_void_p, c_char_p, self.FIX_EXTERNAL_CALLBACK_FUNC, py_object]
self.lib.lammps_set_fix_external_callback.restype = None self.lib.lammps_set_fix_external_callback.restype = None
self.mliappy = MLIAPPY(self)
# ------------------------------------------------------------------------- # -------------------------------------------------------------------------
# shut-down LAMMPS instance # shut-down LAMMPS instance
@ -2924,3 +2926,43 @@ class IPyLammps(PyLammps):
""" """
from IPython.display import HTML from IPython.display import HTML
return HTML("<video controls><source src=\"" + filename + "\"></video>") return HTML("<video controls><source src=\"" + filename + "\"></video>")
class MLIAPPY():
def __init__(self,lammps):
self._module = None
self.lammps = lammps
@property
def module(self):
if self._module:
return self._module
try:
# Begin Importlib magic to find the embedded python module
# This is needed because the filename for liblammps does not
# match the spec for normal python modules, wherein
# file names match with PyInit function names.
# Also, python normally doesn't look for extensions besides '.so'
# We fix both of these problems by providing an explict
# path to the extension module 'mliap_model_python_couple' in
import sys
import importlib.util
import importlib.machinery
path = self.lammps.lib._name
loader = importlib.machinery.ExtensionFileLoader('mliap_model_python_couple',path)
spec = importlib.util.spec_from_loader('mliap_model_python_couple',loader)
module = importlib.util.module_from_spec(spec)
sys.modules['mliap_model_python_couple']=module
spec.loader.exec_module(module)
self._module = module
# End Importlib magic to find the embedded python module
except:
raise ImportError("Could not load MLIAPPY coupling module")
def activate(self):
self.module
def load_model(self,model):
self.module.load_from_python(model)

View File

@ -17,6 +17,10 @@
#include "mliap_model_linear.h" #include "mliap_model_linear.h"
#include "mliap_model_quadratic.h" #include "mliap_model_quadratic.h"
#include "mliap_descriptor_snap.h" #include "mliap_descriptor_snap.h"
#ifdef LMP_MLIAPPY
#include "mliap_model_python.h"
#endif
#include "compute_mliap.h" #include "compute_mliap.h"
#include "atom.h" #include "atom.h"
#include "update.h" #include "update.h"
@ -65,7 +69,14 @@ ComputeMLIAP::ComputeMLIAP(LAMMPS *lmp, int narg, char **arg) :
} else if (strcmp(arg[iarg+1],"quadratic") == 0) { } else if (strcmp(arg[iarg+1],"quadratic") == 0) {
model = new MLIAPModelQuadratic(lmp); model = new MLIAPModelQuadratic(lmp);
iarg += 2; iarg += 2;
} else error->all(FLERR,"Illegal compute mliap command"); }
#ifdef LMP_MLIAPPY
else if (strcmp(arg[iarg+1],"mliappy") == 0) {
model = new MLIAPModelPython(lmp);
iarg += 2;
}
#endif
else error->all(FLERR,"Illegal compute mliap command");
modelflag = 1; modelflag = 1;
} else if (strcmp(arg[iarg],"descriptor") == 0) { } else if (strcmp(arg[iarg],"descriptor") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal compute mliap command"); if (iarg+2 > narg) error->all(FLERR,"Illegal compute mliap command");

View File

@ -25,7 +25,8 @@ MLIAPData::MLIAPData(LAMMPS *lmp, int gradgradflag_in, int *map_in,
class MLIAPModel* model_in, class MLIAPModel* model_in,
class MLIAPDescriptor* descriptor_in, class MLIAPDescriptor* descriptor_in,
class PairMLIAP* pairmliap_in) : class PairMLIAP* pairmliap_in) :
Pointers(lmp), gradforce(nullptr), betas(nullptr), descriptors(nullptr), gamma(nullptr), Pointers(lmp), gradforce(nullptr), betas(nullptr),
descriptors(nullptr), eatoms(nullptr), gamma(nullptr),
gamma_row_index(nullptr), gamma_col_index(nullptr), egradient(nullptr), gamma_row_index(nullptr), gamma_col_index(nullptr), egradient(nullptr),
numneighs(nullptr), iatoms(nullptr), ielems(nullptr), jatoms(nullptr), jelems(nullptr), numneighs(nullptr), iatoms(nullptr), ielems(nullptr), jatoms(nullptr), jelems(nullptr),
rij(nullptr), graddesc(nullptr), model(nullptr), descriptor(nullptr), list(nullptr) rij(nullptr), graddesc(nullptr), model(nullptr), descriptor(nullptr), list(nullptr)
@ -64,6 +65,7 @@ MLIAPData::~MLIAPData()
{ {
memory->destroy(betas); memory->destroy(betas);
memory->destroy(descriptors); memory->destroy(descriptors);
memory->destroy(eatoms);
memory->destroy(gamma_row_index); memory->destroy(gamma_row_index);
memory->destroy(gamma_col_index); memory->destroy(gamma_col_index);
memory->destroy(gamma); memory->destroy(gamma);
@ -133,6 +135,7 @@ void MLIAPData::generate_neighdata(NeighList* list_in, int eflag_in, int vflag_i
if (natoms_max < natoms) { if (natoms_max < natoms) {
memory->grow(betas,natoms,ndescriptors,"MLIAPData:betas"); memory->grow(betas,natoms,ndescriptors,"MLIAPData:betas");
memory->grow(descriptors,natoms,ndescriptors,"MLIAPData:descriptors"); memory->grow(descriptors,natoms,ndescriptors,"MLIAPData:descriptors");
memory->grow(eatoms,natoms,"MLIAPData:eatoms");
natoms_max = natoms; natoms_max = natoms;
} }
@ -267,6 +270,7 @@ double MLIAPData::memory_usage()
bytes += natoms*ndescriptors*sizeof(int); // betas bytes += natoms*ndescriptors*sizeof(int); // betas
bytes += natoms*ndescriptors*sizeof(int); // descriptors bytes += natoms*ndescriptors*sizeof(int); // descriptors
bytes += natoms*sizeof(double); // eatoms
bytes += natomneigh_max*sizeof(int); // iatoms bytes += natomneigh_max*sizeof(int); // iatoms
bytes += natomneigh_max*sizeof(int); // ielems bytes += natomneigh_max*sizeof(int); // ielems

View File

@ -36,6 +36,8 @@ class MLIAPData : protected Pointers {
double **gradforce; double **gradforce;
double** betas; // betas for all atoms in list double** betas; // betas for all atoms in list
double** descriptors; // descriptors for all atoms in list double** descriptors; // descriptors for all atoms in list
double* eatoms; // energies for all atoms in list
double energy; // energy
int ndescriptors; // number of descriptors int ndescriptors; // number of descriptors
int nparams; // number of model parameters per element int nparams; // number of model parameters per element
int nelements; // number of elements int nelements; // number of elements

View File

@ -28,13 +28,9 @@ using namespace LAMMPS_NS;
MLIAPModel::MLIAPModel(LAMMPS* lmp, char* coefffilename) : Pointers(lmp) MLIAPModel::MLIAPModel(LAMMPS* lmp, char* coefffilename) : Pointers(lmp)
{ {
coeffelem = nullptr;
if (coefffilename) read_coeffs(coefffilename);
else {
nparams = 0; nparams = 0;
nelements = 0; nelements = 0;
ndescriptors = 0; ndescriptors = 0;
}
nonlinearflag = 0; nonlinearflag = 0;
} }
@ -42,9 +38,9 @@ MLIAPModel::MLIAPModel(LAMMPS* lmp, char* coefffilename) : Pointers(lmp)
MLIAPModel::~MLIAPModel() MLIAPModel::~MLIAPModel()
{ {
memory->destroy(coeffelem);
} }
/* ---------------------------------------------------------------------- /* ----------------------------------------------------------------------
placeholder placeholder
------------------------------------------------------------------------- */ ------------------------------------------------------------------------- */
@ -73,7 +69,22 @@ void MLIAPModel::set_ndescriptors(int ndescriptors_in)
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
void MLIAPModel::read_coeffs(char *coefffilename)
MLIAPModelSimple::MLIAPModelSimple(LAMMPS* lmp, char* coefffilename) : MLIAPModel(lmp, coefffilename)
{
coeffelem = nullptr;
if (coefffilename) read_coeffs(coefffilename);
}
/* ---------------------------------------------------------------------- */
MLIAPModelSimple::~MLIAPModelSimple()
{
memory->destroy(coeffelem);
}
void MLIAPModelSimple::read_coeffs(char *coefffilename)
{ {
// open coefficient file on proc 0 // open coefficient file on proc 0
@ -165,7 +176,7 @@ void MLIAPModel::read_coeffs(char *coefffilename)
memory usage memory usage
------------------------------------------------------------------------- */ ------------------------------------------------------------------------- */
double MLIAPModel::memory_usage() double MLIAPModelSimple::memory_usage()
{ {
double bytes = 0; double bytes = 0;

View File

@ -30,15 +30,26 @@ public:
virtual void compute_gradgrads(class MLIAPData*)=0; virtual void compute_gradgrads(class MLIAPData*)=0;
virtual void compute_force_gradients(class MLIAPData*)=0; virtual void compute_force_gradients(class MLIAPData*)=0;
virtual void init(); virtual void init();
virtual double memory_usage(); virtual double memory_usage()=0;
int nelements; // # of unique elements int nelements; // # of unique elements
int nonlinearflag; // 1 if gradient() requires escriptors int nonlinearflag; // 1 if gradient() requires descriptors
int ndescriptors; // number of descriptors int ndescriptors; // number of descriptors
int nparams; // number of parameters per element int nparams; // number of parameters per element
protected: protected:
void read_coeffs(char *); virtual void read_coeffs(char *)=0;
};
class MLIAPModelSimple : public MLIAPModel {
public:
MLIAPModelSimple(LAMMPS*, char*);
~MLIAPModelSimple();
virtual double memory_usage();
protected:
double **coeffelem; // element coefficients double **coeffelem; // element coefficients
virtual void read_coeffs(char *);
}; };
} }

View File

@ -21,7 +21,7 @@ using namespace LAMMPS_NS;
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
MLIAPModelLinear::MLIAPModelLinear(LAMMPS* lmp, char* coefffilename) : MLIAPModelLinear::MLIAPModelLinear(LAMMPS* lmp, char* coefffilename) :
MLIAPModel(lmp, coefffilename) MLIAPModelSimple(lmp, coefffilename)
{ {
if (nparams > 0) ndescriptors = nparams - 1; if (nparams > 0) ndescriptors = nparams - 1;
} }
@ -51,8 +51,9 @@ int MLIAPModelLinear::get_nparams()
void MLIAPModelLinear::compute_gradients(MLIAPData* data) void MLIAPModelLinear::compute_gradients(MLIAPData* data)
{ {
data->energy = 0.0;
for (int ii = 0; ii < data->natoms; ii++) { for (int ii = 0; ii < data->natoms; ii++) {
const int i = data->iatoms[ii];
const int ielem = data->ielems[ii]; const int ielem = data->ielems[ii];
double* coeffi = coeffelem[ielem]; double* coeffi = coeffelem[ielem];
@ -74,7 +75,8 @@ void MLIAPModelLinear::compute_gradients(MLIAPData* data)
for (int icoeff = 0; icoeff < data->ndescriptors; icoeff++) for (int icoeff = 0; icoeff < data->ndescriptors; icoeff++)
etmp += coeffi[icoeff+1]*data->descriptors[ii][icoeff]; etmp += coeffi[icoeff+1]*data->descriptors[ii][icoeff];
data->pairmliap->e_tally(i,etmp); data->energy += etmp;
data->eatoms[ii] = etmp;
} }
} }
} }

View File

@ -18,7 +18,7 @@
namespace LAMMPS_NS { namespace LAMMPS_NS {
class MLIAPModelLinear : public MLIAPModel { class MLIAPModelLinear : public MLIAPModelSimple {
public: public:
MLIAPModelLinear(LAMMPS*, char* = nullptr); MLIAPModelLinear(LAMMPS*, char* = nullptr);
~MLIAPModelLinear(); ~MLIAPModelLinear();

View File

@ -22,8 +22,9 @@ using namespace LAMMPS_NS;
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
MLIAPModelQuadratic::MLIAPModelQuadratic(LAMMPS* lmp, char* coefffilename) : MLIAPModelQuadratic::MLIAPModelQuadratic(LAMMPS* lmp, char* coefffilename) :
MLIAPModel(lmp, coefffilename) MLIAPModelSimple(lmp, coefffilename)
{ {
if (coefffilename) read_coeffs(coefffilename);
if (nparams > 0) ndescriptors = sqrt(2*nparams)-1; if (nparams > 0) ndescriptors = sqrt(2*nparams)-1;
nonlinearflag = 1; nonlinearflag = 1;
} }
@ -52,8 +53,9 @@ int MLIAPModelQuadratic::get_nparams()
void MLIAPModelQuadratic::compute_gradients(MLIAPData* data) void MLIAPModelQuadratic::compute_gradients(MLIAPData* data)
{ {
data->energy = 0.0;
for (int ii = 0; ii < data->natoms; ii++) { for (int ii = 0; ii < data->natoms; ii++) {
const int i = data->iatoms[ii];
const int ielem = data->ielems[ii]; const int ielem = data->ielems[ii];
double* coeffi = coeffelem[ielem]; double* coeffi = coeffelem[ielem];
@ -99,7 +101,8 @@ void MLIAPModelQuadratic::compute_gradients(MLIAPData* data)
etmp += coeffi[k++]*bveci*bvecj; etmp += coeffi[k++]*bveci*bvecj;
} }
} }
data->pairmliap->e_tally(i,etmp); data->energy += etmp;
data->eatoms[ii] = etmp;
} }
} }
} }

View File

@ -18,7 +18,7 @@
namespace LAMMPS_NS { namespace LAMMPS_NS {
class MLIAPModelQuadratic : public MLIAPModel { class MLIAPModelQuadratic : public MLIAPModelSimple {
public: public:
MLIAPModelQuadratic(LAMMPS*, char* = nullptr); MLIAPModelQuadratic(LAMMPS*, char* = nullptr);
~MLIAPModelQuadratic(); ~MLIAPModelQuadratic();

View File

@ -17,6 +17,9 @@
#include "mliap_model_linear.h" #include "mliap_model_linear.h"
#include "mliap_model_quadratic.h" #include "mliap_model_quadratic.h"
#include "mliap_descriptor_snap.h" #include "mliap_descriptor_snap.h"
#ifdef LMP_MLIAPPY
#include "mliap_model_python.h"
#endif
#include "atom.h" #include "atom.h"
#include "error.h" #include "error.h"
@ -27,6 +30,7 @@
#include <cmath> #include <cmath>
#include <cstring> #include <cstring>
#include "error.h"
using namespace LAMMPS_NS; using namespace LAMMPS_NS;
@ -65,6 +69,17 @@ PairMLIAP::~PairMLIAP()
void PairMLIAP::compute(int eflag, int vflag) void PairMLIAP::compute(int eflag, int vflag)
{ {
// consistency checks
if (data->ndescriptors != model->ndescriptors) {
error->all(FLERR,"Incompatible model and descriptor descriptor count");
};
if (data->nelements != model->nelements) {
error->all(FLERR,"Incompatible model and descriptor element count");
};
ev_init(eflag,vflag); ev_init(eflag,vflag);
data->generate_neighdata(list, eflag, vflag); data->generate_neighdata(list, eflag, vflag);
@ -78,6 +93,8 @@ void PairMLIAP::compute(int eflag, int vflag)
model->compute_gradients(data); model->compute_gradients(data);
e_tally(data);
// calculate force contributions beta_i*dB_i/dR_j // calculate force contributions beta_i*dB_i/dR_j
descriptor->compute_forces(data); descriptor->compute_forces(data);
@ -107,6 +124,7 @@ void PairMLIAP::allocate()
void PairMLIAP::settings(int narg, char ** arg) void PairMLIAP::settings(int narg, char ** arg)
{ {
if (narg < 4) if (narg < 4)
error->all(FLERR,"Illegal pair_style command"); error->all(FLERR,"Illegal pair_style command");
@ -130,6 +148,12 @@ void PairMLIAP::settings(int narg, char ** arg)
if (iarg+3 > narg) error->all(FLERR,"Illegal pair_style mliap command"); if (iarg+3 > narg) error->all(FLERR,"Illegal pair_style mliap command");
model = new MLIAPModelQuadratic(lmp,arg[iarg+2]); model = new MLIAPModelQuadratic(lmp,arg[iarg+2]);
iarg += 3; iarg += 3;
#ifdef LMP_MLIAPPY
} else if (strcmp(arg[iarg+1],"mliappy") == 0) {
if (iarg+3 > narg) error->all(FLERR,"Illegal pair_style mliap command");
model = new MLIAPModelPython(lmp,arg[iarg+2]);
iarg += 3;
#endif
} else error->all(FLERR,"Illegal pair_style mliap command"); } else error->all(FLERR,"Illegal pair_style mliap command");
modelflag = 1; modelflag = 1;
} else if (strcmp(arg[iarg],"descriptor") == 0) { } else if (strcmp(arg[iarg],"descriptor") == 0) {
@ -211,22 +235,21 @@ void PairMLIAP::coeff(int narg, char **arg)
data = new MLIAPData(lmp, gradgradflag, map, model, descriptor, this); data = new MLIAPData(lmp, gradgradflag, map, model, descriptor, this);
data->init(); data->init();
// consistency checks
if (data->ndescriptors != model->ndescriptors)
error->all(FLERR,"Incompatible model and descriptor definitions");
if (data->nelements != model->nelements)
error->all(FLERR,"Incompatible model and descriptor definitions");
} }
/* ---------------------------------------------------------------------- /* ----------------------------------------------------------------------
add energy of atom i to global and per-atom energy add energies to eng_vdwl and per-atom energy
------------------------------------------------------------------------- */ ------------------------------------------------------------------------- */
void PairMLIAP::e_tally(int i, double ei) void PairMLIAP::e_tally(MLIAPData* data)
{ {
if (eflag_global) eng_vdwl += ei; if (eflag_global) eng_vdwl += data->energy;
if (eflag_atom) eatom[i] += ei; if (eflag_atom)
for (int ii = 0; ii < data->natoms; ii++) {
const int i = data->iatoms[ii];
eatom[i] += data->eatoms[ii];
}
} }
/* ---------------------------------------------------------------------- /* ----------------------------------------------------------------------

View File

@ -31,7 +31,7 @@ public:
virtual void compute(int, int); virtual void compute(int, int);
void settings(int, char **); void settings(int, char **);
virtual void coeff(int, char **); virtual void coeff(int, char **);
void e_tally(int, double); void e_tally(class MLIAPData*);
void v_tally(int, int, double*, double*); void v_tally(int, int, double*, double*);
virtual void init_style(); virtual void init_style();
virtual double init_one(int, int); virtual double init_one(int, int);

53
src/MLIAPPY/Install.sh Executable file
View File

@ -0,0 +1,53 @@
# Install/unInstall package files in LAMMPS
# mode = 0/1/2 for uninstall/install/update
mode=$1
# arg1 = file, arg2 = file it depends on
# enforce using portable C locale
LC_ALL=C
export LC_ALL
action () {
if (test $mode = 0) then
rm -f ../$1
elif (! cmp -s $1 ../$1) then
if (test -z "$2" || test -e ../$2) then
cp $1 ..
if (test $mode = 2) then
echo " updating src/$1"
fi
fi
elif (test -n "$2") then
if (test ! -e ../$2) then
rm -f ../$1
fi
fi
}
# force rebuild of files using python header
touch ../lmppython.h
# all package files with no dependencies
for file in *.cpp *.h; do
test -f ${file} && action $file
done
# edit 2 Makefile.package files to include/exclude package info
if (test $1 = 1) then
if (test -e ../Makefile.package) then
sed -i -e 's|^PKG_INC =[ \t]*|&-DLMP_MLIAPPY |' ../Makefile.package
fi
elif (test $1 = 0) then
if (test -e ../Makefile.package) then
sed -i -e 's/[^ \t]*MLIAPPY[^ \t]* //g' ../Makefile.package
fi
fi

View File

@ -0,0 +1 @@
#TODO

View File

@ -0,0 +1,194 @@
/* ----------------------------------------------------------------------
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 "mliap_model_python.h"
#include "mliap_model_python_couple.h"
#include "pair_mliap.h"
#include "mliap_data.h"
#include "error.h"
#include "utils.h"
#include "lmppython.h"
#include "python_compat.h"
using namespace LAMMPS_NS;
/* ---------------------------------------------------------------------- */
MLIAPModelPython::MLIAPModelPython(LAMMPS* lmp, char* coefffilename) :
MLIAPModel(lmp, coefffilename)
{
model_loaded = 0;
python->init();
PyGILState_STATE gstate = PyGILState_Ensure();
PyObject * pyMain = PyImport_AddModule("__main__");
if (!pyMain) {
PyGILState_Release(gstate);
error->all(FLERR,"Could not initialize embedded Python");
}
PyObject* coupling_module = PyImport_ImportModule("mliap_model_python_couple");
if (!coupling_module) {
PyErr_Print();
PyErr_Clear();
PyGILState_Release(gstate);
error->all(FLERR,"Loading MLIAPPY coupling module failure.");
}
// Recipe from lammps/src/pair_python.cpp :
// add current directory to PYTHONPATH
PyObject * py_path = PySys_GetObject((char *)"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));
}
PyGILState_Release(gstate);
if (coefffilename) read_coeffs(coefffilename);
nonlinearflag=1;
}
/* ---------------------------------------------------------------------- */
MLIAPModelPython::~MLIAPModelPython(){
MLIAPPY_unload_model(this);
}
/* ----------------------------------------------------------------------
get number of parameters
---------------------------------------------------------------------- */
int MLIAPModelPython::get_nparams()
{
return nparams;
}
void MLIAPModelPython::read_coeffs(char * fname)
{
PyGILState_STATE gstate = PyGILState_Ensure();
int loaded = MLIAPPY_load_model(this, fname);
if (PyErr_Occurred()) {
PyErr_Print();
PyErr_Clear();
PyGILState_Release(gstate);
error->all(FLERR,"Loading python model failure.");
}
PyGILState_Release(gstate);
if (loaded) {
this->connect_param_counts();
}
else {
utils::logmesg(lmp,"Loading python model deferred.\n");
}
}
// Finalize loading of the model.
void MLIAPModelPython::connect_param_counts()
{
PyGILState_STATE gstate = PyGILState_Ensure();
nelements = MLIAPPY_nelements(this);
nparams = MLIAPPY_nparams(this);
ndescriptors = MLIAPPY_ndescriptors(this);
if (PyErr_Occurred()) {
PyErr_Print();
PyErr_Clear();
PyGILState_Release(gstate);
error->all(FLERR,"Loading python model failure.");
}
PyGILState_Release(gstate);
model_loaded = 1;
utils::logmesg(lmp,"Loading python model complete.\n");
}
/* ----------------------------------------------------------------------
Calculate model gradients w.r.t descriptors
for each atom beta_i = dE(B_i)/dB_i
---------------------------------------------------------------------- */
void MLIAPModelPython::compute_gradients(MLIAPData* data)
{
if (not model_loaded) {
error->all(FLERR,"Model not loaded.");
}
PyGILState_STATE gstate = PyGILState_Ensure();
MLIAPPY_compute_gradients(this, data);
if (PyErr_Occurred()) {
PyErr_Print();
PyErr_Clear();
PyGILState_Release(gstate);
error->all(FLERR,"Running python model failure.");
}
PyGILState_Release(gstate);
}
/* ----------------------------------------------------------------------
Calculate model double gradients w.r.t descriptors and parameters
for each atom energy gamma_lk = d2E(B)/dB_k/dsigma_l,
where sigma_l is a parameter, B_k a descriptor,
and atom subscript i is omitted
gamma is in CSR format:
nnz = number of non-zero values
gamma_row_index[inz] = l indices, 0 <= l < nparams
gamma_col_indexiinz] = k indices, 0 <= k < ndescriptors
gamma[i][inz] = non-zero values, 0 <= inz < nnz
egradient is derivative of energy w.r.t. parameters
---------------------------------------------------------------------- */
void MLIAPModelPython::compute_gradgrads(class MLIAPData* data)
{
error->all(FLERR,"compute_gradgrads not implemented");
}
/* ----------------------------------------------------------------------
calculate gradients of forces w.r.t. parameters
egradient is derivative of energy w.r.t. parameters
---------------------------------------------------------------------- */
void MLIAPModelPython::compute_force_gradients(class MLIAPData* data)
{
error->all(FLERR,"compute_force_gradients not implemented");
}
/* ----------------------------------------------------------------------
count the number of non-zero entries in gamma matrix
---------------------------------------------------------------------- */
int MLIAPModelPython::get_gamma_nnz(class MLIAPData* data)
{
// todo: get_gamma_nnz
return 0;
}
double MLIAPModelPython::memory_usage()
{
// todo: get approximate memory usage in coupling code.
return 0;
}

View File

@ -0,0 +1,47 @@
/* -*- 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_MLIAP_MODEL_PYTHON_H
#define LMP_MLIAP_MODEL_PYTHON_H
#include "mliap_model.h"
namespace LAMMPS_NS {
class MLIAPModelPython : public MLIAPModel {
public:
MLIAPModelPython(LAMMPS*, char* = NULL);
~MLIAPModelPython();
virtual int get_nparams();
virtual int get_gamma_nnz(class MLIAPData*);
virtual void compute_gradients(class MLIAPData*);
virtual void compute_gradgrads(class MLIAPData*);
virtual void compute_force_gradients(class MLIAPData*);
virtual double memory_usage();
void connect_param_counts(); // If possible convert this to protected/private and
// and figure out how to declare cython fn
// load_from_python as a friend.
int model_loaded;
protected:
virtual void read_coeffs(char *);
private:
};
}
#endif

View File

@ -0,0 +1,123 @@
# cython: language_level=3
# distutils: language = c++
# distutils: define_macros="LMP_MLIAPPY"
# distutils: extra_compile_args= -stdlib=libc++ -std=c++11
# distutils: include_dirs = ../STUBS .. ../MLIAP
# distutils: extra_link_args= -stdlib=libc++
# Note: only the language_level and language commands are needed, the rest pertain
# to building mliap_model_python_couple as a standalone python extension, which
# is experimental.
cimport cython
import pickle
# For converting C arrays to numpy arrays
import numpy as np
# For converting void * to integer for tracking object identity
from libc.stdint cimport uintptr_t
from libcpp.string cimport string
cdef extern from "mliap_data.h" namespace "LAMMPS_NS":
cdef cppclass MLIAPData:
# Array shapes
int natoms
int ndescriptors
# Input data
int * ielems # types for all atoms in list
double ** descriptors # descriptors for all atoms in list
# Output data to write to
double ** betas # betas for all atoms in list
double * eatoms # energy for all atoms in list
double energy
cdef extern from "mliap_model_python.h" namespace "LAMMPS_NS":
cdef cppclass MLIAPModelPython:
void connect_param_counts()
class MLIAPPYModelNotLinked(Exception): pass
LOADED_MODELS = {}
cdef object c_id(MLIAPModelPython * c_model):
"""
Use python-style id of object to keep track of identity.
Note, this is probably not a perfect general strategy but it should work fine with LAMMPS pair styles.
"""
return int(<uintptr_t> c_model)
cdef object retrieve(MLIAPModelPython * c_model):
try:
model = LOADED_MODELS[c_id(c_model)]
except KeyError as ke:
raise KeyError("Model has not been loaded.") from ke
if model is None:
raise MLIAPPYModelNotLinked("Model not linked, connect the model from the python side.")
return model
cdef public int MLIAPPY_load_model(MLIAPModelPython * c_model, char* fname) with gil:
str_fname = fname.decode('utf-8') # Python 3 only; not Python 2 not supported.
if str_fname == "LATER":
model = None
returnval = 0
else:
with open(str_fname,'rb') as pfile:
model = pickle.load(pfile)
returnval = 1
LOADED_MODELS[c_id(c_model)] = model
return returnval
def load_from_python(model):
unloaded_models = [k for k, v in LOADED_MODELS.items() if v is None]
num_models = len(unloaded_models)
cdef MLIAPModelPython * lmp_model
if num_models == 0:
raise ValueError("No model in the waiting area.")
elif num_models > 1:
raise ValueError("Model is amibguous, more than one model in waiting area.")
else:
c_id = unloaded_models[0]
LOADED_MODELS[c_id]=model
lmp_model = <MLIAPModelPython *> <uintptr_t> c_id
lmp_model.connect_param_counts()
cdef public void MLIAPPY_unload_model(MLIAPModelPython * c_model) with gil:
del LOADED_MODELS[c_id(c_model)]
cdef public int MLIAPPY_nparams(MLIAPModelPython * c_model) with gil:
return int(retrieve(c_model).n_params)
cdef public int MLIAPPY_nelements(MLIAPModelPython * c_model) with gil:
return int(retrieve(c_model).n_elements)
cdef public int MLIAPPY_ndescriptors(MLIAPModelPython * c_model) with gil:
return int(retrieve(c_model).n_descriptors)
cdef public void MLIAPPY_compute_gradients(MLIAPModelPython * c_model, MLIAPData * data) with gil:
model = retrieve(c_model)
n_d = data.ndescriptors
n_a = data.natoms
# Make numpy arrays from pointers
beta_np = np.asarray(<double[:n_a,:n_d] > &data.betas[0][0])
desc_np = np.asarray(<double[:n_a,:n_d]> &data.descriptors[0][0])
elem_np = np.asarray(<int[:n_a]> &data.ielems[0])
en_np = np.asarray(<double[:n_a]> &data.eatoms[0])
# Invoke python model on numpy arrays.
model(elem_np,desc_np,beta_np,en_np)
# Get the total energy from the atom energy.
energy = np.sum(en_np)
data.energy = <double> energy
return

View File

@ -0,0 +1,46 @@
import numpy as np
import torch
def calc_n_params(model):
return sum(p.nelement() for p in model.parameters())
class TorchWrapper(torch.nn.Module):
def __init__(self, model,n_descriptors,n_elements,n_params=None):
super().__init__()
self.model = model
self.model.to(self.dtype)
if n_params is None:
n_params = calc_n_params(model)
self.n_params = n_params
self.n_descriptors = n_descriptors
self.n_elements = n_elements
def __call__(self, elems, bispectrum, beta, energy):
bispectrum = torch.from_numpy(bispectrum).to(self.dtype).requires_grad_(True)
elems = torch.from_numpy(elems).to(torch.long) - 1
with torch.autograd.enable_grad():
energy_nn = self.model(bispectrum, elems)
if energy_nn.ndim > 1:
energy_nn = energy_nn.flatten()
beta_nn = torch.autograd.grad(energy_nn.sum(), bispectrum)[0]
beta[:] = beta_nn.detach().cpu().numpy().astype(np.float64)
energy[:] = energy_nn.detach().cpu().numpy().astype(np.float64)
class TorchWrapper32(TorchWrapper):
dtype = torch.float32
class TorchWrapper64(TorchWrapper):
dtype = torch.float64
class IgnoreElems(torch.nn.Module):
def __init__(self,subnet):
super().__init__()
self.subnet = subnet
def forward(self,bispectrum,elems):
return self.subnet(bispectrum)

View File

@ -48,7 +48,7 @@ endif
PACKAGE = asphere body class2 colloid compress coreshell dipole gpu \ PACKAGE = asphere body class2 colloid compress coreshell dipole gpu \
granular kim kokkos kspace latte manybody mc message misc \ granular kim kokkos kspace latte manybody mc message misc \
mliap molecule mpiio mscg opt peri poems \ mliap mliappy molecule mpiio mscg opt peri poems \
python qeq replica rigid shock snap spin srd voronoi python qeq replica rigid shock snap spin srd voronoi
PACKUSER = user-adios user-atc user-awpmd user-bocs user-cgdna user-cgsdk user-colvars \ PACKUSER = user-adios user-atc user-awpmd user-bocs user-cgdna user-cgsdk user-colvars \

View File

@ -26,6 +26,14 @@
#include <cstring> #include <cstring>
#include <Python.h> // IWYU pragma: export #include <Python.h> // IWYU pragma: export
#ifdef LMP_MLIAPPY
#include "mliap_model_python.h"
// The above should somehow really be included in the next file.
// We could get around this with cython --capi-reexport-cincludes
// However, that exposes -too many- headers.
#include "mliap_model_python_couple.h"
#endif
using namespace LAMMPS_NS; using namespace LAMMPS_NS;
enum{NONE,INT,DOUBLE,STRING,PTR}; enum{NONE,INT,DOUBLE,STRING,PTR};
@ -47,11 +55,17 @@ PythonImpl::PythonImpl(LAMMPS *lmp) : Pointers(lmp)
nfunc = 0; nfunc = 0;
pfuncs = nullptr; pfuncs = nullptr;
// one-time initialization of Python interpreter // one-time initialization of Python interpreter
// pyMain stores pointer to main module // pyMain stores pointer to main module
external_interpreter = Py_IsInitialized(); external_interpreter = Py_IsInitialized();
#ifdef LMP_MLIAPPY
// Inform python intialization scheme of the mliappy module.
// This -must- happen before python is initialized.
int err = PyImport_AppendInittab("mliap_model_python_couple", PyInit_mliap_model_python_couple);
if (err) error->all(FLERR,"Could not register MLIAPPY embedded python module.");
#endif
Py_Initialize(); Py_Initialize();
PyEval_InitThreads(); PyEval_InitThreads();