Merge branch 'lammps:master' into master

This commit is contained in:
TD Swinburne (Tom)
2021-06-27 14:10:49 +02:00
committed by GitHub
4826 changed files with 193076 additions and 67029 deletions

1
python/.gitignore vendored
View File

@ -1 +1,2 @@
/build
/*.egg-info

View File

@ -38,13 +38,14 @@ Once you have successfully wrapped LAMMPS, you can run the Python
scripts in the examples sub-directory:
trivial.py read/run a LAMMPS input script thru Python
demo.py invoke various LAMMPS library interface routines
simple.py parallel example, mimicing examples/COUPLE/simple/simple.cpp
demo.py invoke various LAMMPS library interface routines
simple.py parallel example, mimicing examples/COUPLE/simple/simple.cpp
split.py parallel example
mc.py Monte Carlo energy relaxation wrapper on LAMMPS
gui.py GUI go/stop/temperature-slider to control LAMMPS
plot.py real-time temperature plot with GnuPlot via Pizza.py
viz_tool.py real-time viz via some viz package
gui.py GUI go/stop/temperature-slider to control LAMMPS
plot.py real-time temperature plot with GnuPlot via Pizza.py
matplotlib_plot.py real-time temperature plot with Matplotlib via Pizza.py
viz_tool.py real-time viz via some viz package
vizplotgui_tool.py combination of viz.py and plot.py and gui.py
For the viz_tool.py and vizplotgui_tool.py commands, replace "tool"
@ -100,24 +101,24 @@ split.py in.simple # can run in parallel (see below)
gui.py in.gui 100
plot.py in.plot 10 1000 thermo_temp
matplotlib_plot.py in.plot 10 1000 thermo_temp
viz_tool.py in.viz 100 5000
vizplotgui_tool.py in.viz 100 thermo_temp
To run LAMMPS in parallel from Python, so something like this:
% mpirun -np 4 simple.py in.simple
% mpirun -np 4 python split.py in.simple
% mpirun -np P simple.py in.simple
% mpirun -np P python split.py in.simple
If you run simple.py as-is, this will invoke P instances of a
one-processor run, where both Python and LAMMPS will run on single
processors. Each running job will read the same input file, and write
to same log.lammps file, which isn't too useful.
However, if you have either the Pypar or mpi4py packages installed in
your Python, and uncomment the Pypar or mpi4py code in simple.py, then
the above commands will invoke 1 instance of a P-processor run. Both
Python and LAMMPS will run on P processors. The job will read the
input file and write a single log.lammps file.
However, if you have the mpi4py Python package installed and uncomment mpi4py
code in simple.py, then the above commands will invoke 1 instance of a
P-processor run. Both Python and LAMMPS will run on P processors. The job will
read the input file and write a single log.lammps file.
The split.py script can also be run in parallel. It uses mpi4py
version 2.0.0 (or later), which makes it possible to pass a

1
python/examples/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/tmp*

View File

@ -7,8 +7,7 @@
# in.lammps = LAMMPS input script
# Nfreq = query GUI every this many steps
# IMPORTANT: this script cannot yet be run in parallel via Pypar,
# because I can't seem to do a MPI-style broadcast in Pypar
# IMPORTANT: this script cannot yet be run in parallel
from __future__ import print_function
import sys,time
@ -39,10 +38,6 @@ infile = sys.argv[1]
nfreq = int(sys.argv[2])
me = 0
# uncomment if running in parallel via Pypar
#import pypar
#me = pypar.rank()
#nprocs = pypar.size()
from lammps import lammps
lmp = lammps()
@ -110,7 +105,3 @@ while 1:
if runflag: running = 1
else: running = 0
time.sleep(0.01)
# uncomment if running in parallel via Pypar
#print("Proc %d out of %d procs has" % (me,nprocs), lmp)
#pypar.finalize()

View File

@ -12,9 +12,6 @@
from __future__ import print_function
import sys
sys.path.append("./pizza")
import matplotlib
matplotlib.use('tkagg')
import matplotlib.pyplot as plt
# parse command line
@ -30,10 +27,10 @@ nsteps = int(sys.argv[3])
compute = sys.argv[4]
me = 0
# uncomment if running in parallel via Pypar
#import pypar
#me = pypar.rank()
#nprocs = pypar.size()
# uncomment this if running in parallel via mpi4py
#from mpi4py import MPI
#me = MPI.COMM_WORLD.Get_rank()
#nprocs = MPI.COMM_WORLD.Get_size()
from lammps import lammps
lmp = lammps()
@ -79,15 +76,16 @@ while ntimestep < nsteps:
ax = plt.gca()
ax.relim()
ax.autoscale_view(True, True, True)
fig.canvas.draw()
plt.pause(0.001)
lmp.command("run 0 pre no post yes")
# uncomment if running in parallel via Pypar
# uncomment if running in parallel via mpi4py
#print("Proc %d out of %d procs has" % (me,nprocs), lmp)
#pypar.finalize()
if sys.version_info[0] == 3:
input("Press Enter to exit...")
else:
raw_input("Press Enter to exit...")
if me == 0:
if sys.version_info[0] == 3:
input("Press Enter to exit...")
else:
raw_input("Press Enter to exit...")

View File

@ -3,7 +3,7 @@
#
# Copyright (2005) 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
# certain rights in this software. This software is distributed under
# the GNU General Public License.
# for python3 compatibility
@ -35,7 +35,7 @@ time = d.next() read next snapshot from dump files
d.map(1,"id",3,"x") assign names to atom columns (1-N)
not needed if dump file is self-describing
d.tselect.all() select all timesteps
d.tselect.one(N) select only timestep N
d.tselect.none() deselect all timesteps
@ -227,7 +227,7 @@ class dump:
for word in words: self.flist += glob.glob(word)
if len(self.flist) == 0 and len(list) == 1:
raise Exception("no dump file specified")
if len(list) == 1:
self.increment = 0
self.read_all()
@ -270,12 +270,12 @@ class dump:
self.tselect.all()
# set default names for atom columns if file wasn't self-describing
if len(self.snaps) == 0:
print("no column assignments made")
elif len(self.names):
print("assigned columns:",self.names2str())
elif self.snaps[0].atoms == None:
elif self.snaps[0].atoms is None:
print("no column assignments made")
elif len(self.snaps[0].atoms[0]) == 5:
self.map(1,"id",2,"type",3,"x",4,"y",5,"z")
@ -341,7 +341,7 @@ class dump:
# return snapshot or 0 if failed
# assign column names if not already done and file is self-describing
# convert xs,xu to x
def read_snapshot(self,f):
try:
snap = Snap()
@ -414,7 +414,7 @@ class dump:
# --------------------------------------------------------------------
# map atom column names
def map(self,*pairs):
if len(pairs) % 2 != 0:
raise Exception("dump map() requires pairs of mappings")
@ -492,7 +492,7 @@ class dump:
atoms[:,x] = snap.xlo + atoms[:,x]*xprd
atoms[:,y] = snap.ylo + atoms[:,y]*yprd
atoms[:,z] = snap.zlo + atoms[:,z]*zprd
# --------------------------------------------------------------------
# wrap coords from outside box to inside
@ -505,7 +505,7 @@ class dump:
ix = self.names["ix"]
iy = self.names["iy"]
iz = self.names["iz"]
for snap in self.snaps:
xprd = snap.xhi - snap.xlo
yprd = snap.yhi - snap.ylo
@ -527,7 +527,7 @@ class dump:
ix = self.names["ix"]
iy = self.names["iy"]
iz = self.names["iz"]
for snap in self.snaps:
xprd = snap.xhi - snap.xlo
yprd = snap.yhi - snap.ylo
@ -542,7 +542,7 @@ class dump:
def owrap(self,other):
print("Wrapping to other ...")
id = self.names["id"]
x = self.names["x"]
y = self.names["y"]
@ -551,7 +551,7 @@ class dump:
iy = self.names["iy"]
iz = self.names["iz"]
iother = self.names[other]
for snap in self.snaps:
xprd = snap.xhi - snap.xlo
yprd = snap.yhi - snap.ylo
@ -568,7 +568,7 @@ class dump:
# --------------------------------------------------------------------
# convert column names assignment to a string, in column order
def names2str(self):
ncol = len(self.snaps[0].atoms[0])
pairs = self.names.items()
@ -631,7 +631,7 @@ class dump:
print(snap.ylo,snap.yhi,file=f)
print(snap.zlo,snap.zhi,file=f)
print("ITEM: ATOMS",namestr,file=f)
atoms = snap.atoms
nvalues = len(atoms[0])
for i in range(snap.natoms):
@ -655,7 +655,7 @@ class dump:
if not snap.tselect: continue
print(snap.time,end='')
sys.stdout.flush()
file = root + "." + str(snap.time)
f = open(file,"w")
print("ITEM: TIMESTEP",file=f)
@ -667,7 +667,7 @@ class dump:
print(snap.ylo,snap.yhi,file=f)
print(snap.zlo,snap.zhi,file=f)
print("ITEM: ATOMS",namestr,file=f)
atoms = snap.atoms
nvalues = len(atoms[0])
for i in range(snap.natoms):
@ -709,7 +709,7 @@ class dump:
lhs = list[0][1:]
if not self.names.has_key(lhs):
self.newcolumn(lhs)
for item in list:
name = item[1:]
column = self.names[name]
@ -721,7 +721,7 @@ class dump:
if not snap.tselect: continue
for i in range(snap.natoms):
if snap.aselect[i]: exec(ceq)
# --------------------------------------------------------------------
# set a column value via an input vec for all selected snapshots/atoms
@ -741,7 +741,7 @@ class dump:
if snap.aselect[i]:
atoms[i][icol] = vec[m]
m += 1
# --------------------------------------------------------------------
# clone value in col across selected timesteps for atoms with same ID
@ -807,7 +807,7 @@ class dump:
columns.append(self.names[name])
values.append(self.nselect * [0])
ncol = len(columns)
id = self.names["id"]
m = 0
for snap in self.snaps:
@ -823,13 +823,13 @@ class dump:
if len(list) == 1: return values[0]
else: return values
# --------------------------------------------------------------------
# extract vector(s) of values for selected atoms at chosen timestep
def vecs(self,n,*list):
snap = self.snaps[self.findtime(n)]
if len(list) == 0:
raise Exception("no columns specified")
columns = []
@ -884,7 +884,7 @@ class dump:
del self.snaps[i]
else:
i += 1
# --------------------------------------------------------------------
# iterate over selected snapshots
@ -896,11 +896,11 @@ class dump:
self.iterate = i
return i,self.snaps[i].time,1
return 0,0,-1
# --------------------------------------------------------------------
# return list of atoms to viz for snapshot isnap
# augment with bonds, tris, lines if extra() was invoked
def viz(self,isnap):
snap = self.snaps[isnap]
@ -914,7 +914,7 @@ class dump:
# create atom list needed by viz from id,type,x,y,z
# need Numeric/Numpy mode here
atoms = []
for i in range(snap.natoms):
if not snap.aselect[i]: continue
@ -948,12 +948,12 @@ class dump:
elif self.triflag == 2:
timetmp,boxtmp,atomstmp,bondstmp, \
tris,linestmp = self.triobj.viz(time,1)
lines = []
if self.lineflag: lines = self.linelist
return time,box,atoms,bonds,tris,lines
# --------------------------------------------------------------------
def findtime(self,n):
@ -969,12 +969,12 @@ class dump:
xhi = yhi = zhi = None
for snap in self.snaps:
if not snap.tselect: continue
if xlo == None or snap.xlo < xlo: xlo = snap.xlo
if xhi == None or snap.xhi > xhi: xhi = snap.xhi
if ylo == None or snap.ylo < ylo: ylo = snap.ylo
if yhi == None or snap.yhi > yhi: yhi = snap.yhi
if zlo == None or snap.zlo < zlo: zlo = snap.zlo
if zhi == None or snap.zhi > zhi: zhi = snap.zhi
if xlo is None or snap.xlo < xlo: xlo = snap.xlo
if xhi is None or snap.xhi > xhi: xhi = snap.xhi
if ylo is None or snap.ylo < ylo: ylo = snap.ylo
if yhi is None or snap.yhi > yhi: yhi = snap.yhi
if zlo is None or snap.zlo < zlo: zlo = snap.zlo
if zhi is None or snap.zhi > zhi: zhi = snap.zhi
return [xlo,ylo,zlo,xhi,yhi,zhi]
# --------------------------------------------------------------------
@ -997,7 +997,7 @@ class dump:
def extra(self,arg):
# read bonds from bond dump file
if type(arg) is types.StringType:
try:
f = open(arg,'r')
@ -1017,7 +1017,7 @@ class dump:
f.close()
# convert values to int and absolute value since can be negative types
if oldnumeric: bondlist = np.zeros((nbonds,4),np.Int)
else: bondlist = np.zeros((nbonds,4),np.int)
ints = [abs(int(value)) for value in words]
@ -1032,9 +1032,9 @@ class dump:
self.bondlist = bondlist
except:
raise Exception("could not read from bond dump file")
# request bonds from data object
elif type(arg) is types.InstanceType and ".data" in str(arg.__class__):
try:
bondlist = []
@ -1050,7 +1050,7 @@ class dump:
raise Exception("could not extract bonds from data object")
# request tris/lines from cdata object
elif type(arg) is types.InstanceType and ".cdata" in str(arg.__class__):
try:
tmp,tmp,tmp,tmp,tris,lines = arg.viz(0)
@ -1064,7 +1064,7 @@ class dump:
raise Exception("could not extract tris/lines from cdata object")
# request tris from mdump object
elif type(arg) is types.InstanceType and ".mdump" in str(arg.__class__):
try:
self.triflag = 2
@ -1074,7 +1074,7 @@ class dump:
else:
raise Exception("unrecognized argument to dump.extra()")
# --------------------------------------------------------------------
def compare_atom(self,a,b):
@ -1083,7 +1083,7 @@ class dump:
elif a[0] > b[0]:
return 1
else:
return 0
return 0
# --------------------------------------------------------------------
# one snapshot
@ -1098,7 +1098,7 @@ class tselect:
def __init__(self,data):
self.data = data
# --------------------------------------------------------------------
def all(self):
@ -1145,7 +1145,7 @@ class tselect:
data.nselect -= 1
data.aselect.all()
print("%d snapshots selected out of %d" % (data.nselect,data.nsnaps))
# --------------------------------------------------------------------
def test(self,teststr):
@ -1191,7 +1191,7 @@ class aselect:
data = self.data
# replace all $var with snap.atoms references and compile test string
pattern = "\$\w*"
list = re.findall(pattern,teststr)
for item in list:

View File

@ -851,7 +851,7 @@ class gl:
ncolor = self.vizinfo.ntcolor
for tri in self.tridraw:
itype = int(tri[1])
if itype > ncolor: raise StandardError("tri type too big")
if itype > ncolor: raise Exception("tri type too big")
red,green,blue = self.vizinfo.tcolor[itype]
glMaterialfv(GL_FRONT_AND_BACK,GL_EMISSION,[red,green,blue,1.0]);
glMaterialf(GL_FRONT_AND_BACK,GL_SHININESS,self.shiny);
@ -909,7 +909,7 @@ class gl:
ymin >= ylo and ymax <= yhi and zmin >= zlo and zmax <= zhi:
if bond[10] > bound: continue
itype = int(bond[1])
if itype > ncolor: raise StandardError("bond type too big")
if itype > ncolor: raise Exception("bond type too big")
red,green,blue = self.vizinfo.bcolor[itype]
rad = self.vizinfo.brad[itype]
glPushMatrix()
@ -941,7 +941,7 @@ class gl:
ymin >= ylo and ymax <= yhi and \
zmin >= zlo and zmax <= zhi:
itype = int(tri[1])
if itype > ncolor: raise StandardError("tri type too big")
if itype > ncolor: raise Exception("tri type too big")
red,green,blue = self.vizinfo.tcolor[itype]
glMaterialfv(GL_FRONT_AND_BACK,GL_EMISSION,
[red,green,blue,1.0]);

View File

@ -3,7 +3,7 @@
#
# Copyright (2005) 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
# certain rights in this software. This software is distributed under
# the GNU General Public License.
# for python3 compatibility
@ -16,7 +16,7 @@ oneline = "Create plots via GnuPlot plotting program"
docstr = """
g = gnu() start up GnuPlot
g.stop() shut down GnuPlot process
g.plot(a) plot vector A against linear index
g.plot(a,b) plot B against A
g.plot(a,b,c,d,...) plot B against A, D against C, etc
@ -35,14 +35,14 @@ g("plot 'file.dat' using 2:3 with lines") execute string in GnuPlot
g.enter() enter GnuPlot shell
gnuplot> plot sin(x) with lines type commands directly to GnuPlot
gnuplot> exit, quit exit GnuPlot shell
g.export("data",range(100),a,...) create file with columns of numbers
all vectors must be of equal length
could plot from file with GnuPlot command: plot 'data' using 1:2 with lines
g.select(N) figure N becomes the current plot
subsequent commands apply to this plot
g.hide(N) delete window for figure N
@ -87,17 +87,18 @@ g.curve(N,'r') set color of curve N
# Imports and external programs
import types, os
import os
import sys
try: from DEFAULTS import PIZZA_GNUPLOT
except: PIZZA_GNUPLOT = "gnuplot -p"
except ImportError: PIZZA_GNUPLOT = "gnuplot -p"
try: from DEFAULTS import PIZZA_GNUTERM
except: PIZZA_GNUTERM = "x11"
except ImportError: PIZZA_GNUTERM = "x11"
# Class definition
class gnu:
# --------------------------------------------------------------------
def __init__(self):
@ -105,7 +106,7 @@ class gnu:
self.file = "tmp.gnu"
self.figures = []
self.select(1)
# --------------------------------------------------------------------
def stop(self):
@ -117,12 +118,15 @@ class gnu:
def __call__(self,command):
self.GNUPLOT.write(command + '\n')
self.GNUPLOT.flush()
# --------------------------------------------------------------------
def enter(self):
while 1:
command = raw_input("gnuplot> ")
if sys.version_info[0] == 3:
command = input("gnuplot> ")
else:
command = raw_input("gnuplot> ")
if command == "quit" or command == "exit": return
self.__call__(command)
@ -136,7 +140,7 @@ class gnu:
self.export(file,linear,vectors[0])
self.figures[self.current-1].ncurves = 1
else:
if len(vectors) % 2: raise StandardError("vectors must come in pairs")
if len(vectors) % 2: raise Exception("vectors must come in pairs")
for i in range(0,len(vectors),2):
file = self.file + ".%d.%d" % (self.current,i/2+1)
self.export(file,vectors[i],vectors[i+1])
@ -155,7 +159,7 @@ class gnu:
if i: partial_vecs.append(vec[:i])
else: partial_vecs.append([0])
self.plot(*partial_vecs)
if n < 10: newfile = file + "000" + str(n)
elif n < 100: newfile = file + "00" + str(n)
elif n < 1000: newfile = file + "0" + str(n)
@ -163,14 +167,14 @@ class gnu:
self.save(newfile)
n += 1
# --------------------------------------------------------------------
# write list of equal-length vectors to filename
def export(self,filename,*vectors):
n = len(vectors[0])
for vector in vectors:
if len(vector) != n: raise StandardError("vectors must be same length")
if len(vector) != n: raise Exception("vectors must be same length")
f = open(filename,'w')
nvec = len(vectors)
for i in range(n):
@ -204,7 +208,7 @@ class gnu:
# do not continue until plot file is written out
# else script could go forward and change data file
# use tmp.done as semaphore to indicate plot is finished
def save(self,file):
self.__call__("set terminal postscript enhanced solid lw 2 color portrait")
cmd = "set output '%s.eps'" % file
@ -215,7 +219,7 @@ class gnu:
while not os.path.exists("tmp.done"): continue
self.__call__("set output")
self.select(self.current)
# --------------------------------------------------------------------
# restore default attributes by creating a new fig object
@ -224,7 +228,7 @@ class gnu:
fig.ncurves = self.figures[self.current-1].ncurves
self.figures[self.current-1] = fig
self.draw()
# --------------------------------------------------------------------
def aspect(self,value):
@ -248,12 +252,12 @@ class gnu:
else:
self.figures[self.current-1].ylimit = (values[0],values[1])
self.draw()
# --------------------------------------------------------------------
def label(self,x,y,text):
self.figures[self.current-1].labels.append((x,y,text))
self.figures[self.current-1].nlabels += 1
self.figures[self.current-1].nlabels += 1
self.draw()
# --------------------------------------------------------------------
@ -262,7 +266,7 @@ class gnu:
self.figures[self.current-1].nlabel = 0
self.figures[self.current-1].labels = []
self.draw()
# --------------------------------------------------------------------
def title(self,*strings):
@ -279,13 +283,13 @@ class gnu:
def xtitle(self,label):
self.figures[self.current-1].xtitle = label
self.draw()
# --------------------------------------------------------------------
def ytitle(self,label):
self.figures[self.current-1].ytitle = label
self.draw()
# --------------------------------------------------------------------
def xlog(self):
@ -294,7 +298,7 @@ class gnu:
else:
self.figures[self.current-1].xlog = 1
self.draw()
# --------------------------------------------------------------------
def ylog(self):
@ -303,7 +307,7 @@ class gnu:
else:
self.figures[self.current-1].ylog = 1
self.draw()
# --------------------------------------------------------------------
def curve(self,num,color):
@ -319,10 +323,10 @@ class gnu:
def draw(self):
fig = self.figures[self.current-1]
if not fig.ncurves: return
cmd = 'set size ratio ' + str(1.0/float(fig.aspect))
self.__call__(cmd)
cmd = 'set title ' + '"' + fig.title + '"'
self.__call__(cmd)
cmd = 'set xlabel ' + '"' + fig.xtitle + '"'
@ -334,11 +338,11 @@ class gnu:
else: self.__call__("unset logscale x")
if fig.ylog: self.__call__("set logscale y")
else: self.__call__("unset logscale y")
if fig.xlimit:
if fig.xlimit:
cmd = 'set xr [' + str(fig.xlimit[0]) + ':' + str(fig.xlimit[1]) + ']'
self.__call__(cmd)
else: self.__call__("set xr [*:*]")
if fig.ylimit:
if fig.ylimit:
cmd = 'set yr [' + str(fig.ylimit[0]) + ':' + str(fig.ylimit[1]) + ']'
self.__call__(cmd)
else: self.__call__("set yr [*:*]")
@ -368,7 +372,7 @@ class figure:
def __init__(self):
self.ncurves = 0
self.colors = []
self.colors = []
self.title = ""
self.xtitle = ""
self.ytitle = ""

View File

@ -3,7 +3,7 @@
#
# Copyright (2005) 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
# certain rights in this software. This software is distributed under
# the GNU General Public License.
# for python3 compatibility
@ -25,7 +25,7 @@ p = pdbfile("3CRO",d) read in single PDB file with snapshot data
if only one 4-char file specified and it is not found,
it will be downloaded from http://www.rcsb.org as 3CRO.pdb
d arg is object with atom coordinates (dump, data)
p.one() write all output as one big PDB file to tmp.pdb
p.one("mine") write to mine.pdb
p.many() write one PDB file per snapshot: tmp0000.pdb, ...
@ -39,7 +39,7 @@ p.single(N,"new") write as new.pdb
if one file in str arg and d: one new PDB file per snapshot
using input PDB file as template
multiple input PDB files with a d is not allowed
index,time,flag = p.iterator(0)
index,time,flag = p.iterator(1)
@ -68,7 +68,7 @@ index,time,flag = p.iterator(1)
# Imports and external programs
import sys, types, glob, urllib
import sys, glob, urllib
PY3 = sys.version_info[0] == 3
if PY3:
@ -93,31 +93,31 @@ class pdbfile:
elif len(args) == 2:
filestr = args[0]
self.data = args[1]
else: raise StandardError("invalid args for pdb()")
else: raise Exception("invalid args for pdb()")
# flist = full list of all PDB input file names
# append .pdb if needed
if filestr:
list = filestr.split()
flist = []
for file in list:
if '*' in file: flist += glob.glob(file)
else: flist.append(file)
for i in xrange(len(flist)):
for i in range(len(flist)):
if flist[i][-4:] != ".pdb": flist[i] += ".pdb"
if len(flist) == 0:
raise StandardError("no PDB file specified")
raise Exception("no PDB file specified")
self.files = flist
else: self.files = []
if len(self.files) > 1 and self.data:
raise StandardError("cannot use multiple PDB files with data object")
raise Exception("cannot use multiple PDB files with data object")
if len(self.files) == 0 and not self.data:
raise StandardError("no input PDB file(s)")
raise Exception("no input PDB file(s)")
# grab PDB file from http://rcsb.org if not a local file
if len(self.files) == 1 and len(self.files[0]) == 8:
try:
open(self.files[0],'r').close()
@ -127,7 +127,7 @@ class pdbfile:
urllib.urlretrieve(fetchstr,self.files[0])
if self.data and len(self.files): self.read_template(self.files[0])
# --------------------------------------------------------------------
# write a single large PDB file for concatenating all input data or files
# if data exists:
@ -145,7 +145,7 @@ class pdbfile:
f = open(file,'w')
# use template PDB file with each snapshot
if self.data:
n = flag = 0
while 1:
@ -163,7 +163,7 @@ class pdbfile:
print("END",file=f)
print(file,end='')
sys.stdout.flush()
f.close()
print("\nwrote %d datasets to %s in PDB format" % (n,file))
@ -199,7 +199,7 @@ class pdbfile:
f = open(file,'w')
self.convert(f,which)
f.close()
print(time,end='')
sys.stdout.flush()
n += 1
@ -216,13 +216,13 @@ class pdbfile:
else:
file = root + str(n)
file += ".pdb"
f = open(file,'w')
f.write(open(infile,'r').read())
f.close()
print(file,end='')
sys.stdout.flush()
n += 1
print("\nwrote %d datasets to %s*.pdb in PDB format" % (n,root))
@ -249,7 +249,7 @@ class pdbfile:
self.convert(f,which)
else:
f.write(open(self.files[time],'r').read())
f.close()
# --------------------------------------------------------------------
@ -268,8 +268,8 @@ class pdbfile:
# --------------------------------------------------------------------
# read a PDB file and store ATOM lines
def read_template(self,file):
def read_template(self,file):
lines = open(file,'r').readlines()
self.atomlines = {}
for line in lines:

View File

@ -79,7 +79,7 @@ class vizinfo:
# if list of types has a 0, increment each type value
if 0 in ids:
for i in xrange(len(ids)): ids[i] += 1
for i in range(len(ids)): ids[i] += 1
# extend storage list if necessary
# extend other arrays for same "which" so that gl::make_atom_calllist
@ -109,7 +109,7 @@ class vizinfo:
ntypes = len(ids)
nrgbs = len(rgbs)
for i in xrange(ntypes):
for i in range(ntypes):
id = ids[i]
if rgbs[0] == "loop":
@ -157,7 +157,7 @@ class vizinfo:
# if list of types has a 0, increment each type value
if 0 in ids:
for i in xrange(len(ids)): ids[i] += 1
for i in range(len(ids)): ids[i] += 1
# extend storage list if necessary
# extend other arrays for same "which" so that gl::make_atom_calllist
@ -220,7 +220,7 @@ class vizinfo:
# if list of types has a 0, increment each type value
if 0 in ids:
for i in xrange(len(ids)): ids[i] += 1
for i in range(len(ids)): ids[i] += 1
# extend storage list if necessary
# extend other arrays for same "which" so that gl::make_atom_calllist
@ -234,7 +234,7 @@ class vizinfo:
# if list lengths match, set directly, else set types to 1st fill value
if len(fills) == len(ids):
for i in xrange(len(ids)): self.tfill[ids[i]] = int(fills[i])
for i in range(len(ids)): self.tfill[ids[i]] = int(fills[i])
else:
for id in ids: self.tfill[id] = int(fills[0])

View File

@ -45,17 +45,16 @@ v.debug([True|False]) display generated VMD script commands?
# Imports and external programs
import types, os
import numpy
import os
try: from DEFAULTS import PIZZA_VMDNAME
except: PIZZA_VMDNAME = "vmd"
except ImportError: PIZZA_VMDNAME = "vmd"
try: from DEFAULTS import PIZZA_VMDDIR
except: PIZZA_VMDDIR = "/usr/local/lib/vmd"
except ImportError: PIZZA_VMDDIR = "/usr/local/lib/vmd"
try: from DEFAULTS import PIZZA_VMDDEV
except: PIZZA_VMDDEV = "win"
except ImportError: PIZZA_VMDDEV = "win"
try: from DEFAULTS import PIZZA_VMDARCH
except: PIZZA_VMDARCH = "LINUXAMD64"
except ImportError: PIZZA_VMDARCH = "LINUXAMD64"
# try these settings for a Mac
#PIZZA_VMDNAME = "vmd"
@ -64,7 +63,7 @@ except: PIZZA_VMDARCH = "LINUXAMD64"
#PIZZA_VMDARCH = "MACOSXX86"
try: import pexpect
except:
except ImportError:
print("pexpect from http://pypi.python.org/pypi/pexpect", \
"is required for vmd tool")
raise

View File

@ -28,10 +28,10 @@ nsteps = int(sys.argv[3])
compute = sys.argv[4]
me = 0
# uncomment if running in parallel via Pypar
#import pypar
#me = pypar.rank()
#nprocs = pypar.size()
# uncomment this if running in parallel via mpi4py
#from mpi4py import MPI
#me = MPI.COMM_WORLD.Get_rank()
#nprocs = MPI.COMM_WORLD.Get_size()
from lammps import lammps
lmp = lammps()
@ -57,7 +57,7 @@ if me == 0:
gn = gnu()
gn.plot(xaxis,yaxis)
gn.xrange(0,nsteps)
gn.title(compute,"Timestep","Temperature")
gn.title(compute.replace('_', ' '),"Timestep","Temperature")
# run nfreq steps at a time w/out pre/post, query compute, refresh plot
@ -71,6 +71,5 @@ while ntimestep < nsteps:
lmp.command("run 0 pre no post yes")
# uncomment if running in parallel via Pypar
# uncomment if running in parallel via mpi4py
#print("Proc %d out of %d procs has" % (me,nprocs), lmp)
#pypar.finalize()

View File

@ -4,7 +4,7 @@ This folder contains examples showcasing the usage of the PyLammps Python
interface and Jupyter notebooks. To use this you will need LAMMPS compiled as
a shared library and the LAMMPS Python package installed.
An extensive guide on how to achieve this is documented in the [LAMMPS manual](https://lammps.sandia.gov/doc/Python_install.html). There is also a [PyLammps tutorial](https://lammps.sandia.gov/doc/Howto_pylammps.html).
An extensive guide on how to achieve this is documented in the [LAMMPS manual](https://docs.lammps.org/Python_install.html). There is also a [PyLammps tutorial](https://docs.lammps.org/Howto_pylammps.html).
The following will show one way of creating a Python virtual environment
which has both LAMMPS and its Python package installed:

View File

@ -13,7 +13,7 @@
"source": [
"## Prerequisites\n",
"\n",
"Before running this example, make sure your Python environment can find the LAMMPS shared library (`liblammps.so`) and the LAMMPS Python package is installed. If you followed the [README](README.md) in this folder, this should already be the case. You can also find more information about how to compile LAMMPS and install the LAMMPS Python package in the [LAMMPS manual](https://lammps.sandia.gov/doc/Python_install.html). There is also a dedicated [PyLammps HowTo](https://lammps.sandia.gov/doc/Howto_pylammps.html)."
"Before running this example, make sure your Python environment can find the LAMMPS shared library (`liblammps.so`) and the LAMMPS Python package is installed. If you followed the [README](README.md) in this folder, this should already be the case. You can also find more information about how to compile LAMMPS and install the LAMMPS Python package in the [LAMMPS manual](https://docs.lammps.org/Python_install.html). There is also a dedicated [PyLammps HowTo](https://docs.lammps.org/Howto_pylammps.html)."
]
},
{

View File

@ -13,7 +13,7 @@
"source": [
"## Prerequisites\n",
"\n",
"Before running this example, make sure your Python environment can find the LAMMPS shared library (`liblammps.so`) and the LAMMPS Python package is installed. If you followed the [README](README.md) in this folder, this should already be the case. You can also find more information about how to compile LAMMPS and install the LAMMPS Python package in the [LAMMPS manual](https://lammps.sandia.gov/doc/Python_install.html). There is also a dedicated [PyLammps HowTo](https://lammps.sandia.gov/doc/Howto_pylammps.html)."
"Before running this example, make sure your Python environment can find the LAMMPS shared library (`liblammps.so`) and the LAMMPS Python package is installed. If you followed the [README](README.md) in this folder, this should already be the case. You can also find more information about how to compile LAMMPS and install the LAMMPS Python package in the [LAMMPS manual](https://docs.lammps.org/Python_install.html). There is also a dedicated [PyLammps HowTo](https://docs.lammps.org/Howto_pylammps.html)."
]
},
{

View File

@ -20,7 +20,7 @@
"source": [
"## Prerequisites\n",
"\n",
"Before Running this example, make sure your Python environment can find the LAMMPS shared library (`liblammps.so`) and the LAMMPS Python package is installed. If you followed the [README](README.md) in this folder, this should already be the case. You can also find more information about how to compile LAMMPS and install the LAMMPS Python package in the [LAMMPS manual](https://lammps.sandia.gov/doc/Python_install.html). There is also a dedicated [PyLammps HowTo](https://lammps.sandia.gov/doc/Howto_pylammps.html)."
"Before Running this example, make sure your Python environment can find the LAMMPS shared library (`liblammps.so`) and the LAMMPS Python package is installed. If you followed the [README](README.md) in this folder, this should already be the case. You can also find more information about how to compile LAMMPS and install the LAMMPS Python package in the [LAMMPS manual](https://docs.lammps.org/Python_install.html). There is also a dedicated [PyLammps HowTo](https://docs.lammps.org/Howto_pylammps.html)."
]
},
{
@ -111,7 +111,7 @@
"source": [
"## Visualizing the initial state\n",
"\n",
"`IPyLammps` allows you to visualize the current simulation state with the [image](https://lammps.sandia.gov/doc/Python_module.html#lammps.IPyLammps.image) command. Here we use it to create an image of the initial state of the system."
"`IPyLammps` allows you to visualize the current simulation state with the [image](https://docs.lammps.org/Python_module.html#lammps.IPyLammps.image) command. Here we use it to create an image of the initial state of the system."
]
},
{

View File

@ -9,7 +9,7 @@
# Parallel syntax: mpirun -np 4 simple.py in.lammps
# in.lammps = LAMMPS input script
# also need to uncomment either Pypar or mpi4py sections below
# also need to uncomment mpi4py sections below
from __future__ import print_function
import sys
@ -27,11 +27,6 @@ infile = sys.argv[1]
me = 0
# uncomment this if running in parallel via Pypar
#import pypar
#me = pypar.rank()
#nprocs = pypar.size()
# uncomment this if running in parallel via mpi4py
#from mpi4py import MPI
#me = MPI.COMM_WORLD.Get_rank()
@ -133,8 +128,5 @@ lmp.reset_box([0,0,0],[10,10,8],0,0,0)
boxlo,boxhi,xy,yz,xz,periodicity,box_change = lmp.extract_box()
if me == 0: print("Box info",boxlo,boxhi,xy,yz,xz,periodicity,box_change)
# uncomment if running in parallel via Pypar
#print("Proc %d out of %d procs has" % (me,nprocs), lmp)
# uncomment if running in parallel via mpi4py
#print("Proc %d out of %d procs has" % (me,nprocs), lmp)

View File

@ -28,10 +28,10 @@ nfreq = int(sys.argv[2])
nsteps = int(sys.argv[3])
me = 0
# uncomment if running in parallel via Pypar
#import pypar
#me = pypar.rank()
#nprocs = pypar.size()
# uncomment this if running in parallel via mpi4py
#from mpi4py import MPI
#me = MPI.COMM_WORLD.Get_rank()
#nprocs = MPI.COMM_WORLD.Get_size()
from lammps import lammps
lmp = lammps()
@ -68,6 +68,5 @@ while ntimestep < nsteps:
lmp.command("run 0 pre no post yes")
# uncomment if running in parallel via Pypar
# uncomment if running in parallel via mpi4py
#print("Proc %d out of %d procs has" % (me,nprocs), lmp)
#pypar.finalize()

View File

@ -24,10 +24,10 @@ nfreq = int(sys.argv[2])
nsteps = int(sys.argv[3])
me = 0
# uncomment if running in parallel via Pypar
#import pypar
#me = pypar.rank()
#nprocs = pypar.size()
# uncomment this if running in parallel via mpi4py
#from mpi4py import MPI
#me = MPI.COMM_WORLD.Get_rank()
#nprocs = MPI.COMM_WORLD.Get_size()
from lammps import lammps
lmp = lammps()
@ -83,6 +83,5 @@ while ntimestep < nsteps:
lmp.command("run 0 pre no post yes")
# uncomment if running in parallel via Pypar
# uncomment if running in parallel via mpi4py
#print("Proc %d out of %d procs has" % (me,nprocs), lmp)
#pypar.finalize()

View File

@ -24,10 +24,10 @@ nfreq = int(sys.argv[2])
nsteps = int(sys.argv[3])
me = 0
# uncomment if running in parallel via Pypar
#import pypar
#me = pypar.rank()
#nprocs = pypar.size()
# uncomment this if running in parallel via mpi4py
#from mpi4py import MPI
#me = MPI.COMM_WORLD.Get_rank()
#nprocs = MPI.COMM_WORLD.Get_size()
from lammps import lammps
lmp = lammps()
@ -78,6 +78,5 @@ while ntimestep < nsteps:
lmp.command("run 0 pre no post yes")
# uncomment if running in parallel via Pypar
# uncomment if running in parallel via mpi4py
#print("Proc %d out of %d procs has" % (me,nprocs), lmp)
#pypar.finalize()

View File

@ -24,10 +24,10 @@ nfreq = int(sys.argv[2])
nsteps = int(sys.argv[3])
me = 0
# uncomment if running in parallel via Pypar
#import pypar
#me = pypar.rank()
#nprocs = pypar.size()
# uncomment this if running in parallel via mpi4py
#from mpi4py import MPI
#me = MPI.COMM_WORLD.Get_rank()
#nprocs = MPI.COMM_WORLD.Get_size()
from lammps import lammps
lmp = lammps()
@ -87,6 +87,5 @@ if me == 0:
#v.enter()
#v.stop()
# uncomment if running in parallel via Pypar
# uncomment if running in parallel via mpi4py
#print("Proc %d out of %d procs has" % (me,nprocs), lmp)
#pypar.finalize()

View File

@ -9,9 +9,6 @@
# compute-ID = ID of compute that calculates temperature
# (or any other scalar quantity)
# IMPORTANT: this script cannot yet be run in parallel via Pypar,
# because I can't seem to do a MPI-style broadcast in Pypar
from __future__ import print_function
import sys,os,time
sys.path.append("./pizza")
@ -59,10 +56,6 @@ nfreq = int(sys.argv[2])
compute = sys.argv[3]
me = 0
# uncomment if running in parallel via Pypar
#import pypar
#me = pypar.rank()
#nprocs = pypar.size()
from lammps import lammps
lmp = lammps()
@ -163,7 +156,3 @@ while 1:
time.sleep(0.01)
lmp.command("run 0 pre no post yes")
# uncomment if running in parallel via Pypar
#print("Proc %d out of %d procs has" % (me,nprocs), lmp)
#pypar.finalize()

View File

@ -9,9 +9,6 @@
# compute-ID = ID of compute that calculates temperature
# (or any other scalar quantity)
# IMPORTANT: this script cannot yet be run in parallel via Pypar,
# because I can't seem to do a MPI-style broadcast in Pypar
from __future__ import print_function
import sys,time
sys.path.append("./pizza")
@ -55,10 +52,6 @@ nfreq = int(sys.argv[2])
compute = sys.argv[3]
me = 0
# uncomment if running in parallel via Pypar
#import pypar
#me = pypar.rank()
#nprocs = pypar.size()
from lammps import lammps
lmp = lammps()
@ -176,7 +169,3 @@ while 1:
time.sleep(0.01)
lmp.command("run 0 pre no post yes")
# uncomment if running in parallel via Pypar
#print("Proc %d out of %d procs has" % (me,nprocs), lmp)
#pypar.finalize()

View File

@ -9,9 +9,6 @@
# compute-ID = ID of compute that calculates temperature
# (or any other scalar quantity)
# IMPORTANT: this script cannot yet be run in parallel via Pypar,
# because I can't seem to do a MPI-style broadcast in Pypar
from __future__ import print_function
import sys,time
sys.path.append("./pizza")
@ -57,10 +54,6 @@ nfreq = int(sys.argv[2])
compute = sys.argv[3]
me = 0
# uncomment if running in parallel via Pypar
#import pypar
#me = pypar.rank()
#nprocs = pypar.size()
from lammps import lammps
lmp = lammps()
@ -172,7 +165,3 @@ while 1:
time.sleep(0.01)
lmp.command("run 0 pre no post yes")
# uncomment if running in parallel via Pypar
#print("Proc %d out of %d procs has" % (me,nprocs), lmp)
#pypar.finalize()

View File

@ -9,9 +9,6 @@
# compute-ID = ID of compute that calculates temperature
# (or any other scalar quantity)
# IMPORTANT: this script cannot yet be run in parallel via Pypar,
# because I can't seem to do a MPI-style broadcast in Pypar
from __future__ import print_function
import sys,time
sys.path.append("./pizza")
@ -56,10 +53,6 @@ nfreq = int(sys.argv[2])
compute = sys.argv[3]
me = 0
# uncomment if running in parallel via Pypar
#import pypar
#me = pypar.rank()
#nprocs = pypar.size()
from lammps import lammps
lmp = lammps()
@ -171,7 +164,3 @@ while 1:
time.sleep(0.01)
lmp.command("run 0 pre no post yes")
# uncomment if running in parallel via Pypar
#print("Proc %d out of %d procs has" % (me,nprocs), lmp)
#pypar.finalize()

View File

@ -10,7 +10,7 @@ build target in the conventional and CMake based build systems
# copy LAMMPS shared library and lammps package to system dirs
from __future__ import print_function
import sys,os,shutil
import sys,os,shutil,time
from argparse import ArgumentParser
parser = ArgumentParser(prog='install.py',
@ -80,13 +80,15 @@ if args.dir:
sys.exit()
# extract version string from header
# extract LAMMPS version string from header
# and convert to python packaging compatible version
def get_lammps_version(header):
with open(header, 'r') as f:
line = f.readline()
start_pos = line.find('"')+1
end_pos = line.find('"', start_pos)
return "".join(line[start_pos:end_pos].split())
t = time.strptime("".join(line[start_pos:end_pos].split()), "%d%b%Y")
return "{}.{}.{}".format(t.tm_year,t.tm_mon,t.tm_mday)
verstr = get_lammps_version(args.version)
@ -110,7 +112,7 @@ setup_kwargs= dict(name="lammps",
version=verstr,
author="Steve Plimpton",
author_email="sjplimp@sandia.gov",
url="https://lammps.sandia.gov",
url="https://www.lammps.org",
description="LAMMPS Molecular Dynamics Python package",
license="GPL",
packages=pkgs,
@ -121,7 +123,7 @@ try:
sys.argv = ["setup.py","install"] # as if had run "python setup.py install"
setup_kwargs['data_files']=[(os.path.join(get_python_lib(), 'lammps'), [args.lib])]
setup(**setup_kwargs)
except:
except: # lgtm [py/catch-base-exception]
tryuser=True
print ("Installation into global site-packages folder failed.\nTrying user folder %s now." % site.USER_SITE)
@ -130,5 +132,5 @@ if tryuser:
sys.argv = ["setup.py","install","--user"] # as if had run "python setup.py install --user"
setup_kwargs['data_files']=[(os.path.join(site.USER_SITE, 'lammps'), [args.lib])]
setup(**setup_kwargs)
except:
except: # lgtm [py/catch-base-exception]
print("Installation into user site package folder failed.")

View File

@ -8,31 +8,42 @@ LAMMPS module global members:
result of :py:func:`lammps.version`.
"""
from .constants import *
from .core import *
from .data import *
from .pylammps import *
from .constants import * # lgtm [py/polluting-import]
from .core import * # lgtm [py/polluting-import]
from .data import * # lgtm [py/polluting-import]
from .pylammps import * # lgtm [py/polluting-import]
# convert module string version to numeric version
# convert installed module string version to numeric version
def get_version_number():
from datetime import datetime
import time
from os.path import join
from sys import version_info
# must report 0 when inside LAMMPS source tree
if __file__.find(join('python', 'lammps', '__init__.py')) > 0:
return 0
vstring = None
if version_info.major == 3 and version_info.minor >= 8:
from importlib.metadata import version
from importlib.metadata import version, PackageNotFoundError
try:
vstring = version('lammps')
except: pass
except PackageNotFoundError:
# nothing to do, ignore
pass
else:
from pkg_resources import get_distribution
from pkg_resources import get_distribution, DistributionNotFound
try:
vstring = get_distribution('lammps').version
except: pass
except DistributionNotFound:
# nothing to do, ignore
pass
if not vstring:
return 0
d = datetime.strptime(vstring, "%d%b%Y")
return d.year*10000 + d.month*100 + d.day
t = time.strptime(vstring, "%Y.%m.%d")
return t.tm_year*10000 + t.tm_mon*100 + t.tm_mday
__version__ = get_version_number()

View File

@ -1,6 +1,6 @@
# ----------------------------------------------------------------------
# LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
# http://lammps.sandia.gov, Sandia National Laboratories
# https://www.lammps.org/ Sandia National Laboratories
# Steve Plimpton, sjplimp@sandia.gov
#
# Copyright (2003) Sandia Corporation. Under the terms of Contract
@ -11,8 +11,6 @@
# See the README file in the top-level LAMMPS directory.
# -------------------------------------------------------------------------
from ctypes import c_int, c_int32, c_int64
# various symbolic constants to be used
# in certain calls to select data formats
LAMMPS_AUTODETECT = None
@ -42,6 +40,7 @@ LMP_VAR_ATOM = 1
# -------------------------------------------------------------------------
def get_ctypes_int(size):
from ctypes import c_int, c_int32, c_int64
if size == 4:
return c_int32
elif size == 8:

View File

@ -1,6 +1,6 @@
# ----------------------------------------------------------------------
# LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
# http://lammps.sandia.gov, Sandia National Laboratories
# https://www.lammps.org/ Sandia National Laboratories
# Steve Plimpton, sjplimp@sandia.gov
#
# Copyright (2003) Sandia Corporation. Under the terms of Contract
@ -18,15 +18,12 @@ from __future__ import print_function
import os
import sys
import traceback
import types
import warnings
from ctypes import *
from ctypes import * # lgtm [py/polluting-import]
from os.path import dirname,abspath,join
from inspect import getsourcefile
from .constants import *
from .data import *
from .constants import * # lgtm [py/polluting-import]
from .data import * # lgtm [py/polluting-import]
# -------------------------------------------------------------------------
@ -47,7 +44,7 @@ class ExceptionCheck:
def __enter__(self):
pass
def __exit__(self, type, value, traceback):
def __exit__(self, exc_type, exc_value, traceback):
if self.lmp.has_exceptions and self.lmp.lib.lammps_has_error(self.lmp.lmp):
raise self.lmp._lammps_exception
@ -103,7 +100,7 @@ class lammps(object):
try:
if ptr: self.lib = CDLL("",RTLD_GLOBAL)
except:
except OSError:
self.lib = None
# load liblammps.so unless name is given
@ -281,9 +278,13 @@ class lammps(object):
self.lib.lammps_id_name.argtypes = [c_void_p, c_char_p, c_int, c_char_p, c_int]
self.lib.lammps_plugin_count.argtypes = [ ]
self.lib.lammps_plugin_name.argtypes = [c_int, c_char_p, c_char_p, c_int]
self.lib.lammps_version.argtypes = [c_void_p]
self.lib.lammps_get_os_info.argtypes = [c_char_p, c_int]
self.lib.lammps_get_gpu_device_info.argtypes = [c_char_p, c_int]
self.lib.lammps_get_mpi_comm.argtypes = [c_void_p]
@ -309,12 +310,12 @@ class lammps(object):
from mpi4py import __version__ as mpi4py_version
# tested to work with mpi4py versions 2 and 3
self.has_mpi4py = mpi4py_version.split('.')[0] in ['2','3']
except:
except ImportError:
# ignore failing import
pass
# if no ptr provided, create an instance of LAMMPS
# don't know how to pass an MPI communicator from PyPar
# but we can pass an MPI communicator from mpi4py v2.0.0 and later
# we can pass an MPI communicator from mpi4py v2.0.0 and later
# no_mpi call lets LAMMPS use MPI_COMM_WORLD
# cargs = array of C strings from args
# if ptr, then are embedding Python in LAMMPS input script
@ -418,9 +419,16 @@ class lammps(object):
# shut-down LAMMPS instance
def __del__(self):
if self.lmp and self.opened:
self.lib.lammps_close(self.lmp)
self.opened = 0
self.close()
# -------------------------------------------------------------------------
# context manager implementation
def __enter__(self):
return self
def __exit__(self, ex_type, ex_value, ex_traceback):
self.close()
# -------------------------------------------------------------------------
@ -447,7 +455,8 @@ class lammps(object):
This is a wrapper around the :cpp:func:`lammps_close` function of the C-library interface.
"""
if self.opened: self.lib.lammps_close(self.lmp)
if self.lmp and self.opened:
self.lib.lammps_close(self.lmp)
self.lmp = None
self.opened = 0
@ -456,9 +465,7 @@ class lammps(object):
def finalize(self):
"""Shut down the MPI communication through the library interface by calling :cpp:func:`lammps_finalize`.
"""
if self.opened: self.lib.lammps_close(self.lmp)
self.lmp = None
self.opened = 0
self.close()
self.lib.lammps_finalize()
# -------------------------------------------------------------------------
@ -486,7 +493,7 @@ class lammps(object):
sb = create_string_buffer(512)
self.lib.lammps_get_os_info(sb,512)
return sb
return sb.value.decode()
# -------------------------------------------------------------------------
@ -732,12 +739,11 @@ class lammps(object):
def extract_global(self, name, dtype=LAMMPS_AUTODETECT):
"""Query LAMMPS about global settings of different types.
This is a wrapper around the :cpp:func:`lammps_extract_global`
function of the C-library interface. Unlike the C function
this method returns the value and not a pointer and thus can
only return the first value for keywords representing a list
of values. The :cpp:func:`lammps_extract_global` documentation
includes a list of the supported keywords and their data types.
This is a wrapper around the :cpp:func:`lammps_extract_global` function
of the C-library interface. Since there are no pointers in Python, this
method will - unlike the C function - return the value or a list of
values. The :cpp:func:`lammps_extract_global` documentation includes a
list of the supported keywords and their data types.
Since Python needs to know the data type to be able to interpret
the result, by default, this function will try to auto-detect the data type
by asking the library. You can also force a specific data type. For that
@ -749,12 +755,23 @@ class lammps(object):
:type name: string
:param dtype: data type of the returned data (see :ref:`py_datatype_constants`)
:type dtype: int, optional
:return: value of the property or None
:rtype: int, float, or NoneType
:return: value of the property or list of values or None
:rtype: int, float, list, or NoneType
"""
if dtype == LAMMPS_AUTODETECT:
dtype = self.extract_global_datatype(name)
# set length of vector for items that are not a scalar
vec_dict = { 'boxlo':3, 'boxhi':3, 'sublo':3, 'subhi':3,
'sublo_lambda':3, 'subhi_lambda':3, 'periodicity':3 }
if name in vec_dict:
veclen = vec_dict[name]
elif name == 'respa_dt':
veclen = self.extract_global('respa_levels',LAMMPS_INT)
else:
veclen = 1
if name: name = name.encode()
else: return None
@ -769,14 +786,22 @@ class lammps(object):
target_type = float
elif dtype == LAMMPS_STRING:
self.lib.lammps_extract_global.restype = c_char_p
target_type = lambda x: str(x, 'ascii')
target_type = str
else:
target_type = None
ptr = self.lib.lammps_extract_global(self.lmp, name)
if ptr:
return target_type(ptr[0])
if dtype == LAMMPS_STRING:
return ptr.decode('utf-8')
if veclen > 1:
result = []
for i in range(0,veclen):
result.append(target_type(ptr[i]))
return result
else: return target_type(ptr[0])
return None
# -------------------------------------------------------------------------
# extract per-atom info datatype
@ -863,71 +888,71 @@ class lammps(object):
# -------------------------------------------------------------------------
def extract_compute(self,id,style,type):
def extract_compute(self,cid,cstyle,ctype):
"""Retrieve data from a LAMMPS compute
This is a wrapper around the :cpp:func:`lammps_extract_compute`
function of the C-library interface.
This function returns ``None`` if either the compute id is not
recognized, or an invalid combination of :ref:`style <py_style_constants>`
and :ref:`type <py_type_constants>` constants is used. The
recognized, or an invalid combination of :ref:`cstyle <py_style_constants>`
and :ref:`ctype <py_type_constants>` constants is used. The
names and functionality of the constants are the same as for
the corresponding C-library function. For requests to return
a scalar or a size, the value is returned, otherwise a pointer.
:param id: compute ID
:type id: string
:param style: style of the data retrieve (global, atom, or local), see :ref:`py_style_constants`
:type style: int
:param type: type or size of the returned data (scalar, vector, or array), see :ref:`py_type_constants`
:type type: int
:param cid: compute ID
:type cid: string
:param cstyle: style of the data retrieve (global, atom, or local), see :ref:`py_style_constants`
:type cstyle: int
:param ctype: type or size of the returned data (scalar, vector, or array), see :ref:`py_type_constants`
:type ctype: int
:return: requested data as scalar, pointer to 1d or 2d double array, or None
:rtype: c_double, ctypes.POINTER(c_double), ctypes.POINTER(ctypes.POINTER(c_double)), or NoneType
"""
if id: id = id.encode()
if cid: cid = cid.encode()
else: return None
if type == LMP_TYPE_SCALAR:
if style == LMP_STYLE_GLOBAL:
if ctype == LMP_TYPE_SCALAR:
if cstyle == LMP_STYLE_GLOBAL:
self.lib.lammps_extract_compute.restype = POINTER(c_double)
with ExceptionCheck(self):
ptr = self.lib.lammps_extract_compute(self.lmp,id,style,type)
ptr = self.lib.lammps_extract_compute(self.lmp,cid,cstyle,ctype)
return ptr[0]
elif style == LMP_STYLE_ATOM:
elif cstyle == LMP_STYLE_ATOM:
return None
elif style == LMP_STYLE_LOCAL:
elif cstyle == LMP_STYLE_LOCAL:
self.lib.lammps_extract_compute.restype = POINTER(c_int)
with ExceptionCheck(self):
ptr = self.lib.lammps_extract_compute(self.lmp,id,style,type)
ptr = self.lib.lammps_extract_compute(self.lmp,cid,cstyle,ctype)
return ptr[0]
elif type == LMP_TYPE_VECTOR:
elif ctype == LMP_TYPE_VECTOR:
self.lib.lammps_extract_compute.restype = POINTER(c_double)
with ExceptionCheck(self):
ptr = self.lib.lammps_extract_compute(self.lmp,id,style,type)
ptr = self.lib.lammps_extract_compute(self.lmp,cid,cstyle,ctype)
return ptr
elif type == LMP_TYPE_ARRAY:
elif ctype == LMP_TYPE_ARRAY:
self.lib.lammps_extract_compute.restype = POINTER(POINTER(c_double))
with ExceptionCheck(self):
ptr = self.lib.lammps_extract_compute(self.lmp,id,style,type)
ptr = self.lib.lammps_extract_compute(self.lmp,cid,cstyle,ctype)
return ptr
elif type == LMP_SIZE_COLS:
if style == LMP_STYLE_GLOBAL \
or style == LMP_STYLE_ATOM \
or style == LMP_STYLE_LOCAL:
elif ctype == LMP_SIZE_COLS:
if cstyle == LMP_STYLE_GLOBAL \
or cstyle == LMP_STYLE_ATOM \
or cstyle == LMP_STYLE_LOCAL:
self.lib.lammps_extract_compute.restype = POINTER(c_int)
with ExceptionCheck(self):
ptr = self.lib.lammps_extract_compute(self.lmp,id,style,type)
ptr = self.lib.lammps_extract_compute(self.lmp,cid,cstyle,ctype)
return ptr[0]
elif type == LMP_SIZE_VECTOR or type == LMP_SIZE_ROWS:
if style == LMP_STYLE_GLOBAL \
or style == LMP_STYLE_LOCAL:
elif ctype == LMP_SIZE_VECTOR or ctype == LMP_SIZE_ROWS:
if cstyle == LMP_STYLE_GLOBAL \
or cstyle == LMP_STYLE_LOCAL:
self.lib.lammps_extract_compute.restype = POINTER(c_int)
with ExceptionCheck(self):
ptr = self.lib.lammps_extract_compute(self.lmp,id,style,type)
ptr = self.lib.lammps_extract_compute(self.lmp,cid,cstyle,ctype)
return ptr[0]
return None
@ -937,25 +962,25 @@ class lammps(object):
# in case of global data, free memory for 1 double via lammps_free()
# double was allocated by library interface function
def extract_fix(self,id,style,type,nrow=0,ncol=0):
def extract_fix(self,fid,fstyle,ftype,nrow=0,ncol=0):
"""Retrieve data from a LAMMPS fix
This is a wrapper around the :cpp:func:`lammps_extract_fix`
function of the C-library interface.
This function returns ``None`` if either the fix id is not
recognized, or an invalid combination of :ref:`style <py_style_constants>`
and :ref:`type <py_type_constants>` constants is used. The
recognized, or an invalid combination of :ref:`fstyle <py_style_constants>`
and :ref:`ftype <py_type_constants>` constants is used. The
names and functionality of the constants are the same as for
the corresponding C-library function. For requests to return
a scalar or a size, the value is returned, also when accessing
global vectors or arrays, otherwise a pointer.
:param id: fix ID
:type id: string
:param style: style of the data retrieve (global, atom, or local), see :ref:`py_style_constants`
:type style: int
:param type: type or size of the returned data (scalar, vector, or array), see :ref:`py_type_constants`
:type type: int
:param fid: fix ID
:type fid: string
:param fstyle: style of the data retrieve (global, atom, or local), see :ref:`py_style_constants`
:type fstyle: int
:param ftype: type or size of the returned data (scalar, vector, or array), see :ref:`py_type_constants`
:type ftype: int
:param nrow: index of global vector element or row index of global array element
:type nrow: int
:param ncol: column index of global array element
@ -964,53 +989,53 @@ class lammps(object):
:rtype: c_double, ctypes.POINTER(c_double), ctypes.POINTER(ctypes.POINTER(c_double)), or NoneType
"""
if id: id = id.encode()
if fid: fid = fid.encode()
else: return None
if style == LMP_STYLE_GLOBAL:
if type in (LMP_TYPE_SCALAR, LMP_TYPE_VECTOR, LMP_TYPE_ARRAY):
if fstyle == LMP_STYLE_GLOBAL:
if ftype in (LMP_TYPE_SCALAR, LMP_TYPE_VECTOR, LMP_TYPE_ARRAY):
self.lib.lammps_extract_fix.restype = POINTER(c_double)
with ExceptionCheck(self):
ptr = self.lib.lammps_extract_fix(self.lmp,id,style,type,nrow,ncol)
ptr = self.lib.lammps_extract_fix(self.lmp,fid,fstyle,ftype,nrow,ncol)
result = ptr[0]
self.lib.lammps_free(ptr)
return result
elif type in (LMP_SIZE_VECTOR, LMP_SIZE_ROWS, LMP_SIZE_COLS):
elif ftype in (LMP_SIZE_VECTOR, LMP_SIZE_ROWS, LMP_SIZE_COLS):
self.lib.lammps_extract_fix.restype = POINTER(c_int)
with ExceptionCheck(self):
ptr = self.lib.lammps_extract_fix(self.lmp,id,style,type,nrow,ncol)
ptr = self.lib.lammps_extract_fix(self.lmp,fid,fstyle,ftype,nrow,ncol)
return ptr[0]
else:
return None
elif style == LMP_STYLE_ATOM:
if type == LMP_TYPE_VECTOR:
elif fstyle == LMP_STYLE_ATOM:
if ftype == LMP_TYPE_VECTOR:
self.lib.lammps_extract_fix.restype = POINTER(c_double)
elif type == LMP_TYPE_ARRAY:
elif ftype == LMP_TYPE_ARRAY:
self.lib.lammps_extract_fix.restype = POINTER(POINTER(c_double))
elif type == LMP_SIZE_COLS:
elif ftype == LMP_SIZE_COLS:
self.lib.lammps_extract_fix.restype = POINTER(c_int)
else:
return None
with ExceptionCheck(self):
ptr = self.lib.lammps_extract_fix(self.lmp,id,style,type,nrow,ncol)
if type == LMP_SIZE_COLS:
ptr = self.lib.lammps_extract_fix(self.lmp,fid,fstyle,ftype,nrow,ncol)
if ftype == LMP_SIZE_COLS:
return ptr[0]
else:
return ptr
elif style == LMP_STYLE_LOCAL:
if type == LMP_TYPE_VECTOR:
elif fstyle == LMP_STYLE_LOCAL:
if ftype == LMP_TYPE_VECTOR:
self.lib.lammps_extract_fix.restype = POINTER(c_double)
elif type == LMP_TYPE_ARRAY:
elif ftype == LMP_TYPE_ARRAY:
self.lib.lammps_extract_fix.restype = POINTER(POINTER(c_double))
elif type in (LMP_TYPE_SCALAR, LMP_SIZE_VECTOR, LMP_SIZE_ROWS, LMP_SIZE_COLS):
elif ftype in (LMP_TYPE_SCALAR, LMP_SIZE_VECTOR, LMP_SIZE_ROWS, LMP_SIZE_COLS):
self.lib.lammps_extract_fix.restype = POINTER(c_int)
else:
return None
with ExceptionCheck(self):
ptr = self.lib.lammps_extract_fix(self.lmp,id,style,type,nrow,ncol)
if type in (LMP_TYPE_VECTOR, LMP_TYPE_ARRAY):
ptr = self.lib.lammps_extract_fix(self.lmp,fid,fstyle,ftype,nrow,ncol)
if ftype in (LMP_TYPE_VECTOR, LMP_TYPE_ARRAY):
return ptr
else:
return ptr[0]
@ -1099,51 +1124,51 @@ class lammps(object):
# return vector of atom properties gathered across procs
# 3 variants to match src/library.cpp
# name = atom property recognized by LAMMPS in atom->extract()
# type = 0 for integer values, 1 for double values
# dtype = 0 for integer values, 1 for double values
# count = number of per-atom valus, 1 for type or charge, 3 for x or f
# returned data is a 1d vector - doc how it is ordered?
# NOTE: need to insure are converting to/from correct Python type
# e.g. for Python list or NumPy or ctypes
def gather_atoms(self,name,type,count):
def gather_atoms(self,name,dtype,count):
if name: name = name.encode()
natoms = self.get_natoms()
with ExceptionCheck(self):
if type == 0:
if dtype == 0:
data = ((count*natoms)*c_int)()
self.lib.lammps_gather_atoms(self.lmp,name,type,count,data)
elif type == 1:
self.lib.lammps_gather_atoms(self.lmp,name,dtype,count,data)
elif dtype == 1:
data = ((count*natoms)*c_double)()
self.lib.lammps_gather_atoms(self.lmp,name,type,count,data)
self.lib.lammps_gather_atoms(self.lmp,name,dtype,count,data)
else:
return None
return data
# -------------------------------------------------------------------------
def gather_atoms_concat(self,name,type,count):
def gather_atoms_concat(self,name,dtype,count):
if name: name = name.encode()
natoms = self.get_natoms()
with ExceptionCheck(self):
if type == 0:
if dtype == 0:
data = ((count*natoms)*c_int)()
self.lib.lammps_gather_atoms_concat(self.lmp,name,type,count,data)
elif type == 1:
self.lib.lammps_gather_atoms_concat(self.lmp,name,dtype,count,data)
elif dtype == 1:
data = ((count*natoms)*c_double)()
self.lib.lammps_gather_atoms_concat(self.lmp,name,type,count,data)
self.lib.lammps_gather_atoms_concat(self.lmp,name,dtype,count,data)
else:
return None
return data
def gather_atoms_subset(self,name,type,count,ndata,ids):
def gather_atoms_subset(self,name,dtype,count,ndata,ids):
if name: name = name.encode()
with ExceptionCheck(self):
if type == 0:
if dtype == 0:
data = ((count*ndata)*c_int)()
self.lib.lammps_gather_atoms_subset(self.lmp,name,type,count,ndata,ids,data)
elif type == 1:
self.lib.lammps_gather_atoms_subset(self.lmp,name,dtype,count,ndata,ids,data)
elif dtype == 1:
data = ((count*ndata)*c_double)()
self.lib.lammps_gather_atoms_subset(self.lmp,name,type,count,ndata,ids,data)
self.lib.lammps_gather_atoms_subset(self.lmp,name,dtype,count,ndata,ids,data)
else:
return None
return data
@ -1159,17 +1184,17 @@ class lammps(object):
# NOTE: need to insure are converting to/from correct Python type
# e.g. for Python list or NumPy or ctypes
def scatter_atoms(self,name,type,count,data):
def scatter_atoms(self,name,dtype,count,data):
if name: name = name.encode()
with ExceptionCheck(self):
self.lib.lammps_scatter_atoms(self.lmp,name,type,count,data)
self.lib.lammps_scatter_atoms(self.lmp,name,dtype,count,data)
# -------------------------------------------------------------------------
def scatter_atoms_subset(self,name,type,count,ndata,ids,data):
def scatter_atoms_subset(self,name,dtype,count,ndata,ids,data):
if name: name = name.encode()
with ExceptionCheck(self):
self.lib.lammps_scatter_atoms_subset(self.lmp,name,type,count,ndata,ids,data)
self.lib.lammps_scatter_atoms_subset(self.lmp,name,dtype,count,ndata,ids,data)
# return vector of atom/compute/fix properties gathered across procs
# 3 variants to match src/library.cpp
@ -1179,43 +1204,43 @@ class lammps(object):
# returned data is a 1d vector - doc how it is ordered?
# NOTE: need to insure are converting to/from correct Python type
# e.g. for Python list or NumPy or ctypes
def gather(self,name,type,count):
def gather(self,name,dtype,count):
if name: name = name.encode()
natoms = self.get_natoms()
with ExceptionCheck(self):
if type == 0:
if dtype == 0:
data = ((count*natoms)*c_int)()
self.lib.lammps_gather(self.lmp,name,type,count,data)
elif type == 1:
self.lib.lammps_gather(self.lmp,name,dtype,count,data)
elif dtype == 1:
data = ((count*natoms)*c_double)()
self.lib.lammps_gather(self.lmp,name,type,count,data)
self.lib.lammps_gather(self.lmp,name,dtype,count,data)
else:
return None
return data
def gather_concat(self,name,type,count):
def gather_concat(self,name,dtype,count):
if name: name = name.encode()
natoms = self.get_natoms()
with ExceptionCheck(self):
if type == 0:
if dtype == 0:
data = ((count*natoms)*c_int)()
self.lib.lammps_gather_concat(self.lmp,name,type,count,data)
elif type == 1:
self.lib.lammps_gather_concat(self.lmp,name,dtype,count,data)
elif dtype == 1:
data = ((count*natoms)*c_double)()
self.lib.lammps_gather_concat(self.lmp,name,type,count,data)
self.lib.lammps_gather_concat(self.lmp,name,dtype,count,data)
else:
return None
return data
def gather_subset(self,name,type,count,ndata,ids):
def gather_subset(self,name,dtype,count,ndata,ids):
if name: name = name.encode()
with ExceptionCheck(self):
if type == 0:
if dtype == 0:
data = ((count*ndata)*c_int)()
self.lib.lammps_gather_subset(self.lmp,name,type,count,ndata,ids,data)
elif type == 1:
self.lib.lammps_gather_subset(self.lmp,name,dtype,count,ndata,ids,data)
elif dtype == 1:
data = ((count*ndata)*c_double)()
self.lib.lammps_gather_subset(self.lmp,name,type,count,ndata,ids,data)
self.lib.lammps_gather_subset(self.lmp,name,dtype,count,ndata,ids,data)
else:
return None
return data
@ -1229,15 +1254,15 @@ class lammps(object):
# NOTE: need to insure are converting to/from correct Python type
# e.g. for Python list or NumPy or ctypes
def scatter(self,name,type,count,data):
def scatter(self,name,dtype,count,data):
if name: name = name.encode()
with ExceptionCheck(self):
self.lib.lammps_scatter(self.lmp,name,type,count,data)
self.lib.lammps_scatter(self.lmp,name,dtype,count,data)
def scatter_subset(self,name,type,count,ndata,ids,data):
def scatter_subset(self,name,dtype,count,ndata,ids,data):
if name: name = name.encode()
with ExceptionCheck(self):
self.lib.lammps_scatter_subset(self.lmp,name,type,count,ndata,ids,data)
self.lib.lammps_scatter_subset(self.lmp,name,dtype,count,ndata,ids,data)
# -------------------------------------------------------------------------
@ -1329,7 +1354,7 @@ class lammps(object):
id_lmp = (self.c_tagint*n)()
try:
id_lmp[:] = id[0:n]
except:
except: # lgtm [py/catch-base-exception]
return 0
else:
id_lmp = None
@ -1337,21 +1362,21 @@ class lammps(object):
type_lmp = (c_int*n)()
try:
type_lmp[:] = type[0:n]
except:
except: # lgtm [py/catch-base-exception]
return 0
three_n = 3*n
x_lmp = (c_double*three_n)()
try:
x_lmp[:] = x[0:three_n]
except:
except: # lgtm [py/catch-base-exception]
return 0
if v:
v_lmp = (c_double*(three_n))()
try:
v_lmp[:] = v[0:three_n]
except:
except: # lgtm [py/catch-base-exception]
return 0
else:
v_lmp = None
@ -1360,7 +1385,7 @@ class lammps(object):
img_lmp = (self.c_imageint*n)()
try:
img_lmp[:] = image[0:n]
except:
except: # lgtm [py/catch-base-exception]
return 0
else:
img_lmp = None
@ -1530,6 +1555,37 @@ class lammps(object):
# -------------------------------------------------------------------------
@property
def has_gpu_device(self):
""" Availability of GPU package compatible device
This is a wrapper around the :cpp:func:`lammps_has_gpu_device`
function of the C library interface.
:return: True if a GPU package compatible device is present, otherwise False
:rtype: bool
"""
return self.lib.lammps_has_gpu_device() != 0
# -------------------------------------------------------------------------
def get_gpu_device_info(self):
"""Return a string with detailed information about any devices that are
usable by the GPU package.
This is a wrapper around the :cpp:func:`lammps_get_gpu_device_info`
function of the C-library interface.
:return: GPU device info string
:rtype: string
"""
sb = create_string_buffer(8192)
self.lib.lammps_get_gpu_device_info(sb,8192)
return sb.value.decode()
# -------------------------------------------------------------------------
@property
def installed_packages(self):
""" List of the names of enabled packages in the LAMMPS shared library
@ -1643,6 +1699,29 @@ class lammps(object):
# -------------------------------------------------------------------------
def available_plugins(self, category):
"""Returns a list of plugins available for a given category
This is a wrapper around the functions :cpp:func:`lammps_plugin_count()`
and :cpp:func:`lammps_plugin_name()` of the library interface.
.. versionadded:: 10Mar2021
:return: list of style/name pairs of loaded plugins
:rtype: list
"""
available_plugins = []
num = self.lib.lammps_plugin_count(self.lmp)
sty = create_string_buffer(100)
nam = create_string_buffer(100)
for idx in range(num):
self.lib.lammps_plugin_name(idx, sty, nam, 100)
available_plugins.append([sty.value.decode(), nam.value.decode()])
return available_plugins
# -------------------------------------------------------------------------
def set_fix_external_callback(self, fix_name, callback, caller=None):
import numpy as np
@ -1709,17 +1788,23 @@ class lammps(object):
# -------------------------------------------------------------------------
def find_pair_neighlist(self, style, exact=True, nsub=0, request=0):
def find_pair_neighlist(self, style, exact=True, nsub=0, reqid=0):
"""Find neighbor list index of pair style neighbor list
Try finding pair instance that matches style. If exact is set, the pair must
match style exactly. If exact is 0, style must only be contained. If pair is
of style pair/hybrid, style is instead matched the nsub-th hybrid sub-style.
Search for a neighbor list requested by a pair style instance that
matches "style". If exact is True, the pair style name must match
exactly. If exact is False, the pair style name is matched against
"style" as regular expression or sub-string. If the pair style is a
hybrid pair style, the style is instead matched against the hybrid
sub-styles. If the same pair style is used as sub-style multiple
types, you must set nsub to a value n > 0 which indicates the nth
instance of that sub-style to be used (same as for the pair_coeff
command). The default value of 0 will fail to match in that case.
Once the pair instance has been identified, multiple neighbor list requests
may be found. Every neighbor list is uniquely identified by its request
index. Thus, providing this request index ensures that the correct neighbor
list index is returned.
Once the pair style instance has been identified, it may have
requested multiple neighbor lists. Those are uniquely identified by
a request ID > 0 as set by the pair style. Otherwise the request
ID is 0.
:param style: name of pair style that should be searched for
:type style: string
@ -1727,44 +1812,58 @@ class lammps(object):
:type exact: bool, optional
:param nsub: match nsub-th hybrid sub-style, defaults to 0
:type nsub: int, optional
:param request: index of neighbor list request, in case there are more than one, defaults to 0
:type request: int, optional
:param reqid: list request id, > 0 in case there are more than one, defaults to 0
:type reqid: int, optional
:return: neighbor list index if found, otherwise -1
:rtype: int
"""
"""
style = style.encode()
exact = int(exact)
idx = self.lib.lammps_find_pair_neighlist(self.lmp, style, exact, nsub, request)
idx = self.lib.lammps_find_pair_neighlist(self.lmp, style, exact, nsub, reqid)
return idx
# -------------------------------------------------------------------------
def find_fix_neighlist(self, fixid, request=0):
def find_fix_neighlist(self, fixid, reqid=0):
"""Find neighbor list index of fix neighbor list
The fix instance requesting the neighbor list is uniquely identified
by the fix ID. In case the fix has requested multiple neighbor
lists, those are uniquely identified by a request ID > 0 as set by
the fix. Otherwise the request ID is 0 (the default).
:param fixid: name of fix
:type fixid: string
:param request: index of neighbor list request, in case there are more than one, defaults to 0
:type request: int, optional
:param reqid: id of neighbor list request, in case there are more than one request, defaults to 0
:type reqid: int, optional
:return: neighbor list index if found, otherwise -1
:rtype: int
"""
"""
fixid = fixid.encode()
idx = self.lib.lammps_find_fix_neighlist(self.lmp, fixid, request)
idx = self.lib.lammps_find_fix_neighlist(self.lmp, fixid, reqid)
return idx
# -------------------------------------------------------------------------
def find_compute_neighlist(self, computeid, request=0):
def find_compute_neighlist(self, computeid, reqid=0):
"""Find neighbor list index of compute neighbor list
The compute instance requesting the neighbor list is uniquely
identified by the compute ID. In case the compute has requested
multiple neighbor lists, those are uniquely identified by a request
ID > 0 as set by the compute. Otherwise the request ID is 0 (the
default).
:param computeid: name of compute
:type computeid: string
:param request: index of neighbor list request, in case there are more than one, defaults to 0
:type request: int, optional
:param reqid: index of neighbor list request, in case there are more than one request, defaults to 0
:type reqid: int, optional
:return: neighbor list index if found, otherwise -1
:rtype: int
"""
"""
computeid = computeid.encode()
idx = self.lib.lammps_find_compute_neighlist(self.lmp, computeid, request)
idx = self.lib.lammps_find_compute_neighlist(self.lmp, computeid, reqid)
return idx

View File

@ -1,6 +1,6 @@
# ----------------------------------------------------------------------
# LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
# http://lammps.sandia.gov, Sandia National Laboratories
# https://www.lammps.org/ Sandia National Laboratories
# Steve Plimpton, sjplimp@sandia.gov
#
# Copyright (2003) Sandia Corporation. Under the terms of Contract
@ -16,7 +16,7 @@
# Written by Richard Berger <richard.berger@temple.edu>
################################################################################
class NeighList:
class NeighList(object):
"""This is a wrapper class that exposes the contents of a neighbor list.
It can be used like a regular Python list. Each element is a tuple of:
@ -52,7 +52,9 @@ class NeighList:
def get(self, element):
"""
:return: tuple with atom local index, numpy array of neighbor local atom indices
Access a specific neighbor list entry. "element" must be a number from 0 to the size-1 of the list
:return: tuple with atom local index, number of neighbors and ctypes pointer to neighbor's local atom indices
:rtype: (int, int, ctypes.POINTER(c_int))
"""
iatom, numneigh, neighbors = self.lmp.get_neighlist_element_neighbors(self.idx, element)
@ -71,3 +73,20 @@ class NeighList:
for ii in range(inum):
yield self.get(ii)
def find(self, iatom):
"""
Find the neighbor list for a specific (local) atom iatom.
If there is no list for iatom, (-1, None) is returned.
:return: tuple with number of neighbors and ctypes pointer to neighbor's local atom indices
:rtype: (int, ctypes.POINTER(c_int))
"""
inum = self.size
for ii in range(inum):
idx, numneigh, neighbors = self.get(ii)
if idx == iatom:
return numneigh, neighbors
return -1, None

View File

@ -1,6 +1,6 @@
# ----------------------------------------------------------------------
# LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
# http://lammps.sandia.gov, Sandia National Laboratories
# https://www.lammps.org/ Sandia National Laboratories
# Steve Plimpton, sjplimp@sandia.gov
#
# Copyright (2003) Sandia Corporation. Under the terms of Contract
@ -176,7 +176,7 @@ class AvgChunkFile:
current[data_column] = [value]
chunks_read += 1
assert (chunk == chunks_read)
assert chunk == chunks_read
else:
# do not support changing number of chunks
if not (num_chunks == int(parts[1])):

View File

@ -1,6 +1,6 @@
# ----------------------------------------------------------------------
# LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
# http://lammps.sandia.gov, Sandia National Laboratories
# https://www.lammps.org/ Sandia National Laboratories
# Steve Plimpton, sjplimp@sandia.gov
#
# Copyright (2003) Sandia Corporation. Under the terms of Contract

View File

@ -1,6 +1,6 @@
# ----------------------------------------------------------------------
# LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
# http://lammps.sandia.gov, Sandia National Laboratories
# https://www.lammps.org/ Sandia National Laboratories
# Steve Plimpton, sjplimp@sandia.gov
#
# Copyright (2003) Sandia Corporation. Under the terms of Contract

View File

@ -1,6 +1,6 @@
# ----------------------------------------------------------------------
# LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
# http://lammps.sandia.gov, Sandia National Laboratories
# https://www.lammps.org/ Sandia National Laboratories
# Steve Plimpton, sjplimp@sandia.gov
#
# Copyright (2003) Sandia Corporation. Under the terms of Contract
@ -20,7 +20,7 @@ import warnings
from ctypes import POINTER, c_double, c_int, c_int32, c_int64, cast
from .constants import *
from .constants import * # lgtm [py/polluting-import]
from .data import NeighList
@ -142,7 +142,7 @@ class numpy_wrapper:
# -------------------------------------------------------------------------
def extract_compute(self, cid, style, type):
def extract_compute(self, cid, cstyle, ctype):
"""Retrieve data from a LAMMPS compute
This is a wrapper around the
@ -150,50 +150,50 @@ class numpy_wrapper:
It behaves the same as the original method, but returns NumPy arrays
instead of ``ctypes`` pointers.
:param id: compute ID
:type id: string
:param style: style of the data retrieve (global, atom, or local), see :ref:`py_style_constants`
:type style: int
:param type: type of the returned data (scalar, vector, or array), see :ref:`py_type_constants`
:type type: int
:param cid: compute ID
:type cid: string
:param cstyle: style of the data retrieve (global, atom, or local), see :ref:`py_style_constants`
:type cstyle: int
:param ctype: type of the returned data (scalar, vector, or array), see :ref:`py_type_constants`
:type ctype: int
:return: requested data either as float, as NumPy array with direct access to C data, or None
:rtype: float, numpy.array, or NoneType
"""
value = self.lmp.extract_compute(cid, style, type)
value = self.lmp.extract_compute(cid, cstyle, ctype)
if style in (LMP_STYLE_GLOBAL, LMP_STYLE_LOCAL):
if type == LMP_TYPE_VECTOR:
nrows = self.lmp.extract_compute(cid, style, LMP_SIZE_VECTOR)
if cstyle in (LMP_STYLE_GLOBAL, LMP_STYLE_LOCAL):
if ctype == LMP_TYPE_VECTOR:
nrows = self.lmp.extract_compute(cid, cstyle, LMP_SIZE_VECTOR)
return self.darray(value, nrows)
elif type == LMP_TYPE_ARRAY:
nrows = self.lmp.extract_compute(cid, style, LMP_SIZE_ROWS)
ncols = self.lmp.extract_compute(cid, style, LMP_SIZE_COLS)
elif ctype == LMP_TYPE_ARRAY:
nrows = self.lmp.extract_compute(cid, cstyle, LMP_SIZE_ROWS)
ncols = self.lmp.extract_compute(cid, cstyle, LMP_SIZE_COLS)
return self.darray(value, nrows, ncols)
elif style == LMP_STYLE_ATOM:
if type == LMP_TYPE_VECTOR:
elif cstyle == LMP_STYLE_ATOM:
if ctype == LMP_TYPE_VECTOR:
nlocal = self.lmp.extract_global("nlocal")
return self.darray(value, nlocal)
elif type == LMP_TYPE_ARRAY:
elif ctype == LMP_TYPE_ARRAY:
nlocal = self.lmp.extract_global("nlocal")
ncols = self.lmp.extract_compute(cid, style, LMP_SIZE_COLS)
ncols = self.lmp.extract_compute(cid, cstyle, LMP_SIZE_COLS)
return self.darray(value, nlocal, ncols)
return value
# -------------------------------------------------------------------------
def extract_fix(self, fid, style, type, nrow=0, ncol=0):
def extract_fix(self, fid, fstyle, ftype, nrow=0, ncol=0):
"""Retrieve data from a LAMMPS fix
This is a wrapper around the :py:meth:`lammps.extract_fix() <lammps.lammps.extract_fix()>` method.
It behaves the same as the original method, but returns NumPy arrays
instead of ``ctypes`` pointers.
:param id: fix ID
:type id: string
:param style: style of the data retrieve (global, atom, or local), see :ref:`py_style_constants`
:type style: int
:param type: type or size of the returned data (scalar, vector, or array), see :ref:`py_type_constants`
:type type: int
:param fid: fix ID
:type fid: string
:param fstyle: style of the data retrieve (global, atom, or local), see :ref:`py_style_constants`
:type fstyle: int
:param ftype: type or size of the returned data (scalar, vector, or array), see :ref:`py_type_constants`
:type ftype: int
:param nrow: index of global vector element or row index of global array element
:type nrow: int
:param ncol: column index of global array element
@ -202,22 +202,22 @@ class numpy_wrapper:
:rtype: integer or double value, pointer to 1d or 2d double array or None
"""
value = self.lmp.extract_fix(fid, style, type, nrow, ncol)
if style == LMP_STYLE_ATOM:
if type == LMP_TYPE_VECTOR:
value = self.lmp.extract_fix(fid, fstyle, ftype, nrow, ncol)
if fstyle == LMP_STYLE_ATOM:
if ftype == LMP_TYPE_VECTOR:
nlocal = self.lmp.extract_global("nlocal")
return self.darray(value, nlocal)
elif type == LMP_TYPE_ARRAY:
elif ftype == LMP_TYPE_ARRAY:
nlocal = self.lmp.extract_global("nlocal")
ncols = self.lmp.extract_fix(fid, style, LMP_SIZE_COLS, 0, 0)
ncols = self.lmp.extract_fix(fid, fstyle, LMP_SIZE_COLS, 0, 0)
return self.darray(value, nlocal, ncols)
elif style == LMP_STYLE_LOCAL:
if type == LMP_TYPE_VECTOR:
nrows = self.lmp.extract_fix(fid, style, LMP_SIZE_ROWS, 0, 0)
elif fstyle == LMP_STYLE_LOCAL:
if ftype == LMP_TYPE_VECTOR:
nrows = self.lmp.extract_fix(fid, fstyle, LMP_SIZE_ROWS, 0, 0)
return self.darray(value, nrows)
elif type == LMP_TYPE_ARRAY:
nrows = self.lmp.extract_fix(fid, style, LMP_SIZE_ROWS, 0, 0)
ncols = self.lmp.extract_fix(fid, style, LMP_SIZE_COLS, 0, 0)
elif ftype == LMP_TYPE_ARRAY:
nrows = self.lmp.extract_fix(fid, fstyle, LMP_SIZE_ROWS, 0, 0)
ncols = self.lmp.extract_fix(fid, fstyle, LMP_SIZE_COLS, 0, 0)
return self.darray(value, nrows, ncols)
return value
@ -293,7 +293,11 @@ class numpy_wrapper:
ptr = cast(raw_ptr[0], POINTER(c_int_type * nelem * dim))
a = np.frombuffer(ptr.contents, dtype=np_int_type)
a.shape = (nelem, dim)
if dim > 1:
a.shape = (nelem, dim)
else:
a.shape = (nelem)
return a
# -------------------------------------------------------------------------
@ -306,7 +310,11 @@ class numpy_wrapper:
ptr = cast(raw_ptr[0], POINTER(c_double * nelem * dim))
a = np.frombuffer(ptr.contents)
a.shape = (nelem, dim)
if dim > 1:
a.shape = (nelem, dim)
else:
a.shape = (nelem)
return a
# -------------------------------------------------------------------------
@ -331,8 +339,25 @@ class NumPyNeighList(NeighList):
def get(self, element):
"""
Access a specific neighbor list entry. "element" must be a number from 0 to the size-1 of the list
:return: tuple with atom local index, numpy array of neighbor local atom indices
:rtype: (int, numpy.array)
"""
iatom, neighbors = self.lmp.numpy.get_neighlist_element_neighbors(self.idx, element)
return iatom, neighbors
def find(self, iatom):
"""
Find the neighbor list for a specific (local) atom iatom.
If there is no list for iatom, None is returned.
:return: numpy array of neighbor local atom indices
:rtype: numpy.array or None
"""
inum = self.size
for ii in range(inum):
idx, neighbors = self.get(ii)
if idx == iatom:
return neighbors
return None

View File

@ -1,6 +1,6 @@
# ----------------------------------------------------------------------
# LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
# http://lammps.sandia.gov, Sandia National Laboratories
# https://www.lammps.org/ Sandia National Laboratories
# Steve Plimpton, sjplimp@sandia.gov
#
# Copyright (2003) Sandia Corporation. Under the terms of Contract
@ -23,7 +23,6 @@ from __future__ import print_function
import os
import re
import select
import sys
from collections import namedtuple
from .core import lammps
@ -41,7 +40,7 @@ class OutputCapture(object):
os.dup2(self.stdout_pipe_write, self.stdout_fd)
return self
def __exit__(self, type, value, tracebac):
def __exit__(self, exc_type, exc_value, traceback):
os.dup2(self.stdout, self.stdout_fd)
os.close(self.stdout)
os.close(self.stdout_pipe_read)
@ -351,6 +350,7 @@ def get_thermo_data(output):
for i, col in enumerate(columns):
current_run[col].append(values[i])
except ValueError:
# cannot convert. must be a non-thermo output. ignore.
pass
return runs
@ -409,6 +409,12 @@ class PyLammps(object):
self._enable_cmd_history = False
self.runs = []
def __enter__(self):
return self
def __exit__(self, ex_type, ex_value, ex_traceback):
self.close()
def __del__(self):
if self.lmp: self.lmp.close()
self.lmp = None

View File

@ -1,26 +1,39 @@
# this only installs the LAMMPS python package
# it assumes the LAMMPS shared library is already installed
from distutils.core import setup
import os
from sys import version_info
import os,time
LAMMPS_PYTHON_DIR = os.path.dirname(os.path.realpath(__file__))
LAMMPS_DIR = os.path.dirname(LAMMPS_PYTHON_DIR)
LAMMPS_SOURCE_DIR = os.path.join(LAMMPS_DIR, 'src')
if not os.path.exists(LAMMPS_SOURCE_DIR):
# allows installing and building wheel from current directory
LAMMPS_DIR = os.path.realpath(os.path.join(os.environ['PWD'], '..'))
LAMMPS_SOURCE_DIR = os.path.join(LAMMPS_DIR, 'src')
def get_lammps_version():
with open(os.path.join(LAMMPS_SOURCE_DIR, 'version.h'), 'r') as f:
version_h_file = os.path.join(LAMMPS_SOURCE_DIR, 'version.h')
with open(version_h_file, 'r') as f:
line = f.readline()
start_pos = line.find('"')+1
end_pos = line.find('"', start_pos)
return "".join(line[start_pos:end_pos].split())
t = time.strptime("".join(line[start_pos:end_pos].split()), "%d%b%Y")
return "{}.{}.{}".format(t.tm_year,t.tm_mon,t.tm_mday)
if version_info.major >= 3:
pkgs = ['lammps', 'lammps.mliap']
else:
pkgs = ['lammps']
setup(
name = "lammps",
version = get_lammps_version(),
author = "Steve Plimpton",
author_email = "sjplimp@sandia.gov",
url = "https://lammps.sandia.gov",
url = "https://www.lammps.org",
description = "LAMMPS Molecular Dynamics Python package",
license = "GPL",
packages=["lammps","lammps.mliap"],
packages=pkgs,
)