add python interface with optional numpy support for lammps_gather_bonds()

unit tests are included
This commit is contained in:
Axel Kohlmeyer
2021-07-26 22:36:00 -04:00
parent cc87e7eee3
commit 458253b452
9 changed files with 447 additions and 2 deletions

View File

@ -56,6 +56,7 @@ It documents the following functions:
:project: progguide :project: progguide
----------------------- -----------------------
.. doxygenfunction:: lammps_gather .. doxygenfunction:: lammps_gather
:project: progguide :project: progguide

View File

@ -201,6 +201,9 @@ class lammps(object):
[c_void_p,c_char_p,c_int,c_int,c_int,POINTER(c_int),c_void_p] [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 self.lib.lammps_scatter_atoms_subset.restype = None
self.lib.lammps_gather_bonds.argtypes = [c_void_p,c_void_p]
self.lib.lammps_gather_bonds.restype = None
self.lib.lammps_gather.argtypes = \ self.lib.lammps_gather.argtypes = \
[c_void_p,c_char_p,c_int,c_int,c_void_p] [c_void_p,c_char_p,c_int,c_int,c_void_p]
self.lib.lammps_gather.restype = None self.lib.lammps_gather.restype = None
@ -1206,6 +1209,32 @@ class lammps(object):
with ExceptionCheck(self): with ExceptionCheck(self):
self.lib.lammps_scatter_atoms_subset(self.lmp,name,dtype,count,ndata,ids,data) self.lib.lammps_scatter_atoms_subset(self.lmp,name,dtype,count,ndata,ids,data)
# -------------------------------------------------------------------------
def gather_bonds(self):
"""Retrieve global list of bonds
This is a wrapper around the :cpp:func:`lammps_gather_bonds`
function of the C-library interface.
This function returns a tuple with the number of bonds and a
flat list of ctypes integer values with the bond type, bond atom1,
bond atom2 for each bond.
.. versionadded:: 28Jul2021
:return: a tuple with the number of bonds and a list of c_int or c_long
:rtype: (int, 3*nbonds*c_tagint)
"""
nbonds = self.extract_global("nbonds")
with ExceptionCheck(self):
data = ((3*nbonds)*self.c_tagint)()
self.lib.lammps_gather_bonds(self.lmp,data)
return nbonds,data
# -------------------------------------------------------------------------
# return vector of atom/compute/fix properties gathered across procs # return vector of atom/compute/fix properties gathered across procs
# 3 variants to match src/library.cpp # 3 variants to match src/library.cpp
# name = atom property recognized by LAMMPS in atom->extract() # name = atom property recognized by LAMMPS in atom->extract()

View File

@ -248,6 +248,24 @@ class numpy_wrapper:
# ------------------------------------------------------------------------- # -------------------------------------------------------------------------
def gather_bonds(self):
"""Retrieve global list of bonds as NumPy array
This is a wrapper around :py:meth:`lammps.gather_bonds() <lammps.lammps.gather_bonds()>`
It behaves the same as the original method, but returns a NumPy array instead
of a ``ctypes`` list.
.. versionadded:: 28Jul2021
:return: the requested data as a 2d-integer numpy array
:rtype: numpy.array(nbonds,3)
"""
import numpy as np
nbonds, value = self.lmp.gather_bonds()
return np.ctypeslib.as_array(value).reshape(nbonds,3)
# -------------------------------------------------------------------------
def fix_external_get_force(self, fix_id): def fix_external_get_force(self, fix_id):
"""Get access to the array with per-atom forces of a fix external instance with a given fix ID. """Get access to the array with per-atom forces of a fix external instance with a given fix ID.

View File

@ -2695,15 +2695,17 @@ the calling code. The buffer will be filled with bond type, bond atom 1,
bond atom 2 for each bond. Thus the buffer has to be allocated to the bond atom 2 for each bond. Thus the buffer has to be allocated to the
dimension of 3 times the **total** number of bonds times the size of dimension of 3 times the **total** number of bonds times the size of
the LAMMPS "tagint" type, which is either 4 or 8 bytes depending on the LAMMPS "tagint" type, which is either 4 or 8 bytes depending on
whether they are stored in 32-bit or 64-bit integers, respectively. whether they are stored in 32-bit or 64-bit integers, respectively.
This size depends on the compile time settings used when compiling This size depends on the compile time settings used when compiling
the LAMMPS library and can be queried by calling the LAMMPS library and can be queried by calling
:cpp:func:`lammps_extract_setting()` with the keyword "tagint". :cpp:func:`lammps_extract_setting()` with the keyword "tagint".
When running in parallel, the data buffer must be allocated on **all** When running in parallel, the data buffer must be allocated on **all**
MPI ranks and will be filled with the information for **all** bonds MPI ranks and will be filled with the information for **all** bonds
in the system. in the system.
.. versionadded:: 28Jul2021
Below is a brief C code demonstrating accessing this collected bond information. Below is a brief C code demonstrating accessing this collected bond information.
.. code-block:: c .. code-block:: c

View File

@ -29,6 +29,7 @@ if(Python_EXECUTABLE)
# prepare to augment the environment so that the LAMMPS python module and the shared library is found. # prepare to augment the environment so that the LAMMPS python module and the shared library is found.
set(PYTHON_TEST_ENVIRONMENT PYTHONPATH=${LAMMPS_PYTHON_DIR}:$ENV{PYTHONPATH}) set(PYTHON_TEST_ENVIRONMENT PYTHONPATH=${LAMMPS_PYTHON_DIR}:$ENV{PYTHONPATH})
list(APPEND PYTHON_TEST_ENVIRONMENT "LAMMPS_POTENTIALS=${LAMMPS_POTENTIALS_DIR}") list(APPEND PYTHON_TEST_ENVIRONMENT "LAMMPS_POTENTIALS=${LAMMPS_POTENTIALS_DIR}")
list(APPEND PYTHON_TEST_ENVIRONMENT "TEST_INPUT_DIR=${CMAKE_CURRENT_SOURCE_DIR}")
if(APPLE) if(APPLE)
list(APPEND PYTHON_TEST_ENVIRONMENT "DYLD_LIBRARY_PATH=${CMAKE_BINARY_DIR}:$ENV{DYLD_LIBRARY_PATH};LAMMPS_CMAKE_CACHE=${CMAKE_BINARY_DIR}/CMakeCache.txt") list(APPEND PYTHON_TEST_ENVIRONMENT "DYLD_LIBRARY_PATH=${CMAKE_BINARY_DIR}:$ENV{DYLD_LIBRARY_PATH};LAMMPS_CMAKE_CACHE=${CMAKE_BINARY_DIR}/CMakeCache.txt")
else() else()
@ -90,6 +91,12 @@ if(Python_EXECUTABLE)
COMMAND ${PYTHON_TEST_RUNNER} ${CMAKE_CURRENT_SOURCE_DIR}/python-fix-external.py -v COMMAND ${PYTHON_TEST_RUNNER} ${CMAKE_CURRENT_SOURCE_DIR}/python-fix-external.py -v
WORKING_DIRECTORY ${EXECUTABLE_OUTPUT_PATH}) WORKING_DIRECTORY ${EXECUTABLE_OUTPUT_PATH})
set_tests_properties(PythonFixExternal PROPERTIES ENVIRONMENT "${PYTHON_TEST_ENVIRONMENT}") set_tests_properties(PythonFixExternal PROPERTIES ENVIRONMENT "${PYTHON_TEST_ENVIRONMENT}")
add_test(NAME PythonScatterGather
COMMAND ${PYTHON_TEST_RUNNER} ${CMAKE_CURRENT_SOURCE_DIR}/python-scatter-gather.py -v
WORKING_DIRECTORY ${EXECUTABLE_OUTPUT_PATH})
set_tests_properties(PythonScatterGather PROPERTIES ENVIRONMENT "${PYTHON_TEST_ENVIRONMENT}")
else() else()
message(STATUS "Skipping Tests for the LAMMPS Python Module: no suitable Python interpreter") message(STATUS "Skipping Tests for the LAMMPS Python Module: no suitable Python interpreter")
endif() endif()

View File

@ -0,0 +1,210 @@
LAMMPS data file via write_data, version 5 May 2020, timestep = 0
29 atoms
5 atom types
24 bonds
5 bond types
30 angles
4 angle types
31 dihedrals
5 dihedral types
2 impropers
2 improper types
-6.024572 8.975428 xlo xhi
-7.692866 7.307134 ylo yhi
-8.086924 6.913076 zlo zhi
Masses
1 12.0107
2 4.00794
3 14.0067
4 15.9994
5 15.9994
Pair Coeffs # zero
1
2
3
4
5
Bond Coeffs # zero
1 1.5
2 1.1
3 1.3
4 1.2
5 1
Angle Coeffs # zero
1 110.1
2 111
3 120
4 108.5
Atoms # full
10 2 1 7.0000000000000007e-02 2.0185283555536988e+00 -1.4283966846517357e+00 -9.6733527271133024e-01 0 0 0
11 2 2 8.9999999999999997e-02 1.7929780509347666e+00 -1.9871047540768743e+00 -1.8840626643185674e+00 0 0 0
12 2 1 -2.7000000000000002e-01 3.0030247876861225e+00 -4.8923319967572748e-01 -1.6188658531537248e+00 0 0 0
13 2 2 8.9999999999999997e-02 4.0447273787895934e+00 -9.0131998547446246e-01 -1.6384447268320836e+00 0 0 0
14 2 2 8.9999999999999997e-02 2.6033152817257075e+00 -4.0789761505963579e-01 -2.6554413538823063e+00 0 0 0
2 1 2 3.1000000000000000e-01 3.0197083955402204e-01 2.9515239068888608e+00 -8.5689735572907566e-01 0 0 0
3 1 1 -2.0000000000000000e-02 -6.9435377880558602e-01 1.2440473127136711e+00 -6.2233801468892025e-01 0 0 0
4 1 2 8.9999999999999997e-02 -1.5771614164685133e+00 1.4915333140468066e+00 -1.2487126845040522e+00 0 0 0
6 1 1 5.1000000000000001e-01 2.9412607937706009e-01 2.2719282656652909e-01 -1.2843094067857870e+00 0 0 0
7 1 4 -5.1000000000000001e-01 3.4019871062879609e-01 -9.1277350075786561e-03 -2.4633113224304561e+00 0 0 0
19 3 2 4.2359999999999998e-01 1.5349125211132961e+00 2.6315969880333707e+00 -4.2472859440220647e+00 0 0 0
15 2 2 8.9999999999999997e-02 2.9756315249791303e+00 5.6334269722969288e-01 -1.2437650754599008e+00 0 0 0
18 3 4 -8.4719999999999995e-01 2.1384791188033843e+00 3.0177261773770208e+00 -3.5160827596876225e+00 0 0 0
20 3 2 4.2359999999999998e-01 2.7641167828863153e+00 3.6833419064000221e+00 -3.9380850623312638e+00 0 0 0
8 2 3 -4.6999999999999997e-01 1.1641187171852805e+00 -4.8375305955385234e-01 -6.7659823767368688e-01 0 0 0
9 2 2 3.1000000000000000e-01 1.3777459838125838e+00 -2.5366338669522998e-01 2.6877644730326306e-01 0 0 0
16 2 1 5.1000000000000001e-01 2.6517554244980306e+00 -2.3957110424978438e+00 3.2908335999178327e-02 0 0 0
17 2 4 -5.1000000000000001e-01 2.2309964792710639e+00 -2.1022918943319384e+00 1.1491948328949437e+00 0 0 0
1 1 3 -4.6999999999999997e-01 -2.7993683669226832e-01 2.4726588069312840e+00 -1.7200860244148433e-01 0 0 0
5 1 2 8.9999999999999997e-02 -8.9501761359359255e-01 9.3568128743071344e-01 4.0227731871484346e-01 0 0 0
21 4 5 -8.4719999999999995e-01 4.9064454390208301e+00 -4.0751205255383196e+00 -3.6215576073601046e+00 0 0 0
22 4 2 4.2359999999999998e-01 4.3687453488627543e+00 -4.2054270536772504e+00 -4.4651491269372565e+00 0 0 0
23 4 2 4.2359999999999998e-01 5.7374928154769504e+00 -3.5763355905184966e+00 -3.8820297194230728e+00 0 0 0
24 5 5 -8.4719999999999995e-01 2.0684115301174013e+00 3.1518221747664397e+00 3.1554242678474576e+00 0 0 0
25 5 2 4.2359999999999998e-01 1.2998381073113014e+00 3.2755513587518097e+00 2.5092990173114837e+00 0 0 0
26 5 2 4.2359999999999998e-01 2.5807438597688113e+00 4.0120175892854135e+00 3.2133398379059099e+00 0 0 0
27 6 5 -8.4719999999999995e-01 -1.9613581876744359e+00 -4.3556300596085160e+00 2.1101467673534788e+00 0 0 0
28 6 2 4.2359999999999998e-01 -2.7406520384725965e+00 -4.0207251278130975e+00 1.5828689861678511e+00 0 0 0
29 6 2 4.2359999999999998e-01 -1.3108232656499081e+00 -3.5992986322410760e+00 2.2680459788743503e+00 0 0 0
Velocities
1 7.7867804888392077e-04 5.8970331623292821e-04 -2.2179517633030531e-04
2 2.7129529964126462e-03 4.6286427111164284e-03 3.5805549693846352e-03
3 -1.2736791029204805e-03 1.6108674226414498e-03 -3.3618185901550799e-04
4 -9.2828595122009308e-04 -1.2537885319521818e-03 -4.1204974953432108e-03
5 -1.1800848061603740e-03 7.5424401975844038e-04 6.9023177964912290e-05
6 -3.0914004879905335e-04 1.2755385764678133e-03 7.9574303350202582e-04
7 -1.1037894966874103e-04 -7.6764845099077425e-04 -7.7217630460203659e-04
8 3.9060281273221989e-04 -8.1444231918053418e-04 1.5134641148324972e-04
9 1.2475530960659720e-03 -2.6608454451432528e-03 1.1117602907112732e-03
10 4.5008983776042893e-04 4.9530197647538077e-04 -2.3336234361093645e-04
11 -3.6977669078869707e-04 -1.5289071951960539e-03 -2.9176389881837113e-03
12 1.0850834530183159e-03 -6.4965897903201833e-04 -1.2971152622619948e-03
13 4.0754559196230639e-03 3.5043502394946119e-03 -7.8324487687854666e-04
14 -1.3837220448746613e-04 -4.0656048637594394e-03 -3.9333461173944500e-03
15 -4.3301707382721859e-03 -3.1802661664634938e-03 3.2037919043360571e-03
16 -9.6715751018414326e-05 -5.0016572678960377e-04 1.4945658875149626e-03
17 6.5692180538157174e-04 3.6635779995305095e-04 8.3495414466050911e-04
18 -6.0936815808025862e-04 -9.3774557532468582e-04 -3.3558072507805731e-04
19 -6.9919768291957119e-04 -3.6060777270430031e-03 4.2833405289822791e-03
20 4.7777805013736515e-03 5.1003745845520452e-03 1.8002873923729241e-03
21 -9.5568188553430398e-04 1.6594630943762931e-04 -1.8199788009966615e-04
22 -3.3137518957653462e-03 -2.8683968287936054e-03 3.6384389958326871e-03
23 2.4209481134686401e-04 -4.5457709985051130e-03 2.7663581642115042e-03
24 2.5447450568861086e-04 4.8412447786110117e-04 -4.8021914527341357e-04
25 4.3722771097312743e-03 -4.5184411669545515e-03 2.5200952006556795e-03
26 -1.9250110555001179e-03 -3.0342169883610837e-03 3.5062814567984532e-03
27 -2.6510179146429716e-04 3.6306203629019116e-04 -5.6235585400647747e-04
28 -2.3068708109787484e-04 -8.5663070212203200e-04 2.1302563179109169e-03
29 -2.5054744388303732e-03 -1.6773997805290820e-04 2.8436699761004796e-03
Bonds
1 5 1 2
2 3 1 3
3 2 3 4
4 2 3 5
5 1 3 6
6 3 6 8
7 4 6 7
8 5 8 9
9 3 8 10
10 2 10 11
11 1 10 12
12 1 10 16
13 2 12 13
14 2 12 14
15 2 12 15
16 4 16 17
17 5 18 19
18 5 18 20
19 5 21 22
20 5 21 23
21 5 24 25
22 5 24 26
23 5 27 28
24 5 27 29
Angles
1 4 2 1 3
2 4 1 3 5
3 4 1 3 4
4 4 1 3 6
5 4 4 3 5
6 2 5 3 6
7 2 4 3 6
8 3 3 6 7
9 3 3 6 8
10 3 7 6 8
11 2 6 8 9
12 2 9 8 10
13 3 6 8 10
14 2 8 10 11
15 3 8 10 16
16 2 11 10 12
17 1 12 10 16
18 1 8 10 12
19 2 11 10 16
20 2 10 12 15
21 2 10 12 14
22 2 10 12 13
23 4 13 12 15
24 4 13 12 14
25 4 14 12 15
26 4 10 16 17
27 1 19 18 20
28 1 22 21 23
29 1 25 24 26
30 1 28 27 29
Dihedrals
1 2 2 1 3 6
2 2 2 1 3 4
3 3 2 1 3 5
4 1 1 3 6 8
5 1 1 3 6 7
6 5 4 3 6 8
7 5 4 3 6 7
8 5 5 3 6 8
9 5 5 3 6 7
10 4 3 6 8 9
11 3 3 6 8 10
12 3 7 6 8 9
13 4 7 6 8 10
14 2 6 8 10 12
15 2 6 8 10 16
16 2 6 8 10 11
17 2 9 8 10 12
18 4 9 8 10 16
19 5 9 8 10 11
20 5 8 10 12 13
21 1 8 10 12 14
22 5 8 10 12 15
23 4 8 10 16 17
24 5 11 10 12 13
25 5 11 10 12 14
26 5 11 10 12 15
27 2 11 10 16 17
28 2 12 10 16 17
29 5 16 10 12 13
30 5 16 10 12 14
31 5 16 10 12 15
Impropers
1 1 6 3 8 7
2 2 8 6 10 9

View File

@ -0,0 +1,25 @@
variable units index real
variable input_dir index .
variable data_file index ${input_dir}/data.fourmol
variable pair_style index 'zero 8.0'
variable bond_style index zero
variable angle_style index zero
variable dihedral_style index zero
variable improper_style index zero
atom_style full
atom_modify map array
neigh_modify delay 2 every 2 check no
units ${units}
timestep 0.1
pair_style ${pair_style}
bond_style ${bond_style}
angle_style ${angle_style}
dihedral_style ${dihedral_style}
improper_style ${improper_style}
read_data ${data_file}
dihedral_coeff *
improper_coeff *

View File

@ -15,6 +15,17 @@ try:
except: except:
pass pass
has_full=False
try:
machine=None
if 'LAMMPS_MACHINE_NAME' in os.environ:
machine=os.environ['LAMMPS_MACHINE_NAME']
lmp=lammps(name=machine)
has_full = lmp.has_style("atom","full")
lmp.close()
except:
pass
try: try:
import numpy import numpy
NUMPY_INSTALLED = True NUMPY_INSTALLED = True
@ -32,6 +43,14 @@ class PythonNumpy(unittest.TestCase):
def tearDown(self): def tearDown(self):
del self.lmp del self.lmp
def checkBond(self, vals, btype, batom1, batom2):
if ((vals[1] == batom1 and vals[2] == batom2)
or (vals[1] == batom2 and vals[2] == batom1)):
self.assertEqual(vals[0], btype)
return 1
else:
return 0
def testLammpsPointer(self): def testLammpsPointer(self):
self.assertEqual(type(self.lmp.lmp), c_void_p) self.assertEqual(type(self.lmp.lmp), c_void_p)
@ -148,6 +167,50 @@ class PythonNumpy(unittest.TestCase):
self.assertTrue((x[1] == (1.0, 1.0, 1.5)).all()) self.assertTrue((x[1] == (1.0, 1.0, 1.5)).all())
self.assertEqual(len(v), 2) self.assertEqual(len(v), 2)
@unittest.skipIf(not has_full,"Gather bonds test")
def testGatherBond_newton_on(self):
self.lmp.command('shell cd ' + os.environ['TEST_INPUT_DIR'])
self.lmp.command("newton on on")
self.lmp.file("in.fourmol")
self.lmp.command("run 0 post no")
bonds = self.lmp.numpy.gather_bonds()
self.assertEqual(len(bonds),24)
count = 0
for bond in bonds:
count += self.checkBond(bond, 5, 1, 2)
count += self.checkBond(bond, 3, 1, 3)
count += self.checkBond(bond, 2, 3, 4)
count += self.checkBond(bond, 2, 3, 5)
count += self.checkBond(bond, 1, 6, 3)
count += self.checkBond(bond, 3, 6, 8)
count += self.checkBond(bond, 4, 6, 7)
count += self.checkBond(bond, 5, 8, 9)
count += self.checkBond(bond, 5, 27, 28)
count += self.checkBond(bond, 5, 29, 27)
self.assertEqual(count,10)
@unittest.skipIf(not has_full,"Gather bonds test")
def testGatherBond_newton_off(self):
self.lmp.command('shell cd ' + os.environ['TEST_INPUT_DIR'])
self.lmp.command("newton off off")
self.lmp.file("in.fourmol")
self.lmp.command("run 0 post no")
bonds = self.lmp.numpy.gather_bonds()
self.assertEqual(len(bonds),24)
count = 0
for bond in bonds:
count += self.checkBond(bond, 5, 1, 2)
count += self.checkBond(bond, 3, 1, 3)
count += self.checkBond(bond, 2, 3, 4)
count += self.checkBond(bond, 2, 3, 5)
count += self.checkBond(bond, 1, 6, 3)
count += self.checkBond(bond, 3, 6, 8)
count += self.checkBond(bond, 4, 6, 7)
count += self.checkBond(bond, 5, 8, 9)
count += self.checkBond(bond, 5, 27, 28)
count += self.checkBond(bond, 5, 29, 27)
self.assertEqual(count,10)
def testNeighborListSimple(self): def testNeighborListSimple(self):
self.lmp.commands_string(""" self.lmp.commands_string("""
units lj units lj

View File

@ -0,0 +1,90 @@
import sys,os,unittest
from lammps import lammps
has_full=False
try:
machine=None
if 'LAMMPS_MACHINE_NAME' in os.environ:
machine=os.environ['LAMMPS_MACHINE_NAME']
lmp=lammps(name=machine)
has_full = lmp.has_style("atom","full")
lmp.close()
except:
pass
class PythonGather(unittest.TestCase):
def setUp(self):
machine=None
if 'LAMMPS_MACHINE_NAME' in os.environ:
machine=os.environ['LAMMPS_MACHINE_NAME']
self.lmp=lammps(name=machine,
cmdargs=['-nocite',
'-log','none',
'-echo','screen'])
self.lmp.command('shell cd ' + os.environ['TEST_INPUT_DIR'])
# clean up temporary files
def tearDown(self):
self.lmp.close()
# bond data comparison
def checkBond(self, vals, btype, batom1, batom2):
if ((vals[1] == batom1 and vals[2] == batom2)
or (vals[1] == batom2 and vals[2] == batom1)):
self.assertEqual(vals[0], btype)
return 1
else:
return 0
##############################
@unittest.skipIf(not has_full, "Gather_bonds test")
def testGatherBond_newton_on(self):
"""Test gather_bonds() with newton on"""
self.lmp.command("newton on on")
self.lmp.file("in.fourmol")
self.lmp.command("run 0 post no")
nbonds, bonds = self.lmp.gather_bonds()
self.assertEqual(nbonds, 24)
self.assertEqual(len(bonds), 3*24)
count = 0;
for i in range(0,nbonds):
count += self.checkBond(bonds[3*i:3*i+3], 5, 1, 2)
count += self.checkBond(bonds[3*i:3*i+3], 3, 1, 3)
count += self.checkBond(bonds[3*i:3*i+3], 2, 3, 4)
count += self.checkBond(bonds[3*i:3*i+3], 2, 3, 5)
count += self.checkBond(bonds[3*i:3*i+3], 1, 6, 3)
count += self.checkBond(bonds[3*i:3*i+3], 3, 6, 8)
count += self.checkBond(bonds[3*i:3*i+3], 4, 6, 7)
count += self.checkBond(bonds[3*i:3*i+3], 5, 8, 9)
count += self.checkBond(bonds[3*i:3*i+3], 5, 27, 28)
count += self.checkBond(bonds[3*i:3*i+3], 5, 29, 27)
self.assertEqual(count,10)
@unittest.skipIf(not has_full, "Gather_bonds test")
def testGatherBond_newton_off(self):
"""Test gather_bonds() with newton off"""
self.lmp.command("newton off off")
self.lmp.file("in.fourmol")
self.lmp.command("run 0 post no")
nbonds, bonds = self.lmp.gather_bonds()
self.assertEqual(nbonds, 24)
self.assertEqual(len(bonds), 3*24)
count = 0;
for i in range(0,nbonds):
count += self.checkBond(bonds[3*i:3*i+3], 5, 1, 2)
count += self.checkBond(bonds[3*i:3*i+3], 3, 1, 3)
count += self.checkBond(bonds[3*i:3*i+3], 2, 3, 4)
count += self.checkBond(bonds[3*i:3*i+3], 2, 3, 5)
count += self.checkBond(bonds[3*i:3*i+3], 1, 3, 6)
count += self.checkBond(bonds[3*i:3*i+3], 3, 6, 8)
count += self.checkBond(bonds[3*i:3*i+3], 4, 6, 7)
count += self.checkBond(bonds[3*i:3*i+3], 5, 8, 9)
count += self.checkBond(bonds[3*i:3*i+3], 5, 27, 28)
count += self.checkBond(bonds[3*i:3*i+3], 5, 27, 29)
self.assertEqual(count,10)
##############################
if __name__ == "__main__":
unittest.main()