diff --git a/examples/mdi/README b/examples/mdi/README index dedf388a3b..51268e57ee 100644 --- a/examples/mdi/README +++ b/examples/mdi/README @@ -2,32 +2,47 @@ These are examples that work the MDI package in LAMMPS which uses the MolSSI MDI library for coupling codes together and communicating between them with MDI messages. -To use the serial_drive.py example you will need Python 3 with Numpy -and mpi4py available in your Python. Make sure LAMMPS and Python are -using same the same version of MPI. - In MDI lingo, one code is the driver and another code is the engine. The 2 codes can be written in any language; C++ (LAMMPS) and Python -are illustrated here. The 2 codes can be run on different numbers of -processors. - -The 2 codes can communicate either via TCP (sockets) or via MPI. For -the TCP case, the driver and engine need to be launched separately, +are illustrated here. The 2 codes can each be stand-alone codes, in +which case they can be run on different numbers of processors. The 2 +codes can communicate either via TCP (sockets) or via MPI. For the +TCP case, the driver and engine need to be launched separately, e.g. in 2 windows on your desktop machine. For the MPI case, a single mpirun command launches both codes. -The example run commands below have variants for these options. +Alternatively the engine code can be a plugin library which the driver +code loads, in which case the driver and engine run on the same +processors. + +LAMMPS supports operating in all these modes. It can be an engine +operating either as a stand-alone code or as a plugin. It can also be +a driver and couple to an engine that is either a stand-alone code or +a plugin. Examples for all these use cases are in this directory. +The example run commands below illustrate all the variants. + +To use LAMMPS as a plugin engine, you must build it as a shared library. +Something like this: + +cd src +make yes-mdi +make mode=shlib mpi + +To use the serial_driver.py example you will need Python 3 with Numpy +and mpi4py available in your Python. Make sure LAMMPS and Python are +using same the same version of MPI. ------------------------------------------------- ------------------------------------------------- -* Example #1 = run AIMD with 2 instances of LAMMPS as driver and engine - as an engine, LAMMPS is a surrogate for a quantum code +* Example #1 = run ab inito MD (AIMD) + 2 instances of LAMMPS operate as a driver and engine + as an engine, LAMMPS is a surrogate for a quantum code Note that the 2 input scripts in.aimd.alone and in.aimd.driver have an option for running in NVE vs NPT mode. Comment in/out the appropriate line to change modes. Nothing needs to be -changed in the 3rd input script in.aimd.engine. +changed in the in.aimd.engine or in.aimd.engine.plugin scripts. --- @@ -83,13 +98,13 @@ Run in plugin mode: 3 procs ------------------------------------------------- * Example #2 = Python driver runs sequence of unrelated LAMMPS calculations - calcs can be single-point, MD runs, or minimizations + Each calculation can be a single-point evaluation, an MD run, or a minimization. The sequence_driver.py code allows for optional switches in addition to -mdi (required) and the -plugin and -plugin_args switches which are used to link to an engine as a plugin library. The example run commands below just use the default values of the optional switches. -The switches are also explained the top of the file; the info is +The switches are also explained at the top of the file; the info is copied here: # -n 10 @@ -163,7 +178,7 @@ The aimd_driver.py code allows for an optional switch in addition to -mdi (required) and the -plugin and -plugin_args swiches which are used to link to the 2 engines as a plugin libraries. The example run commands below use the default values of the optional switch. The -switches are also explained the top of the file; the info is copied +switch is also explained the top of the file; the info is copied here: # -nsteps 5 diff --git a/examples/mdi/in.aimd.driver.plugin b/examples/mdi/in.aimd.driver.plugin index 655fd3c134..a974bff9df 100644 --- a/examples/mdi/in.aimd.driver.plugin +++ b/examples/mdi/in.aimd.driver.plugin @@ -23,12 +23,12 @@ fix 1 all nve # NPT #fix 1 all npt temp 1.0 1.0 0.1 iso 1.0 1.0 1.0 -fix 2 all mdi/aimd +fix 2 all mdi/aimd plugin fix_modify 2 energy yes virial yes thermo_style custom step temp pe etotal press vol thermo 1 -mdi/plugin lammps & - args '-mdi "-role ENGINE -name lammps -method LINK"' & +mdi/plugin lammps mdi "-role ENGINE -name lammps -method LINK" & + infile in.aimd.engine extra "-log log.aimd.engine.plugin" & command "run 5" diff --git a/src/MDI/fix_mdi_aimd.cpp b/src/MDI/fix_mdi_aimd.cpp index e3f86fa58f..31989a4938 100644 --- a/src/MDI/fix_mdi_aimd.cpp +++ b/src/MDI/fix_mdi_aimd.cpp @@ -30,7 +30,7 @@ enum{NATIVE,REAL,METAL}; // LAMMPS units which MDI supports FixMDIAimd::FixMDIAimd(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg) { - if (narg != 3) error->all(FLERR, "Illegal fix mdi/aimd command"); + if (narg > 4) error->all(FLERR, "Illegal fix mdi/aimd command"); scalar_flag = 1; global_freq = 1; @@ -39,6 +39,14 @@ FixMDIAimd::FixMDIAimd(LAMMPS *lmp, int narg, char **arg) : virial_global_flag = 1; thermo_energy = thermo_virial = 1; + // check for plugin arg + + plugin = 0; + if (narg == 4) { + if (strcmp(arg[3],"plugin") == 0) plugin = 1; + else error->all(FLERR, "Illegal fix mdi/aimd command"); + } + // check requirements for LAMMPS to work with MDI as an engine if (atom->tag_enable == 0) @@ -67,10 +75,12 @@ FixMDIAimd::FixMDIAimd(LAMMPS *lmp, int narg, char **arg) : unit_conversions(); - // connect to MDI engine + // connect to MDI engine, only if engine is stand-alone code - // MDI_Accept_communicator(&mdicomm); - // if (mdicomm <= 0) error->all(FLERR, "Unable to connect to MDI engine"); + if (!plugin) { + MDI_Accept_communicator(&mdicomm); + if (mdicomm <= 0) error->all(FLERR, "Unable to connect to MDI engine"); + } nprocs = comm->nprocs; } @@ -79,10 +89,12 @@ FixMDIAimd::FixMDIAimd(LAMMPS *lmp, int narg, char **arg) : FixMDIAimd::~FixMDIAimd() { - // send exit command to engine + // send exit command to engine, only if engine is stand-alone code - //int ierr = MDI_Send_command("EXIT",mdicomm); - //if (ierr) error->all(FLERR,"MDI: EXIT command"); + if (!plugin) { + int ierr = MDI_Send_command("EXIT",mdicomm); + if (ierr) error->all(FLERR,"MDI: EXIT command"); + } // clean up diff --git a/src/MDI/fix_mdi_aimd.h b/src/MDI/fix_mdi_aimd.h index 0d891bd47b..dd3b2ab981 100644 --- a/src/MDI/fix_mdi_aimd.h +++ b/src/MDI/fix_mdi_aimd.h @@ -44,6 +44,8 @@ class FixMDIAimd : public Fix { private: int nprocs; + int plugin; + int eflag_caller; double engine_energy; int lmpunits; @@ -65,7 +67,6 @@ class FixMDIAimd : public Fix { void reallocate(); void unit_conversions(); - }; } diff --git a/src/MDI/mdi_plugin.cpp b/src/MDI/mdi_plugin.cpp index 77b4b200ad..8d4bb376c8 100644 --- a/src/MDI/mdi_plugin.cpp +++ b/src/MDI/mdi_plugin.cpp @@ -37,27 +37,52 @@ void MDIPlugin::command(int narg, char **arg) if (narg < 1) error->all(FLERR,"Illegal mdi/plugin command"); char *plugin_name = arg[0]; - char *plugin_args = nullptr; - plugin_command = nullptr; - printf("NARG %d\n",narg); + char *mdi_arg = nullptr; + char *infile_arg = nullptr; + char *extra_arg = nullptr; + lammps_command = nullptr; int iarg = 1; while (iarg < narg) { - if (strcmp(arg[iarg],"args") == 0) { + if (strcmp(arg[iarg],"mdi") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal mdi/plugin command"); - plugin_args = arg[iarg+1]; + mdi_arg = arg[iarg+1]; + iarg += 2; + } else if (strcmp(arg[iarg],"infile") == 0) { + if (iarg+2 > narg) error->all(FLERR,"Illegal mdi/plugin command"); + infile_arg = arg[iarg+1]; + iarg += 2; + } else if (strcmp(arg[iarg],"extra") == 0) { + if (iarg+2 > narg) error->all(FLERR,"Illegal mdi/plugin command"); + extra_arg = arg[iarg+1]; iarg += 2; } else if (strcmp(arg[iarg],"command") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal mdi/plugin command"); - plugin_command = arg[iarg+1]; + int n = strlen(arg[iarg+1]) + 1; + lammps_command = new char[n]; + strcpy(lammps_command,arg[iarg+1]); iarg += 2; } else error->all(FLERR,"Illegal mdi/plugin command"); } - // error if no command was specified + // error checks - if (!plugin_command) error->all(FLERR,"MDI/plugin must specify command"); + if (!mdi_arg || !infile_arg || !lammps_command) + error->all(FLERR,"MDI/plugin must specify mdi, infile, command keywords"); + + // build full plugin_args string for args to plugin library + + int n = strlen(mdi_arg) + strlen(infile_arg) + strlen(extra_arg) + 16; + char *plugin_args = new char[n]; + strcat(plugin_args,"-mdi \""); + strcat(plugin_args,mdi_arg); + strcat(plugin_args,"\" -in "); + strcat(plugin_args,infile_arg); + if (extra_arg) { + strcat(plugin_args," "); + strcat(plugin_args,extra_arg); + } // find FixMDIAimd instance so can reset its mdicomm @@ -72,6 +97,8 @@ void MDIPlugin::command(int narg, char **arg) printf("ARGS %s\n",plugin_args); MDI_Launch_plugin(plugin_name,plugin_args,world,plugin_wrapper,(void *)this); + + delete [] plugin_args; } /* ---------------------------------------------------------------------- @@ -81,25 +108,27 @@ void MDIPlugin::command(int narg, char **arg) ---------------------------------------------------------------------- */ int MDIPlugin::plugin_wrapper(void *pmpicomm, MDI_Comm mdicomm, - void *ptr) + void *vptr) { printf("INSIDE CALLBACK\n"); MPI_Comm mpicomm = *(MPI_Comm *) pmpicomm; - MDIPlugin *thisptr = (MDIPlugin *) ptr; - LAMMPS *lammps = thisptr->lmp; + MDIPlugin *ptr = (MDIPlugin *) vptr; + LAMMPS *lammps = ptr->lmp; + char *lammps_command = ptr->lammps_command; // set FixMDIAimd mdicomm to this mdicomm - FixMDIAimd *aimdptr = (FixMDIAimd *) (thisptr->fixptr); + FixMDIAimd *aimdptr = (FixMDIAimd *) (ptr->fixptr); aimdptr->mdicomm = mdicomm; // invoke the specified LAMMPS command // that operation will issue MDI commands to the plugin engine - printf("PRE RUN command\n"); + printf("PRE RUN command: %s\n",lammps_command); - lammps->input->one(thisptr->plugin_command); + lammps->input->one(lammps_command); + delete [] lammps_command; // send MDI exit to plugin, which unloads the plugin diff --git a/src/MDI/mdi_plugin.h b/src/MDI/mdi_plugin.h index 37cf042d31..54bb1c5f4b 100644 --- a/src/MDI/mdi_plugin.h +++ b/src/MDI/mdi_plugin.h @@ -31,7 +31,7 @@ class MDIPlugin : public Command { void command(int, char **) override; private: - char *plugin_command; + char *lammps_command; class Fix *fixptr; static int plugin_wrapper(void *, MDI_Comm, void *); diff --git a/src/library.cpp b/src/library.cpp index ace9905451..a983b24b7f 100644 --- a/src/library.cpp +++ b/src/library.cpp @@ -172,6 +172,9 @@ void *lammps_open(int argc, char **argv, MPI_Comm comm, void **ptr) lammps_mpi_init(); if (ptr) ptr_argument_warning(); + printf("LAMMPS instantiate argc %d argv[1] %s argv[2] %s\n", + argc,argv[1],argv[2]); + #ifdef LAMMPS_EXCEPTIONS try { @@ -183,7 +186,9 @@ void *lammps_open(int argc, char **argv, MPI_Comm comm, void **ptr) if (ptr) *ptr = nullptr; } #else + printf("PRE-INSTANTIATE\n"); lmp = new LAMMPS(argc, argv, comm); + printf("POST-INSTANTIATE %p\n",lmp); if (ptr) *ptr = (void *) lmp; #endif return (void *) lmp;