first try at implementing lammps_extract_atom_size()

This commit is contained in:
Axel Kohlmeyer
2024-08-30 22:50:42 -04:00
parent e921af8efa
commit 9d9e591b54
13 changed files with 411 additions and 133 deletions

View File

@ -318,6 +318,8 @@ class lammps(object):
self.lib.lammps_extract_atom.argtypes = [c_void_p, c_char_p]
self.lib.lammps_extract_atom_datatype.argtypes = [c_void_p, c_char_p]
self.lib.lammps_extract_atom_datatype.restype = c_int
self.lib.lammps_extract_atom_size.argtypes = [c_void_p, c_char_p, c_int]
self.lib.lammps_extract_atom_size.restype = c_int
self.lib.lammps_extract_fix.argtypes = [c_void_p, c_char_p, c_int, c_int, c_int, c_int]
@ -1070,31 +1072,59 @@ class lammps(object):
else: return None
return self.lib.lammps_extract_atom_datatype(self.lmp, newname)
# -------------------------------------------------------------------------
# extract per-atom info datatype
def extract_atom_size(self, name, dtype):
"""Retrieve per-atom property dimensions from LAMMPS
This is a wrapper around the :cpp:func:`lammps_extract_atom_size`
function of the C-library interface. Its documentation includes a
list of the supported keywords.
This function returns ``None`` if the keyword is not
recognized. Otherwise it will return an integer value with the size
of the per-atom vector or array. If *name* corresponds to a per-atom
array, the *dtype* keyword must be either LMP_SIZE_ROWS or LMP_SIZE_COLS
from the :ref:`type <py_type_constants>` constants defined in the
:py:mod:`lammps` module. The return value is the requested size.
If *name* corresponds to a per-atom vector the *dtype* keyword is ignored.
:param name: name of the property
:type name: string
:param type: either LMP_SIZE_ROWS or LMP_SIZE_COLS for arrays, otherwise ignored
:type type: int
:return: data type of per-atom property (see :ref:`py_datatype_constants`)
:rtype: int
"""
if name: newname = name.encode()
else: return None
return self.lib.lammps_extract_atom_size(self.lmp, newname, dtype)
# -------------------------------------------------------------------------
# extract per-atom info
def extract_atom(self, name, dtype=LAMMPS_AUTODETECT):
"""Retrieve per-atom properties from LAMMPS
This is a wrapper around the :cpp:func:`lammps_extract_atom`
function of the C-library interface. Its 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 by setting ``dtype``
to one of the :ref:`data type <py_datatype_constants>` constants defined in the
:py:mod:`lammps` module.
This function returns ``None`` if either the keyword is not
recognized, or an invalid data type constant is used.
This is a wrapper around the :cpp:func:`lammps_extract_atom` function of the
C-library interface. Its 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 by setting ``dtype`` to one of the :ref:`data type
<py_datatype_constants>` constants defined in the :py:mod:`lammps` module.
This function returns ``None`` if either the keyword is not recognized, or
an invalid data type constant is used.
.. note::
While the returned arrays of per-atom data are dimensioned
for the range [0:nmax] - as is the underlying storage -
the data is usually only valid for the range of [0:nlocal],
unless the property of interest is also updated for ghost
atoms. In some cases, this depends on a LAMMPS setting, see
for example :doc:`comm_modify vel yes <comm_modify>`.
While the returned vectors or arrays of per-atom data are dimensioned for
the range [0:nmax] - as is the underlying storage - the data is usually
only valid for the range of [0:nlocal], unless the property of interest
is also updated for ghost atoms. In some cases, this depends on a LAMMPS
setting, see for example :doc:`comm_modify vel yes <comm_modify>`.
The actual size can be determined by calling
py:meth:`extract_atom_size() <lammps.lammps.extract_atom_size>`.
:param name: name of the property
:type name: string
@ -1105,6 +1135,7 @@ class lammps(object):
ctypes.POINTER(ctypes.c_int64), ctypes.POINTER(ctypes.POINTER(ctypes.c_int64)),
ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.POINTER(ctypes.c_double)),
or NoneType
"""
if dtype == LAMMPS_AUTODETECT:
dtype = self.extract_atom_datatype(name)
@ -2522,3 +2553,8 @@ class lammps(object):
newcomputeid = computeid.encode()
idx = self.lib.lammps_find_compute_neighlist(self.lmp, newcomputeid, reqid)
return idx
# Local Variables:
# fill-column: 80
# End:

View File

@ -54,7 +54,8 @@ class numpy_wrapper:
# -------------------------------------------------------------------------
def extract_atom(self, name, dtype=LAMMPS_AUTODETECT, nelem=LAMMPS_AUTODETECT, dim=LAMMPS_AUTODETECT):
def extract_atom(self, name, dtype=LAMMPS_AUTODETECT, nelem=LAMMPS_AUTODETECT,
dim=LAMMPS_AUTODETECT):
"""Retrieve per-atom properties from LAMMPS as NumPy arrays
This is a wrapper around the :py:meth:`lammps.extract_atom()` method.
@ -63,16 +64,16 @@ class numpy_wrapper:
.. note::
The returned arrays of per-atom data are by default dimensioned
for the range [0:nlocal] since that data is *always* valid. The
underlying storage for the data, however, is typically allocated
for the range of [0:nmax]. Whether there is valid data in the range
[nlocal:nlocal+nghost] depends on whether the property of interest
is also updated for ghost atoms. This is not often the case. In
some cases, it depends on a LAMMPS setting, see for example
:doc:`comm_modify vel yes <comm_modify>`. By using the optional
*nelem* parameter the size of the returned NumPy can be overridden.
There is no check whether the number of elements chosen is valid.
The returned vectors or arrays of per-atom data are dimensioned
according to the return value of :py:meth:`lammps.extract_atom_size()`.
Except for the "mass" property, the underlying storage will always be
dimensioned for the range [0:nmax]. The actual usable data may be
only in the range [0:nlocal] or [0:nlocal][0:dim]. Whether there is
valid data in the range [nlocal:nlocal+nghost] or [nlocal:local+nghost][0:dim]
depends on whether the property of interest is also updated for ghost atoms.
Also the value of *dim* depends on the value of *name*. By using the optional
*nelem* and *dim* parameters the dimensions of the returned NumPy array can
be overridden. There is no check whether the number of elements chosen is valid.
:param name: name of the property
:type name: string
@ -89,21 +90,10 @@ class numpy_wrapper:
dtype = self.lmp.extract_atom_datatype(name)
if nelem == LAMMPS_AUTODETECT:
if name == "mass":
nelem = self.lmp.extract_global("ntypes") + 1
else:
nelem = self.lmp.extract_global("nlocal")
nelem = self.lmp.extract_atom_size(name, LMP_SIZE_ROWS)
if dim == LAMMPS_AUTODETECT:
if dtype in (LAMMPS_INT_2D, LAMMPS_DOUBLE_2D, LAMMPS_INT64_2D):
# TODO add other fields
if name in ("x", "v", "f", "x0","omega", "angmom", "torque", "csforce", "vforce", "vest"):
dim = 3
elif name == "smd_data_9":
dim = 9
elif name == "smd_stress":
dim = 6
else:
dim = 2
dim = self.lmp.extract_atom_size(name, LMP_SIZE_COLS)
else:
dim = 1
@ -119,37 +109,6 @@ class numpy_wrapper:
# -------------------------------------------------------------------------
def extract_atom_iarray(self, name, nelem, dim=1):
warnings.warn("deprecated, use extract_atom instead", DeprecationWarning)
if name in ['id', 'molecule']:
c_int_type = self.lmp.c_tagint
elif name in ['image']:
c_int_type = self.lmp.c_imageint
else:
c_int_type = c_int
if dim == 1:
raw_ptr = self.lmp.extract_atom(name, LAMMPS_INT)
else:
raw_ptr = self.lmp.extract_atom(name, LAMMPS_INT_2D)
return self.iarray(c_int_type, raw_ptr, nelem, dim)
# -------------------------------------------------------------------------
def extract_atom_darray(self, name, nelem, dim=1):
warnings.warn("deprecated, use extract_atom instead", DeprecationWarning)
if dim == 1:
raw_ptr = self.lmp.extract_atom(name, LAMMPS_DOUBLE)
else:
raw_ptr = self.lmp.extract_atom(name, LAMMPS_DOUBLE_2D)
return self.darray(raw_ptr, nelem, dim)
# -------------------------------------------------------------------------
def extract_compute(self, cid, cstyle, ctype):
"""Retrieve data from a LAMMPS compute