Unverified Commit b571f542 authored by Steve Plimpton's avatar Steve Plimpton Committed by GitHub
Browse files

Merge pull request #850 from lammps/addlib

a few new lib interface methods
parents 24e48760 1956d93a
Loading
Loading
Loading
Loading
+80 −56
Original line number Diff line number Diff line
@@ -1856,9 +1856,21 @@ internal LAMMPS operations. Note that LAMMPS classes are defined
within a LAMMPS namespace (LAMMPS_NS) if you use them from another C++
application.

Library.cpp contains these functions for creating and destroying an
instance of LAMMPS and sending it commands to execute.  See the
documentation in the src/library.cpp file for details:
The examples/COUPLE and python/examples directories have example C++
and C and Python codes which show how a driver code can link to LAMMPS
as a library, run LAMMPS on a subset of processors, grab data from
LAMMPS, change it, and put it back into LAMMPS.

The file src/library.cpp contains the following functions for creating
and destroying an instance of LAMMPS and sending it commands to
execute.  See the documentation in the src/library.cpp file for
details.

NOTE: You can write code for additional functions as needed to define
how your code talks to LAMMPS and add them to src/library.cpp and
src/library.h, as well as to the "Python
interface"_Section_python.html.  The added functions can access or
change any internal LAMMPS data you wish.

void lammps_open(int, char **, MPI_Comm, void **)
void lammps_open_no_mpi(int, char **, void **)
@@ -1932,11 +1944,12 @@ the library allocated previously via other function calls. See
comments in src/library.cpp file for which other functions need this
clean-up.

Library.cpp also contains these functions for extracting information
from LAMMPS and setting value within LAMMPS.  Again, see the
documentation in the src/library.cpp file for details, including
The file src/library.cpp also contains these functions for extracting
information from LAMMPS and setting value within LAMMPS.  Again, see
the documentation in the src/library.cpp file for details, including
which quantities can be queried by name:

int lammps_extract_setting(void *, char *)
void *lammps_extract_global(void *, char *)
void lammps_extract_box(void *, double *, double *,
                        double *, double *, double *, int *, int *)
@@ -1945,55 +1958,77 @@ void *lammps_extract_compute(void *, char *, int, int)
void *lammps_extract_fix(void *, char *, int, int, int, int)
void *lammps_extract_variable(void *, char *, char *) :pre

void lammps_reset_box(void *, double *, double *, double, double, double)
int lammps_set_variable(void *, char *, char *) :pre
The extract_setting() function returns info on the size
of data types (e.g. 32-bit or 64-bit atom IDs) used
by the LAMMPS executable (a compile-time choice).

The other extract functions return a pointer to various global or
per-atom quantities stored in LAMMPS or to values calculated by a
compute, fix, or variable.  The pointer returned by the
extract_global() function can be used as a permanent reference to a
value which may change.  For the extract_atom() method, see the
extract() method in the src/atom.cpp file for a list of valid per-atom
properties.  New names could easily be added if the property you want
is not listed.  For the other extract functions, the underlying
storage may be reallocated as LAMMPS runs, so you need to re-call the
function to assure a current pointer or returned value(s).

double lammps_get_thermo(void *, char *)
int lammps_get_natoms(void *)
void lammps_gather_atoms(void *, double *)
void lammps_scatter_atoms(void *, double *) :pre
void lammps_create_atoms(void *, int, tagint *, int *, double *, double *,
                         imageint *, int) :pre
int lammps_get_natoms(void *) :pre

The extract functions return a pointer to various global or per-atom
quantities stored in LAMMPS or to values calculated by a compute, fix,
or variable.  The pointer returned by the extract_global() function
can be used as a permanent reference to a value which may change.  For
the extract_atom() method, see the extract() method in the
src/atom.cpp file for a list of valid per-atom properties.  New names
could easily be added if the property you want is not listed.  For the
other extract functions, the underlying storage may be reallocated as
LAMMPS runs, so you need to re-call the function to assure a current
pointer or returned value(s).
int lammps_set_variable(void *, char *, char *)
void lammps_reset_box(void *, double *, double *, double, double, double) :pre

The lammps_reset_box() function resets the size and shape of the
simulation box, e.g. as part of restoring a previously extracted and
saved state of a simulation.
The lammps_get_thermo() function returns the current value of a thermo
keyword as a double precision value.

The lammps_get_natoms() function returns the total number of atoms in
the system and can be used by the caller to allocate memory for the
lammps_gather_atoms() and lammps_scatter_atoms() functions.

The lammps_set_variable() function can set an existing string-style
variable to a new string value, so that subsequent LAMMPS commands can
access the variable.

The lammps_get_thermo() function returns the current value of a thermo
keyword as a double precision value.
The lammps_reset_box() function resets the size and shape of the
simulation box, e.g. as part of restoring a previously extracted and
saved state of a simulation.

The lammps_get_natoms() function returns the total number of atoms in
the system and can be used by the caller to allocate space for the
lammps_gather_atoms() and lammps_scatter_atoms() functions.  The
gather function collects peratom info of the requested type (atom
coords, types, forces, etc) from all processors, orders them by atom
ID, and returns a full list to each calling processor.  The scatter
function does the inverse.  It distributes the same peratom values,
passed by the caller, to each atom owned by individual processors.
Both methods are thus a means to extract or assign (overwrite) any
peratom quantities within LAMMPS.  See the extract() method in the
src/atom.cpp file for a list of valid per-atom properties.  New names
could easily be added if the property you want is not listed.
A special treatment is applied for accessing image flags via the
"image" property. Image flags are stored in a packed format with all
three image flags stored in a single integer. When signaling to access
the image flags as 3 individual values per atom instead of 1, the data
is transparently packed or unpacked by the library interface.
void lammps_gather_atoms(void *, char *, int, int, void *)
void lammps_gather_atoms_concat(void *, char *, int, int, void *)
void lammps_gather_atoms_subset(void *, char *, int, int, int, int *, void *)
void lammps_scatter_atoms(void *, char *, int, int, void *)
void lammps_scatter_atoms_subset(void *, char *, int, int, int, int *, void *) :pre

void lammps_create_atoms(void *, int, tagint *, int *, double *, double *,
                         imageint *, int) :pre

The gather functions collect peratom info of the requested type (atom
coords, atom types, forces, etc) from all processors, and returns the
same vector of values to each callling processor.  The scatter
functions do the inverse.  They distribute a vector of peratom values,
passed by all calling processors, to invididual atoms, which may be
owned by different processos.

The lammps_gather_atoms() function does this for all N atoms in the
system, ordered by atom ID, from 1 to N.  The
lammps_gather_atoms_concat() function does it for all N atoms, but
simply concatenates the subset of atoms owned by each processor.  The
resulting vector is not ordered by atom ID.  Atom IDs can be requetsed
by the same function if the caller needs to know the ordering.  The
lammps_gather_subset() function allows the caller to request values
for only a subset of atoms (identified by ID).
For all 3 gather function, per-atom image flags can be retrieved in 2 ways.
If the count is specified as 1, they are returned 
in a packed format with all three image flags stored in a single integer.
If the count is specified as 3, the values are unpacked into xyz flags
by the library before returning them.

The lammps_scatter_atoms() function takes a list of values for all N
atoms in the system, ordered by atom ID, from 1 to N, and assigns
those values to each atom in the system.  The
lammps_scatter_atoms_subset() function takes a subset of IDs as an
argument and only scatters those values to the owning atoms.

The lammps_create_atoms() function takes a list of N atoms as input
with atom types and coords (required), an optionally atom IDs and
@@ -2005,17 +2040,6 @@ of a simulation. Additional properties for the new atoms can then be
assigned via the lammps_scatter_atoms() or lammps_extract_atom()
functions.

The examples/COUPLE and python directories have example C++ and C and
Python codes which show how a driver code can link to LAMMPS as a
library, run LAMMPS on a subset of processors, grab data from LAMMPS,
change it, and put it back into LAMMPS.

NOTE: You can write code for additional functions as needed to define
how your code talks to LAMMPS and add them to src/library.cpp and
src/library.h, as well as to the "Python
interface"_Section_python.html.  The added functions can access or
change any LAMMPS data you wish.

:line

6.20 Calculating thermal conductivity :link(howto_20),h4
+63 −62
Original line number Diff line number Diff line
@@ -551,11 +551,14 @@ Python script, as follows:
from lammps import lammps :pre

These are the methods defined by the lammps module.  If you look at
the files src/library.cpp and src/library.h you will see that they
the files src/library.cpp and src/library.h you will see they
correspond one-to-one with calls you can make to the LAMMPS library
from a C++ or C or Fortran program, and which are described in
"Section 6.19"_Section_howto.html#howto_19 of the manual.

The python/examples directory has Python scripts which show how Python
can run LAMMPS, grab data, change it, and put it back into LAMMPS.

lmp = lammps()           # create a LAMMPS object using the default liblammps.so library
                         # 4 optional args are allowed: name, cmdargs, ptr, comm
lmp = lammps(ptr=lmpptr) # use lmpptr as previously created LAMMPS object
@@ -565,18 +568,22 @@ lmp = lammps(name="g++",cmdargs=list) # add LAMMPS command-line args, e.g. li

lmp.close()              # destroy a LAMMPS object :pre

version = lmp.version()  # return the numerical version id, e.g. LAMMPS 2 Sep 2015 -> 20150902
version = lmp.version()  # return the numerical version id, e.g. LAMMPS 2 Sep 2015 -> 20150902 :pre

lmp.file(file)           # run an entire input script, file = "in.lj"
lmp.command(cmd)         # invoke a single LAMMPS command, cmd = "run 100" :pre
lmp.command(cmd)         # invoke a single LAMMPS command, cmd = "run 100"
lmp.commands_list(cmdlist)     # invoke commands in cmdlist = ["run 10", "run 20"]
lmp.commands_string(multicmd)  # invoke commands in multicmd = "run 10\nrun 20"
lmp.commands_string(multicmd)  # invoke commands in multicmd = "run 10\nrun 20" :pre

size = lmp.extract_setting(name)     # return data type info :pre

xlo = lmp.extract_global(name,type)  # extract a global quantity
                                     # name = "boxxlo", "nlocal", etc
                                     # type = 0 = int
                                     #        1 = double :pre

boxlo,boxhi,xy,yz,xz,periodicity,box_change = lmp.extract_box()  # extract box info :pre

coords = lmp.extract_atom(name,type)      # extract a per-atom quantity
                                          # name = "x", "type", etc
                                          # type = 0 = vector of ints
@@ -601,16 +608,23 @@ var = lmp.extract_variable(name,group,flag) # extract value(s) from a variable
                                             # flag = 0 = equal-style variable
                                             #        1 = atom-style variable :pre

flag = lmp.set_variable(name,value)       # set existing named string-style variable to value, flag = 0 if successful
value = lmp.get_thermo(name)              # return current value of a thermo keyword
natoms = lmp.get_natoms()                 # total # of atoms as int :pre

flag = lmp.set_variable(name,value)       # set existing named string-style variable to value, flag = 0 if successful
lmp.reset_box(boxlo,boxhi,xy,yz,xz)       # reset the simulation box size :pre

natoms = lmp.get_natoms()                 # total # of atoms as int
data = lmp.gather_atoms(name,type,count)  # return per-atom property of all atoms gathered into data, ordered by atom ID
                                          # name = "x", "charge", "type", etc
                                          # count = # of per-atom values, 1 or 3, etc
data = lmp.gather_atoms_concat(name,type,count)  # ditto, but concatenated atom values from each proc (unordered)
data = lmp.gather_atoms_subset(name,type,count,ndata,ids)  # ditto, but for subset of Ndata atoms with IDs :pre

lmp.scatter_atoms(name,type,count,data)   # scatter per-atom property to all atoms from data, ordered by atom ID
                                          # name = "x", "charge", "type", etc
                                          # count = # of per-atom values, 1 or 3, etc :pre
lmp.scatter_atoms_subset(name,type,count,ndata,ids,data)  # ditto, but for subset of Ndata atoms with IDs :pre

lmp.create_atoms(n,ids,types,x,v,image,shrinkexceed)   # create N atoms with IDs, types, x, v, and image flags :pre

:line

@@ -655,9 +669,10 @@ The file(), command(), commands_list(), commands_string() methods
allow an input script, a single command, or multiple commands to be
invoked.

The extract_global(), extract_atom(), extract_compute(),
extract_fix(), and extract_variable() methods return values or
pointers to data structures internal to LAMMPS.
The extract_setting(), extract_global(), extract_box(),
extract_atom(), extract_compute(), extract_fix(), and
extract_variable() methods return values or pointers to data
structures internal to LAMMPS.

For extract_global() see the src/library.cpp file for the list of
valid names.  New names could easily be added.  A double or integer is
@@ -697,60 +712,46 @@ doubles is returned, one value per atom, which you can use via normal
Python subscripting. The values will be zero for atoms not in the
specified group.

The get_thermo() method returns returns the current value of a thermo
keyword as a float.

The get_natoms() method returns the total number of atoms in the
simulation, as an int.

The gather_atoms() method allows any per-atom property (coordinates,
velocities, etc) to be extracted from LAMMPS.  It returns a ctypes
vector of ints or doubles as specified by type, of length
count*natoms, for the named property for all atoms in the simulation.
The data is ordered by count and then by atom ID.  See the extract()
method in the src/atom.cpp file for a list of valid names.  Again, new
names could easily be added if the property you want is missing.  The
vector can be used via normal Python subscripting.  If atom IDs are
not consecutively ordered within LAMMPS, a None is returned as
indication of an error. A special treatment is applied for image flags
stored in the "image" property. All three image flags are stored in
a packed format in a single integer, so count would be 1 to retrieve
that integer, however also a count value of 3 can be used and then
the image flags will be unpacked into 3 individual integers, ordered
in a similar fashion as coordinates.

Note that the data structure gather_atoms("x") returns is different
from the data structure returned by extract_atom("x") in four ways.
(1) Gather_atoms() returns a vector which you index as x\[i\];
extract_atom() returns an array which you index as x\[i\]\[j\].  (2)
Gather_atoms() orders the atoms by atom ID while extract_atom() does
not.  (3) Gathert_atoms() returns a list of all atoms in the
simulation; extract_atoms() returns just the atoms local to each
processor.  (4) Finally, the gather_atoms() data structure is a copy
of the atom coords stored internally in LAMMPS, whereas extract_atom()
returns an array that effectively points directly to the internal
data.  This means you can change values inside LAMMPS from Python by
assigning a new values to the extract_atom() array.  To do this with
the gather_atoms() vector, you need to change values in the vector,
then invoke the scatter_atoms() method.

The scatter_atoms() method allows any per-atom property (coordinates,
velocities, etc) to be inserted into LAMMPS, overwriting the current
property.  It takes a vector of ints or doubles as specified by type,
of length count*natoms, for the named property for all atoms in the
simulation.  The data should be ordered by count and then by atom ID.
See the extract() method in the src/atom.cpp file for a list of valid
names.  Again, new names could easily be added if the property you
want is missing.  It uses the vector of data to overwrite the
corresponding properties for each atom inside LAMMPS.  This requires
LAMMPS to have its "map" option enabled; see the
"atom_modify"_atom_modify.html command for details.  If it is not, or
if atom IDs are not consecutively ordered, no coordinates are reset.
Similar as for gather_atoms() a special treatment is applied for image
flags, which can be provided in packed (count = 1) or unpacked (count = 3)
format and in the latter case, they will be packed before applied to
atoms.

The array of coordinates passed to scatter_atoms() must be a ctypes
vector of ints or doubles, allocated and initialized something like
this:
The set_variable() methosd sets an existing string-style variable to a
new string value, so that subsequent LAMMPS commands can access the
variable.

The reset_box() emthods resets the size and shape of the simulation
box, e.g. as part of restoring a previously extracted and saved state
of a simulation.

The gather methods collect peratom info of the requested type (atom
coords, atom types, forces, etc) from all processors, and returns the
same vector of values to each callling processor.  The scatter
functions do the inverse.  They distribute a vector of peratom values,
passed by all calling processors, to invididual atoms, which may be
owned by different processos.

Note that the data returned by the gather methods,
e.g. gather_atoms("x"), is different from the data structure returned
by extract_atom("x") in four ways.  (1) Gather_atoms() returns a
vector which you index as x\[i\]; extract_atom() returns an array
which you index as x\[i\]\[j\].  (2) Gather_atoms() orders the atoms
by atom ID while extract_atom() does not.  (3) Gather_atoms() returns
a list of all atoms in the simulation; extract_atoms() returns just
the atoms local to each processor.  (4) Finally, the gather_atoms()
data structure is a copy of the atom coords stored internally in
LAMMPS, whereas extract_atom() returns an array that effectively
points directly to the internal data.  This means you can change
values inside LAMMPS from Python by assigning a new values to the
extract_atom() array.  To do this with the gather_atoms() vector, you
need to change values in the vector, then invoke the scatter_atoms()
method.

For the scatter methods, the array of coordinates passed to must be a
ctypes vector of ints or doubles, allocated and initialized something
like this:

from ctypes import *
natoms = lmp.get_natoms()
@@ -765,7 +766,7 @@ x\[n3-1\] = z coord of atom with ID natoms
lmp.scatter_atoms("x",1,3,x) :pre

Alternatively, you can just change values in the vector returned by
gather_atoms("x",1,3), since it is a ctypes vector of doubles.
the gather methods, since they are also ctypes vectors.

:line

+49 −2
Original line number Diff line number Diff line
@@ -80,12 +80,59 @@ lmp.commands_list(cmds)
# initial thermo should be same as step 20

natoms = lmp.get_natoms()
type = natoms*[1]
atype = natoms*[1]

lmp.command("delete_atoms group all");
lmp.create_atoms(natoms,None,type,x,v);
lmp.create_atoms(natoms,None,atype,x,v);
lmp.command("run 10");

############
# test of new gather/scatter and box extract/reset methods
# can try this in parallel and with/without atom_modify sort enabled

lmp.command("write_dump all custom tmp.simple id type x y z fx fy fz");

x = lmp.gather_atoms("x",1,3)
f = lmp.gather_atoms("f",1,3)

if me == 0: print("Gather XF:",x[3],x[9],f[3],f[9])

ids = lmp.gather_atoms_concat("id",0,1)
x = lmp.gather_atoms_concat("x",1,3)
f = lmp.gather_atoms_concat("f",1,3)

if me == 0: print("Gather concat XF:",ids[0],ids[1],x[0],x[3],f[0],f[3])

ids = (2*ctypes.c_int)()
ids[0] = 2
ids[1] = 4
x = lmp.gather_atoms_subset("x",1,3,2,ids)
f = lmp.gather_atoms_subset("f",1,3,2,ids)

if me == 0: print("Gather subset XF:",x[0],x[3],f[0],f[3])

x[0] = -1.0
x[1] = 0.0
x[2] = 0.0
x[3] = -2.0
x[4] = 0.0
x[5] = 0.0
ids[0] = 100
ids[1] = 200
lmp.scatter_atoms_subset("x",1,3,2,ids,x)

x = lmp.gather_atoms("x",1,3)
if me == 0: print("Gather post scatter subset:",
                  x[3],x[9],x[297],x[298],x[299],x[597],x[598],x[599])

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)

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)

+126 −30

File changed.

Preview size limit exceeded, changes collapsed.

+489 −57

File changed.

Preview size limit exceeded, changes collapsed.

Loading