diff --git a/doc/src/Library_scatter.rst b/doc/src/Library_scatter.rst index 40a79c2d9b..b45f45f6fb 100644 --- a/doc/src/Library_scatter.rst +++ b/doc/src/Library_scatter.rst @@ -76,7 +76,7 @@ It documents the following functions: ----------------------- -.. doxygenfunction:: lammps_create_atoms(void *handle, int n, int *id, int *type, double *x, double *v, int *image, int bexpand) +.. doxygenfunction:: lammps_create_atoms(void *handle, int n, const int *id, const int *type, const double *x, const double *v, const int *image, int bexpand) :project: progguide diff --git a/doc/src/Python_module.rst b/doc/src/Python_module.rst index d2564986de..c19d4b0345 100644 --- a/doc/src/Python_module.rst +++ b/doc/src/Python_module.rst @@ -142,7 +142,7 @@ Style Constants Type Constants -------------- -.. py:data:: LMP_TYPE_SCALAR, LMP_TYLE_VECTOR, LMP_TYPE_ARRAY, LMP_SIZE_VECTOR, LMP_SIZE_ROWS, LMP_SIZE_COLS +.. py:data:: LMP_TYPE_SCALAR, LMP_TYPE_VECTOR, LMP_TYPE_ARRAY, LMP_SIZE_VECTOR, LMP_SIZE_ROWS, LMP_SIZE_COLS :type: int Constants in the :py:mod:`lammps` module to select what type of data diff --git a/doc/src/Python_neighbor.rst b/doc/src/Python_neighbor.rst index cba117ad20..00c4cc8996 100644 --- a/doc/src/Python_neighbor.rst +++ b/doc/src/Python_neighbor.rst @@ -1,6 +1,43 @@ Neighbor list access ==================== +Access to neighbor lists is handled through a couple of wrapper classes +that allows to treat it like either a python list or a NumPy array. The +access procedure is similar to that of the C-library interface: use one +of the "find" functions to look up the index of the neighbor list in the +global table of neighbor lists and then get access to the neighbor list +data. The code sample below demonstrates reading the neighbor list data +using the NumPy access method. + +.. code-block:: python + + from lammps import lammps + import numpy as np + + lmp = lammps() + lmp.commands_string(""" + region box block -2 2 -2 2 -2 2 + lattice fcc 1.0 + create_box 1 box + create_atoms 1 box + mass 1 1.0 + pair_style lj/cut 2.5 + pair_coeff 1 1 1.0 1.0 + run 0 post no""") + + # look up the neighbor list + nlidx = lmp.find_pair_neighlist('lj/cut') + nl = lmp.numpy.get_neighlist(nlidx) + tags = lmp.extract_atom('id') + print("half neighbor list with {} entries".format(nl.size)) + # print neighbor list contents + for i in range(0,nl.size): + idx, nlist = nl.get(i) + print("\natom {} with ID {} has {} neighbors:".format(idx,tags[idx],nlist.size)) + if nlist.size > 0: + for n in np.nditer(nlist): + print(" atom {} with ID {}".format(n,tags[n])) + **Methods:** * :py:meth:`lammps.get_neighlist() `: Get neighbor list for given index diff --git a/doc/src/fix_ave_histo.rst b/doc/src/fix_ave_histo.rst index d50112ac48..3a2857f383 100644 --- a/doc/src/fix_ave_histo.rst +++ b/doc/src/fix_ave_histo.rst @@ -138,8 +138,8 @@ vector or columns of the array had been listed one by one. E.g. these .. code-block:: LAMMPS compute myCOM all com/chunk - fix 1 all ave/histo 100 1 100 c_myCOM[*] file tmp1.com mode vector - fix 2 all ave/histo 100 1 100 c_myCOM[1] c_myCOM[2] c_myCOM[3] file tmp2.com mode vector + fix 1 all ave/histo 100 1 100 -10.0 10.0 100 c_myCOM[*] file tmp1.com mode vector + fix 2 all ave/histo 100 1 100 -10.0 10.0 100 c_myCOM[1] c_myCOM[2] c_myCOM[3] file tmp2.com mode vector If the fix ave/histo/weight command is used, exactly two values must be specified. If the values are vectors, they must be the same diff --git a/doc/utils/sphinx-config/false_positives.txt b/doc/utils/sphinx-config/false_positives.txt index 38a6971f4c..c10e978428 100644 --- a/doc/utils/sphinx-config/false_positives.txt +++ b/doc/utils/sphinx-config/false_positives.txt @@ -2681,6 +2681,7 @@ representable Reproducibility reproducibility repuls +reqid rescale rescaled rescales diff --git a/python/lammps/core.py b/python/lammps/core.py index 57cbfd0c10..1f606f67f4 100644 --- a/python/lammps/core.py +++ b/python/lammps/core.py @@ -1747,17 +1747,23 @@ class lammps(object): # ------------------------------------------------------------------------- - def find_pair_neighlist(self, style, exact=True, nsub=0, request=0): + def find_pair_neighlist(self, style, exact=True, nsub=0, reqid=0): """Find neighbor list index of pair style neighbor list - Try finding pair instance that matches style. If exact is set, the pair must - match style exactly. If exact is 0, style must only be contained. If pair is - of style pair/hybrid, style is instead matched the nsub-th hybrid sub-style. + Search for a neighbor list requested by a pair style instance that + matches "style". If exact is True, the pair style name must match + exactly. If exact is False, the pair style name is matched against + "style" as regular expression or sub-string. If the pair style is a + hybrid pair style, the style is instead matched against the hybrid + sub-styles. If the same pair style is used as sub-style multiple + types, you must set nsub to a value n > 0 which indicates the nth + instance of that sub-style to be used (same as for the pair_coeff + command). The default value of 0 will fail to match in that case. - Once the pair instance has been identified, multiple neighbor list requests - may be found. Every neighbor list is uniquely identified by its request - index. Thus, providing this request index ensures that the correct neighbor - list index is returned. + Once the pair style instance has been identified, it may have + requested multiple neighbor lists. Those are uniquely identified by + a request ID > 0 as set by the pair style. Otherwise the request + ID is 0. :param style: name of pair style that should be searched for :type style: string @@ -1765,44 +1771,58 @@ class lammps(object): :type exact: bool, optional :param nsub: match nsub-th hybrid sub-style, defaults to 0 :type nsub: int, optional - :param request: index of neighbor list request, in case there are more than one, defaults to 0 - :type request: int, optional + :param reqid: list request id, > 0 in case there are more than one, defaults to 0 + :type reqid: int, optional :return: neighbor list index if found, otherwise -1 :rtype: int - """ + + """ style = style.encode() exact = int(exact) - idx = self.lib.lammps_find_pair_neighlist(self.lmp, style, exact, nsub, request) + idx = self.lib.lammps_find_pair_neighlist(self.lmp, style, exact, nsub, reqid) return idx # ------------------------------------------------------------------------- - def find_fix_neighlist(self, fixid, request=0): + def find_fix_neighlist(self, fixid, reqid=0): """Find neighbor list index of fix neighbor list + The fix instance requesting the neighbor list is uniquely identified + by the fix ID. In case the fix has requested multiple neighbor + lists, those are uniquely identified by a request ID > 0 as set by + the fix. Otherwise the request ID is 0 (the default). + :param fixid: name of fix :type fixid: string - :param request: index of neighbor list request, in case there are more than one, defaults to 0 - :type request: int, optional + :param reqid: id of neighbor list request, in case there are more than one request, defaults to 0 + :type reqid: int, optional :return: neighbor list index if found, otherwise -1 :rtype: int - """ + + """ fixid = fixid.encode() - idx = self.lib.lammps_find_fix_neighlist(self.lmp, fixid, request) + idx = self.lib.lammps_find_fix_neighlist(self.lmp, fixid, reqid) return idx # ------------------------------------------------------------------------- - def find_compute_neighlist(self, computeid, request=0): + def find_compute_neighlist(self, computeid, reqid=0): """Find neighbor list index of compute neighbor list + The compute instance requesting the neighbor list is uniquely + identified by the compute ID. In case the compute has requested + multiple neighbor lists, those are uniquely identified by a request + ID > 0 as set by the compute. Otherwise the request ID is 0 (the + default). + :param computeid: name of compute :type computeid: string - :param request: index of neighbor list request, in case there are more than one, defaults to 0 - :type request: int, optional + :param reqid: index of neighbor list request, in case there are more than one request, defaults to 0 + :type reqid: int, optional :return: neighbor list index if found, otherwise -1 :rtype: int - """ + + """ computeid = computeid.encode() - idx = self.lib.lammps_find_compute_neighlist(self.lmp, computeid, request) + idx = self.lib.lammps_find_compute_neighlist(self.lmp, computeid, reqid) return idx diff --git a/python/lammps/data.py b/python/lammps/data.py index 2cf100ed82..892d628356 100644 --- a/python/lammps/data.py +++ b/python/lammps/data.py @@ -52,7 +52,9 @@ class NeighList: def get(self, element): """ - :return: tuple with atom local index, numpy array of neighbor local atom indices + Access a specific neighbor list entry. "element" must be a number from 0 to the size-1 of the list + + :return: tuple with atom local index, number of neighbors and ctypes pointer to neighbor's local atom indices :rtype: (int, int, ctypes.POINTER(c_int)) """ iatom, numneigh, neighbors = self.lmp.get_neighlist_element_neighbors(self.idx, element) @@ -71,3 +73,20 @@ class NeighList: for ii in range(inum): yield self.get(ii) + + def find(self, iatom): + """ + Find the neighbor list for a specific (local) atom iatom. + If there is no list for iatom, (-1, None) is returned. + + :return: tuple with number of neighbors and ctypes pointer to neighbor's local atom indices + :rtype: (int, ctypes.POINTER(c_int)) + """ + + inum = self.size + for ii in range(inum): + idx, numneigh, neighbors = self.get(ii) + if idx == iatom: + return numneigh, neighbors + + return -1, None diff --git a/python/lammps/numpy_wrapper.py b/python/lammps/numpy_wrapper.py index ce64d68c90..1ecaf3163b 100644 --- a/python/lammps/numpy_wrapper.py +++ b/python/lammps/numpy_wrapper.py @@ -331,8 +331,25 @@ class NumPyNeighList(NeighList): def get(self, element): """ + Access a specific neighbor list entry. "element" must be a number from 0 to the size-1 of the list + :return: tuple with atom local index, numpy array of neighbor local atom indices :rtype: (int, numpy.array) """ iatom, neighbors = self.lmp.numpy.get_neighlist_element_neighbors(self.idx, element) return iatom, neighbors + + def find(self, iatom): + """ + Find the neighbor list for a specific (local) atom iatom. + If there is no list for iatom, None is returned. + + :return: numpy array of neighbor local atom indices + :rtype: numpy.array or None + """ + inum = self.size + for ii in range(inum): + idx, neighbors = self.get(ii) + if idx == iatom: + return neighbors + return None diff --git a/src/USER-QUIP/pair_quip.cpp b/src/USER-QUIP/pair_quip.cpp index 2d338da158..20a6c98cb8 100644 --- a/src/USER-QUIP/pair_quip.cpp +++ b/src/USER-QUIP/pair_quip.cpp @@ -318,7 +318,6 @@ void PairQUIP::init_style() // Initialise neighbor list int irequest_full = neighbor->request(this); - neighbor->requests[irequest_full]->id = 1; neighbor->requests[irequest_full]->half = 0; neighbor->requests[irequest_full]->full = 1; } diff --git a/src/library.cpp b/src/library.cpp index b6341c058b..b72c8d7220 100644 --- a/src/library.cpp +++ b/src/library.cpp @@ -1615,7 +1615,7 @@ lists the available options. * \return pointer (cast to ``void *``) to the location of the * requested data or ``NULL`` if not found. */ -void *lammps_extract_compute(void *handle, char *id, int style, int type) +void *lammps_extract_compute(void *handle, const char *id, int style, int type) { LAMMPS *lmp = (LAMMPS *) handle; @@ -1801,7 +1801,7 @@ The following table lists the available options. * \return pointer (cast to ``void *``) to the location of the * requested data or ``NULL`` if not found. */ -void *lammps_extract_fix(void *handle, char *id, int style, int type, +void *lammps_extract_fix(void *handle, const char *id, int style, int type, int nrow, int ncol) { LAMMPS *lmp = (LAMMPS *) handle; @@ -3822,8 +3822,8 @@ X(1),Y(1),Z(1),X(2),Y(2),Z(2),...,X(N),Y(N),Z(N). * \return number of atoms created on success; -1 on failure (no box, no atom IDs, etc.) */ -int lammps_create_atoms(void *handle, int n, tagint *id, int *type, - double *x, double *v, imageint *image, +int lammps_create_atoms(void *handle, int n, const tagint *id, const int *type, + const double *x, const double *v, const imageint *image, int bexpand) { LAMMPS *lmp = (LAMMPS *) handle; @@ -3859,13 +3859,17 @@ int lammps_create_atoms(void *handle, int n, tagint *id, int *type, int nlocal_prev = nlocal; double xdata[3]; + imageint idata, *img; for (int i = 0; i < n; i++) { xdata[0] = x[3*i]; xdata[1] = x[3*i+1]; xdata[2] = x[3*i+2]; - imageint * img = image ? image + i : nullptr; - tagint tag = id ? id[i] : 0; + if (image) { + idata = image[i]; + img = &idata; + } else img = nullptr; + const tagint tag = id ? id[i] : 0; // create atom only on MPI rank that would own it @@ -3917,40 +3921,43 @@ int lammps_create_atoms(void *handle, int n, tagint *id, int *type, // Library functions for accessing neighbor lists // ---------------------------------------------------------------------- -/** Find neighbor list index of pair style neighbor list +/** Find index of a neighbor list requested by a pair style * - * Try finding pair instance that matches style. If exact is set, the pair must - * match style exactly. If exact is 0, style must only be contained. If pair is - * of style pair/hybrid, style is instead matched the nsub-th hybrid sub-style. + * This function determines which of the available neighbor lists for + * pair styles matches the given conditions. It first matches the style + * name. If exact is 1 the name must match exactly, if exact is 0, a + * regular expression or sub-string match is done. If the pair style is + * hybrid or hybrid/overlay the style is matched against the sub styles + * instead. + * If a the same pair style is used multiple times as a sub-style, the + * nsub argument must be > 0 and represents the nth instance of the sub-style + * (same as for the pair_coeff command, for example). In that case + * nsub=0 will not produce a match and this function will return -1. * - * Once the pair instance has been identified, multiple neighbor list requests - * may be found. Every neighbor list is uniquely identified by its request - * index. Thus, providing this request index ensures that the correct neighbor - * list index is returned. + * The final condition to be checked is the request ID (reqid). This + * will normally be 0, but some pair styles request multiple neighbor + * lists and set the request ID to a value > 0. * * \param handle pointer to a previously created LAMMPS instance cast to ``void *``. * \param style String used to search for pair style instance * \param exact Flag to control whether style should match exactly or only - * must be contained in pair style name - * \param nsub match nsub-th hybrid sub-style - * \param request request index that specifies which neighbor list should be - * returned, in case there are multiple neighbor lists requests - * for the found pair style + * a regular expression / sub-string match is applied. + * \param nsub match nsub-th hybrid sub-style instance of the same style + * \param reqid request id to identify neighbor list in case there are + * multiple requests from the same pair style instance * \return return neighbor list index if found, otherwise -1 */ -int lammps_find_pair_neighlist(void* handle, char * style, int exact, int nsub, int request) { - LAMMPS * lmp = (LAMMPS *) handle; - Pair* pair = lmp->force->pair_match(style, exact, nsub); +int lammps_find_pair_neighlist(void *handle, const char *style, int exact, int nsub, int reqid) { + LAMMPS *lmp = (LAMMPS *) handle; + Pair *pair = lmp->force->pair_match(style, exact, nsub); if (pair != nullptr) { // find neigh list for (int i = 0; i < lmp->neighbor->nlist; i++) { - NeighList * list = lmp->neighbor->lists[i]; - if (list->requestor_type != NeighList::PAIR || pair != list->requestor) continue; - - if (list->index == request) { - return i; - } + NeighList *list = lmp->neighbor->lists[i]; + if ( (list->requestor_type == NeighList::PAIR) + && (pair == list->requestor) + && (list->id == reqid) ) return i; } } return -1; @@ -3958,74 +3965,60 @@ int lammps_find_pair_neighlist(void* handle, char * style, int exact, int nsub, /* ---------------------------------------------------------------------- */ -/** Find neighbor list index of fix neighbor list +/** Find index of a neighbor list requested by a fix + * + * The neighbor list request from a fix is identified by the fix ID and + * the request ID. The request ID is typically 0, but will be > 0 in + * case a fix has multiple neighbor list requests. * * \param handle pointer to a previously created LAMMPS instance cast to ``void *``. * \param id Identifier of fix instance - * \param request request index that specifies which request should be returned, - * in case there are multiple neighbor lists for this fix + * \param reqid request id to identify neighbor list in case there are + * multiple requests from the same fix * \return return neighbor list index if found, otherwise -1 */ -int lammps_find_fix_neighlist(void* handle, char *id, int request) { - LAMMPS * lmp = (LAMMPS *) handle; - Fix* fix = nullptr; - const int nfix = lmp->modify->nfix; +int lammps_find_fix_neighlist(void *handle, const char *id, int reqid) { + LAMMPS *lmp = (LAMMPS *) handle; + const int ifix = lmp->modify->find_fix(id); + if (ifix < 0) return -1; - // find fix with name - for (int ifix = 0; ifix < nfix; ifix++) { - if (strcmp(lmp->modify->fix[ifix]->id, id) == 0) { - fix = lmp->modify->fix[ifix]; - break; - } - } - - if (fix != nullptr) { - // find neigh list - for (int i = 0; i < lmp->neighbor->nlist; i++) { - NeighList * list = lmp->neighbor->lists[i]; - if (list->requestor_type != NeighList::FIX || fix != list->requestor) continue; - - if (list->index == request) { - return i; - } - } + Fix *fix = lmp->modify->fix[ifix]; + // find neigh list + for (int i = 0; i < lmp->neighbor->nlist; i++) { + NeighList *list = lmp->neighbor->lists[i]; + if ( (list->requestor_type == NeighList::FIX) + && (fix == list->requestor) + && (list->id == reqid) ) return i; } return -1; } /* ---------------------------------------------------------------------- */ -/** Find neighbor list index of compute neighbor list +/** Find index of a neighbor list requested by a compute + * + * The neighbor list request from a compute is identified by the compute + * ID and the request ID. The request ID is typically 0, but will be + * > 0 in case a compute has multiple neighbor list requests. * * \param handle pointer to a previously created LAMMPS instance cast to ``void *``. - * \param id Identifier of fix instance - * \param request request index that specifies which request should be returned, - * in case there are multiple neighbor lists for this fix + * \param id Identifier of compute instance + * \param reqid request id to identify neighbor list in case there are + * multiple requests from the same compute * \return return neighbor list index if found, otherwise -1 */ -int lammps_find_compute_neighlist(void* handle, char *id, int request) { - LAMMPS * lmp = (LAMMPS *) handle; - Compute* compute = nullptr; - const int ncompute = lmp->modify->ncompute; +int lammps_find_compute_neighlist(void* handle, const char *id, int reqid) { + LAMMPS *lmp = (LAMMPS *) handle; + const int icompute = lmp->modify->find_compute(id); + if (icompute < 0) return -1; - // find compute with name - for (int icompute = 0; icompute < ncompute; icompute++) { - if (strcmp(lmp->modify->compute[icompute]->id, id) == 0) { - compute = lmp->modify->compute[icompute]; - break; - } - } - - if (compute != nullptr) { - // find neigh list - for (int i = 0; i < lmp->neighbor->nlist; i++) { - NeighList * list = lmp->neighbor->lists[i]; - if (list->requestor_type != NeighList::COMPUTE || compute != list->requestor) continue; - - if (list->index == request) { - return i; - } - } + Compute *compute = lmp->modify->compute[icompute]; + // find neigh list + for (int i = 0; i < lmp->neighbor->nlist; i++) { + NeighList * list = lmp->neighbor->lists[i]; + if ( (list->requestor_type == NeighList::COMPUTE) + && (compute == list->requestor) + && (list->id == reqid) ) return i; } return -1; } diff --git a/src/library.h b/src/library.h index 11cd72388a..8db19f7eb2 100644 --- a/src/library.h +++ b/src/library.h @@ -138,8 +138,8 @@ void *lammps_extract_atom(void *handle, const char *name); * Library functions to access data from computes, fixes, variables in LAMMPS * ---------------------------------------------------------------------- */ -void *lammps_extract_compute(void *handle, char *id, int, int); -void *lammps_extract_fix(void *handle, char *, int, int, int, int); +void *lammps_extract_compute(void *handle, const char *, int, int); +void *lammps_extract_fix(void *handle, const char *, int, int, int, int); void *lammps_extract_variable(void *handle, const char *, const char *); int lammps_set_variable(void *, char *, char *); @@ -160,20 +160,20 @@ void lammps_scatter(void *handle, char *name, int type, int count, void *data); void lammps_scatter_subset(void *handle, char *name, int type, int count, int ndata, int *ids, void *data); #if !defined(LAMMPS_BIGBIG) -int lammps_create_atoms(void *handle, int n, int *id, int *type, - double *x, double *v, int *image, int bexpand); +int lammps_create_atoms(void *handle, int n, const int *id, const int *type, + const double *x, const double *v, const int *image, int bexpand); #else -int lammps_create_atoms(void *handle, int n, int64_t *id, int *type, - double *x, double *v, int64_t* image, int bexpand); +int lammps_create_atoms(void *handle, int n, const int64_t *id, const int *type, + const double *x, const double *v, const int64_t* image, int bexpand); #endif /* ---------------------------------------------------------------------- * Library functions for accessing neighbor lists * ---------------------------------------------------------------------- */ -int lammps_find_pair_neighlist(void *handle, char *style, int exact, int nsub, int request); -int lammps_find_fix_neighlist(void *handle, char *id, int request); -int lammps_find_compute_neighlist(void *handle, char *id, int request); +int lammps_find_pair_neighlist(void *handle, const char *style, int exact, int nsub, int request); +int lammps_find_fix_neighlist(void *handle, const char *id, int request); +int lammps_find_compute_neighlist(void *handle, const char *id, int request); int lammps_neighlist_num_elements(void *handle, int idx); void lammps_neighlist_element_neighbors(void *handle, int idx, int element, int *iatom, int *numneigh, int **neighbors); diff --git a/src/neigh_list.cpp b/src/neigh_list.cpp index 308ecbbf6e..a51ecb7518 100644 --- a/src/neigh_list.cpp +++ b/src/neigh_list.cpp @@ -143,6 +143,7 @@ void NeighList::post_constructor(NeighRequest *nq) respamiddle = nq->respamiddle; respainner = nq->respainner; copy = nq->copy; + id = nq->id; if (nq->copy) { listcopy = neighbor->lists[nq->copylist]; diff --git a/src/neigh_list.h b/src/neigh_list.h index d69b844dc8..ad8e104f2a 100644 --- a/src/neigh_list.h +++ b/src/neigh_list.h @@ -44,6 +44,7 @@ class NeighList : protected Pointers { int copy; // 1 if this list is copied from another list int kk2cpu; // 1 if this list is copied from Kokkos to CPU int copymode; // 1 if this is a Kokkos on-device copy + int id; // copied from neighbor list request // data structs to store neighbor pairs I,J and associated values diff --git a/unittest/c-library/CMakeLists.txt b/unittest/c-library/CMakeLists.txt index 121c42f7fd..3c24cdcff4 100644 --- a/unittest/c-library/CMakeLists.txt +++ b/unittest/c-library/CMakeLists.txt @@ -11,6 +11,7 @@ add_executable(test_library_properties test_library_properties.cpp test_main.cpp target_link_libraries(test_library_properties PRIVATE lammps GTest::GTest GTest::GMock) target_compile_definitions(test_library_properties PRIVATE -DTEST_INPUT_FOLDER=${CMAKE_CURRENT_SOURCE_DIR}) add_test(LibraryProperties test_library_properties) +set_tests_properties(LibraryProperties PROPERTIES ENVIRONMENT "LAMMPS_POTENTIALS=${LAMMPS_POTENTIALS_DIR}") set(TEST_CONFIG_DEFS "-DTEST_INPUT_FOLDER=${CMAKE_CURRENT_SOURCE_DIR};-DLAMMPS_${LAMMPS_SIZES}") set(PKG_COUNT 0) diff --git a/unittest/c-library/test_library_properties.cpp b/unittest/c-library/test_library_properties.cpp index 182beee7d0..07e920bda7 100644 --- a/unittest/c-library/test_library_properties.cpp +++ b/unittest/c-library/test_library_properties.cpp @@ -160,7 +160,9 @@ TEST_F(LibraryProperties, box) boxlo[0] = -6.1; boxhi[1] = 7.3; xy = 0.1; + if (!verbose) ::testing::internal::CaptureStdout(); lammps_reset_box(lmp, boxlo, boxhi, xy, yz, xz); + if (!verbose) ::testing::internal::GetCapturedStdout(); lammps_extract_box(lmp, boxlo, boxhi, &xy, &yz, &xz, pflags, &boxflag); EXPECT_DOUBLE_EQ(boxlo[0], -6.1); EXPECT_DOUBLE_EQ(boxlo[1], -7.692866); @@ -313,6 +315,121 @@ TEST_F(LibraryProperties, global) EXPECT_DOUBLE_EQ((*d_ptr), 0.1); }; +TEST_F(LibraryProperties, neighlist) +{ + if (!lammps_has_style(lmp, "pair", "sw")) GTEST_SKIP(); + const char sysinit[] = "boundary f f f\n" + "units real\n" + "region box block -5 5 -5 5 -5 5\n" + "create_box 2 box\n" + "mass 1 1.0\n" + "mass 2 1.0\n" + "pair_style hybrid/overlay lj/cut 4.0 lj/cut 4.0 morse 4.0 sw\n" + "pair_coeff * * sw Si.sw Si NULL\n" + "pair_coeff 1 2 morse 0.2 2.0 2.0\n" + "pair_coeff 2 2 lj/cut 1 0.1 2.0\n" + "pair_coeff * * lj/cut 2 0.01 2.0\n" + "compute dist all pair/local dist\n" + "fix dist all ave/histo 1 1 1 0.0 3.0 4 c_dist mode vector\n" + "thermo_style custom f_dist[*]"; + + const double pos[] = {0.0, 0.0, 0.0, -1.1, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, -1.1, + 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, -1.1, 0.0, 0.0, 1.0}; + const tagint ids[] = {1, 2, 3, 4, 5, 6, 7}; + const int types[] = {1, 1, 1, 1, 2, 2, 2}; + + const int numatoms = sizeof(ids) / sizeof(tagint); + + if (!verbose) ::testing::internal::CaptureStdout(); + lammps_commands_string(lmp, sysinit); + lammps_create_atoms(lmp, numatoms, ids, types, pos, nullptr, nullptr, 0); + lammps_command(lmp, "run 0 post no"); + if (!verbose) ::testing::internal::GetCapturedStdout(); + + int nhisto = + *(double *)lammps_extract_fix(lmp, "dist", LMP_STYLE_GLOBAL, LMP_TYPE_VECTOR, 0, 0); + int nskip = *(double *)lammps_extract_fix(lmp, "dist", LMP_STYLE_GLOBAL, LMP_TYPE_VECTOR, 1, 0); + double minval = + *(double *)lammps_extract_fix(lmp, "dist", LMP_STYLE_GLOBAL, LMP_TYPE_VECTOR, 2, 0); + double maxval = + *(double *)lammps_extract_fix(lmp, "dist", LMP_STYLE_GLOBAL, LMP_TYPE_VECTOR, 3, 0); + // 21 pair distances counted, none skipped, smallest 1.0, largest 2.1 + EXPECT_EQ(nhisto, 21); + EXPECT_EQ(nskip, 0); + EXPECT_DOUBLE_EQ(minval, 1.0); + EXPECT_DOUBLE_EQ(maxval, 2.1); + + const int nlocal = lammps_extract_setting(lmp, "nlocal"); + EXPECT_EQ(nlocal, numatoms); + EXPECT_NE(lammps_find_pair_neighlist(lmp, "sw", 1, 0, 0), -1); + EXPECT_NE(lammps_find_pair_neighlist(lmp, "morse", 1, 0, 0), -1); + EXPECT_NE(lammps_find_pair_neighlist(lmp, "lj/cut", 1, 1, 0), -1); + EXPECT_NE(lammps_find_pair_neighlist(lmp, "lj/cut", 1, 2, 0), -1); + EXPECT_EQ(lammps_find_pair_neighlist(lmp, "lj/cut", 1, 0, 0), -1); + EXPECT_EQ(lammps_find_pair_neighlist(lmp, "hybrid/overlay", 1, 0, 0), -1); + EXPECT_NE(lammps_find_compute_neighlist(lmp, "dist", 0), -1); + EXPECT_EQ(lammps_find_fix_neighlist(lmp, "dist", 0), -1); + EXPECT_EQ(lammps_find_compute_neighlist(lmp, "xxx", 0), -1); + + // full neighbor list for 4 type 1 atoms + // all have 3 type 1 atom neighbors + int idx = lammps_find_pair_neighlist(lmp, "sw", 1, 0, 0); + int num = lammps_neighlist_num_elements(lmp, idx); + EXPECT_EQ(num, 4); + int iatom, inum, *neighbors; + for (int i = 0; i < num; ++i) { + lammps_neighlist_element_neighbors(lmp, idx, i, &iatom, &inum, &neighbors); + EXPECT_EQ(iatom, i); + EXPECT_EQ(inum, 3); + EXPECT_NE(neighbors, nullptr); + } + + // half neighbor list for all pairs between type 1 and type 2 + // 4 type 1 atoms with 3 type 2 neighbors and 3 type 2 atoms without neighbors + idx = lammps_find_pair_neighlist(lmp, "morse", 0, 0, 0); + num = lammps_neighlist_num_elements(lmp, idx); + EXPECT_EQ(num, nlocal); + for (int i = 0; i < num; ++i) { + lammps_neighlist_element_neighbors(lmp, idx, i, &iatom, &inum, &neighbors); + if (i < 4) + EXPECT_EQ(inum, 3); + else + EXPECT_EQ(inum, 0); + EXPECT_NE(neighbors, nullptr); + } + + // half neighbor list between type 2 atoms only + // 3 pairs with 2, 1, 0 neighbors + idx = lammps_find_pair_neighlist(lmp, "lj/cut", 1, 1, 0); + num = lammps_neighlist_num_elements(lmp, idx); + EXPECT_EQ(num, 3); + for (int i = 0; i < num; ++i) { + lammps_neighlist_element_neighbors(lmp, idx, i, &iatom, &inum, &neighbors); + EXPECT_EQ(inum, 2 - i); + EXPECT_NE(neighbors, nullptr); + } + + // half neighbor list between all pairs. same as simple lj/cut case + idx = lammps_find_pair_neighlist(lmp, "lj/cut", 1, 2, 0); + num = lammps_neighlist_num_elements(lmp, idx); + EXPECT_EQ(num, nlocal); + for (int i = 0; i < num; ++i) { + lammps_neighlist_element_neighbors(lmp, idx, i, &iatom, &inum, &neighbors); + EXPECT_EQ(inum, nlocal - 1 - i); + EXPECT_NE(neighbors, nullptr); + } + + // the compute has a half neighbor list + idx = lammps_find_compute_neighlist(lmp, "dist", 0); + num = lammps_neighlist_num_elements(lmp, idx); + EXPECT_EQ(num, nlocal); + for (int i = 0; i < num; ++i) { + lammps_neighlist_element_neighbors(lmp, idx, i, &iatom, &inum, &neighbors); + EXPECT_EQ(inum, nlocal - 1 - i); + EXPECT_NE(neighbors, nullptr); + } +}; + class AtomProperties : public ::testing::Test { protected: void *lmp; diff --git a/unittest/python/CMakeLists.txt b/unittest/python/CMakeLists.txt index d1db17c941..b51d6e340a 100644 --- a/unittest/python/CMakeLists.txt +++ b/unittest/python/CMakeLists.txt @@ -28,6 +28,7 @@ endif() if(Python_EXECUTABLE) # 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}) + list(APPEND PYTHON_TEST_ENVIRONMENT "LAMMPS_POTENTIALS=${LAMMPS_POTENTIALS_DIR}") 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") else() diff --git a/unittest/python/python-commands.py b/unittest/python/python-commands.py index 3661feb8a0..f3526d6d4b 100644 --- a/unittest/python/python-commands.py +++ b/unittest/python/python-commands.py @@ -1,6 +1,17 @@ import sys,os,unittest -from lammps import lammps, LMP_VAR_ATOM +from lammps import lammps, LMP_VAR_ATOM, LMP_STYLE_GLOBAL, LMP_TYPE_VECTOR + +has_manybody=False +try: + machine=None + if 'LAMMPS_MACHINE_NAME' in os.environ: + machine=os.environ['LAMMPS_MACHINE_NAME'] + lmp=lammps(name=machine) + has_manybody = lmp.has_style("pair","sw") + lmp.close() +except: + pass class PythonCommand(unittest.TestCase): @@ -85,36 +96,35 @@ create_atoms 1 single & natoms = self.lmp.get_natoms() self.assertEqual(natoms,2) - def testNeighborList(self): - self.lmp.command("units lj") - self.lmp.command("atom_style atomic") - self.lmp.command("atom_modify map array") - self.lmp.command("boundary f f f") - self.lmp.command("region box block 0 2 0 2 0 2") - self.lmp.command("create_box 1 box") - - x = [ - 1.0, 1.0, 1.0, - 1.0, 1.0, 1.5 - ] + def testNeighborListSimple(self): + self.lmp.commands_string(""" + units lj + atom_style atomic + atom_modify map array + boundary f f f + region box block 0 2 0 2 0 2 + create_box 1 box""") + x = [ 1.0, 1.0, 1.0, 1.0, 1.0, 1.5 ] types = [1, 1] self.assertEqual(self.lmp.create_atoms(2, id=None, type=types, x=x), 2) nlocal = self.lmp.extract_global("nlocal") self.assertEqual(nlocal, 2) - self.lmp.command("mass 1 1.0") - self.lmp.command("velocity all create 3.0 87287") - self.lmp.command("pair_style lj/cut 2.5") - self.lmp.command("pair_coeff 1 1 1.0 1.0 2.5") - self.lmp.command("neighbor 0.1 bin") - self.lmp.command("neigh_modify every 20 delay 0 check no") + self.lmp.commands_string(""" + mass 1 1.0 + velocity all create 3.0 87287 + pair_style lj/cut 2.5 + pair_coeff 1 1 1.0 1.0 2.5 + neighbor 0.1 bin + neigh_modify every 20 delay 0 check no + run 0 post no""") - self.lmp.command("run 0") - - self.assertEqual(self.lmp.find_pair_neighlist("lj/cut"), 0) - nlist = self.lmp.get_neighlist(0) + idx = self.lmp.find_pair_neighlist("lj/cut") + self.assertNotEqual(idx, -1) + self.assertEqual(self.lmp.find_pair_neighlist("morse"), -1) + nlist = self.lmp.get_neighlist(idx) self.assertEqual(len(nlist), 2) atom_i, numneigh_i, neighbors_i = nlist[0] atom_j, numneigh_j, _ = nlist[1] @@ -127,6 +137,193 @@ create_atoms 1 single & self.assertEqual(1, neighbors_i[0]) + def testNeighborListHalf(self): + self.lmp.commands_string(""" + boundary f f f + units real + region box block -5 5 -5 5 -5 5 + create_box 1 box + mass 1 1.0 + pair_style lj/cut 4.0 + pair_coeff 1 1 0.2 2.0 + """) + x = [ 0.0, 0.0, 0.0, -1.1, 0.0, 0.0, 1.0, 0.0, 0.0, + 0.0, -1.1, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, -1.1, + 0.0, 0.0, 1.0 ] + tags = [1, 2, 3, 4, 5, 6, 7] + types = [1, 1, 1, 1, 1, 1, 1] + + self.assertEqual(self.lmp.create_atoms(7, id=tags, type=types, x=x), 7) + nlocal = self.lmp.extract_global("nlocal") + self.assertEqual(nlocal, 7) + + self.lmp.command("run 0 post no") + + self.assertEqual(self.lmp.find_pair_neighlist("lj/cut"),0) + nlist = self.lmp.get_neighlist(0) + self.assertEqual(nlist.size, 7) + for i in range(0,nlist.size): + idx, num, neighs = nlist.get(i) + self.assertEqual(idx,i) + self.assertEqual(num,nlocal-1-i) + + # look up neighbor list by atom index + num, neighs = nlist.find(2) + self.assertEqual(num,4) + self.assertIsNotNone(neighs,None) + # this one will fail + num, neighs = nlist.find(10) + self.assertEqual(num,-1) + self.assertIsNone(neighs,None) + + @unittest.skipIf(not has_manybody,"Full neighbor list test for manybody potential") + def testNeighborListFull(self): + self.lmp.commands_string(""" + boundary f f f + units metal + region box block -5 5 -5 5 -5 5 + create_box 1 box + mass 1 1.0 + pair_style sw + pair_coeff * * Si.sw Si + """) + x = [ 0.0, 0.0, 0.0, -1.1, 0.0, 0.0, 1.0, 0.0, 0.0, + 0.0, -1.1, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, -1.1, + 0.0, 0.0, 1.0 ] + tags = [1, 2, 3, 4, 5, 6, 7] + types = [1, 1, 1, 1, 1, 1, 1] + + self.assertEqual(self.lmp.create_atoms(7, id=tags, type=types, x=x), 7) + nlocal = self.lmp.extract_global("nlocal") + self.assertEqual(nlocal, 7) + + self.lmp.command("run 0 post no") + + self.assertEqual(self.lmp.find_pair_neighlist("sw"),0) + nlist = self.lmp.get_neighlist(0) + self.assertEqual(nlist.size, 7) + for i in range(0,nlist.size): + idx, num, neighs = nlist.get(i) + self.assertEqual(idx,i) + self.assertEqual(num,nlocal-1) + + @unittest.skipIf(not has_manybody,"Hybrid neighbor list test for manybody potential") + def testNeighborListHybrid(self): + self.lmp.commands_string(""" + boundary f f f + units metal + region box block -5 5 -5 5 -5 5 + create_box 2 box + mass * 1.0 + pair_style hybrid/overlay morse 4.0 lj/cut 4.0 lj/cut 4.0 sw + pair_coeff * * sw Si.sw Si NULL + pair_coeff 1 2 morse 0.2 2.0 2.0 + pair_coeff 2 2 lj/cut 1 0.1 2.0 + pair_coeff * * lj/cut 2 0.01 2.0 + """) + x = [ 0.0, 0.0, 0.0, -1.1, 0.0, 0.0, 1.0, 0.0, 0.0, + 0.0, -1.1, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, -1.1, + 0.0, 0.0, 1.0 ] + tags = [1, 2, 3, 4, 5, 6, 7] + types = [1, 1, 1, 1, 2, 2, 2] + + self.assertEqual(self.lmp.create_atoms(7, id=tags, type=types, x=x), 7) + nlocal = self.lmp.extract_global("nlocal") + self.assertEqual(nlocal, 7) + + self.lmp.command("run 0 post no") + + # valid and invalid lookups + self.assertNotEqual(self.lmp.find_pair_neighlist("sw"),-1) + self.assertNotEqual(self.lmp.find_pair_neighlist("morse"),-1) + self.assertNotEqual(self.lmp.find_pair_neighlist("lj/cut",nsub=1),-1) + self.assertNotEqual(self.lmp.find_pair_neighlist("lj/cut",nsub=2),-1) + self.assertEqual(self.lmp.find_pair_neighlist("lj/cut"),-1) + self.assertEqual(self.lmp.find_pair_neighlist("hybrid/overlay"),-1) + self.assertNotEqual(self.lmp.get_neighlist(4).size,0) + self.assertEqual(self.lmp.get_neighlist(5).size,-1) + + # full neighbor list for 4 type 1 atoms + # all have 3 type 1 atom neighbors + nlist = self.lmp.get_neighlist(self.lmp.find_pair_neighlist("sw")) + self.assertEqual(nlist.size, 4) + for i in range(0,nlist.size): + idx, num, neighs = nlist.get(i) + self.assertEqual(idx,i) + self.assertEqual(num,3) + + # half neighbor list for all pairs between type 1 and type 2 + # 4 type 1 atoms with 3 type 2 neighbors and 3 type 2 atoms without neighbors + nlist = self.lmp.get_neighlist(self.lmp.find_pair_neighlist("morse")) + self.assertEqual(nlist.size, 7) + for i in range(0,nlist.size): + idx, num, neighs = nlist.get(i) + if (i < 4): self.assertEqual(num,3) + else: self.assertEqual(num,0) + + # half neighbor list between type 2 atoms only + # 3 pairs with 2, 1, 0 neighbors + nlist = self.lmp.get_neighlist(self.lmp.find_pair_neighlist("lj/cut",nsub=1)) + self.assertEqual(nlist.size, 3) + for i in range(0,nlist.size): + idx, num, neighs = nlist.get(i) + self.assertEqual(num,2-i) + + # half neighbor list between all pairs. same as simple lj/cut case + nlist = self.lmp.get_neighlist(self.lmp.find_pair_neighlist("lj/cut",nsub=2)) + self.assertEqual(nlist.size, 7) + for i in range(0,nlist.size): + idx, num, neighs = nlist.get(i) + self.assertEqual(num,nlocal-1-i) + + def testNeighborListCompute(self): + self.lmp.commands_string(""" + boundary f f f + units real + region box block -5 5 -5 5 -5 5 + create_box 1 box + mass 1 1.0 + pair_style lj/cut 4.0 + pair_coeff 1 1 0.2 2.0 + compute dist all pair/local dist + fix dist all ave/histo 1 1 1 0.0 3.0 4 c_dist mode vector + thermo_style custom f_dist[*] + """) + x = [ 0.0, 0.0, 0.0, -1.1, 0.0, 0.0, 1.0, 0.0, 0.0, + 0.0, -1.1, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, -1.1, + 0.0, 0.0, 1.0 ] + tags = [1, 2, 3, 4, 5, 6, 7] + types = [1, 1, 1, 1, 1, 1, 1] + + self.assertEqual(self.lmp.create_atoms(7, id=tags, type=types, x=x), 7) + nlocal = self.lmp.extract_global("nlocal") + self.assertEqual(nlocal, 7) + + self.lmp.command("run 0 post no") + # check compute data from histogram summary + nhisto = self.lmp.extract_fix("dist",LMP_STYLE_GLOBAL,LMP_TYPE_VECTOR,nrow=0) + nskip = self.lmp.extract_fix("dist",LMP_STYLE_GLOBAL,LMP_TYPE_VECTOR,nrow=1) + minval = self.lmp.extract_fix("dist",LMP_STYLE_GLOBAL,LMP_TYPE_VECTOR,nrow=2) + maxval = self.lmp.extract_fix("dist",LMP_STYLE_GLOBAL,LMP_TYPE_VECTOR,nrow=3) + # 21 pair distances counted, none skipped, smallest 1.0, largest 2.1 + self.assertEqual(nhisto,21) + self.assertEqual(nskip,0) + self.assertEqual(minval,1.0) + self.assertEqual(maxval,2.1) + + self.assertNotEqual(self.lmp.find_pair_neighlist("lj/cut"),-1) + self.assertNotEqual(self.lmp.find_compute_neighlist("dist"),-1) + self.assertEqual(self.lmp.find_compute_neighlist("xxx"),-1) + self.assertEqual(self.lmp.find_fix_neighlist("dist"),-1) + + # the compute has a half neighbor list + nlist = self.lmp.get_neighlist(self.lmp.find_compute_neighlist("dist")) + self.assertEqual(nlist.size, 7) + for i in range(0,nlist.size): + idx, num, neighs = nlist.get(i) + self.assertEqual(idx,i) + self.assertEqual(num,nlocal-1-i) + def test_extract_box_non_periodic(self): self.lmp.command("boundary f f f") self.lmp.command("region box block 0 2 0 2 0 2") diff --git a/unittest/python/python-numpy.py b/unittest/python/python-numpy.py index 9f1d5f12c8..dc121691ab 100644 --- a/unittest/python/python-numpy.py +++ b/unittest/python/python-numpy.py @@ -4,6 +4,17 @@ from lammps import lammps, LAMMPS_INT, LMP_STYLE_GLOBAL, LMP_STYLE_LOCAL, \ LMP_VAR_ATOM from ctypes import c_void_p +has_manybody=False +try: + machine=None + if 'LAMMPS_MACHINE_NAME' in os.environ: + machine=os.environ['LAMMPS_MACHINE_NAME'] + lmp=lammps(name=machine) + has_manybody = lmp.has_style("pair","sw") + lmp.close() +except: + pass + try: import numpy NUMPY_INSTALLED = True @@ -137,36 +148,34 @@ class PythonNumpy(unittest.TestCase): self.assertTrue((x[1] == (1.0, 1.0, 1.5)).all()) self.assertEqual(len(v), 2) - def testNeighborList(self): - self.lmp.command("units lj") - self.lmp.command("atom_style atomic") - self.lmp.command("atom_modify map array") - self.lmp.command("boundary f f f") - self.lmp.command("region box block 0 2 0 2 0 2") - self.lmp.command("create_box 1 box") - - x = [ - 1.0, 1.0, 1.0, - 1.0, 1.0, 1.5 - ] + def testNeighborListSimple(self): + self.lmp.commands_string(""" + units lj + atom_style atomic + atom_modify map array + boundary f f f + region box block 0 2 0 2 0 2 + create_box 1 box""") + x = [ 1.0, 1.0, 1.0, 1.0, 1.0, 1.5 ] types = [1, 1] self.assertEqual(self.lmp.create_atoms(2, id=None, type=types, x=x), 2) nlocal = self.lmp.extract_global("nlocal") self.assertEqual(nlocal, 2) - self.lmp.command("mass 1 1.0") - self.lmp.command("velocity all create 3.0 87287") - self.lmp.command("pair_style lj/cut 2.5") - self.lmp.command("pair_coeff 1 1 1.0 1.0 2.5") - self.lmp.command("neighbor 0.1 bin") - self.lmp.command("neigh_modify every 20 delay 0 check no") + self.lmp.commands_string(""" + mass 1 1.0 + velocity all create 3.0 87287 + pair_style lj/cut 2.5 + pair_coeff 1 1 1.0 1.0 2.5 + neighbor 0.1 bin + neigh_modify every 20 delay 0 check no + run 0 post no""") - self.lmp.command("run 0") - - self.assertEqual(self.lmp.find_pair_neighlist("lj/cut"), 0) - nlist = self.lmp.numpy.get_neighlist(0) + idx = self.lmp.find_pair_neighlist("lj/cut") + self.assertNotEqual(idx, -1) + nlist = self.lmp.numpy.get_neighlist(idx) self.assertEqual(len(nlist), 2) atom_i, neighbors_i = nlist[0] atom_j, neighbors_j = nlist[1] @@ -180,6 +189,192 @@ class PythonNumpy(unittest.TestCase): self.assertIn(1, neighbors_i) self.assertNotIn(0, neighbors_j) + def testNeighborListHalf(self): + self.lmp.commands_string(""" + boundary f f f + units real + region box block -5 5 -5 5 -5 5 + create_box 1 box + mass 1 1.0 + pair_style lj/cut 4.0 + pair_coeff 1 1 0.2 2.0 + """) + x = [ 0.0, 0.0, 0.0, -1.1, 0.0, 0.0, 1.0, 0.0, 0.0, + 0.0, -1.1, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, -1.1, + 0.0, 0.0, 1.0 ] + tags = [1, 2, 3, 4, 5, 6, 7] + types = [1, 1, 1, 1, 1, 1, 1] + + self.assertEqual(self.lmp.create_atoms(7, id=tags, type=types, x=x), 7) + nlocal = self.lmp.extract_global("nlocal") + self.assertEqual(nlocal, 7) + + self.lmp.command("run 0 post no") + + self.assertEqual(self.lmp.find_pair_neighlist("lj/cut"),0) + nlist = self.lmp.numpy.get_neighlist(0) + self.assertEqual(nlist.size, 7) + for i in range(0,nlist.size): + idx, neighs = nlist.get(i) + self.assertEqual(idx,i) + self.assertEqual(neighs.size,nlocal-1-i) + + # look up neighbor list by atom index + neighs = nlist.find(2) + self.assertEqual(neighs.size,4) + self.assertIsNotNone(neighs,None) + # this one will fail + neighs = nlist.find(10) + self.assertIsNone(neighs,None) + + @unittest.skipIf(not has_manybody,"Full neighbor list test for manybody potential") + def testNeighborListFull(self): + self.lmp.commands_string(""" + boundary f f f + units metal + region box block -5 5 -5 5 -5 5 + create_box 1 box + mass 1 1.0 + pair_style sw + pair_coeff * * Si.sw Si + """) + x = [ 0.0, 0.0, 0.0, -1.1, 0.0, 0.0, 1.0, 0.0, 0.0, + 0.0, -1.1, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, -1.1, + 0.0, 0.0, 1.0 ] + tags = [1, 2, 3, 4, 5, 6, 7] + types = [1, 1, 1, 1, 1, 1, 1] + + self.assertEqual(self.lmp.create_atoms(7, id=tags, type=types, x=x), 7) + nlocal = self.lmp.extract_global("nlocal") + self.assertEqual(nlocal, 7) + + self.lmp.command("run 0 post no") + + self.assertEqual(self.lmp.find_pair_neighlist("sw"),0) + nlist = self.lmp.numpy.get_neighlist(0) + self.assertEqual(nlist.size, 7) + for i in range(0,nlist.size): + idx, neighs = nlist.get(i) + self.assertEqual(idx,i) + self.assertEqual(neighs.size,nlocal-1) + + @unittest.skipIf(not has_manybody,"Hybrid neighbor list test for manybody potential") + def testNeighborListHybrid(self): + self.lmp.commands_string(""" + boundary f f f + units metal + region box block -5 5 -5 5 -5 5 + create_box 2 box + mass * 1.0 + pair_style hybrid/overlay morse 4.0 lj/cut 4.0 lj/cut 4.0 sw + pair_coeff * * sw Si.sw Si NULL + pair_coeff 1 2 morse 0.2 2.0 2.0 + pair_coeff 2 2 lj/cut 1 0.1 2.0 + pair_coeff * * lj/cut 2 0.01 2.0 + """) + x = [ 0.0, 0.0, 0.0, -1.1, 0.0, 0.0, 1.0, 0.0, 0.0, + 0.0, -1.1, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, -1.1, + 0.0, 0.0, 1.0 ] + tags = [1, 2, 3, 4, 5, 6, 7] + types = [1, 1, 1, 1, 2, 2, 2] + + self.assertEqual(self.lmp.create_atoms(7, id=tags, type=types, x=x), 7) + nlocal = self.lmp.extract_global("nlocal") + self.assertEqual(nlocal, 7) + + self.lmp.command("run 0 post no") + + # valid and invalid lookups + self.assertNotEqual(self.lmp.find_pair_neighlist("sw"),-1) + self.assertNotEqual(self.lmp.find_pair_neighlist("morse"),-1) + self.assertNotEqual(self.lmp.find_pair_neighlist("lj/cut",nsub=1),-1) + self.assertNotEqual(self.lmp.find_pair_neighlist("lj/cut",nsub=2),-1) + self.assertEqual(self.lmp.find_pair_neighlist("lj/cut"),-1) + self.assertEqual(self.lmp.find_pair_neighlist("hybrid/overlay"),-1) + self.assertNotEqual(self.lmp.numpy.get_neighlist(4).size,0) + self.assertEqual(self.lmp.numpy.get_neighlist(5).size,-1) + + # full neighbor list for 4 type 1 atoms + # all have 3 type 1 atom neighbors + nlist = self.lmp.numpy.get_neighlist(self.lmp.find_pair_neighlist("sw")) + self.assertEqual(nlist.size, 4) + for i in range(0,nlist.size): + idx, neighs = nlist.get(i) + self.assertEqual(idx,i) + self.assertEqual(neighs.size,3) + + # half neighbor list for all pairs between type 1 and type 2 + # 4 type 1 atoms with 3 type 2 neighbors and 3 type 2 atoms without neighbors + nlist = self.lmp.numpy.get_neighlist(self.lmp.find_pair_neighlist("morse")) + self.assertEqual(nlist.size, 7) + for i in range(0,nlist.size): + idx, neighs = nlist.get(i) + if (i < 4): self.assertEqual(neighs.size,3) + else: self.assertEqual(neighs.size,0) + + # half neighbor list between type 2 atoms only + # 3 pairs with 2, 1, 0 neighbors + nlist = self.lmp.numpy.get_neighlist(self.lmp.find_pair_neighlist("lj/cut",nsub=1)) + self.assertEqual(nlist.size, 3) + for i in range(0,nlist.size): + idx, neighs = nlist.get(i) + self.assertEqual(neighs.size,2-i) + + # half neighbor list between all pairs. same as simple lj/cut case + nlist = self.lmp.numpy.get_neighlist(self.lmp.find_pair_neighlist("lj/cut",nsub=2)) + self.assertEqual(nlist.size, 7) + for i in range(0,nlist.size): + idx, neighs = nlist.get(i) + self.assertEqual(neighs.size,nlocal-1-i) + + def testNeighborListCompute(self): + self.lmp.commands_string(""" + boundary f f f + units real + region box block -5 5 -5 5 -5 5 + create_box 1 box + mass 1 1.0 + pair_style lj/cut 4.0 + pair_coeff 1 1 0.2 2.0 + compute dist all pair/local dist + fix dist all ave/histo 1 1 1 0.0 3.0 4 c_dist mode vector + thermo_style custom f_dist[*] + """) + x = [ 0.0, 0.0, 0.0, -1.1, 0.0, 0.0, 1.0, 0.0, 0.0, + 0.0, -1.1, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, -1.1, + 0.0, 0.0, 1.0 ] + tags = [1, 2, 3, 4, 5, 6, 7] + types = [1, 1, 1, 1, 1, 1, 1] + + self.assertEqual(self.lmp.create_atoms(7, id=tags, type=types, x=x), 7) + nlocal = self.lmp.extract_global("nlocal") + self.assertEqual(nlocal, 7) + + self.lmp.command("run 0 post no") + # check compute data from histogram summary + nhisto = self.lmp.extract_fix("dist",LMP_STYLE_GLOBAL,LMP_TYPE_VECTOR,nrow=0) + nskip = self.lmp.extract_fix("dist",LMP_STYLE_GLOBAL,LMP_TYPE_VECTOR,nrow=1) + minval = self.lmp.extract_fix("dist",LMP_STYLE_GLOBAL,LMP_TYPE_VECTOR,nrow=2) + maxval = self.lmp.extract_fix("dist",LMP_STYLE_GLOBAL,LMP_TYPE_VECTOR,nrow=3) + # 21 pair distances counted, none skipped, smallest 1.0, largest 2.1 + self.assertEqual(nhisto,21) + self.assertEqual(nskip,0) + self.assertEqual(minval,1.0) + self.assertEqual(maxval,2.1) + + self.assertNotEqual(self.lmp.find_pair_neighlist("lj/cut"),-1) + self.assertNotEqual(self.lmp.find_compute_neighlist("dist"),-1) + self.assertEqual(self.lmp.find_compute_neighlist("xxx"),-1) + self.assertEqual(self.lmp.find_fix_neighlist("dist"),-1) + + # the compute has a half neighbor list + nlist = self.lmp.numpy.get_neighlist(self.lmp.find_compute_neighlist("dist")) + self.assertEqual(nlist.size, 7) + for i in range(0,nlist.size): + idx, neighs = nlist.get(i) + self.assertEqual(idx,i) + self.assertEqual(neighs.size,nlocal-1-i) + def test_extract_variable_equalstyle(self): self.lmp.command("variable a equal 100") a = self.lmp.numpy.extract_variable("a")