refactor handling of plugin loading to make plugin a global property

This commit is contained in:
Axel Kohlmeyer
2025-06-11 02:52:28 -04:00
parent 464b9f4b03
commit df08818fef
15 changed files with 305 additions and 55 deletions

View File

@ -69,10 +69,11 @@ statement. Internally, it will call either
:cpp:func:`lammps_open_fortran` or :cpp:func:`lammps_open_no_mpi` from :cpp:func:`lammps_open_fortran` or :cpp:func:`lammps_open_no_mpi` from
the C library API to create the class instance. All arguments are the C library API to create the class instance. All arguments are
optional and :cpp:func:`lammps_mpi_init` will be called automatically optional and :cpp:func:`lammps_mpi_init` will be called automatically
if it is needed. Similarly, a possible call to if it is needed. Similarly, optional calls to
:cpp:func:`lammps_mpi_finalize` is integrated into the :f:func:`close` :cpp:func:`lammps_mpi_finalize`, :cpp:func:`lammps_kokkos_finalize`,
function and triggered with the optional logical argument set to :cpp:func:`lammps_python_finalize`, and :cpp:func:`lammps_plugin_finalize`
``.TRUE.``. Here is a simple example: are integrated into the :f:func:`close` function and triggered with the
optional logical argument set to ``.TRUE.``. Here is a simple example:
.. code-block:: fortran .. code-block:: fortran
@ -521,8 +522,8 @@ Procedures Bound to the :f:type:`lammps` Derived Type
This method will close down the LAMMPS instance through calling This method will close down the LAMMPS instance through calling
:cpp:func:`lammps_close`. If the *finalize* argument is present and :cpp:func:`lammps_close`. If the *finalize* argument is present and
has a value of ``.TRUE.``, then this subroutine also calls has a value of ``.TRUE.``, then this subroutine also calls
:cpp:func:`lammps_kokkos_finalize` and :cpp:func:`lammps_kokkos_finalize`, :cpp:func:`lammps_mpi_finalize`,
:cpp:func:`lammps_mpi_finalize`. :cpp:func:`lammps_python_finalize`, and :cpp:func:`lammps_plugin_finalize`.
:o finalize: shut down the MPI environment of the LAMMPS :o finalize: shut down the MPI environment of the LAMMPS
library if ``.TRUE.``. library if ``.TRUE.``.
@ -530,6 +531,8 @@ Procedures Bound to the :f:type:`lammps` Derived Type
:to: :cpp:func:`lammps_close` :to: :cpp:func:`lammps_close`
:to: :cpp:func:`lammps_mpi_finalize` :to: :cpp:func:`lammps_mpi_finalize`
:to: :cpp:func:`lammps_kokkos_finalize` :to: :cpp:func:`lammps_kokkos_finalize`
:to: :cpp:func:`lammps_python_finalize`
:to: :cpp:func:`lammps_plugin_finalize`
-------- --------

View File

@ -11,6 +11,7 @@ This section documents the following functions:
- :cpp:func:`lammps_mpi_finalize` - :cpp:func:`lammps_mpi_finalize`
- :cpp:func:`lammps_kokkos_finalize` - :cpp:func:`lammps_kokkos_finalize`
- :cpp:func:`lammps_python_finalize` - :cpp:func:`lammps_python_finalize`
- :cpp:func:`lammps_plugin_finalize`
- :cpp:func:`lammps_error` - :cpp:func:`lammps_error`
-------------------- --------------------
@ -119,5 +120,10 @@ calling program.
----------------------- -----------------------
.. doxygenfunction:: lammps_plugin_finalize
:project: progguide
-----------------------
.. doxygenfunction:: lammps_error .. doxygenfunction:: lammps_error
:project: progguide :project: progguide

View File

@ -10,7 +10,7 @@ Syntax
plugin command args plugin command args
* command = *load* or *unload* or *list* or *clear* * command = *load* or *unload* or *list* or *clear* or *restore*
* args = list of arguments for a particular plugin command * args = list of arguments for a particular plugin command
.. parsed-literal:: .. parsed-literal::
@ -20,6 +20,7 @@ Syntax
*style* = *pair* or *bond* or *angle* or *dihedral* or *improper* or *kspace* or *compute* or *fix* or *region* or *command* or *run* or *min* *style* = *pair* or *bond* or *angle* or *dihedral* or *improper* or *kspace* or *compute* or *fix* or *region* or *command* or *run* or *min*
*list* = print a list of currently loaded plugins *list* = print a list of currently loaded plugins
*clear* = unload all currently loaded plugins *clear* = unload all currently loaded plugins
*restore* = restore all loaded plugins
Examples Examples
"""""""" """"""""
@ -31,6 +32,7 @@ Examples
plugin unload command hello plugin unload command hello
plugin list plugin list
plugin clear plugin clear
plugin restore
Description Description
""""""""""" """""""""""
@ -40,22 +42,46 @@ commands into a LAMMPS binary from so-called dynamic shared object (DSO)
files. This enables to add new functionality to an existing LAMMPS files. This enables to add new functionality to an existing LAMMPS
binary without having to recompile and link the entire executable. binary without having to recompile and link the entire executable.
.. admonition:: Plugins are a global, per-executable property
:class: Hint
Unlike most settings in LAMMPS, plugins are a per-executable global
property. Loading a plugin means that it is not only available for
the current LAMMPS instance but for all *future* LAMMPS instances.
After a :doc:`clear <clear>` command, all currently loaded plugins
will be restored and do not need to be loaded again.
When using the library interface or the Python or Fortran module
to create multiple concurrent LAMMPS instances, all plugins should
be loaded by the first created LAMMPS instance as all future instances
will inherit them. To import plugins that were loaded by a different
LAMMPS instance, use the *restore* command.
The *load* command will load and initialize all plugins contained in the The *load* command will load and initialize all plugins contained in the
plugin DSO with the given filename. A message with information the plugin DSO with the given filename. A message with information about
plugin style and name and more will be printed. Individual DSO files the plugin style and name and more will be printed. Individual DSO
may contain multiple plugins. More details about how to write and files may contain multiple plugins. If a plugin is already loaded
it will be skipped. More details about how to write and
compile the plugin DSO is given in programmer's guide part of the manual compile the plugin DSO is given in programmer's guide part of the manual
under :doc:`Developer_plugins`. under :doc:`Developer_plugins`.
The *unload* command will remove the given style or the given name from The *unload* command will remove the given style or the given name from
the list of available styles. If the plugin style is currently in use, the list of available styles. If the plugin style is currently in use,
that style instance will be deleted. that style instance will be deleted and replaced by the default setting
for that style.
The *list* command will print a list of the loaded plugins and their The *list* command will print a list of the loaded plugins and their
styles and names. styles and names.
The *clear* command will unload all currently loaded plugins. The *clear* command will unload all currently loaded plugins.
.. versionadded:: TBD
The *restore* command will restore all currently loaded plugins.
This allows to "import" plugins into a different LAMMPS instance.
.. admonition:: Automatic loading of plugins .. admonition:: Automatic loading of plugins
:class: note :class: note
@ -79,7 +105,7 @@ If plugins access functions or classes from a package,
LAMMPS must have been compiled with that package included. LAMMPS must have been compiled with that package included.
Plugins are dependent on the LAMMPS binary interface (ABI) Plugins are dependent on the LAMMPS binary interface (ABI)
and particularly the MPI library used. So they are not guaranteed and particularly the MPI library used. So they are not guaranteed
to work when the plugin was compiled with a different MPI library to work when the plugin was compiled with a different MPI library
or different compilation settings or a different LAMMPS version. or different compilation settings or a different LAMMPS version.
There are no checks, so if there is a mismatch the plugin object There are no checks, so if there is a mismatch the plugin object

View File

@ -79,6 +79,7 @@ liblammpsplugin_t *liblammpsplugin_load(const char *lib)
ADDSYM(mpi_finalize); ADDSYM(mpi_finalize);
ADDSYM(kokkos_finalize); ADDSYM(kokkos_finalize);
ADDSYM(python_finalize); ADDSYM(python_finalize);
ADDSYM(plugin_finalize);
ADDSYM(error); ADDSYM(error);
ADDSYM(expand); ADDSYM(expand);

View File

@ -134,6 +134,7 @@ struct _liblammpsplugin {
void (*mpi_finalize)(); void (*mpi_finalize)();
void (*kokkos_finalize)(); void (*kokkos_finalize)();
void (*python_finalize)(); void (*python_finalize)();
void (*plugin_finalize)();
void (*error)(void *, int, const char *); void (*error)(void *, int, const char *);
char *(*expand)(void *, const char *); char *(*expand)(void *, const char *);

View File

@ -408,6 +408,12 @@ MODULE LIBLAMMPS
SUBROUTINE lammps_kokkos_finalize() BIND(C) SUBROUTINE lammps_kokkos_finalize() BIND(C)
END SUBROUTINE lammps_kokkos_finalize END SUBROUTINE lammps_kokkos_finalize
SUBROUTINE lammps_python_finalize() BIND(C)
END SUBROUTINE lammps_python_finalize
SUBROUTINE lammps_plugin_finalize() BIND(C)
END SUBROUTINE lammps_plugin_finalize
SUBROUTINE lammps_error(handle, error_type, error_text) BIND(C) SUBROUTINE lammps_error(handle, error_type, error_text) BIND(C)
IMPORT :: c_ptr, c_int IMPORT :: c_ptr, c_int
IMPLICIT NONE IMPLICIT NONE
@ -1135,7 +1141,7 @@ CONTAINS
SIZE_IMAGEINT = lmp_extract_setting(lmp_open, 'imageint') SIZE_IMAGEINT = lmp_extract_setting(lmp_open, 'imageint')
END FUNCTION lmp_open END FUNCTION lmp_open
! Combined Fortran wrapper around lammps_close() and lammps_mpi_finalize() ! Combined Fortran wrapper around lammps_close() and lammps_*_finalize()
SUBROUTINE lmp_close(self, finalize) SUBROUTINE lmp_close(self, finalize)
CLASS(lammps), INTENT(IN) :: self CLASS(lammps), INTENT(IN) :: self
LOGICAL, INTENT(IN), OPTIONAL :: finalize LOGICAL, INTENT(IN), OPTIONAL :: finalize
@ -1146,6 +1152,8 @@ CONTAINS
IF (finalize) THEN IF (finalize) THEN
CALL lammps_kokkos_finalize() CALL lammps_kokkos_finalize()
CALL lammps_mpi_finalize() CALL lammps_mpi_finalize()
CALL lammps_python_finalize()
CALL lammps_plugin_finalize()
END IF END IF
END IF END IF
END SUBROUTINE lmp_close END SUBROUTINE lmp_close

View File

@ -653,8 +653,9 @@ class lammps(object):
def finalize(self): def finalize(self):
"""Shut down the MPI communication and Kokkos environment (if active) through the """Shut down the MPI communication and Kokkos environment (if active) through the
library interface by calling :cpp:func:`lammps_mpi_finalize` and library interface by calling :cpp:func:`lammps_mpi_finalize`,
:cpp:func:`lammps_kokkos_finalize`. :cpp:func:`lammps_kokkos_finalize`, :cpp:func:`lammps_python_finalize`, and
:cpp:func:`lammps_plugin_finalize`
You cannot create or use any LAMMPS instances after this function is called You cannot create or use any LAMMPS instances after this function is called
unless LAMMPS was compiled without MPI and without Kokkos support. unless LAMMPS was compiled without MPI and without Kokkos support.
@ -662,6 +663,8 @@ class lammps(object):
self.close() self.close()
self.lib.lammps_kokkos_finalize() self.lib.lammps_kokkos_finalize()
self.lib.lammps_mpi_finalize() self.lib.lammps_mpi_finalize()
self.lib.lammps_python_finalize()
self.lib.lammps_plugin_finalize()
# ------------------------------------------------------------------------- # -------------------------------------------------------------------------

View File

@ -58,6 +58,9 @@ void Plugin::command(int narg, char **arg)
} else if (cmd == "clear") { } else if (cmd == "clear") {
plugin_clear(lmp); plugin_clear(lmp);
} else if (cmd == "restore") {
plugin_restore(lmp, false);
} else if (cmd == "list") { } else if (cmd == "list") {
if (comm->me == 0) { if (comm->me == 0) {
int num = plugin_get_num_plugins(); int num = plugin_get_num_plugins();
@ -68,15 +71,16 @@ void Plugin::command(int narg, char **arg)
} }
} }
} else } else
error->all(FLERR, "Illegal plugin command"); error->all(FLERR, "Unknown plugin command {}", cmd);
} }
// auto-load DSOs from designated folder(s) // auto-load DSOs from designated folder(s)
void plugin_auto_load(LAMMPS *lmp) void plugin_auto_load(LAMMPS *lmp)
{ {
#if defined(LMP_PLUGIN) #if defined(LMP_PLUGIN)
bool oldverbose = verbose;
verbose = false;
for (const auto &plugin_dir : platform::list_pathenv("LAMMPS_PLUGIN_PATH")) { for (const auto &plugin_dir : platform::list_pathenv("LAMMPS_PLUGIN_PATH")) {
verbose = false;
int count = 0; int count = 0;
for (const auto &file : platform::list_directory(plugin_dir)) { for (const auto &file : platform::list_directory(plugin_dir)) {
if (utils::strmatch(file, "\\plugin.so$")) if (utils::strmatch(file, "\\plugin.so$"))
@ -84,6 +88,7 @@ void plugin_auto_load(LAMMPS *lmp)
} }
if (lmp->comm->me == 0) utils::logmesg(lmp, "Loaded {} plugins from {}\n", count, plugin_dir); if (lmp->comm->me == 0) utils::logmesg(lmp, "Loaded {} plugins from {}\n", count, plugin_dir);
} }
verbose = oldverbose;
#endif #endif
} }
@ -262,7 +267,8 @@ void plugin_register(lammpsplugin_t *plugin, void *ptr)
auto minimize_map = lmp->update->minimize_map; auto minimize_map = lmp->update->minimize_map;
if (minimize_map->find(plugin->name) != minimize_map->end()) { if (minimize_map->find(plugin->name) != minimize_map->end()) {
if (lmp->comm->me == 0) if (lmp->comm->me == 0)
lmp->error->warning(FLERR, "Overriding built-in run style {} from plugin", plugin->name); lmp->error->warning(FLERR, "Overriding built-in minimize style {} from plugin",
plugin->name);
} }
(*minimize_map)[plugin->name] = (Update::MinimizeCreator) plugin->creator.v1; (*minimize_map)[plugin->name] = (Update::MinimizeCreator) plugin->creator.v1;
@ -319,9 +325,6 @@ void plugin_unload(const char *style, const char *name, LAMMPS *lmp)
std::string pstyle = style; std::string pstyle = style;
if (pstyle == "pair") { if (pstyle == "pair") {
auto found = lmp->force->pair_map->find(name);
if (found != lmp->force->pair_map->end()) lmp->force->pair_map->erase(found);
// must delete pair style instance if in use // must delete pair style instance if in use
if (lmp->force->pair_style) { if (lmp->force->pair_style) {
@ -332,82 +335,90 @@ void plugin_unload(const char *style, const char *name, LAMMPS *lmp)
} }
} }
} else if (pstyle == "bond") { auto found = lmp->force->pair_map->find(name);
if (found != lmp->force->pair_map->end()) lmp->force->pair_map->erase(found);
auto found = lmp->force->bond_map->find(name); } else if (pstyle == "bond") {
if (found != lmp->force->bond_map->end()) lmp->force->bond_map->erase(found);
// must delete bond style instance if in use // must delete bond style instance if in use
if ((lmp->force->bond_style != nullptr) && (lmp->force->bond_match(name) != nullptr)) if ((lmp->force->bond_style != nullptr) && (lmp->force->bond_match(name) != nullptr))
lmp->force->create_bond("none", 0); lmp->force->create_bond("none", 0);
} else if (pstyle == "angle") { auto found = lmp->force->bond_map->find(name);
if (found != lmp->force->bond_map->end()) lmp->force->bond_map->erase(found);
auto found = lmp->force->angle_map->find(name); } else if (pstyle == "angle") {
if (found != lmp->force->angle_map->end()) lmp->force->angle_map->erase(found);
// must delete angle style instance if in use // must delete angle style instance if in use
if ((lmp->force->angle_style != nullptr) && (lmp->force->angle_match(name) != nullptr)) if ((lmp->force->angle_style != nullptr) && (lmp->force->angle_match(name) != nullptr))
lmp->force->create_angle("none", 0); lmp->force->create_angle("none", 0);
} else if (pstyle == "dihedral") { auto found = lmp->force->angle_map->find(name);
if (found != lmp->force->angle_map->end()) lmp->force->angle_map->erase(found);
auto found = lmp->force->dihedral_map->find(name); } else if (pstyle == "dihedral") {
if (found != lmp->force->dihedral_map->end()) lmp->force->dihedral_map->erase(found);
// must delete dihedral style instance if in use // must delete dihedral style instance if in use
if ((lmp->force->dihedral_style) && (lmp->force->dihedral_match(name) != nullptr)) if ((lmp->force->dihedral_style) && (lmp->force->dihedral_match(name) != nullptr))
lmp->force->create_dihedral("none", 0); lmp->force->create_dihedral("none", 0);
} else if (pstyle == "improper") { auto found = lmp->force->dihedral_map->find(name);
if (found != lmp->force->dihedral_map->end()) lmp->force->dihedral_map->erase(found);
auto found = lmp->force->improper_map->find(name); } else if (pstyle == "improper") {
if (found != lmp->force->improper_map->end()) lmp->force->improper_map->erase(found);
// must delete improper style instance if in use // must delete improper style instance if in use
if ((lmp->force->improper_style != nullptr) && (lmp->force->improper_match(name) != nullptr)) if ((lmp->force->improper_style != nullptr) && (lmp->force->improper_match(name) != nullptr))
lmp->force->create_improper("none", 0); lmp->force->create_improper("none", 0);
auto found = lmp->force->improper_map->find(name);
if (found != lmp->force->improper_map->end()) lmp->force->improper_map->erase(found);
} else if (pstyle == "kspace") { } else if (pstyle == "kspace") {
// must delete kspace style instance if in use
if ((lmp->force->kspace_style != nullptr) && (lmp->force->kspace_match(name, 1) != nullptr))
lmp->force->create_kspace("none", 0);
auto kspace_map = lmp->force->kspace_map; auto kspace_map = lmp->force->kspace_map;
auto found = kspace_map->find(name); auto found = kspace_map->find(name);
if (found != kspace_map->end()) kspace_map->erase(name); if (found != kspace_map->end()) kspace_map->erase(name);
} else if (pstyle == "compute") { } else if (pstyle == "compute") {
auto compute_map = lmp->modify->compute_map;
auto found = compute_map->find(name);
if (found != compute_map->end()) compute_map->erase(name);
// must delete all compute instances using this compute style // must delete all compute instances using this compute style
for (auto &icompute : lmp->modify->get_compute_by_style(name)) for (auto &icompute : lmp->modify->get_compute_by_style(name))
lmp->modify->delete_compute(icompute->id); lmp->modify->delete_compute(icompute->id);
} else if (pstyle == "fix") { auto compute_map = lmp->modify->compute_map;
auto found = compute_map->find(name);
if (found != compute_map->end()) compute_map->erase(name);
auto fix_map = lmp->modify->fix_map; } else if (pstyle == "fix") {
auto found = fix_map->find(name);
if (found != fix_map->end()) fix_map->erase(name);
// must delete all fix instances using this fix style // must delete all fix instances using this fix style
for (auto &ifix : lmp->modify->get_fix_by_style(name)) lmp->modify->delete_fix(ifix->id); for (auto &ifix : lmp->modify->get_fix_by_style(name)) lmp->modify->delete_fix(ifix->id);
auto fix_map = lmp->modify->fix_map;
auto found = fix_map->find(name);
if (found != fix_map->end()) fix_map->erase(name);
} else if (pstyle == "region") { } else if (pstyle == "region") {
for (auto &iregion : lmp->domain->get_region_by_style(name))
lmp->domain->delete_region(iregion);
auto region_map = lmp->domain->region_map; auto region_map = lmp->domain->region_map;
auto found = region_map->find(name); auto found = region_map->find(name);
if (found != region_map->end()) region_map->erase(name); if (found != region_map->end()) region_map->erase(name);
for (auto &iregion : lmp->domain->get_region_by_style(name))
lmp->domain->delete_region(iregion);
} else if (pstyle == "command") { } else if (pstyle == "command") {
auto command_map = lmp->input->command_map; auto command_map = lmp->input->command_map;
@ -416,12 +427,24 @@ void plugin_unload(const char *style, const char *name, LAMMPS *lmp)
} else if (pstyle == "run") { } else if (pstyle == "run") {
// must restore default run style if plugin style is in use
if (strcmp(name, lmp->update->integrate_style) == 0) {
char *str = (char *) "verlet";
lmp->update->create_integrate(1, &str, 1);
}
auto integrate_map = lmp->update->integrate_map; auto integrate_map = lmp->update->integrate_map;
auto found = integrate_map->find(name); auto found = integrate_map->find(name);
if (found != integrate_map->end()) integrate_map->erase(name); if (found != integrate_map->end()) integrate_map->erase(name);
} else if (pstyle == "min") { } else if (pstyle == "min") {
// must restore default minimize style if plugin style is in use
if (strcmp(name, lmp->update->minimize_style) == 0) {
char *str = (char *) "cg";
lmp->update->create_minimize(1, &str, 1);
}
auto minimize_map = lmp->update->minimize_map; auto minimize_map = lmp->update->minimize_map;
auto found = minimize_map->find(name); auto found = minimize_map->find(name);
if (found != minimize_map->end()) minimize_map->erase(name); if (found != minimize_map->end()) minimize_map->erase(name);
@ -434,18 +457,157 @@ void plugin_unload(const char *style, const char *name, LAMMPS *lmp)
#endif #endif
} }
/* --------------------------------------------------------------------
restore previously loaded plugins
-------------------------------------------------------------------- */
void plugin_restore(LAMMPS *lmp, bool warnflag)
{
for (auto &plugin : pluginlist) {
if (lmp->comm->me == 0)
utils::logmesg(lmp, "Restoring plugin: {} by {}\n", plugin.info, plugin.author);
std::string pstyle = plugin.style;
if (pstyle == "pair") {
auto pair_map = lmp->force->pair_map;
if (pair_map->find(plugin.name) != pair_map->end()) {
if (warnflag && (lmp->comm->me == 0))
lmp->error->warning(FLERR, "Overriding built-in pair style {} from plugin", plugin.name);
}
(*pair_map)[plugin.name] = (Force::PairCreator) plugin.creator.v1;
} else if (pstyle == "bond") {
auto bond_map = lmp->force->bond_map;
if (bond_map->find(plugin.name) != bond_map->end()) {
if (warnflag && (lmp->comm->me == 0))
lmp->error->warning(FLERR, "Overriding built-in bond style {} from plugin", plugin.name);
}
(*bond_map)[plugin.name] = (Force::BondCreator) plugin.creator.v1;
} else if (pstyle == "angle") {
auto angle_map = lmp->force->angle_map;
if (angle_map->find(plugin.name) != angle_map->end()) {
if (warnflag && (lmp->comm->me == 0))
lmp->error->warning(FLERR, "Overriding built-in angle style {} from plugin", plugin.name);
}
(*angle_map)[plugin.name] = (Force::AngleCreator) plugin.creator.v1;
} else if (pstyle == "dihedral") {
auto dihedral_map = lmp->force->dihedral_map;
if (dihedral_map->find(plugin.name) != dihedral_map->end()) {
if (warnflag && (lmp->comm->me == 0))
lmp->error->warning(FLERR, "Overriding built-in dihedral style {} from plugin",
plugin.name);
}
(*dihedral_map)[plugin.name] = (Force::DihedralCreator) plugin.creator.v1;
} else if (pstyle == "improper") {
auto improper_map = lmp->force->improper_map;
if (improper_map->find(plugin.name) != improper_map->end()) {
if (warnflag && (lmp->comm->me == 0))
lmp->error->warning(FLERR, "Overriding built-in improper style {} from plugin",
plugin.name);
}
(*improper_map)[plugin.name] = (Force::ImproperCreator) plugin.creator.v1;
} else if (pstyle == "kspace") {
auto kspace_map = lmp->force->kspace_map;
if (kspace_map->find(plugin.name) != kspace_map->end()) {
if (warnflag && (lmp->comm->me == 0))
lmp->error->warning(FLERR, "Overriding built-in kspace style {} from plugin",
plugin.name);
}
(*kspace_map)[plugin.name] = (Force::KSpaceCreator) plugin.creator.v1;
} else if (pstyle == "compute") {
auto compute_map = lmp->modify->compute_map;
if (compute_map->find(plugin.name) != compute_map->end()) {
if (warnflag && (lmp->comm->me == 0))
lmp->error->warning(FLERR, "Overriding built-in compute style {} from plugin",
plugin.name);
}
(*compute_map)[plugin.name] = (Modify::ComputeCreator) plugin.creator.v2;
} else if (pstyle == "fix") {
auto fix_map = lmp->modify->fix_map;
if (fix_map->find(plugin.name) != fix_map->end()) {
if (warnflag && (lmp->comm->me == 0))
lmp->error->warning(FLERR, "Overriding built-in fix style {} from plugin", plugin.name);
}
(*fix_map)[plugin.name] = (Modify::FixCreator) plugin.creator.v2;
} else if (pstyle == "region") {
auto region_map = lmp->domain->region_map;
if (region_map->find(plugin.name) != region_map->end()) {
if (warnflag && (lmp->comm->me == 0))
lmp->error->warning(FLERR, "Overriding built-in region style {} from plugin",
plugin.name);
}
(*region_map)[plugin.name] = (Domain::RegionCreator) plugin.creator.v2;
} else if (pstyle == "command") {
auto command_map = lmp->input->command_map;
if (command_map->find(plugin.name) != command_map->end()) {
if (warnflag && (lmp->comm->me == 0))
lmp->error->warning(FLERR, "Overriding built-in command style {} from plugin",
plugin.name);
}
(*command_map)[plugin.name] = (Input::CommandCreator) plugin.creator.v1;
} else if (pstyle == "run") {
auto integrate_map = lmp->update->integrate_map;
if (integrate_map->find(plugin.name) != integrate_map->end()) {
if (warnflag && (lmp->comm->me == 0))
lmp->error->warning(FLERR, "Overriding built-in run style {} from plugin", plugin.name);
}
(*integrate_map)[plugin.name] = (Update::IntegrateCreator) plugin.creator.v2;
} else if (pstyle == "min") {
auto minimize_map = lmp->update->minimize_map;
if (minimize_map->find(plugin.name) != minimize_map->end()) {
if (warnflag && (lmp->comm->me == 0))
lmp->error->warning(FLERR, "Overriding built-in minimize style {} from plugin",
plugin.name);
}
(*minimize_map)[plugin.name] = (Update::MinimizeCreator) plugin.creator.v1;
}
}
}
/* -------------------------------------------------------------------- /* --------------------------------------------------------------------
unload all loaded plugins unload all loaded plugins
-------------------------------------------------------------------- */ -------------------------------------------------------------------- */
void plugin_clear(LAMMPS *lmp) void plugin_clear(LAMMPS *lmp)
{ {
bool oldverbose = verbose;
verbose = true; verbose = true;
while (pluginlist.size() > 0) { while (pluginlist.size() > 0) {
auto p = pluginlist.begin(); auto p = pluginlist.begin();
plugin_unload(p->style, p->name, lmp); plugin_unload(p->style, p->name, lmp);
} }
verbose = true; verbose = oldverbose;
}
/* --------------------------------------------------------------------
unload all shared objects
-------------------------------------------------------------------- */
void plugin_finalize()
{
#if defined(LMP_PLUGIN)
while (pluginlist.size() > 0) {
auto p = pluginlist.begin();
void *handle = p->handle;
plugin_erase(p->style, p->name);
// if reference count is down to zero, close DSO handle.
--dso_refcounter[handle];
if (dso_refcounter[handle] == 0) { platform::dlclose(handle); }
}
#endif
} }
/* -------------------------------------------------------------------- /* --------------------------------------------------------------------

View File

@ -34,10 +34,12 @@ class Plugin : public Command {
void plugin_auto_load(LAMMPS *); void plugin_auto_load(LAMMPS *);
int plugin_load(const char *, LAMMPS *); int plugin_load(const char *, LAMMPS *);
void plugin_register(lammpsplugin_t *, void *); void plugin_register(lammpsplugin_t *, void *);
void plugin_restore(LAMMPS *, bool);
void plugin_unload(const char *, const char *, LAMMPS *); void plugin_unload(const char *, const char *, LAMMPS *);
void plugin_erase(const char *, const char *); void plugin_erase(const char *, const char *);
void plugin_clear(LAMMPS *); void plugin_clear(LAMMPS *);
void plugin_finalize();
int plugin_get_num_plugins(); int plugin_get_num_plugins();
int plugin_find(const char *, const char *); int plugin_find(const char *, const char *);

View File

@ -883,8 +883,9 @@ void LAMMPS::create()
python = new Python(this); python = new Python(this);
// auto-load plugins // restore and auto-load plugins
#if defined(LMP_PLUGIN) #if defined(LMP_PLUGIN)
plugin_restore(this, true);
plugin_auto_load(this); plugin_auto_load(this);
#endif #endif
} }
@ -991,11 +992,6 @@ void LAMMPS::init()
void LAMMPS::destroy() void LAMMPS::destroy()
{ {
// must wipe out all plugins first, if configured
#if defined(LMP_PLUGIN)
plugin_clear(this);
#endif
delete update; delete update;
update = nullptr; update = nullptr;

View File

@ -357,7 +357,8 @@ completed and then MPI is cleanly shut down. After calling this
function no more MPI calls may be made. function no more MPI calls may be made.
*See also* *See also*
:cpp:func:`lammps_kokkos_finalize`, :cpp:func:`lammps_python_finalize` :cpp:func:`lammps_kokkos_finalize`, :cpp:func:`lammps_python_finalize`,
:cpp:func:`lammps_plugin_finalize`
\endverbatim */ \endverbatim */
void lammps_mpi_finalize() void lammps_mpi_finalize()
@ -389,7 +390,8 @@ closed (to release associated resources).
After calling this function no Kokkos functionality may be used. After calling this function no Kokkos functionality may be used.
*See also* *See also*
:cpp:func:`lammps_mpi_finalize`, :cpp:func:`lammps_python_finalize` :cpp:func:`lammps_mpi_finalize`, :cpp:func:`lammps_python_finalize`,
:cpp:func:`lammps_plugin_finalize`
\endverbatim */ \endverbatim */
void lammps_kokkos_finalize() void lammps_kokkos_finalize()
@ -399,6 +401,35 @@ void lammps_kokkos_finalize()
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
/** Unload all plugins and release the corresponding DSO handles
*
\verbatim embed:rst
.. versionadded:: TBD
This function clears the list of all loaded plugins and closes the
corresponding DSO handles and releases the imported executable code.
However, this is **not** done when a LAMMPS instance is deleted because
plugins and their shared objects are global properties.
This function can be called to explicitly clear out all loaded plugins
in case it is safe to do so.
*See also*
:cpp:func:`lammps_mpi_finalize`, :cpp:func:`lammps_kokkos_finalize`,
:cpp:func:`lammps_python_finalize`
\endverbatim */
void lammps_plugin_finalize()
{
#if defined(LMP_PLUGIN)
plugin_finalize();
#endif
}
/* ---------------------------------------------------------------------- */
/** Clear the embedded Python environment /** Clear the embedded Python environment
* *
\verbatim embed:rst \verbatim embed:rst
@ -425,7 +456,8 @@ This function can be called to explicitly clear the Python
environment in case it is safe to do so. environment in case it is safe to do so.
*See also* *See also*
:cpp:func:`lammps_mpi_finalize`, :cpp:func:`lammps_kokkos_finalize` :cpp:func:`lammps_mpi_finalize`, :cpp:func:`lammps_kokkos_finalize`,
:cpp:func:`lammps_plugin_finalize`
\endverbatim */ \endverbatim */
void lammps_python_finalize() void lammps_python_finalize()
@ -433,7 +465,6 @@ void lammps_python_finalize()
Python::finalize(); Python::finalize();
} }
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
/** Call a LAMMPS Error class function /** Call a LAMMPS Error class function

View File

@ -140,6 +140,7 @@ void lammps_close(void *handle);
void lammps_mpi_init(); void lammps_mpi_init();
void lammps_mpi_finalize(); void lammps_mpi_finalize();
void lammps_kokkos_finalize(); void lammps_kokkos_finalize();
void lammps_plugin_finalize();
void lammps_python_finalize(); void lammps_python_finalize();
void lammps_error(void *handle, int error_type, const char *error_text); void lammps_error(void *handle, int error_type, const char *error_text);

View File

@ -35,6 +35,7 @@ static void finalize()
{ {
lammps_kokkos_finalize(); lammps_kokkos_finalize();
lammps_python_finalize(); lammps_python_finalize();
lammps_plugin_finalize();
} }
/* ---------------------------------------------------------------------- /* ----------------------------------------------------------------------

View File

@ -99,6 +99,13 @@ Update::Update(LAMMPS *lmp) :
Update::~Update() Update::~Update()
{ {
// restore default styles to avoid segfaults from plugins
char *str = (char *) "verlet";
create_integrate(1, &str, 1);
str = (char *) "cg";
create_minimize(1, &str, 1);
delete[] unit_style; delete[] unit_style;
delete[] integrate_style; delete[] integrate_style;

View File

@ -116,6 +116,7 @@ extern void lammps_mpi_init();
extern void lammps_mpi_finalize(); extern void lammps_mpi_finalize();
extern void lammps_kokkos_finalize(); extern void lammps_kokkos_finalize();
extern void lammps_python_finalize(); extern void lammps_python_finalize();
extern void lammps_plugin_finalize();
extern void lammps_error(void *handle, int error_type, const char *error_text); extern void lammps_error(void *handle, int error_type, const char *error_text);
extern char *lammps_expand(void *handle, const char *line); extern char *lammps_expand(void *handle, const char *line);
@ -315,6 +316,7 @@ extern void lammps_mpi_init();
extern void lammps_mpi_finalize(); extern void lammps_mpi_finalize();
extern void lammps_kokkos_finalize(); extern void lammps_kokkos_finalize();
extern void lammps_python_finalize(); extern void lammps_python_finalize();
extern void lammps_plugin_finalize();
extern void lammps_error(void *handle, int error_type, const char *error_text); extern void lammps_error(void *handle, int error_type, const char *error_text);
extern char *lammps_expand(void *handle, const char *line); extern char *lammps_expand(void *handle, const char *line);