Files
lammps/src/MDI/mdi_engine.cpp

344 lines
12 KiB
C++

/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
https://www.lammps.org/ 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.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Contributing author: Taylor Barnes (MolSSI)
MolSSI Driver Interface (MDI) support for LAMMPS
------------------------------------------------------------------------- */
#include "mdi_engine.h"
#include "atom.h"
#include "error.h"
#include "integrate.h"
#include "fix_mdi_engine.h"
#include "mdi.h"
#include "min.h"
#include "modify.h"
#include "output.h"
#include "timer.h"
#include "update.h"
#include <cstring>
#include <limits>
using namespace LAMMPS_NS;
/* ----------------------------------------------------------------------
trigger LAMMPS to start acting as an MDI engine
endlessly loop over receiving commands from driver and responding
much of the logic for this is in FixMDIEngine
when EXIT command is received, mdi/engine command exits
---------------------------------------------------------------------- */
void MDIEngine::command(int narg, char ** /*arg*/)
{
// list of nodes and commands that a MDI-compliant MD code should support
// default node and its commands
MDI_Register_node("@DEFAULT");
MDI_Register_command("@DEFAULT", "<@");
MDI_Register_command("@DEFAULT", "<CELL");
MDI_Register_command("@DEFAULT", "<CELL_DISPL");
MDI_Register_command("@DEFAULT", "<CHARGES");
MDI_Register_command("@DEFAULT", "<COORDS");
MDI_Register_command("@DEFAULT", "<LABELS");
MDI_Register_command("@DEFAULT", "<MASSES");
MDI_Register_command("@DEFAULT", "<NATOMS");
MDI_Register_command("@DEFAULT", "<TYPES");
MDI_Register_command("@DEFAULT", ">CELL");
MDI_Register_command("@DEFAULT", ">CELL_DISPL");
MDI_Register_command("@DEFAULT", ">COORDS");
MDI_Register_command("@DEFAULT", "@INIT_MD");
MDI_Register_command("@DEFAULT", "@INIT_OPTG");
MDI_Register_command("@DEFAULT", "EXIT");
// node for setting up and running a dynamics simulation
MDI_Register_node("@INIT_MD");
MDI_Register_command("@INIT_MD", "<@");
MDI_Register_command("@INIT_MD", "<CELL");
MDI_Register_command("@INIT_MD", "<CELL_DISPL");
MDI_Register_command("@INIT_MD", "<CHARGES");
MDI_Register_command("@INIT_MD", "<COORDS");
MDI_Register_command("@INIT_MD", "<ENERGY");
MDI_Register_command("@INIT_MD", "<FORCES");
MDI_Register_command("@INIT_MD", "<KE");
MDI_Register_command("@INIT_MD", "<LABELS");
MDI_Register_command("@INIT_MD", "<MASSES");
MDI_Register_command("@INIT_MD", "<NATOMS");
MDI_Register_command("@INIT_MD", "<PE");
MDI_Register_command("@INIT_MD", "<TYPES");
MDI_Register_command("@INIT_MD", ">CELL");
MDI_Register_command("@INIT_MD", ">CELL_DISPL");
MDI_Register_command("@INIT_MD", ">COORDS");
MDI_Register_command("@INIT_MD", ">FORCES");
MDI_Register_command("@INIT_MD", ">+FORCES");
MDI_Register_command("@INIT_MD", "@");
MDI_Register_command("@INIT_MD", "@COORDS");
MDI_Register_command("@INIT_MD", "@DEFAULT");
MDI_Register_command("@INIT_MD", "@FORCES");
MDI_Register_command("@INIT_MD", "EXIT");
// node for setting up and running a minimization
MDI_Register_node("@INIT_OPTG");
MDI_Register_command("@INIT_OPTG", "<@");
MDI_Register_command("@INIT_OPTG", "<CELL");
MDI_Register_command("@INIT_OPTG", "<CELL_DISPL");
MDI_Register_command("@INIT_OPTG", "<CHARGES");
MDI_Register_command("@INIT_OPTG", "<COORDS");
MDI_Register_command("@INIT_OPTG", "<ENERGY");
MDI_Register_command("@INIT_OPTG", "<FORCES");
MDI_Register_command("@INIT_OPTG", "<KE");
MDI_Register_command("@INIT_OPTG", "<LABELS");
MDI_Register_command("@INIT_OPTG", "<MASSES");
MDI_Register_command("@INIT_OPTG", "<NATOMS");
MDI_Register_command("@INIT_OPTG", "<PE");
MDI_Register_command("@INIT_OPTG", "<TYPES");
MDI_Register_command("@INIT_OPTG", ">CELL");
MDI_Register_command("@INIT_OPTG", ">CELL_DISPL");
MDI_Register_command("@INIT_OPTG", ">COORDS");
MDI_Register_command("@INIT_OPTG", ">FORCES");
MDI_Register_command("@INIT_OPTG", ">+FORCES");
MDI_Register_command("@INIT_OPTG", "@");
MDI_Register_command("@INIT_OPTG", "@COORDS");
MDI_Register_command("@INIT_OPTG", "@DEFAULT");
MDI_Register_command("@INIT_OPTG", "@FORCES");
MDI_Register_command("@INIT_OPTG", "EXIT");
// node at POST_FORCE location in timestep
MDI_Register_node("@FORCES");
MDI_Register_callback("@FORCES", ">FORCES");
MDI_Register_callback("@FORCES", ">+FORCES");
MDI_Register_command("@FORCES", "<@");
MDI_Register_command("@FORCES", "<CELL");
MDI_Register_command("@FORCES", "<CELL_DISPL");
MDI_Register_command("@FORCES", "<CHARGES");
MDI_Register_command("@FORCES", "<COORDS");
MDI_Register_command("@FORCES", "<ENERGY");
MDI_Register_command("@FORCES", "<FORCES");
MDI_Register_command("@FORCES", "<KE");
MDI_Register_command("@FORCES", "<LABELS");
MDI_Register_command("@FORCES", "<MASSES");
MDI_Register_command("@FORCES", "<NATOMS");
MDI_Register_command("@FORCES", "<PE");
MDI_Register_command("@FORCES", "<TYPES");
MDI_Register_command("@FORCES", ">CELL");
MDI_Register_command("@FORCES", ">CELL_DISPL");
MDI_Register_command("@FORCES", ">COORDS");
MDI_Register_command("@FORCES", ">FORCES");
MDI_Register_command("@FORCES", ">+FORCES");
MDI_Register_command("@FORCES", "@");
MDI_Register_command("@FORCES", "@COORDS");
MDI_Register_command("@FORCES", "@DEFAULT");
MDI_Register_command("@FORCES", "@FORCES");
MDI_Register_command("@FORCES", "EXIT");
// node at POST_INTEGRATE location in timestep
MDI_Register_node("@COORDS");
MDI_Register_command("@COORDS", "<@");
MDI_Register_command("@COORDS", "<CELL");
MDI_Register_command("@COORDS", "<CELL_DISPL");
MDI_Register_command("@COORDS", "<CHARGES");
MDI_Register_command("@COORDS", "<COORDS");
MDI_Register_command("@COORDS", "<ENERGY");
MDI_Register_command("@COORDS", "<FORCES");
MDI_Register_command("@COORDS", "<KE");
MDI_Register_command("@COORDS", "<LABELS");
MDI_Register_command("@COORDS", "<MASSES");
MDI_Register_command("@COORDS", "<NATOMS");
MDI_Register_command("@COORDS", "<PE");
MDI_Register_command("@COORDS", "<TYPES");
MDI_Register_command("@COORDS", ">CELL");
MDI_Register_command("@COORDS", ">CELL_DISPL");
MDI_Register_command("@COORDS", ">COORDS");
MDI_Register_command("@COORDS", ">FORCES");
MDI_Register_command("@COORDS", ">+FORCES");
MDI_Register_command("@COORDS", "@");
MDI_Register_command("@COORDS", "@COORDS");
MDI_Register_command("@COORDS", "@DEFAULT");
MDI_Register_command("@COORDS", "@FORCES");
MDI_Register_command("@COORDS", "EXIT");
// if the mdi/engine fix is not already present, add it now
int ifix = modify->find_fix_by_style("mdi/engine");
bool added_mdi_engine_fix = false;
if (ifix < 0) {
modify->add_fix("MDI_ENGINE_INTERNAL all mdi/engine");
added_mdi_engine_fix = true;
}
// identify the mdi_engine fix
ifix = modify->find_fix_by_style("mdi/engine");
mdi_fix = static_cast<FixMDIEngine *>(modify->fix[ifix]);
// check that LAMMPS is setup as a compatible MDI engine
if (narg > 0) error->all(FLERR, "Illegal mdi/engine command");
if (atom->tag_enable == 0) error->all(FLERR, "Cannot use mdi/engine without atom IDs");
if (atom->tag_consecutive() == 0) error->all(FLERR, "mdi/engine requires consecutive atom IDs");
// endless engine loop, responding to driver commands
char *command;
while (1) {
// mdi/engine command only recognizes three nodes
// DEFAULT, INIT_MD, INIT_OPTG
command = mdi_fix->engine_mode("@DEFAULT");
// MDI commands for dynamics or minimization
if (strcmp(command, "@INIT_MD") == 0) {
command = mdi_md();
if (strcmp(command, "EXIT")) break;
} else if (strcmp(command, "@INIT_OPTG") == 0) {
command = mdi_optg();
if (strcmp(command, "EXIT")) break;
} else if (strcmp(command, "EXIT") == 0) {
break;
} else
error->all(FLERR, "MDI node exited with invalid command: {}", command);
}
// remove mdi/engine fix that mdi/engine instantiated
if (added_mdi_engine_fix) modify->delete_fix("MDI_ENGINE_INTERNAL");
}
/* ----------------------------------------------------------------------
run an MD simulation under control of driver
---------------------------------------------------------------------- */
char *MDIEngine::mdi_md()
{
// initialize an MD simulation
update->whichflag = 1;
timer->init_timeout();
update->nsteps = 1;
update->ntimestep = 0;
update->firststep = update->ntimestep;
update->laststep = update->ntimestep + update->nsteps;
update->beginstep = update->firststep;
update->endstep = update->laststep;
lmp->init();
// engine is now at @INIT_MD node
char *command = nullptr;
command = mdi_fix->engine_mode("@INIT_MD");
if (strcmp(command, "@DEFAULT") == 0 || strcmp(command, "EXIT") == 0) return command;
// setup the MD simulation
update->integrate->setup(1);
command = mdi_fix->engine_mode("@FORCES");
if (strcmp(command, "@DEFAULT") == 0 || strcmp(command, "EXIT") == 0) return command;
// run MD one step at a time
while (1) {
update->whichflag = 1;
timer->init_timeout();
update->nsteps += 1;
update->laststep += 1;
update->endstep = update->laststep;
output->next = update->ntimestep + 1;
// single MD timestep
update->integrate->run(1);
// done with MD if driver sends @DEFAULT or EXIT
command = mdi_fix->command;
if (strcmp(command, "@DEFAULT") == 0 || strcmp(command, "EXIT") == 0) return command;
}
return nullptr;
}
/* ----------------------------------------------------------------------
perform minimization under control of driver
---------------------------------------------------------------------- */
char *MDIEngine::mdi_optg()
{
// setup the minimizer in a way that ensures optimization
// will continue until MDI driver exits
update->etol = std::numeric_limits<double>::min();
update->ftol = std::numeric_limits<double>::min();
update->nsteps = std::numeric_limits<int>::max();
update->max_eval = std::numeric_limits<int>::max();
update->whichflag = 2;
update->beginstep = update->firststep = update->ntimestep;
update->endstep = update->laststep = update->firststep + update->nsteps;
lmp->init();
// engine is now at @INIT_OPTG node
char *command = nullptr;
command = mdi_fix->engine_mode("@INIT_OPTG");
if (strcmp(command, "@DEFAULT") == 0 || strcmp(command, "EXIT") == 0) return command;
// setup the minimization
update->minimize->setup();
// get new command
command = mdi_fix->command;
if (strcmp(command, "@DEFAULT") == 0 || strcmp(command, "EXIT") == 0) return command;
// Start a minimization, which is configured to run (essentially)
// infinite steps. When the driver sends the EXIT command,
// the minimizer's energy and force tolerances are set to
// extremely large values, causing the minimization to end.
update->minimize->iterate(update->nsteps);
// return if driver sends @DEFAULT or EXIT
command = mdi_fix->command;
if (strcmp(command, "@DEFAULT") == 0 || strcmp(command, "EXIT") == 0) return command;
error->all(FLERR, "MDI reached end of OPTG simulation with invalid command: {}", command);
return nullptr;
}