From 2d5f02a398f3eac80d036cff5e33d27ce8cc76c2 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sat, 14 Jun 2025 12:46:36 -0400 Subject: [PATCH] add lammps_add_molecule API to the C-library interface and python/fortran module --- doc/src/Fortran.rst | 16 ++++++++- doc/src/Library_scatter.rst | 5 +++ examples/COUPLE/plugin/liblammpsplugin.c | 1 + examples/COUPLE/plugin/liblammpsplugin.h | 1 + fortran/lammps.f90 | 21 +++++++++++ python/lammps/core.py | 24 +++++++++++++ src/library.cpp | 45 ++++++++++++++++++++++++ src/library.h | 2 ++ tools/swig/lammps.i | 12 ++++--- 9 files changed, 122 insertions(+), 5 deletions(-) diff --git a/doc/src/Fortran.rst b/doc/src/Fortran.rst index 3d61473068..0fd9697344 100644 --- a/doc/src/Fortran.rst +++ b/doc/src/Fortran.rst @@ -2099,7 +2099,7 @@ Procedures Bound to the :f:type:`lammps` Derived Type -------- -.. f:subroutine:: create_atoms([id,] type, x, [v,] [image,] [bexpand]) +.. f:function:: create_atoms([id,] type, x, [v,] [image,] [bexpand]) This method calls :cpp:func:`lammps_create_atoms` to create additional atoms from a given list of coordinates and a list of atom types. Additionally, @@ -2128,6 +2128,8 @@ Procedures Bound to the :f:type:`lammps` Derived Type will be created, not dropped, and the box dimensions will be extended. Default is ``.FALSE.`` :otype bexpand: logical,optional + :r atoms: number of created atoms + :rtype atoms: integer(c_int) :to: :cpp:func:`lammps_create_atoms` .. note:: @@ -2152,6 +2154,18 @@ Procedures Bound to the :f:type:`lammps` Derived Type -------- +.. f:subroutine:: create_molecule(id, jsonstr) + + Add molecule template from string with JSON data + + .. versionadded:: TBD + + :p character(len=\*) id: desired molecule-ID + :p character(len=\*) jsonstr: string with JSON data defining the molecule template + :to: :cpp:func:`lammps_create_molecule` + +-------- + .. f:function:: find_pair_neighlist(style[, exact][, nsub][, reqid]) Find index of a neighbor list requested by a pair style. diff --git a/doc/src/Library_scatter.rst b/doc/src/Library_scatter.rst index 4c20b78c4c..93d75cf48e 100644 --- a/doc/src/Library_scatter.rst +++ b/doc/src/Library_scatter.rst @@ -27,6 +27,7 @@ It documents the following functions: - :cpp:func:`lammps_scatter` - :cpp:func:`lammps_scatter_subset` - :cpp:func:`lammps_create_atoms` +- :cpp:func:`lammps_create_molecule` ----------------------- @@ -103,4 +104,8 @@ It documents the following functions: .. 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 +----------------------- + +.. doxygenfunction:: lammps_create_molecule + :project: progguide diff --git a/examples/COUPLE/plugin/liblammpsplugin.c b/examples/COUPLE/plugin/liblammpsplugin.c index 21f330df9e..d79a807488 100644 --- a/examples/COUPLE/plugin/liblammpsplugin.c +++ b/examples/COUPLE/plugin/liblammpsplugin.c @@ -141,6 +141,7 @@ liblammpsplugin_t *liblammpsplugin_load(const char *lib) ADDSYM(scatter_subset); ADDSYM(create_atoms); + ADDSYM(create_molecule); ADDSYM(find_pair_neighlist); ADDSYM(find_fix_neighlist); diff --git a/examples/COUPLE/plugin/liblammpsplugin.h b/examples/COUPLE/plugin/liblammpsplugin.h index 637f3db79b..dcc9d982d5 100644 --- a/examples/COUPLE/plugin/liblammpsplugin.h +++ b/examples/COUPLE/plugin/liblammpsplugin.h @@ -207,6 +207,7 @@ struct _liblammpsplugin { int (*create_atoms)(void *, int, const int64_t *, const int *, const double *, const double *, const int64_t *, int); #endif + int (*create_molecule)(void *, const char *, const char *); int (*find_pair_neighlist)(void *, const char *, int, int, int); int (*find_fix_neighlist)(void *, const char *, int); diff --git a/fortran/lammps.f90 b/fortran/lammps.f90 index ed9e7b2b6b..6d55eb4fc0 100644 --- a/fortran/lammps.f90 +++ b/fortran/lammps.f90 @@ -197,6 +197,8 @@ MODULE LIBLAMMPS PROCEDURE, PRIVATE :: lmp_create_atoms_bigbig GENERIC :: create_atoms => lmp_create_atoms_int, & lmp_create_atoms_bigbig + PROCEDURE :: create_molecule => lmp_create_molecule + PROCEDURE :: find_pair_neighlist => lmp_find_pair_neighlist PROCEDURE :: find_fix_neighlist => lmp_find_fix_neighlist PROCEDURE :: find_compute_neighlist => lmp_find_compute_neighlist @@ -762,6 +764,12 @@ MODULE LIBLAMMPS INTEGER(c_int) :: lammps_create_atoms END FUNCTION lammps_create_atoms + SUBROUTINE lammps_create_molecule(handle, id, jsonstr) BIND(C) + IMPORT :: c_ptr + IMPLICIT NONE + TYPE(c_ptr), VALUE :: handle, id, jsonstr + END SUBROUTINE lammps_create_molecule + FUNCTION lammps_find_pair_neighlist(handle, style, exact, nsub, reqid) & BIND(C) IMPORT :: c_ptr, c_int @@ -2881,6 +2889,19 @@ CONTAINS END IF END SUBROUTINE lmp_create_atoms_bigbig + ! equivalent function to lammps_create_molecule + SUBROUTINE lmp_create_molecule(self, id, jsonstr) + CLASS(lammps), INTENT(IN) :: self + CHARACTER(LEN=*), INTENT(IN) :: id, jsonstr + TYPE(c_ptr) :: Cid, Cjsonstr + + Cid = f2c_string(id) + Cjsonstr = f2c_string(jsonstr) + CALL lammps_create_molecule(self%handle, Cid, Cjsonstr) + CALL lammps_free(Cid) + CALL lammps_free(Cjsonstr) + END SUBROUTINE lmp_create_molecule + ! equivalent function to lammps_find_pair_neighlist INTEGER(c_int) FUNCTION lmp_find_pair_neighlist(self, style, exact, nsub, & reqid) diff --git a/python/lammps/core.py b/python/lammps/core.py index e6ced9703b..62422a6fb2 100644 --- a/python/lammps/core.py +++ b/python/lammps/core.py @@ -325,6 +325,8 @@ class lammps(object): POINTER(c_double), POINTER(c_double), POINTER(self.c_imageint), c_int] self.lib.lammps_create_atoms.retype = c_int + self.lib.lammps_create_molecule.argtypes = [c_void_p, c_char_p, c_char_p] + self.lib.lammps_create_molecule.restype = None self.lib.lammps_find_pair_neighlist.argtypes = [c_void_p, c_char_p, c_int, c_int, c_int] self.lib.lammps_find_pair_neighlist.restype = c_int @@ -2101,6 +2103,28 @@ class lammps(object): # ------------------------------------------------------------------------- + def create_molecule(self, id, jsonstr): + """ Create new molecule template from string with JSON data + + .. versionadded:: TBD + + This is a wrapper around the :cpp:func:`lammps_create_molecule` function + of the library interface. + + :param id: molecule-id of the new molecule template + :type name: string + :param jsonstr: JSON data defining a new molecule template + :type jsonstr: string + """ + if id: newid = id.encode() + else: newid = None + if id: newjsonstr = jsonstr.encode() + else: newjsonstr = None + with ExceptionCheck(self): + self.lib.lammps_create_molecule(self.lmp, newid, newjsonstr) + + # ------------------------------------------------------------------------- + @property def has_mpi_support(self): """ Report whether the LAMMPS shared library was compiled with a diff --git a/src/library.cpp b/src/library.cpp index 55b3059e4c..5b16985183 100644 --- a/src/library.cpp +++ b/src/library.cpp @@ -36,6 +36,7 @@ #include "group.h" #include "info.h" #include "input.h" +#include "json.h" #include "lattice.h" #include "lmppython.h" #include "memory.h" @@ -6200,6 +6201,50 @@ int lammps_create_atoms(void *handle, int n, const tagint *id, const int *type, return (int) lmp->atom->natoms - natoms_prev; } +/* ---------------------------------------------------------------------- */ + +/** Create new molecule template from JSON data provided as C-style string + * +\verbatim embed:rst + +.. versionadded:: TBD + +This function creates a new molecule template similar to the +:doc:`molecule command `, but uses JSON data passed +as a C-style string instead of reading it from a file. + +\endverbatim + * + * \param handle pointer to a previously created LAMMPS instance + * \param id molecule-ID + * \param json molecule data in JSON format as C-style string */ + +void lammps_create_molecule(void *handle, const char *id, const char *jsonstr) +{ + auto *lmp = (LAMMPS *) handle; + if (!lmp || !lmp->atom || !lmp->comm || !lmp->domain || !lmp->error) { + const auto mesg = fmt::format("ERROR: {}(): Invalid LAMMPS handle\n", FNERR); + STORE_ERROR_MESSAGE(lmp, mesg); + return; + } + if (!id || !jsonstr) { + const auto mesg = fmt::format("ERROR: {}(): Non-NULL arguments required\n", FNERR); + STORE_ERROR_MESSAGE(lmp, mesg); + return; + } + + BEGIN_CAPTURE + { + try { + auto jsondata = json::parse(jsonstr); + lmp->atom->add_molecule(id, jsondata); + } catch (std::exception &e) { + STORE_ERROR_MESSAGE(lmp, e.what()); + } + } + END_CAPTURE; +} + // ---------------------------------------------------------------------- // Library functions for accessing neighbor lists // ---------------------------------------------------------------------- diff --git a/src/library.h b/src/library.h index 08b619eb78..acddca89a2 100644 --- a/src/library.h +++ b/src/library.h @@ -240,6 +240,8 @@ int lammps_create_atoms(void *handle, int n, const int64_t *id, const int *type, const double *v, const int64_t *image, int bexpand); #endif +void lammps_create_molecule(void *handle, const char *id, const char *json); + /* ---------------------------------------------------------------------- * Library functions for accessing neighbor lists * ---------------------------------------------------------------------- */ diff --git a/tools/swig/lammps.i b/tools/swig/lammps.i index 6761ce7acf..0c3a55da4d 100644 --- a/tools/swig/lammps.i +++ b/tools/swig/lammps.i @@ -176,8 +176,10 @@ extern void lammps_scatter(void *, const char *, int, int, void *); extern void lammps_scatter_subset(void *, const char *, int, int, int, int *, void *); extern 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); -/* - extern int lammps_create_atoms(void *handle, int n, int64_t *id, int *type, */ +/* extern int lammps_create_atoms(void *handle, int n, const int64_t *id, int *type, + const double *x, const double *v, const int64_t *image, int bexpand); */ +extern void lammps_create_molecule(void *handle, const char *id, const char *json); + extern int lammps_find_pair_neighlist(void *, const char *, int, int, int); extern int lammps_find_fix_neighlist(void *, const char *, int); extern int lammps_find_compute_neighlist(void *, const char *, int); @@ -375,8 +377,10 @@ extern void lammps_scatter(void *, const char *, int, int, void *); extern void lammps_scatter_subset(void *, const char *, int, int, int, int *, void *); extern 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); -/* - extern int lammps_create_atoms(void *handle, int n, int64_t *id, int *type, */ +/* extern int lammps_create_atoms(void *handle, int n, const int64_t *id, int *type, + const double *x, const double *v, const int64_t *image, int bexpand); */ +extern void lammps_create_molecule(void *handle, const char *id, const char *json); + extern int lammps_find_pair_neighlist(void*, const char *, int, int, int); extern int lammps_find_fix_neighlist(void*, const char *, int); extern int lammps_find_compute_neighlist(void*, const char *, int);