debugging plugin mode

This commit is contained in:
Steve Plimpton
2022-03-23 11:17:51 -06:00
parent 1ee40f8f8f
commit c4425a1b0e
5 changed files with 232 additions and 159 deletions

View File

@ -99,7 +99,7 @@ the info is copied here:
Run with TCP: 1 proc each Run with TCP: 1 proc each
% python3 series_driver.py -mdi "-role DRIVER -name aimd -method TCP -port 8021" % python3 series_driver.py -mdi "-role DRIVER -name series -method TCP -port 8021"
% lmp_mpi -mdi "-role ENGINE -name LAMMPS -method TCP -port 8021 -hostname localhost" -log log.series -in in.series % lmp_mpi -mdi "-role ENGINE -name LAMMPS -method TCP -port 8021 -hostname localhost" -log log.series -in in.series
@ -107,7 +107,7 @@ Run with TCP: 1 proc each
Run with TCP: 2 proc + 4 procs Run with TCP: 2 proc + 4 procs
% mpirun -np 2 python3 series_driver.py -mdi "-role DRIVER -name aimd -method TCP -port 8021" % mpirun -np 2 python3 series_driver.py -mdi "-role DRIVER -name series -method TCP -port 8021"
% mpirun -np 4 lmp_mpi -mdi "-role ENGINE -name LAMMPS -method TCP -port 8021 -hostname localhost" -log log.series -in in.series % mpirun -np 4 lmp_mpi -mdi "-role ENGINE -name LAMMPS -method TCP -port 8021 -hostname localhost" -log log.series -in in.series
@ -115,12 +115,19 @@ Run with TCP: 2 proc + 4 procs
Run with MPI: 1 proc each Run with MPI: 1 proc each
% mpirun -np 1 python3 series_driver.py -mdi "-role DRIVER -name aimd -method MPI" : -np 1 lmp_mpi -mdi "-role ENGINE -name LAMMPS -method MPI" -log log.series -in in.series % mpirun -np 1 python3 series_driver.py -mdi "-role DRIVER -name series -method MPI" : -np 1 lmp_mpi -mdi "-role ENGINE -name LAMMPS -method MPI" -log log.series -in in.series
--- ---
Run with MPI: 2 procs + 3 procs Run with MPI: 2 procs + 3 procs
% mpirun -np 2 python3 series_driver.py -mdi "-role DRIVER -name aimd -method MPI" : -np 3 lmp_mpi -mdi "-role ENGINE -name LAMMPS -method MPI" -log log.series -in in.series % mpirun -np 2 python3 series_driver.py -mdi "-role DRIVER -name series -method MPI" : -np 3 lmp_mpi -mdi "-role ENGINE -name LAMMPS -method MPI" -log log.series -in in.series
---
Run in plugin mode: 1 proc
% python3 series_driver.py -plugin lammps -mdi "-role DRIVER -name series -method LINK -plugin_path /home/sjplimp/lammps/git/src" -plugin_args "-log log.series -in in.series"
mpiexec -n 1 python3 plugin_driver.py --plugin_name "lammps" --mdi "-role DRIVER -name driver -method LINK -plugin_path /home/sjplimp/lammps/git/src" --plugin_command_line "foo -in in.series"

View File

@ -1,10 +1,20 @@
# MDI driver to perform a series of independent calculations # MDI driver to perform a series of independent calculations
# using LAMMPS as an engine # using LAMMPS as a standalone engine
# Syntax: python3 series_driver.py switch arg switch arg ... # Syntax: python3 series_driver.py switch arg switch arg ...
# possible switches: # possible switches:
# -mdi "-role DRIVER ..." # -mdi "-role DRIVER ..."
# required switch # required switch
# example for stand-alone mode:
# -mdi "-role DRIVER -name sequence -method TCP -port 8021"
# example for plugin mode:
# -mdi "-role DRIVER -name sequemce -method LINK
# -plugin_path /home/sjplimp/lammps/src/"
# -plugin name
# name of plugin library, only when using plugin mode
# -plugin_args arglist
# args to add when launching plugin library, only when using plugin mode
# enclose arglist in quotes if multiple words
# -n 10 # -n 10
# number of calculations to perform, default = 1 # number of calculations to perform, default = 1
# -mode eval/run/min # -mode eval/run/min
@ -15,7 +25,7 @@
# -rho 0.75 0.1 # -rho 0.75 0.1
# reduced density and random variation thereof, default = 0.75 0.1 # reduced density and random variation thereof, default = 0.75 0.1
# -delta 0.1 # -delta 0.1
# randomly perturb atoms initially by this distance, default 0.0 # randomly perturb atoms initially by this distance, default 0.1
# -nsteps 100 # -nsteps 100
# number of timesteps in dynamics runs, default = 100 # number of timesteps in dynamics runs, default = 100
# -temp 1.0 # -temp 1.0
@ -36,20 +46,176 @@ def error(txt=None):
if txt: raise Exception(txt) if txt: raise Exception(txt)
raise Exception("Syntax: python3 series_driver.py switch arg switch arg ...") raise Exception("Syntax: python3 series_driver.py switch arg switch arg ...")
# send a LAMMPS input script command to MDI engine # loop over all the tasks to exchange MDI Sends/Receives with the engine
# for standalone mode, this is called by main program below
# for plugin mode, this is a callback function invoked by MDI
def send_command(cmd): def perform_tasks(world,mdicomm,dummy):
mdi.MDI_Send_Command("NBYTES",mdicomm)
mdi.MDI_Send(len(cmd),1,mdi.MDI_INT,mdicomm)
mdi.MDI_Send_Command("COMMAND",mdicomm)
mdi.MDI_Send(cmd,len(cmd)+1,mdi.MDI_CHAR,mdicomm)
# parse command-line args print("PT start",world,mdicomm,dummy)
me = world.Get_rank()
nprocs = world.Get_size()
# allocate vectors for per-atom types, coords, vels, forces
natoms = nx * ny * nz
atypes = np.zeros(natoms,dtype=np.int)
coords = np.zeros(3*natoms,dtype=np.float64)
vels = np.zeros(3*natoms,dtype=np.float64)
forces = np.zeros(3*natoms,dtype=np.float64)
atypes[:] = 1
# initialize RN generator
random.seed(seed)
# loop over sequence of calculations
for icalc in range(ncalc):
# define simulation box
onerho = rho + (random.random()-0.5)*rhodelta;
sigma = pow(1.0/onerho,1.0/3.0)
xlo = ylo = zlo = 0.0
xhi = nx * sigma
yhi = ny * sigma
zhi = nz * sigma
# send simulation box to engine
vec = [xhi-xlo,0.0,0.0] + [0.0,yhi-ylo,0.0] + [0.0,0.0,zhi-zlo]
print("PRE-CELL",mdicomm)
mdi.MDI_Send_command(">CELL",mdicomm)
mdi.MDI_Send(vec,9,mdi.MDI_DOUBLE,mdicomm)
print("POST-CELL")
# create atoms on perfect lattice
m = 0
for k in range(nz):
for j in range(ny):
for i in range(nx):
coords[m] = i * sigma
coords[m+1] = j * sigma
coords[m+2] = k * sigma
m += 3
# perturb lattice
for m in range(3*natoms):
coords[m] += 2.0*random.random()*delta - delta
# define initial velocities
for m in range(3*natoms):
vels[m] = random.random() - 0.5
tcurrent = 0.0
for m in range(3*natoms):
tcurrent += vels[m]*vels[m]
tcurrent /= 3*(natoms-1)
factor = math.sqrt(tinitial/tcurrent)
for m in range(3*natoms):
vels[m] *= factor
# send atoms and their properties to engine
mdi.MDI_Send_command(">NATOMS",mdicomm)
mdi.MDI_Send(natoms,1,mdi.MDI_INT,mdicomm)
mdi.MDI_Send_command(">TYPES",mdicomm)
mdi.MDI_Send(atypes,natoms,mdi.MDI_INT,mdicomm)
mdi.MDI_Send_command(">COORDS",mdicomm)
mdi.MDI_Send(coords,3*natoms,mdi.MDI_DOUBLE,mdicomm)
mdi.MDI_Send_command(">VELOCITIES",mdicomm)
mdi.MDI_Send(vels,3*natoms,mdi.MDI_DOUBLE,mdicomm)
# eval or run or minimize
if mode == "eval":
pass
elif mode == "run":
mdi.MDI_Send_command("@INIT_MD",mdicomm)
mdi.MDI_Send_command(">NITERATE",mdicomm)
mdi.MDI_Send(nsteps,1,mdi.MDI_INT,mdicomm)
mdi.MDI_Send_command("@DEFAULT",mdicomm)
elif mode == "min":
mdi.MDI_Send_command("@INIT_OPTG",mdicomm)
mdi.MDI_Send_command(">TOLERANCE",mdicomm)
params = [1.0e-4,1.0e-4,100.0,100.0]
mdi.MDI_Send(params,4,mdi.MDI_DOUBLE,mdicomm)
mdi.MDI_Send_command("@DEFAULT",mdicomm)
# request potential energy
print("PRE-PE")
mdi.MDI_Send_command("<PE",mdicomm)
print("POST-PE")
pe = mdi.MDI_Recv(1,mdi.MDI_DOUBLE,mdicomm)
pe = world.bcast(pe,root=0)
# request virial tensor
mdi.MDI_Send_command("<STRESS",mdicomm)
virial = mdi.MDI_Recv(6,mdi.MDI_DOUBLE,mdicomm)
virial = world.bcast(virial,root=0)
# request forces
mdi.MDI_Send_command("<FORCES",mdicomm)
mdi.MDI_Recv(3*natoms,mdi.MDI_DOUBLE,mdicomm,buf=forces)
world.Bcast(forces,root=0)
# final output from each calculation
# pressure = just virial component, no kinetic component
aveeng = pe/natoms
pressure = (virial[0] + virial[1] + virial[2]) / 3.0
m = 0
fx = fy = fz = 0.0
for i in range(natoms):
fx += forces[m]
fy += forces[m+1]
fz += forces[m+2]
m += 3
fx /= natoms
fy /= natoms
fz /= natoms
line = "Calc %d: eng %7.5g pressure %7.5g aveForce %7.5g %7.5g %7.5g" % \
(icalc+1,aveeng,pressure,fx,fy,fz)
if me == 0: print(line)
# send EXIT command to engine
# in plugin mode, removes the plugin library
mdi.MDI_Send_command("EXIT",mdicomm)
# return needed for plugin callback mode
return 0
# ------------------------
# main program
# ------------------------
args = sys.argv[1:] args = sys.argv[1:]
narg = len(args) narg = len(args)
mdiarg = 0 # defaults for command-line args
mdiarg = ""
plugin = ""
plugin_args = ""
ncalc = 1 ncalc = 1
mode = "eval" mode = "eval"
nx = ny = nz = 2 nx = ny = nz = 2
@ -61,11 +227,21 @@ tinitial = 1.0
tol = 0.001 tol = 0.001
seed = 12345 seed = 12345
# parse command-line args
iarg = 0 iarg = 0
while iarg < narg: while iarg < narg:
if args[iarg] == "-mdi": if args[iarg] == "-mdi":
if iarg+2 > narg: error() if iarg+2 > narg: error()
mdiarg = iarg + 1 mdiarg = args[iarg+1]
iarg += 2
elif args[iarg] == "-plugin":
if iarg+2 > narg: error()
plugin = args[iarg+1]
iarg += 2
elif args[iarg] == "-plugin_args":
if iarg+2 > narg: error()
plugin_args = args[iarg+1]
iarg += 2 iarg += 2
elif args[iarg] == "-n": elif args[iarg] == "-n":
if iarg+2 > narg: error() if iarg+2 > narg: error()
@ -118,153 +294,29 @@ while iarg < narg:
if not mdiarg: error() if not mdiarg: error()
# initialize MDI Library # LAMMPS engine is a stand-alone code
# world = MPI communicator for just this driver
# invoke perform_tasks() directly
mdi.MDI_Init(args[mdiarg]) if not plugin:
mdi.MDI_Init(mdiarg)
world = mdi.MDI_MPI_get_world_comm()
# MPI communicator for just the driver # connect to engine
world = mdi.MDI_MPI_get_world_comm() mdicomm = mdi.MDI_Accept_Communicator()
me = world.Get_rank()
nprocs = world.Get_size()
# connect to engine perform_tasks(world,mdicomm,None)
mdicomm = mdi.MDI_Accept_Communicator() # LAMMPS engine is a plugin library
# launch plugin
# MDI will call back to perform_tasks()
# allocate vectors for per-atom types, coords, vels, forces print("PRE PLUGIN");
natoms = nx * ny * nz if plugin:
atypes = np.zeros(natoms,dtype=np.int) mdi.MDI_Init(mdiarg)
coords = np.zeros(3*natoms,dtype=np.float64) world = MPI.COMM_WORLD
vels = np.zeros(3*natoms,dtype=np.float64) plugin_args += " -mdi \"-role ENGINE -name lammps -method LINK\""
forces = np.zeros(3*natoms,dtype=np.float64) print("PRE LAUNCH",plugin_args)
mdi.MDI_Launch_plugin(plugin,plugin_args,world,perform_tasks,None)
atypes[:] = 1
# initialize RN generator
random.seed(seed)
# loop over sequence of calculations
for icalc in range(ncalc):
# define simulation box
onerho = rho + (random.random()-0.5)*rhodelta;
sigma = pow(1.0/onerho,1.0/3.0)
xlo = ylo = zlo = 0.0
xhi = nx * sigma
yhi = ny * sigma
zhi = nz * sigma
# send simulation box to engine
vec = [xhi-xlo,0.0,0.0] + [0.0,yhi-ylo,0.0] + [0.0,0.0,zhi-zlo]
mdi.MDI_Send_command(">CELL",mdicomm)
mdi.MDI_Send(vec,9,mdi.MDI_DOUBLE,mdicomm)
# create atoms on perfect lattice
m = 0
for k in range(nz):
for j in range(ny):
for i in range(nx):
coords[m] = i * sigma
coords[m+1] = j * sigma
coords[m+2] = k * sigma
m += 3
# perturb lattice
for m in range(3*natoms):
coords[m] += 2.0*random.random()*delta - delta
# define initial velocities
for m in range(3*natoms):
vels[m] = random.random() - 0.5
tcurrent = 0.0
for m in range(3*natoms):
tcurrent += vels[m]*vels[m]
tcurrent /= 3*(natoms-1)
factor = math.sqrt(tinitial/tcurrent)
for m in range(3*natoms):
vels[m] *= factor
# send atoms and their properties to engine
mdi.MDI_Send_command(">NATOMS",mdicomm)
mdi.MDI_Send(natoms,1,mdi.MDI_INT,mdicomm)
mdi.MDI_Send_command(">TYPES",mdicomm)
mdi.MDI_Send(atypes,natoms,mdi.MDI_INT,mdicomm)
mdi.MDI_Send_command(">COORDS",mdicomm)
mdi.MDI_Send(coords,3*natoms,mdi.MDI_DOUBLE,mdicomm)
mdi.MDI_Send_command(">VELOCITIES",mdicomm)
mdi.MDI_Send(vels,3*natoms,mdi.MDI_DOUBLE,mdicomm)
# eval or run or minimize
if mode == "eval":
pass
elif mode == "run":
mdi.MDI_Send_command("@INIT_MD",mdicomm)
mdi.MDI_Send_command(">NITERATE",mdicomm)
mdi.MDI_Send(nsteps,1,mdi.MDI_INT,mdicomm)
mdi.MDI_Send_command("@DEFAULT",mdicomm)
elif mode == "min":
mdi.MDI_Send_command("@INIT_OPTG",mdicomm)
mdi.MDI_Send_command(">TOLERANCE",mdicomm)
params = [1.0e-4,1.0e-4,100.0,100.0]
mdi.MDI_Send(params,4,mdi.MDI_DOUBLE,mdicomm)
mdi.MDI_Send_command("@DEFAULT",mdicomm)
# request potential energy
mdi.MDI_Send_command("<PE",mdicomm)
pe = mdi.MDI_Recv(1,mdi.MDI_DOUBLE,mdicomm)
pe = world.bcast(pe,root=0)
# request virial tensor
mdi.MDI_Send_command("<STRESS",mdicomm)
virial = mdi.MDI_Recv(6,mdi.MDI_DOUBLE,mdicomm)
virial = world.bcast(virial,root=0)
# request forces
mdi.MDI_Send_command("<FORCES",mdicomm)
mdi.MDI_Recv(3*natoms,mdi.MDI_DOUBLE,mdicomm,buf=forces)
world.Bcast(forces,root=0)
# final output from each calculation
# pressure = just virial component, no kinetic component
aveeng = pe/natoms
pressure = (virial[0] + virial[1] + virial[2]) / 3.0
m = 0
fx = fy = fz = 0.0
for i in range(natoms):
fx += forces[m]
fy += forces[m+1]
fz += forces[m+2]
m += 3
fx /= natoms
fy /= natoms
fz /= natoms
line = "Calc %d: eng %7.5g pressure %7.5g aveForce %7.5g %7.5g %7.5g" % \
(icalc+1,aveeng,pressure,fx,fy,fz)
if me == 0: print(line)
# send EXIT command to engine
mdi.MDI_Send_command("EXIT",mdicomm)

View File

@ -34,7 +34,7 @@ make lib-meam args="-m ifort" # build MEAM lib with custom Makefile.ifort (usi
# settings # settings
version = "1.2.9" version = "1.3.0"
url = "https://github.com/MolSSI-MDI/MDI_Library/archive/v%s.tar.gz" % version url = "https://github.com/MolSSI-MDI/MDI_Library/archive/v%s.tar.gz" % version
# known checksums for different MDI versions. used to validate the download. # known checksums for different MDI versions. used to validate the download.

View File

@ -54,6 +54,8 @@ command-line argument, which must be provided by the MDI driver.
int MDI_Plugin_init_lammps() int MDI_Plugin_init_lammps()
{ {
printf("LMP PLUGIN init\n");
// initialize MDI // initialize MDI
int mdi_argc; int mdi_argc;
@ -69,6 +71,8 @@ int MDI_Plugin_init_lammps()
// find the -in argument // find the -in argument
printf("LMP PLUGIN init %d %s %s\n",mdi_argc,mdi_argv[0],mdi_argv[1]);
int iarg = 0; int iarg = 0;
char *filename; char *filename;
bool found_filename = false; bool found_filename = false;
@ -93,6 +97,8 @@ int MDI_Plugin_init_lammps()
// create and run a LAMMPS instance // create and run a LAMMPS instance
printf("LMP PLUGIN init %d %s %s\n",mdi_argc,mdi_argv[0],mdi_argv[1]);
void *lmp = nullptr; void *lmp = nullptr;
if (lammps_config_has_mpi_support() > 0) if (lammps_config_has_mpi_support() > 0)
lmp = lammps_open(mdi_argc, mdi_argv, mpi_world_comm, nullptr); lmp = lammps_open(mdi_argc, mdi_argv, mpi_world_comm, nullptr);

View File

@ -174,6 +174,8 @@ void MDIEngine::mdi_engine(int narg, char **arg)
MDI_Accept_communicator(&mdicomm); MDI_Accept_communicator(&mdicomm);
if (mdicomm <= 0) error->all(FLERR,"Unable to connect to MDI driver"); if (mdicomm <= 0) error->all(FLERR,"Unable to connect to MDI driver");
printf("ENG post accept MDI comm\n");
// endless engine loop, responding to driver commands // endless engine loop, responding to driver commands
mode = DEFAULT; mode = DEFAULT;
@ -235,6 +237,8 @@ void MDIEngine::engine_node(const char *node)
{ {
int ierr; int ierr;
printf("ENG ENODE %s\n",node);
// do not process commands if engine and driver request are not the same // do not process commands if engine and driver request are not the same
strncpy(node_engine,node,MDI_COMMAND_LENGTH); strncpy(node_engine,node,MDI_COMMAND_LENGTH);
@ -249,9 +253,13 @@ void MDIEngine::engine_node(const char *node)
// read the next command from the driver // read the next command from the driver
// all procs call this, but only proc 0 receives the command // all procs call this, but only proc 0 receives the command
printf("ENG PRE-RECV %d\n",mdicomm);
ierr = MDI_Recv_command(mdicmd,mdicomm); ierr = MDI_Recv_command(mdicmd,mdicomm);
if (ierr) error->all(FLERR,"MDI: Unable to receive command from driver"); if (ierr) error->all(FLERR,"MDI: Unable to receive command from driver");
printf("ENG POST-RECV %s\n",mdicmd);
// broadcast command to the other MPI tasks // broadcast command to the other MPI tasks
MPI_Bcast(mdicmd,MDI_COMMAND_LENGTH,MPI_CHAR,0,world); MPI_Bcast(mdicmd,MDI_COMMAND_LENGTH,MPI_CHAR,0,world);