From 9209cbba92a9a271b8642a86b766b4e507f9d2ee Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 11 Mar 2021 21:19:04 -0500 Subject: [PATCH] add support for loading plugins for fixes --- doc/src/Developer_plugins.rst | 41 ++++++- examples/plugins/Makefile | 8 ++ examples/plugins/fix_nve2.cpp | 171 ++++++++++++++++++++++++++++++ examples/plugins/fix_nve2.h | 58 ++++++++++ examples/plugins/morse2plugin.cpp | 5 +- examples/plugins/nve2plugin.cpp | 30 ++++++ src/lammpsplugin.h | 6 +- src/plugin.cpp | 14 ++- 8 files changed, 325 insertions(+), 8 deletions(-) create mode 100644 examples/plugins/fix_nve2.cpp create mode 100644 examples/plugins/fix_nve2.h create mode 100644 examples/plugins/nve2plugin.cpp diff --git a/doc/src/Developer_plugins.rst b/doc/src/Developer_plugins.rst index ffbcf8a667..59402165d1 100644 --- a/doc/src/Developer_plugins.rst +++ b/doc/src/Developer_plugins.rst @@ -57,17 +57,54 @@ function would look like this: plugin.name = "morse2"; plugin.info = "Morse2 variant pair style v1.0"; plugin.author = "Axel Kohlmeyer (akohlmey@gmail.com)"; - plugin.creator = (lammpsplugin_factory *) &morse2creator; + plugin.creator1 = (lammpsplugin_factory1 *) &morse2creator; + plugin.creator2 = nullptr; 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 +receives a pointer to the LAMMPS class as only argument and thus has to +be assigned to the *creator1* member of the plugin struct and cast to the +``lammpsplugin_factory1`` pointer type. It 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. +If the factory function would be for a fix or compute, which take three +arguments (a pointer to the LAMMPS class, the number of arguments and the +list of argument strings), then the pointer type is ``lammpsplugin_factory2`` +and it must be assigned to the *creator2* member of the plugin struct. +Below is an example for that: + +.. code-block:: C++ + + #include "lammpsplugin.h" + #include "version.h" + #include "fix_nve2.h" + + using namespace LAMMPS_NS; + + static Fix *nve2creator(LAMMPS *lmp, int argc, char **argv) + { + return new FixNVE2(lmp,argc,argv); + } + + 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 = "fix"; + plugin.name = "nve2"; + plugin.info = "NVE2 variant fix style v1.0"; + plugin.author = "Axel Kohlmeyer (akohlmey@gmail.com)"; + plugin.creator1 = nullptr; + plugin.creator2 = (lammpsplugin_factory2 *) &nve2creator; + plugin.handle = handle; + (*register_plugin)(&plugin,lmp); + } The initialization function **must** be called ``lammpsplugin_init``, it **must** have C bindings and it takes three void pointers as arguments. diff --git a/examples/plugins/Makefile b/examples/plugins/Makefile index 5d60ae8651..c8ec554d5d 100644 --- a/examples/plugins/Makefile +++ b/examples/plugins/Makefile @@ -2,9 +2,14 @@ CXX=mpicxx CXXFLAGS=-I../../src -Wall -Wextra -O3 -fPIC -I../../src/USER-OMP -fopenmp LD=$(CXX) -shared -rdynamic -fopenmp +default: morse2plugin.so nve2plugin.so + morse2plugin.so: morse2plugin.o pair_morse2.o pair_morse2_omp.o $(LD) -o $@ $^ +nve2plugin.so: nve2plugin.o fix_nve2.o + $(LD) -o $@ $^ + .cpp.o: $(CXX) -o $@ $(CXXFLAGS) -c $< @@ -12,6 +17,9 @@ pair_morse2.o: pair_morse2.cpp pair_morse2.h pair_morse2_omp.o: pair_morse2_omp.cpp pair_morse2_omp.h pair_morse2.h morse2plugin.o: morse2plugin.cpp pair_morse2.h pair_morse2_omp.h +fix_nve2.o: fix_nve2.cpp fix_nve2.h +nve2plugin.o: nve2plugin.cpp fix_nve2.h + clean: rm -f *~ *.so *.o log.lammps diff --git a/examples/plugins/fix_nve2.cpp b/examples/plugins/fix_nve2.cpp new file mode 100644 index 0000000000..bb6f53b810 --- /dev/null +++ b/examples/plugins/fix_nve2.cpp @@ -0,0 +1,171 @@ +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + https://lammps.sandia.gov/, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +#include "fix_nve2.h" +#include +#include "atom.h" +#include "force.h" +#include "update.h" +#include "respa.h" +#include "error.h" + +using namespace LAMMPS_NS; +using namespace FixConst; + +/* ---------------------------------------------------------------------- */ + +FixNVE2::FixNVE2(LAMMPS *lmp, int narg, char **arg) : + Fix(lmp, narg, arg) +{ + if (strcmp(style,"nve/sphere") != 0 && narg < 3) + error->all(FLERR,"Illegal fix nve command"); + + dynamic_group_allow = 1; + time_integrate = 1; +} + +/* ---------------------------------------------------------------------- */ + +int FixNVE2::setmask() +{ + int mask = 0; + mask |= INITIAL_INTEGRATE; + mask |= FINAL_INTEGRATE; + mask |= INITIAL_INTEGRATE_RESPA; + mask |= FINAL_INTEGRATE_RESPA; + return mask; +} + +/* ---------------------------------------------------------------------- */ + +void FixNVE2::init() +{ + dtv = update->dt; + dtf = 0.5 * update->dt * force->ftm2v; + + if (strstr(update->integrate_style,"respa")) + step_respa = ((Respa *) update->integrate)->step; +} + +/* ---------------------------------------------------------------------- + allow for both per-type and per-atom mass +------------------------------------------------------------------------- */ + +void FixNVE2::initial_integrate(int /*vflag*/) +{ + double dtfm; + + // update v and x of atoms in group + + double **x = atom->x; + double **v = atom->v; + double **f = atom->f; + double *rmass = atom->rmass; + double *mass = atom->mass; + int *type = atom->type; + int *mask = atom->mask; + int nlocal = atom->nlocal; + if (igroup == atom->firstgroup) nlocal = atom->nfirst; + + if (rmass) { + for (int i = 0; i < nlocal; i++) + if (mask[i] & groupbit) { + dtfm = dtf / rmass[i]; + v[i][0] += dtfm * f[i][0]; + v[i][1] += dtfm * f[i][1]; + v[i][2] += dtfm * f[i][2]; + x[i][0] += dtv * v[i][0]; + x[i][1] += dtv * v[i][1]; + x[i][2] += dtv * v[i][2]; + } + + } else { + for (int i = 0; i < nlocal; i++) + if (mask[i] & groupbit) { + dtfm = dtf / mass[type[i]]; + v[i][0] += dtfm * f[i][0]; + v[i][1] += dtfm * f[i][1]; + v[i][2] += dtfm * f[i][2]; + x[i][0] += dtv * v[i][0]; + x[i][1] += dtv * v[i][1]; + x[i][2] += dtv * v[i][2]; + } + } +} + +/* ---------------------------------------------------------------------- */ + +void FixNVE2::final_integrate() +{ + double dtfm; + + // update v of atoms in group + + double **v = atom->v; + double **f = atom->f; + double *rmass = atom->rmass; + double *mass = atom->mass; + int *type = atom->type; + int *mask = atom->mask; + int nlocal = atom->nlocal; + if (igroup == atom->firstgroup) nlocal = atom->nfirst; + + if (rmass) { + for (int i = 0; i < nlocal; i++) + if (mask[i] & groupbit) { + dtfm = dtf / rmass[i]; + v[i][0] += dtfm * f[i][0]; + v[i][1] += dtfm * f[i][1]; + v[i][2] += dtfm * f[i][2]; + } + + } else { + for (int i = 0; i < nlocal; i++) + if (mask[i] & groupbit) { + dtfm = dtf / mass[type[i]]; + v[i][0] += dtfm * f[i][0]; + v[i][1] += dtfm * f[i][1]; + v[i][2] += dtfm * f[i][2]; + } + } +} + +/* ---------------------------------------------------------------------- */ + +void FixNVE2::initial_integrate_respa(int vflag, int ilevel, int /*iloop*/) +{ + dtv = step_respa[ilevel]; + dtf = 0.5 * step_respa[ilevel] * force->ftm2v; + + // innermost level - NVE update of v and x + // all other levels - NVE update of v + + if (ilevel == 0) initial_integrate(vflag); + else final_integrate(); +} + +/* ---------------------------------------------------------------------- */ + +void FixNVE2::final_integrate_respa(int ilevel, int /*iloop*/) +{ + dtf = 0.5 * step_respa[ilevel] * force->ftm2v; + final_integrate(); +} + +/* ---------------------------------------------------------------------- */ + +void FixNVE2::reset_dt() +{ + dtv = update->dt; + dtf = 0.5 * update->dt * force->ftm2v; +} diff --git a/examples/plugins/fix_nve2.h b/examples/plugins/fix_nve2.h new file mode 100644 index 0000000000..f1b2244128 --- /dev/null +++ b/examples/plugins/fix_nve2.h @@ -0,0 +1,58 @@ +/* -*- c++ -*- ---------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +#ifdef FIX_CLASS + +FixStyle(nve2,FixNVE2) + +#else + +#ifndef LMP_FIX_NVE2_H +#define LMP_FIX_NVE2_H + +#include "fix.h" + +namespace LAMMPS_NS { + +class FixNVE2 : public Fix { + public: + FixNVE2(class LAMMPS *, int, char **); + virtual ~FixNVE2() {} + int setmask(); + virtual void init(); + virtual void initial_integrate(int); + virtual void final_integrate(); + virtual void initial_integrate_respa(int, int, int); + virtual void final_integrate_respa(int, int); + virtual void reset_dt(); + + protected: + double dtv,dtf; + double *step_respa; + int mass_require; +}; + +} + +#endif +#endif + +/* ERROR/WARNING messages: + +E: Illegal ... command + +Self-explanatory. Check the input script syntax and compare to the +documentation for the command. You can use -echo screen as a +command-line option when running LAMMPS to see the offending line. + +*/ diff --git a/examples/plugins/morse2plugin.cpp b/examples/plugins/morse2plugin.cpp index 286aa30c35..7151e35cd2 100644 --- a/examples/plugins/morse2plugin.cpp +++ b/examples/plugins/morse2plugin.cpp @@ -31,13 +31,14 @@ extern "C" void lammpsplugin_init(void *lmp, void *handle, void *regfunc) plugin.name = "morse2"; plugin.info = "Morse2 variant pair style v1.0"; plugin.author = "Axel Kohlmeyer (akohlmey@gmail.com)"; - plugin.creator = (lammpsplugin_factory *) &morse2creator; + plugin.creator1 = (lammpsplugin_factory1 *) &morse2creator; + plugin.creator2 = nullptr; plugin.handle = handle; (*register_plugin)(&plugin,lmp); // also register morse2/omp pair style. only need to update changed fields plugin.name = "morse2/omp"; plugin.info = "Morse2 variant pair style for OpenMP v1.0"; - plugin.creator = (lammpsplugin_factory *) &morse2ompcreator; + plugin.creator1 = (lammpsplugin_factory1 *) &morse2ompcreator; (*register_plugin)(&plugin,lmp); } diff --git a/examples/plugins/nve2plugin.cpp b/examples/plugins/nve2plugin.cpp new file mode 100644 index 0000000000..9c9ce3d8d2 --- /dev/null +++ b/examples/plugins/nve2plugin.cpp @@ -0,0 +1,30 @@ + +#include "lammpsplugin.h" + +#include "version.h" + +#include + +#include "fix_nve2.h" + +using namespace LAMMPS_NS; + +static Fix *nve2creator(LAMMPS *lmp, int argc, char **argv) +{ + return new FixNVE2(lmp, argc, argv); +} + +extern "C" void lammpsplugin_init(void *lmp, void *handle, void *regfunc) +{ + lammpsplugin_t plugin; + lammpsplugin_regfunc register_plugin = (lammpsplugin_regfunc) regfunc; + + plugin.version = LAMMPS_VERSION; + plugin.style = "fix"; + plugin.name = "nve2"; + plugin.info = "NVE2 variant fix style v1.0"; + plugin.author = "Axel Kohlmeyer (akohlmey@gmail.com)"; + plugin.creator2 = (lammpsplugin_factory2 *) &nve2creator; + plugin.handle = handle; + (*register_plugin)(&plugin,lmp); +} diff --git a/src/lammpsplugin.h b/src/lammpsplugin.h index 34a0b60811..958235fdaa 100644 --- a/src/lammpsplugin.h +++ b/src/lammpsplugin.h @@ -18,7 +18,8 @@ extern "C" { - typedef void *(lammpsplugin_factory)(void *); + typedef void *(lammpsplugin_factory1)(void *); + typedef void *(lammpsplugin_factory2)(void *, int, char **); typedef struct { const char *version; @@ -26,7 +27,8 @@ extern "C" { const char *name; const char *info; const char *author; - lammpsplugin_factory *creator; + lammpsplugin_factory1 *creator1; + lammpsplugin_factory2 *creator2; void *handle; } lammpsplugin_t; diff --git a/src/plugin.cpp b/src/plugin.cpp index f2499e6528..7a42734bd9 100644 --- a/src/plugin.cpp +++ b/src/plugin.cpp @@ -114,10 +114,20 @@ namespace LAMMPS_NS plugin->name)); } - (*pair_map)[plugin->name] = (Force::PairCreator)plugin->creator; + (*pair_map)[plugin->name] = (Force::PairCreator)plugin->creator1; + } else if (pstyle == "fix") { + auto fix_map = lmp->modify->fix_map; + if (fix_map->find(plugin->name) != fix_map->end()) { + if (lmp->comm->me == 0) + lmp->error->warning(FLERR,fmt::format("Overriding built-in fix " + "style {} from plugin", + plugin->name)); + } + + (*fix_map)[plugin->name] = (Modify::FixCreator)plugin->creator2; } else { utils::logmesg(lmp,fmt::format("Loading plugin for {} styles not " - "yet implemented\n", pstyle)); + "yet implemented\n",pstyle)); pluginlist.pop_back(); } }