a few new lib interface methods
This commit is contained in:
@ -1856,9 +1856,20 @@ 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.
|
||||
|
||||
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 **)
|
||||
@ -1937,6 +1948,7 @@ 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 +1957,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).
|
||||
|
||||
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_set_variable() function can set an existing string-style
|
||||
variable to a new string value, so that subsequent LAMMPS commands can
|
||||
access the variable.
|
||||
int lammps_set_variable(void *, char *, char *)
|
||||
void lammps_reset_box(void *, double *, double *, double, double, double) :pre
|
||||
|
||||
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 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.
|
||||
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_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.
|
||||
|
||||
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 +2039,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
|
||||
|
||||
@ -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.
|
||||
The set_variable() methosd sets an existing string-style variable to a
|
||||
new string value, so that subsequent LAMMPS commands can access the
|
||||
variable.
|
||||
|
||||
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 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 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 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.
|
||||
|
||||
The array of coordinates passed to scatter_atoms() must be a ctypes
|
||||
vector of ints or doubles, allocated and initialized something like
|
||||
this:
|
||||
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
|
||||
|
||||
|
||||
@ -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)
|
||||
|
||||
|
||||
156
python/lammps.py
156
python/lammps.py
@ -94,6 +94,39 @@ class lammps(object):
|
||||
if not name: self.lib = CDLL("liblammps.so",RTLD_GLOBAL)
|
||||
else: self.lib = CDLL("liblammps_%s.so" % name,RTLD_GLOBAL)
|
||||
|
||||
# define ctypes API for each library method
|
||||
# NOTE: should add one of these for each lib function
|
||||
|
||||
self.lib.lammps_extract_box.argtypes = \
|
||||
[c_void_p,POINTER(c_double),POINTER(c_double),
|
||||
POINTER(c_double),POINTER(c_double),POINTER(c_double),
|
||||
POINTER(c_int),POINTER(c_int)]
|
||||
self.lib.lammps_extract_box.restype = None
|
||||
|
||||
self.lib.lammps_reset_box.argtypes = \
|
||||
[c_void_p,POINTER(c_double),POINTER(c_double),c_double,c_double,c_double]
|
||||
self.lib.lammps_reset_box.restype = None
|
||||
|
||||
self.lib.lammps_gather_atoms.argtypes = \
|
||||
[c_void_p,c_char_p,c_int,c_int,c_void_p]
|
||||
self.lib.lammps_gather_atoms.restype = None
|
||||
|
||||
self.lib.lammps_gather_atoms_concat.argtypes = \
|
||||
[c_void_p,c_char_p,c_int,c_int,c_void_p]
|
||||
self.lib.lammps_gather_atoms_concat.restype = None
|
||||
|
||||
self.lib.lammps_gather_atoms_subset.argtypes = \
|
||||
[c_void_p,c_char_p,c_int,c_int,c_int,POINTER(c_int),c_void_p]
|
||||
self.lib.lammps_gather_atoms_subset.restype = None
|
||||
|
||||
self.lib.lammps_scatter_atoms.argtypes = \
|
||||
[c_void_p,c_char_p,c_int,c_int,c_void_p]
|
||||
self.lib.lammps_scatter_atoms.restype = None
|
||||
|
||||
self.lib.lammps_scatter_atoms_subset.argtypes = \
|
||||
[c_void_p,c_char_p,c_int,c_int,c_int,POINTER(c_int),c_void_p]
|
||||
self.lib.lammps_scatter_atoms_subset.restype = None
|
||||
|
||||
# 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
|
||||
@ -177,6 +210,8 @@ class lammps(object):
|
||||
self.c_tagint = get_ctypes_int(self.extract_setting("tagint"))
|
||||
self.c_imageint = get_ctypes_int(self.extract_setting("imageint"))
|
||||
|
||||
# shut-down LAMMPS instance
|
||||
|
||||
def __del__(self):
|
||||
if self.lmp and self.opened:
|
||||
self.lib.lammps_close(self.lmp)
|
||||
@ -219,10 +254,16 @@ class lammps(object):
|
||||
# send a string of commands
|
||||
|
||||
def commands_string(self,multicmd):
|
||||
if type(multicmd) is str:
|
||||
multicmd = multicmd.encode()
|
||||
if type(multicmd) is str: multicmd = multicmd.encode()
|
||||
self.lib.lammps_commands_string(self.lmp,c_char_p(multicmd))
|
||||
|
||||
# extract lammps type byte sizes
|
||||
|
||||
def extract_setting(self, name):
|
||||
if name: name = name.encode()
|
||||
self.lib.lammps_extract_atom.restype = c_int
|
||||
return int(self.lib.lammps_extract_setting(self.lmp,name))
|
||||
|
||||
# extract global info
|
||||
|
||||
def extract_global(self,name,type):
|
||||
@ -235,8 +276,35 @@ class lammps(object):
|
||||
ptr = self.lib.lammps_extract_global(self.lmp,name)
|
||||
return ptr[0]
|
||||
|
||||
# extract global info
|
||||
|
||||
def extract_box(self):
|
||||
boxlo = (3*c_double)()
|
||||
boxhi = (3*c_double)()
|
||||
xy = c_double()
|
||||
yz = c_double()
|
||||
xz = c_double()
|
||||
periodicity = (3*c_int)()
|
||||
box_change = c_int()
|
||||
|
||||
self.lib.lammps_extract_box(self.lmp,boxlo,boxhi,
|
||||
byref(xy),byref(yz),byref(xz),
|
||||
periodicity,byref(box_change))
|
||||
|
||||
boxlo = boxlo[:3]
|
||||
boxhi = boxhi[:3]
|
||||
xy = xy.value
|
||||
yz = yz.value
|
||||
xz = xz.value
|
||||
periodicity = periodicity[:3]
|
||||
box_change = box_change.value
|
||||
|
||||
return boxlo,boxhi,xy,yz,xz,periodicity,box_change
|
||||
|
||||
# extract per-atom info
|
||||
|
||||
# NOTE: need to insure are converting to/from correct Python type
|
||||
# e.g. for Python list or NumPy or ctypes
|
||||
|
||||
def extract_atom(self,name,type):
|
||||
if name: name = name.encode()
|
||||
if type == 0:
|
||||
@ -250,14 +318,7 @@ class lammps(object):
|
||||
else: return None
|
||||
ptr = self.lib.lammps_extract_atom(self.lmp,name)
|
||||
return ptr
|
||||
|
||||
# extract lammps type byte sizes
|
||||
|
||||
def extract_setting(self, name):
|
||||
if name: name = name.encode()
|
||||
self.lib.lammps_extract_atom.restype = c_int
|
||||
return int(self.lib.lammps_extract_setting(self.lmp,name))
|
||||
|
||||
|
||||
@property
|
||||
def numpy(self):
|
||||
if not self._numpy:
|
||||
@ -378,15 +439,6 @@ class lammps(object):
|
||||
return result
|
||||
return None
|
||||
|
||||
# set variable value
|
||||
# value is converted to string
|
||||
# returns 0 for success, -1 if failed
|
||||
|
||||
def set_variable(self,name,value):
|
||||
if name: name = name.encode()
|
||||
if value: value = str(value).encode()
|
||||
return self.lib.lammps_set_variable(self.lmp,name,value)
|
||||
|
||||
# return current value of thermo keyword
|
||||
|
||||
def get_thermo(self,name):
|
||||
@ -399,14 +451,30 @@ class lammps(object):
|
||||
def get_natoms(self):
|
||||
return self.lib.lammps_get_natoms(self.lmp)
|
||||
|
||||
# return vector of atom properties gathered across procs, ordered by atom ID
|
||||
# set variable value
|
||||
# value is converted to string
|
||||
# returns 0 for success, -1 if failed
|
||||
|
||||
def set_variable(self,name,value):
|
||||
if name: name = name.encode()
|
||||
if value: value = str(value).encode()
|
||||
return self.lib.lammps_set_variable(self.lmp,name,value)
|
||||
|
||||
# reset simulation box size
|
||||
|
||||
def reset_box(self,boxlo,boxhi,xy,yz,xz):
|
||||
cboxlo = (3*c_double)(*boxlo)
|
||||
cboxhi = (3*c_double)(*boxhi)
|
||||
self.lib.lammps_reset_box(self.lmp,cboxlo,cboxhi,xy,yz,xz)
|
||||
|
||||
# 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
|
||||
# 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: how could we insure are converting to correct Python type
|
||||
# e.g. for Python list or NumPy, etc
|
||||
# ditto for extract_atom() above
|
||||
# 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):
|
||||
if name: name = name.encode()
|
||||
@ -419,19 +487,47 @@ class lammps(object):
|
||||
self.lib.lammps_gather_atoms(self.lmp,name,type,count,data)
|
||||
else: return None
|
||||
return data
|
||||
|
||||
def gather_atoms_concat(self,name,type,count):
|
||||
if name: name = name.encode()
|
||||
natoms = self.lib.lammps_get_natoms(self.lmp)
|
||||
if type == 0:
|
||||
data = ((count*natoms)*c_int)()
|
||||
self.lib.lammps_gather_atoms_concat(self.lmp,name,type,count,data)
|
||||
elif type == 1:
|
||||
data = ((count*natoms)*c_double)()
|
||||
self.lib.lammps_gather_atoms_concat(self.lmp,name,type,count,data)
|
||||
else: return None
|
||||
return data
|
||||
|
||||
# scatter vector of atom properties across procs, ordered by atom ID
|
||||
def gather_atoms_subset(self,name,type,count,ndata,ids):
|
||||
if name: name = name.encode()
|
||||
if type == 0:
|
||||
data = ((count*ndata)*c_int)()
|
||||
self.lib.lammps_gather_atoms_subset(self.lmp,name,type,count,ndata,ids,data)
|
||||
elif type == 1:
|
||||
data = ((count*ndata)*c_double)()
|
||||
self.lib.lammps_gather_atoms_subset(self.lmp,name,type,count,ndata,ids,data)
|
||||
else: return None
|
||||
return data
|
||||
|
||||
# scatter vector of atom properties across procs
|
||||
# 2 variants to match src/library.cpp
|
||||
# name = atom property recognized by LAMMPS in atom->extract()
|
||||
# type = 0 for integer values, 1 for double values
|
||||
# count = number of per-atom valus, 1 for type or charge, 3 for x or f
|
||||
# assume data is of correct type and length, as created by gather_atoms()
|
||||
# NOTE: how could we insure are passing correct type to LAMMPS
|
||||
# e.g. for Python list or NumPy, etc
|
||||
|
||||
# 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):
|
||||
if name: name = name.encode()
|
||||
self.lib.lammps_scatter_atoms(self.lmp,name,type,count,data)
|
||||
|
||||
def scatter_atoms_subset(self,name,type,count,ndata,ids,data):
|
||||
if name: name = name.encode()
|
||||
self.lib.lammps_scatter_atoms_subset(self.lmp,name,type,count,ndata,ids,data)
|
||||
|
||||
# create N atoms on all procs
|
||||
# N = global number of atoms
|
||||
# id = ID of each atom (optional, can be None)
|
||||
@ -457,8 +553,8 @@ class lammps(object):
|
||||
|
||||
type_lmp = (c_int * n)()
|
||||
type_lmp[:] = type
|
||||
self.lib.lammps_create_atoms(self.lmp,n,id_lmp,type_lmp,x,v,image_lmp,shrinkexceed)
|
||||
|
||||
self.lib.lammps_create_atoms(self.lmp,n,id_lmp,type_lmp,x,v,image_lmp,
|
||||
shrinkexceed)
|
||||
|
||||
@property
|
||||
def uses_exceptions(self):
|
||||
|
||||
554
src/library.cpp
554
src/library.cpp
@ -685,55 +685,6 @@ void *lammps_extract_variable(void *ptr, char *name, char *group)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
reset simulation box parameters
|
||||
see domain.h for definition of these arguments
|
||||
assumes domain->set_initial_box() has been invoked previously
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
void lammps_reset_box(void *ptr, double *boxlo, double *boxhi,
|
||||
double xy, double yz, double xz)
|
||||
{
|
||||
LAMMPS *lmp = (LAMMPS *) ptr;
|
||||
Domain *domain = lmp->domain;
|
||||
|
||||
domain->boxlo[0] = boxlo[0];
|
||||
domain->boxlo[1] = boxlo[1];
|
||||
domain->boxlo[2] = boxlo[2];
|
||||
domain->boxhi[0] = boxhi[0];
|
||||
domain->boxhi[1] = boxhi[1];
|
||||
domain->boxhi[2] = boxhi[2];
|
||||
|
||||
domain->xy = xy;
|
||||
domain->yz = yz;
|
||||
domain->xz = xz;
|
||||
|
||||
domain->set_global_box();
|
||||
lmp->comm->set_proc_grid();
|
||||
domain->set_local_box();
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
set the value of a STRING variable to str
|
||||
return -1 if variable doesn't exist or not a STRING variable
|
||||
return 0 for success
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
int lammps_set_variable(void *ptr, char *name, char *str)
|
||||
{
|
||||
LAMMPS *lmp = (LAMMPS *) ptr;
|
||||
int err = -1;
|
||||
|
||||
BEGIN_CAPTURE
|
||||
{
|
||||
err = lmp->input->variable->set_string(name,str);
|
||||
}
|
||||
END_CAPTURE
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
return the current value of a thermo keyword as a double
|
||||
unlike lammps_extract_global() this does not give access to the
|
||||
@ -771,14 +722,72 @@ int lammps_get_natoms(void *ptr)
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
gather the named atom-based entity across all processors
|
||||
atom IDs must be consecutive from 1 to N
|
||||
set the value of a STRING variable to str
|
||||
return -1 if variable doesn't exist or not a STRING variable
|
||||
return 0 for success
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
int lammps_set_variable(void *ptr, char *name, char *str)
|
||||
{
|
||||
LAMMPS *lmp = (LAMMPS *) ptr;
|
||||
int err = -1;
|
||||
|
||||
BEGIN_CAPTURE
|
||||
{
|
||||
err = lmp->input->variable->set_string(name,str);
|
||||
}
|
||||
END_CAPTURE
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
reset simulation box parameters
|
||||
see domain.h for definition of these arguments
|
||||
assumes domain->set_initial_box() has been invoked previously
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
void lammps_reset_box(void *ptr, double *boxlo, double *boxhi,
|
||||
double xy, double yz, double xz)
|
||||
{
|
||||
LAMMPS *lmp = (LAMMPS *) ptr;
|
||||
Domain *domain = lmp->domain;
|
||||
|
||||
domain->boxlo[0] = boxlo[0];
|
||||
domain->boxlo[1] = boxlo[1];
|
||||
domain->boxlo[2] = boxlo[2];
|
||||
domain->boxhi[0] = boxhi[0];
|
||||
domain->boxhi[1] = boxhi[1];
|
||||
domain->boxhi[2] = boxhi[2];
|
||||
|
||||
domain->xy = xy;
|
||||
domain->yz = yz;
|
||||
domain->xz = xz;
|
||||
|
||||
domain->set_global_box();
|
||||
lmp->comm->set_proc_grid();
|
||||
domain->set_local_box();
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
gather the named atom-based entity for all atoms
|
||||
return it in user-allocated data
|
||||
data will be ordered by atom ID
|
||||
requirement for consecutive atom IDs (1 to N)
|
||||
see gather_atoms_concat() to return data for all atoms, unordered
|
||||
see gather_atoms_subset() to return data for only a subset of atoms
|
||||
name = desired quantity, e.g. x or charge
|
||||
type = 0 for integer values, 1 for double values
|
||||
count = # of per-atom values, e.g. 1 for type or charge, 3 for x or f
|
||||
use count = 3 with "image" if want single image flag unpacked into xyz
|
||||
return atom-based values in 1d data, ordered by count, then by atom ID
|
||||
e.g. x[0][0],x[0][1],x[0][2],x[1][0],x[1][1],x[1][2],x[2][0],...
|
||||
data must be pre-allocated by caller to correct length
|
||||
correct length = count*Natoms, as queried by get_natoms()
|
||||
method:
|
||||
alloc and zero count*Natom length vector
|
||||
loop over Nlocal to fill vector with my values
|
||||
Allreduce to sum vector into data across all procs
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
void lammps_gather_atoms(void *ptr, char *name,
|
||||
@ -788,7 +797,10 @@ void lammps_gather_atoms(void *ptr, char *name,
|
||||
|
||||
BEGIN_CAPTURE
|
||||
{
|
||||
int i,j,offset;
|
||||
|
||||
// error if tags are not defined or not consecutive
|
||||
// NOTE: test that name = image or ids is not a 64-bit int in code?
|
||||
|
||||
int flag = 0;
|
||||
if (lmp->atom->tag_enable == 0 || lmp->atom->tag_consecutive() == 0)
|
||||
@ -802,11 +814,10 @@ void lammps_gather_atoms(void *ptr, char *name,
|
||||
|
||||
int natoms = static_cast<int> (lmp->atom->natoms);
|
||||
|
||||
int i,j,offset;
|
||||
void *vptr = lmp->atom->extract(name);
|
||||
if(vptr == NULL) {
|
||||
lmp->error->warning(FLERR,"lammps_gather_atoms: unknown property name");
|
||||
return;
|
||||
if (vptr == NULL) {
|
||||
lmp->error->warning(FLERR,"lammps_gather_atoms: unknown property name");
|
||||
return;
|
||||
}
|
||||
|
||||
// copy = Natom length vector of per-atom values
|
||||
@ -828,10 +839,11 @@ void lammps_gather_atoms(void *ptr, char *name,
|
||||
tagint *tag = lmp->atom->tag;
|
||||
int nlocal = lmp->atom->nlocal;
|
||||
|
||||
if (count == 1)
|
||||
if (count == 1) {
|
||||
for (i = 0; i < nlocal; i++)
|
||||
copy[tag[i]-1] = vector[i];
|
||||
else if (imgunpack) {
|
||||
|
||||
} else if (imgunpack) {
|
||||
for (i = 0; i < nlocal; i++) {
|
||||
offset = count*(tag[i]-1);
|
||||
const int image = vector[i];
|
||||
@ -839,12 +851,14 @@ void lammps_gather_atoms(void *ptr, char *name,
|
||||
copy[offset++] = ((image >> IMGBITS) & IMGMASK) - IMGMAX;
|
||||
copy[offset++] = ((image >> IMG2BITS) & IMGMASK) - IMGMAX;
|
||||
}
|
||||
} else
|
||||
|
||||
} else {
|
||||
for (i = 0; i < nlocal; i++) {
|
||||
offset = count*(tag[i]-1);
|
||||
for (j = 0; j < count; j++)
|
||||
copy[offset++] = array[i][j];
|
||||
}
|
||||
}
|
||||
|
||||
MPI_Allreduce(copy,data,count*natoms,MPI_INT,MPI_SUM,lmp->world);
|
||||
lmp->memory->destroy(copy);
|
||||
@ -865,6 +879,7 @@ void lammps_gather_atoms(void *ptr, char *name,
|
||||
if (count == 1) {
|
||||
for (i = 0; i < nlocal; i++)
|
||||
copy[tag[i]-1] = vector[i];
|
||||
|
||||
} else {
|
||||
for (i = 0; i < nlocal; i++) {
|
||||
offset = count*(tag[i]-1);
|
||||
@ -881,13 +896,305 @@ void lammps_gather_atoms(void *ptr, char *name,
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
scatter the named atom-based entity across all processors
|
||||
atom IDs must be consecutive from 1 to N
|
||||
gather the named atom-based entity for all atoms
|
||||
return it in user-allocated data
|
||||
data will be a concatenation of chunks of each proc's atoms,
|
||||
in whatever order the atoms are on each proc
|
||||
no requirement for consecutive atom IDs (1 to N)
|
||||
can do a gather_atoms_concat for "id" if need to know atom IDs
|
||||
see gather_atoms() to return data ordered by consecutive atom IDs
|
||||
see gather_atoms_subset() to return data for only a subset of atoms
|
||||
name = desired quantity, e.g. x or charge
|
||||
type = 0 for integer values, 1 for double values
|
||||
count = # of per-atom values, e.g. 1 for type or charge, 3 for x or f
|
||||
use count = 3 with "image" if want single image flag unpacked into xyz
|
||||
return atom-based values in 1d data, ordered by count, then by atom
|
||||
e.g. x[0][0],x[0][1],x[0][2],x[1][0],x[1][1],x[1][2],x[2][0],...
|
||||
data must be pre-allocated by caller to correct length
|
||||
correct length = count*Natoms, as queried by get_natoms()
|
||||
method:
|
||||
Allgather Nlocal atoms from each proc into data
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
void lammps_gather_atoms_concat(void *ptr, char *name,
|
||||
int type, int count, void *data)
|
||||
{
|
||||
LAMMPS *lmp = (LAMMPS *) ptr;
|
||||
|
||||
BEGIN_CAPTURE
|
||||
{
|
||||
int i,j,offset;
|
||||
|
||||
// error if tags are not defined
|
||||
// NOTE: test that name = image or ids is not a 64-bit int in code?
|
||||
|
||||
int flag = 0;
|
||||
if (lmp->atom->tag_enable == 0) flag = 1;
|
||||
if (lmp->atom->natoms > MAXSMALLINT) flag = 1;
|
||||
if (flag) {
|
||||
if (lmp->comm->me == 0)
|
||||
lmp->error->warning(FLERR,"Library error in lammps_gather_atoms");
|
||||
return;
|
||||
}
|
||||
|
||||
int natoms = static_cast<int> (lmp->atom->natoms);
|
||||
|
||||
void *vptr = lmp->atom->extract(name);
|
||||
if (vptr == NULL) {
|
||||
lmp->error->warning(FLERR,"lammps_gather_atoms: unknown property name");
|
||||
return;
|
||||
}
|
||||
|
||||
// perform MPI_Allgatherv on each proc's chunk of Nlocal atoms
|
||||
|
||||
int nprocs = lmp->comm->nprocs;
|
||||
|
||||
int *recvcounts,*displs;
|
||||
lmp->memory->create(recvcounts,nprocs,"lib/gather:recvcounts");
|
||||
lmp->memory->create(displs,nprocs,"lib/gather:displs");
|
||||
|
||||
if (type == 0) {
|
||||
int *vector = NULL;
|
||||
int **array = NULL;
|
||||
const int imgunpack = (count == 3) && (strcmp(name,"image") == 0);
|
||||
|
||||
if ((count == 1) || imgunpack) vector = (int *) vptr;
|
||||
else array = (int **) vptr;
|
||||
|
||||
int *copy;
|
||||
lmp->memory->create(copy,count*natoms,"lib/gather:copy");
|
||||
for (i = 0; i < count*natoms; i++) copy[i] = 0;
|
||||
|
||||
tagint *tag = lmp->atom->tag;
|
||||
int nlocal = lmp->atom->nlocal;
|
||||
|
||||
if (count == 1) {
|
||||
MPI_Allgather(&nlocal,1,MPI_INT,recvcounts,1,MPI_INT,lmp->world);
|
||||
displs[0] = 0;
|
||||
for (i = 1; i < nprocs; i++)
|
||||
displs[i] = displs[i-1] + recvcounts[i-1];
|
||||
MPI_Allgatherv(vector,nlocal,MPI_INT,data,recvcounts,displs,
|
||||
MPI_INT,lmp->world);
|
||||
|
||||
} else if (imgunpack) {
|
||||
int *copy;
|
||||
lmp->memory->create(copy,count*nlocal,"lib/gather:copy");
|
||||
offset = 0;
|
||||
for (i = 0; i < nlocal; i++) {
|
||||
const int image = vector[i];
|
||||
copy[offset++] = (image & IMGMASK) - IMGMAX;
|
||||
copy[offset++] = ((image >> IMGBITS) & IMGMASK) - IMGMAX;
|
||||
copy[offset++] = ((image >> IMG2BITS) & IMGMASK) - IMGMAX;
|
||||
}
|
||||
int n = count*nlocal;
|
||||
MPI_Allgather(&n,1,MPI_INT,recvcounts,1,MPI_INT,lmp->world);
|
||||
displs[0] = 0;
|
||||
for (i = 1; i < nprocs; i++)
|
||||
displs[i] = displs[i-1] + recvcounts[i-1];
|
||||
MPI_Allgatherv(copy,count*nlocal,MPI_INT,
|
||||
data,recvcounts,displs,MPI_INT,lmp->world);
|
||||
lmp->memory->destroy(copy);
|
||||
|
||||
} else {
|
||||
int n = count*nlocal;
|
||||
MPI_Allgather(&n,1,MPI_INT,recvcounts,1,MPI_INT,lmp->world);
|
||||
displs[0] = 0;
|
||||
for (i = 1; i < nprocs; i++)
|
||||
displs[i] = displs[i-1] + recvcounts[i-1];
|
||||
MPI_Allgatherv(&array[0][0],count*nlocal,MPI_INT,
|
||||
data,recvcounts,displs,MPI_INT,lmp->world);
|
||||
}
|
||||
|
||||
} else {
|
||||
double *vector = NULL;
|
||||
double **array = NULL;
|
||||
if (count == 1) vector = (double *) vptr;
|
||||
else array = (double **) vptr;
|
||||
|
||||
int nlocal = lmp->atom->nlocal;
|
||||
|
||||
if (count == 1) {
|
||||
MPI_Allgather(&nlocal,1,MPI_INT,recvcounts,1,MPI_INT,lmp->world);
|
||||
displs[0] = 0;
|
||||
for (i = 1; i < nprocs; i++)
|
||||
displs[i] = displs[i-1] + recvcounts[i-1];
|
||||
MPI_Allgatherv(vector,nlocal,MPI_DOUBLE,data,recvcounts,displs,
|
||||
MPI_DOUBLE,lmp->world);
|
||||
|
||||
} else {
|
||||
int n = count*nlocal;
|
||||
MPI_Allgather(&n,1,MPI_INT,recvcounts,1,MPI_INT,lmp->world);
|
||||
displs[0] = 0;
|
||||
for (i = 1; i < nprocs; i++)
|
||||
displs[i] = displs[i-1] + recvcounts[i-1];
|
||||
MPI_Allgatherv(&array[0][0],count*nlocal,MPI_DOUBLE,
|
||||
data,recvcounts,displs,MPI_DOUBLE,lmp->world);
|
||||
}
|
||||
}
|
||||
|
||||
lmp->memory->destroy(recvcounts);
|
||||
lmp->memory->destroy(displs);
|
||||
}
|
||||
END_CAPTURE
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
gather the named atom-based entity for a subset of atoms
|
||||
return it in user-allocated data
|
||||
data will be ordered by requested atom IDs
|
||||
no requirement for consecutive atom IDs (1 to N)
|
||||
see gather_atoms() to return data for all atoms, ordered by consecutive IDs
|
||||
see gather_atoms_concat() to return data for all atoms, unordered
|
||||
name = desired quantity, e.g. x or charge
|
||||
type = 0 for integer values, 1 for double values
|
||||
count = # of per-atom values, e.g. 1 for type or charge, 3 for x or f
|
||||
use count = 3 with "image" if want single image flag unpacked into xyz
|
||||
ndata = # of atoms to return data for (could be all atoms)
|
||||
ids = list of Ndata atom IDs to return data for
|
||||
return atom-based values in 1d data, ordered by count, then by atom
|
||||
e.g. x[0][0],x[0][1],x[0][2],x[1][0],x[1][1],x[1][2],x[2][0],...
|
||||
data must be pre-allocated by caller to correct length
|
||||
correct length = count*Ndata
|
||||
method:
|
||||
alloc and zero count*Ndata length vector
|
||||
loop over Ndata to fill vector with my values
|
||||
Allreduce to sum vector into data across all procs
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
void lammps_gather_atoms_subset(void *ptr, char *name,
|
||||
int type, int count,
|
||||
int ndata, int *ids, void *data)
|
||||
{
|
||||
LAMMPS *lmp = (LAMMPS *) ptr;
|
||||
|
||||
BEGIN_CAPTURE
|
||||
{
|
||||
int i,j,m,offset;
|
||||
tagint id;
|
||||
|
||||
// error if tags are not defined
|
||||
// NOTE: test that name = image or ids is not a 64-bit int in code?
|
||||
|
||||
int flag = 0;
|
||||
if (lmp->atom->tag_enable == 0) flag = 1;
|
||||
if (lmp->atom->natoms > MAXSMALLINT) flag = 1;
|
||||
if (flag) {
|
||||
if (lmp->comm->me == 0)
|
||||
lmp->error->warning(FLERR,"Library error in lammps_gather_atoms_subset");
|
||||
return;
|
||||
}
|
||||
|
||||
void *vptr = lmp->atom->extract(name);
|
||||
if (vptr == NULL) {
|
||||
lmp->error->warning(FLERR,"lammps_gather_atoms_subset: "
|
||||
"unknown property name");
|
||||
return;
|
||||
}
|
||||
|
||||
// copy = Ndata length vector of per-atom values
|
||||
// use atom ID to insert each atom's values into copy
|
||||
// MPI_Allreduce with MPI_SUM to merge into data
|
||||
|
||||
if (type == 0) {
|
||||
int *vector = NULL;
|
||||
int **array = NULL;
|
||||
const int imgunpack = (count == 3) && (strcmp(name,"image") == 0);
|
||||
|
||||
if ((count == 1) || imgunpack) vector = (int *) vptr;
|
||||
else array = (int **) vptr;
|
||||
|
||||
int *copy;
|
||||
lmp->memory->create(copy,count*ndata,"lib/gather:copy");
|
||||
for (i = 0; i < count*ndata; i++) copy[i] = 0;
|
||||
|
||||
tagint *tag = lmp->atom->tag;
|
||||
int nlocal = lmp->atom->nlocal;
|
||||
|
||||
if (count == 1) {
|
||||
for (i = 0; i < ndata; i++) {
|
||||
id = ids[i];
|
||||
if ((m = lmp->atom->map(id)) >= 0 && m < nlocal)
|
||||
copy[i] = vector[m];
|
||||
}
|
||||
|
||||
} else if (imgunpack) {
|
||||
for (i = 0; i < ndata; i++) {
|
||||
id = ids[i];
|
||||
if ((m = lmp->atom->map(id)) >= 0 && m < nlocal) {
|
||||
offset = count*i;
|
||||
const int image = vector[m];
|
||||
copy[offset++] = (image & IMGMASK) - IMGMAX;
|
||||
copy[offset++] = ((image >> IMGBITS) & IMGMASK) - IMGMAX;
|
||||
copy[offset++] = ((image >> IMG2BITS) & IMGMASK) - IMGMAX;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
for (i = 0; i < ndata; i++) {
|
||||
id = ids[i];
|
||||
if ((m = lmp->atom->map(id)) >= 0 && m < nlocal) {
|
||||
offset = count*i;
|
||||
for (j = 0; j < count; j++)
|
||||
copy[offset++] = array[m][j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MPI_Allreduce(copy,data,count*ndata,MPI_INT,MPI_SUM,lmp->world);
|
||||
lmp->memory->destroy(copy);
|
||||
|
||||
} else {
|
||||
double *vector = NULL;
|
||||
double **array = NULL;
|
||||
if (count == 1) vector = (double *) vptr;
|
||||
else array = (double **) vptr;
|
||||
|
||||
double *copy;
|
||||
lmp->memory->create(copy,count*ndata,"lib/gather:copy");
|
||||
for (i = 0; i < count*ndata; i++) copy[i] = 0.0;
|
||||
|
||||
tagint *tag = lmp->atom->tag;
|
||||
int nlocal = lmp->atom->nlocal;
|
||||
|
||||
if (count == 1) {
|
||||
for (i = 0; i < ndata; i++) {
|
||||
id = ids[i];
|
||||
if ((m = lmp->atom->map(id)) >= 0 && m < nlocal)
|
||||
copy[i] = vector[m];
|
||||
}
|
||||
|
||||
} else {
|
||||
for (i = 0; i < ndata; i++) {
|
||||
id = ids[i];
|
||||
if ((m = lmp->atom->map(id)) >= 0 && m < nlocal) {
|
||||
offset = count*i;
|
||||
for (j = 0; j < count; j++)
|
||||
copy[offset++] = array[m][j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MPI_Allreduce(copy,data,count*ndata,MPI_DOUBLE,MPI_SUM,lmp->world);
|
||||
lmp->memory->destroy(copy);
|
||||
}
|
||||
}
|
||||
END_CAPTURE
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
scatter the named atom-based entity in data to all atoms
|
||||
data is ordered by atom ID
|
||||
requirement for consecutive atom IDs (1 to N)
|
||||
see scatter_atoms_subset() to scatter data for some (or all) atoms, unordered
|
||||
name = desired quantity, e.g. x or charge
|
||||
type = 0 for integer values, 1 for double values
|
||||
count = # of per-atom values, e.g. 1 for type or charge, 3 for x or f
|
||||
use count = 3 with "image" for xyz to be packed into single image flag
|
||||
data = atom-based values in 1d data, ordered by count, then by atom ID
|
||||
e.g. x[0][0],x[0][1],x[0][2],x[1][0],x[1][1],x[1][2],x[2][0],...
|
||||
data must be correct length = count*Natoms, as queried by get_natoms()
|
||||
method:
|
||||
loop over Natoms, if I own atom ID, set its values from data
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
void lammps_scatter_atoms(void *ptr, char *name,
|
||||
@ -897,7 +1204,10 @@ void lammps_scatter_atoms(void *ptr, char *name,
|
||||
|
||||
BEGIN_CAPTURE
|
||||
{
|
||||
int i,j,m,offset;
|
||||
|
||||
// error if tags are not defined or not consecutive or no atom map
|
||||
// NOTE: test that name = image or ids is not a 64-bit int in code?
|
||||
|
||||
int flag = 0;
|
||||
if (lmp->atom->tag_enable == 0 || lmp->atom->tag_consecutive() == 0)
|
||||
@ -912,7 +1222,6 @@ void lammps_scatter_atoms(void *ptr, char *name,
|
||||
|
||||
int natoms = static_cast<int> (lmp->atom->natoms);
|
||||
|
||||
int i,j,m,offset;
|
||||
void *vptr = lmp->atom->extract(name);
|
||||
if(vptr == NULL) {
|
||||
lmp->error->warning(FLERR,
|
||||
@ -937,6 +1246,7 @@ void lammps_scatter_atoms(void *ptr, char *name,
|
||||
for (i = 0; i < natoms; i++)
|
||||
if ((m = lmp->atom->map(i+1)) >= 0)
|
||||
vector[m] = dptr[i];
|
||||
|
||||
} else if (imgpack) {
|
||||
for (i = 0; i < natoms; i++)
|
||||
if ((m = lmp->atom->map(i+1)) >= 0) {
|
||||
@ -946,6 +1256,7 @@ void lammps_scatter_atoms(void *ptr, char *name,
|
||||
image += (dptr[offset++] + IMGMAX) << IMG2BITS;
|
||||
vector[m] = image;
|
||||
}
|
||||
|
||||
} else {
|
||||
for (i = 0; i < natoms; i++)
|
||||
if ((m = lmp->atom->map(i+1)) >= 0) {
|
||||
@ -954,6 +1265,7 @@ void lammps_scatter_atoms(void *ptr, char *name,
|
||||
array[m][j] = dptr[offset++];
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
double *vector = NULL;
|
||||
double **array = NULL;
|
||||
@ -965,6 +1277,7 @@ void lammps_scatter_atoms(void *ptr, char *name,
|
||||
for (i = 0; i < natoms; i++)
|
||||
if ((m = lmp->atom->map(i+1)) >= 0)
|
||||
vector[m] = dptr[i];
|
||||
|
||||
} else {
|
||||
for (i = 0; i < natoms; i++) {
|
||||
if ((m = lmp->atom->map(i+1)) >= 0) {
|
||||
@ -979,6 +1292,125 @@ void lammps_scatter_atoms(void *ptr, char *name,
|
||||
END_CAPTURE
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
scatter the named atom-based entity in data to a subset of atoms
|
||||
data is ordered by provided atom IDs
|
||||
no requirement for consecutive atom IDs (1 to N)
|
||||
see scatter_atoms() to scatter data for all atoms, ordered by consecutive IDs
|
||||
name = desired quantity, e.g. x or charge
|
||||
type = 0 for integer values, 1 for double values
|
||||
count = # of per-atom values, e.g. 1 for type or charge, 3 for x or f
|
||||
use count = 3 with "image" for xyz to be packed into single image flag
|
||||
ndata = # of atoms in ids and data (could be all atoms)
|
||||
ids = list of Ndata atom IDs to scatter data to
|
||||
data = atom-based values in 1d data, ordered by count, then by atom ID
|
||||
e.g. x[0][0],x[0][1],x[0][2],x[1][0],x[1][1],x[1][2],x[2][0],...
|
||||
data must be correct length = count*Ndata
|
||||
method:
|
||||
loop over Ndata, if I own atom ID, set its values from data
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
void lammps_scatter_atoms_subset(void *ptr, char *name,
|
||||
int type, int count,
|
||||
int ndata, int *ids, void *data)
|
||||
{
|
||||
LAMMPS *lmp = (LAMMPS *) ptr;
|
||||
|
||||
BEGIN_CAPTURE
|
||||
{
|
||||
int i,j,m,offset;
|
||||
tagint id;
|
||||
|
||||
// error if tags are not defined or no atom map
|
||||
// NOTE: test that name = image or ids is not a 64-bit int in code?
|
||||
|
||||
int flag = 0;
|
||||
if (lmp->atom->tag_enable == 0) flag = 1;
|
||||
if (lmp->atom->natoms > MAXSMALLINT) flag = 1;
|
||||
if (lmp->atom->map_style == 0) flag = 1;
|
||||
if (flag) {
|
||||
if (lmp->comm->me == 0)
|
||||
lmp->error->warning(FLERR,"Library error in lammps_scatter_atoms_subset");
|
||||
return;
|
||||
}
|
||||
|
||||
void *vptr = lmp->atom->extract(name);
|
||||
if(vptr == NULL) {
|
||||
lmp->error->warning(FLERR,
|
||||
"lammps_scatter_atoms_subset: unknown property name");
|
||||
return;
|
||||
}
|
||||
|
||||
// copy = Natom length vector of per-atom values
|
||||
// use atom ID to insert each atom's values into copy
|
||||
// MPI_Allreduce with MPI_SUM to merge into data, ordered by atom ID
|
||||
|
||||
if (type == 0) {
|
||||
int *vector = NULL;
|
||||
int **array = NULL;
|
||||
const int imgpack = (count == 3) && (strcmp(name,"image") == 0);
|
||||
|
||||
if ((count == 1) || imgpack) vector = (int *) vptr;
|
||||
else array = (int **) vptr;
|
||||
int *dptr = (int *) data;
|
||||
|
||||
if (count == 1) {
|
||||
for (i = 0; i < ndata; i++)
|
||||
if ((m = lmp->atom->map(i+1)) >= 0)
|
||||
vector[m] = dptr[i];
|
||||
|
||||
} else if (imgpack) {
|
||||
for (i = 0; i < ndata; i++) {
|
||||
id = ids[i];
|
||||
if ((m = lmp->atom->map(id)) >= 0) {
|
||||
offset = count*i;
|
||||
int image = dptr[offset++] + IMGMAX;
|
||||
image += (dptr[offset++] + IMGMAX) << IMGBITS;
|
||||
image += (dptr[offset++] + IMGMAX) << IMG2BITS;
|
||||
vector[m] = image;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
for (i = 0; i < ndata; i++) {
|
||||
id = ids[i];
|
||||
if ((m = lmp->atom->map(id)) >= 0) {
|
||||
offset = count*i;
|
||||
for (j = 0; j < count; j++)
|
||||
array[m][j] = dptr[offset++];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
double *vector = NULL;
|
||||
double **array = NULL;
|
||||
if (count == 1) vector = (double *) vptr;
|
||||
else array = (double **) vptr;
|
||||
double *dptr = (double *) data;
|
||||
|
||||
if (count == 1) {
|
||||
for (i = 0; i < ndata; i++) {
|
||||
id = ids[i];
|
||||
if ((m = lmp->atom->map(id)) >= 0)
|
||||
vector[m] = dptr[i];
|
||||
}
|
||||
|
||||
} else {
|
||||
for (i = 0; i < ndata; i++) {
|
||||
id = ids[i];
|
||||
if ((m = lmp->atom->map(id)) >= 0) {
|
||||
offset = count*i;
|
||||
for (j = 0; j < count; j++)
|
||||
array[m][j] = dptr[offset++];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
END_CAPTURE
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
create N atoms and assign them to procs based on coords
|
||||
id = atom IDs (optional, NULL will generate 1 to N)
|
||||
|
||||
@ -43,13 +43,17 @@ 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 *);
|
||||
|
||||
void lammps_reset_box(void *, double *, double *, double, double, double);
|
||||
int lammps_set_variable(void *, char *, char *);
|
||||
double lammps_get_thermo(void *, char *);
|
||||
|
||||
int lammps_get_natoms(void *);
|
||||
|
||||
int lammps_set_variable(void *, char *, char *);
|
||||
void lammps_reset_box(void *, double *, double *, double, double, double);
|
||||
|
||||
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 *);
|
||||
|
||||
// lammps_create_atoms() takes tagint and imageint as args
|
||||
// ifdef insures they are compatible with rest of LAMMPS
|
||||
|
||||
Reference in New Issue
Block a user