diff --git a/doc/src/Commands_all.rst b/doc/src/Commands_all.rst index 132425948e..b43fd0ed56 100644 --- a/doc/src/Commands_all.rst +++ b/doc/src/Commands_all.rst @@ -86,6 +86,7 @@ An alphabetic list of all general LAMMPS commands. * :doc:`pair_style ` * :doc:`pair_write ` * :doc:`partition ` + * :doc:`plugin ` * :doc:`prd ` * :doc:`print ` * :doc:`processors ` diff --git a/doc/src/Developer.rst b/doc/src/Developer.rst index 3a0c03b7ea..f54bc4152f 100644 --- a/doc/src/Developer.rst +++ b/doc/src/Developer.rst @@ -14,6 +14,7 @@ of time and requests from the LAMMPS user community. Developer_flow Developer_write Developer_notes + Developer_plugins Developer_unittest Classes Developer_utils diff --git a/doc/src/Developer_plugins.rst b/doc/src/Developer_plugins.rst new file mode 100644 index 0000000000..ffbcf8a667 --- /dev/null +++ b/doc/src/Developer_plugins.rst @@ -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. diff --git a/doc/src/commands_list.rst b/doc/src/commands_list.rst index 2ec20ac220..e30d5c52dc 100644 --- a/doc/src/commands_list.rst +++ b/doc/src/commands_list.rst @@ -77,6 +77,7 @@ Commands pair_style pair_write partition + plugin prd print processors