add preliminary documentation for plugin command and about how to write plugins

This commit is contained in:
Axel Kohlmeyer
2021-03-11 19:33:07 -05:00
parent 3ec9f2fd5e
commit c61de8740c
4 changed files with 101 additions and 0 deletions

View File

@ -0,0 +1,98 @@
Writing plugins
---------------
Plugins provide a mechanism to add functionality to a LAMMPS executable
without recompiling LAMMPS. This uses the operating system's
capability to load dynamic shared object (DSO) files in a way similar
shared libraries and then references specific functions those DSOs.
Any DSO file with plugins has to include an initialization function
with a specific name that has to follow specific rules. When loading
the DSO, this function is called and will then register the contained
plugin(s) with LAMMPS.
From the programmer perspective this can work because of the object
oriented design where all pair style commands are derived from the class
Pair, all fix style commands from the class Fix and so on and only
functions from those base classes are called directly. When a
:doc:`pair_style` command or :doc:`fix` command is issued a new
instance of such a derived class is created. This is done by a
so-called factory function which is mapped to the style name. Thus
when, for example, the LAMMPS processes the command
``pair_style lj/cut 2.5``, LAMMPS will look up the factory function
for creating the ``PairLJCut`` class and then execute it. The return
value of that function is a ``Pair *`` pointer and the pointer will
be assigned to the location for the currently active pair style.
A plugin thus has to implement such a factory function and register it
with LAMMPS so that it gets added to the map of available styles of
the given category. To register a plugin with LAMMPS an initialization
function has to be called that follows specific rules explained below.
As an example, for a hypothetical pair style "morse2" implemented in a
class ``PairMorse2`` in the files ``pair_morse2.h`` and
``pair_morse2.cpp`` the file with the factory function and initialization
function would look like this:
.. code-block:: C++
#include "lammpsplugin.h"
#include "version.h"
#include "pair_morse2.h"
using namespace LAMMPS_NS;
static Pair *morse2creator(LAMMPS *lmp)
{
return new PairMorse2(lmp);
}
extern "C" void lammpsplugin_init(void *lmp, void *handle, void *regfunc)
{
lammpsplugin_regfunc register_plugin = (lammpsplugin_regfunc) regfunc;
lammpsplugin_t plugin;
plugin.version = LAMMPS_VERSION;
plugin.style = "pair";
plugin.name = "morse2";
plugin.info = "Morse2 variant pair style v1.0";
plugin.author = "Axel Kohlmeyer (akohlmey@gmail.com)";
plugin.creator = (lammpsplugin_factory *) &morse2creator;
plugin.handle = handle;
(*register_plugin)(&plugin,lmp);
}
The factory function in this example is called ``morse2creator()``. It
receives a pointer to the LAMMPS class as argument and returns a
pointer to the allocated class instance derived from the ``Pair`` class.
This function may be declared static to avoid clashes with other plugins.
The name of the derived class, ``PairMorse2``, must be unique inside
the entire LAMMPS executable.
The initialization function **must** be called ``lammpsplugin_init``, it
**must** have C bindings and it takes three void pointers as arguments.
The first is a pointer to the LAMMPS class that calls it and it needs to
be passed to the registration function. The second argument is a
pointer to the internal handle of the DSO file, this needs to added to
the plugin info struct, so that the DSO can be close and unloaded when
all its contained plugins are unloaded. The third argument is a
function pointer to the registration function and needs to be stored
in a variable of ``lammpsplugin_regfunc`` type.
To register a plugin a struct of the ``lammpsplugin_t`` needs to be filled
with relevant info: current LAMMPS version string, kind of style, name of
style, info string, author string, pointer to factory function, DSO handle.
The the registration function is called with a pointer to the address of
this struct and the pointer of the LAMMPS class. The registration function
will then add the factory function of the plugin style to the respective
style map under the provided name. It will also make a copy of the struct
in a list of all loaded plugins and update the reference counter for loaded
plugins from this specific DSO file.
The pair style itself (i.e. the PairMorse2 class in this example) can be
written just like any other pair style that is included in LAMMPS. For
a plugin, the use of the ``PairStyle`` macro in the section encapsulated
by ``#ifdef PAIR_CLASS`` is not needed, since the mapping of the class
name to the style name is done by the plugin registration function with
the information from the ``lammpsplugin_t`` struct. It may be included
in case the new code is intended to be later included in LAMMPS directly.