diff --git a/examples/README b/examples/README index 76ddf77498..5310ad5f15 100644 --- a/examples/README +++ b/examples/README @@ -83,6 +83,7 @@ hyper: global and local hyperdynamics of diffusion on Pt surface indent: spherical indenter into a 2d solid kim: use of potentials in Knowledge Base for Interatomic Models (KIM) latte: use of LATTE density-functional tight-binding quantum code +mdi: use of the MDI package and MolSSI MDI code coupling library meam: MEAM test for SiC and shear (same as shear examples) melt: rapid melt of 3d LJ system message: client/server coupling of 2 codes diff --git a/examples/mdi/README b/examples/mdi/README new file mode 100644 index 0000000000..0c4c931519 --- /dev/null +++ b/examples/mdi/README @@ -0,0 +1,113 @@ +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, +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. + +------------------------------------------------- +------------------------------------------------- + +* Example #1 = AIMD with LAMMPS as both a driver and engine + As an engine, LAMMPS is acting as 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. + +--- + +Run the entire calculation with a single instance of LAMMPS by itself + results should be identical to running in driver/engine mode + +% lmp_mpi < in.aimd.alone + +--- + +Run with TCP: 1 proc each + +% lmp_mpi -mdi "-name driver -role DRIVER -method TCP -port 8021" -log log.aimd.driver -in in.aimd.driver + +% lmp_mpi -mdi "-name LAMMPS -role ENGINE -method TCP -port 8021 -hostname localhost" -log log.aimd.engine -in in.aimd.engine + +--- + +Run with TCP: 3 procs + 4 procs + +% mpirun -np 3 lmp_mpi -mdi "-name driver -role DRIVER -method TCP -port 8021" -log log.aimd.driver -in in.aimd.driver + +% mpirun -np 4 lmp_mpi -mdi "-name LAMMPS -role ENGINE -method TCP -port 8021 -hostname localhost" -log log.aimd.engine -in in.aimd.engine + +--- + +Run with MPI: 1 proc each + +% mpirun -np 1 lmp_mpi -mdi "-name driver -role DRIVER -method MPI" -log log.aimd.driver -in in.aimd.driver : -np 1 ../lammps/git/src/lmp_mpi -mdi "-name LAMMPS -role ENGINE -method MPI" -log log.aimd.engine -in in.aimd.engine + +--- + +Run with MPI: 3 procs + 4 procs + +% mpirun -np 3 lmp_mpi -mdi "-name driver -role DRIVER -method MPI" -log log.aimd.driver -in in.aimd.driver : -np 4 ../lammps/git/src/lmp_mpi -mdi "-name LAMMPS -role ENGINE -method MPI" -log log.aimd.engine -in in.aimd.engine + +------------------------------------------------- +------------------------------------------------- + +* Example #2 = Use a Python driver code to run a series of independent + LAMMPS calculations + +Note that the series_driver.py code allows for optional arguments in +addition to -mdi (required). The example run commands below just +using the default values. The options are explained the top of the file; +the info is copied here: + +# -n 10 +# number of calculations to perform, default = 1 +# -mode eval/run/min +# style of calculations: single snapshot evals, dynamics, minimization +# default = eval +# -size Nx Ny Nz +# cubic lattice, default = 2 2 2 +# -rho 0.75 0.1 +# reduced density and random variation thereof, default = 0.75 0.1 +# -delta 0.1 +# randomly perturb atoms initially by this distance, default 0.0 +# -nsteps 100 +# number of timesteps in dynamics runs, default = 100 +# -temp 1.0 +# initial temperature in dynamics runs, default = 1.0 +# -tol 0.001 +# tolerance for minimizations, default = 0.001 +# -seed 12345 +# random number seed > 0, default = 12345 + +--- + +Run with TCP: 1 proc each + +% python3 series_driver.py -mdi "-role DRIVER -name aimd -method TCP -port 8021" + +% lmp_mpi -mdi "-role ENGINE -name LAMMPS -method TCP -port 8021 -hostname localhost" -log log.series -in in.series + +--- + +Run with TCP: 1 proc + 4 procs + +% python3 series_driver.py -mdi "-role DRIVER -name aimd -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 + diff --git a/examples/mdi/in.aimd.alone b/examples/mdi/in.aimd.alone new file mode 100644 index 0000000000..e2857c5704 --- /dev/null +++ b/examples/mdi/in.aimd.alone @@ -0,0 +1,32 @@ +# 3d Lennard-Jones melt - MDI driver script + +variable x index 5 +variable y index 5 +variable z index 5 + +units lj +atom_style atomic + +lattice fcc 0.8442 +region box block 0 $x 0 $y 0 $z +create_box 1 box +create_atoms 1 box +mass 1 1.0 + +velocity all create 1.44 87287 loop geom + +pair_style lj/cut 2.5 +pair_coeff 1 1 1.0 1.0 2.5 + +neighbor 0.3 bin +neigh_modify delay 0 every 1 check yes + +# NVE +fix 1 all nve +# NPT +#fix 1 all npt temp 1.0 1.0 0.1 iso 1.0 1.0 1.0 + +thermo_style custom step temp pe etotal press vol +thermo 1 + +run 5 diff --git a/examples/mdi/in.aimd.driver b/examples/mdi/in.aimd.driver new file mode 100644 index 0000000000..5ee23ebe8d --- /dev/null +++ b/examples/mdi/in.aimd.driver @@ -0,0 +1,32 @@ +# 3d Lennard-Jones melt - MDI driver script + +variable x index 5 +variable y index 5 +variable z index 5 + +units lj +atom_style atomic + +lattice fcc 0.8442 +region box block 0 $x 0 $y 0 $z +create_box 1 box +create_atoms 1 box +mass 1 1.0 + +velocity all create 1.44 87287 loop geom + +neighbor 0.3 bin +neigh_modify delay 0 every 1 check yes + +# NVE +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_modify 2 energy yes virial yes + +thermo_style custom step temp pe etotal press vol +thermo 1 + +run 5 diff --git a/examples/mdi/in.aimd.engine b/examples/mdi/in.aimd.engine new file mode 100644 index 0000000000..11d22c750e --- /dev/null +++ b/examples/mdi/in.aimd.engine @@ -0,0 +1,22 @@ +# 3d Lennard-Jones melt - MDI engine script + +variable x index 5 +variable y index 5 +variable z index 5 + +units lj +atom_style atomic + +lattice fcc 0.8442 +region box block 0 $x 0 $y 0 $z +create_box 1 box +create_atoms 1 box +mass 1 1.0 + +pair_style lj/cut 2.5 +pair_coeff 1 1 1.0 1.0 2.5 + +neighbor 0.3 bin +neigh_modify delay 0 every 1 check yes + +mdi engine diff --git a/examples/mdi/in.series b/examples/mdi/in.series new file mode 100644 index 0000000000..c094326ae7 --- /dev/null +++ b/examples/mdi/in.series @@ -0,0 +1,21 @@ +# MDI engine script to process a series of evaulate, run, minimize commands + +units lj +atom_style atomic + +lattice fcc 0.8442 +region box block 0 1 0 1 0 1 +create_box 1 box +mass 1 1.0 + +pair_style lj/cut 2.5 +pair_coeff 1 1 1.0 1.0 2.5 + +neighbor 0.3 bin +neigh_modify delay 0 every 1 check yes + +fix 1 all nve + +thermo 10 + +mdi engine diff --git a/examples/mdi/series_driver.py b/examples/mdi/series_driver.py new file mode 100644 index 0000000000..682a6365ec --- /dev/null +++ b/examples/mdi/series_driver.py @@ -0,0 +1,266 @@ +# MDI driver to perform a series of independent calculations +# using LAMMPS as an engine + +# Syntax: python3 series_driver.py switch arg switch arg ... +# possible switches: +# -mdi "-role DRIVER ..." +# required switch +# -n 10 +# number of calculations to perform, default = 1 +# -mode eval/run/min +# style of calculations: single snapshot evals, dynamics, minimization +# default = eval +# -size Nx Ny Nz +# cubic lattice, default = 2 2 2 +# -rho 0.75 0.1 +# reduced density and random variation thereof, default = 0.75 0.1 +# -delta 0.1 +# randomly perturb atoms initially by this distance, default 0.0 +# -nsteps 100 +# number of timesteps in dynamics runs, default = 100 +# -temp 1.0 +# initial temperature in dynamics runs, default = 1.0 +# -tol 0.001 +# tolerance for minimizations, default = 0.001 +# -seed 12345 +# random number seed > 0, default = 12345 + +import sys,math,random +import mdi +import numpy as np +from mpi4py import MPI + +# error message + +def error(txt=None): + if txt: raise Exception(txt) + raise Exception("Syntax: python3 series_driver.py switch arg switch arg ...") + +# send a LAMMPS input script command to MDI engine + +def send_command(cmd): + 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 + +args = sys.argv[1:] +narg = len(args) + +mdiarg = 0 +ncalc = 1 +mode = "eval" +nx = ny = nz = 2 +rho = 0.75 +rhodelta = 0.1 +delta = 0.0 +nsteps = 100 +tinitial = 1.0 +tol = 0.001 +seed = 12345 + +iarg = 0 +while iarg < narg: + if args[iarg] == "-mdi": + if iarg+2 > narg: error() + mdiarg = iarg + 1 + iarg += 2 + elif args[iarg] == "-n": + if iarg+2 > narg: error() + ncalc = int(args[iarg+1]) + iarg += 2 + elif args[iarg] == "-mode": + if iarg+2 > narg: error() + mode = args[iarg+1] + if mode != "eval" and mode != "run" and mode != "min": error() + iarg += 2 + elif args[iarg] == "-size": + if iarg+4 > narg: error() + nx = int(args[iarg+1]) + ny = int(args[iarg+2]) + nz = int(args[iarg+3]) + if nx <= 0 or ny <= 0 or nz <= 0: error() + iarg += 4 + elif args[iarg] == "-rho": + if iarg+3 > narg: error() + rho = float(args[iarg+1]) + rhodelta = float(args[iarg+2]) + if rho-rhodelta <= 0.0: error() + iarg += 4 + elif args[iarg] == "-delta": + if iarg+2 > narg: error() + delta = float(args[iarg+1]) + if delta < 0.0: error() + iarg += 2 + elif args[iarg] == "-nsteps": + if iarg+2 > narg: error() + nsteps = int(args[iarg+1]) + if nsteps < 0: error() + iarg += 2 + elif args[iarg] == "-temp": + if iarg+2 > narg: error() + tinitial = float(args[iarg+1]) + if tinitial < 0.0: error() + iarg += 2 + elif args[iarg] == "-tol": + if iarg+2 > narg: error() + tol = float(args[iarg+1]) + if tol < 0.0: error() + iarg += 2 + elif args[iarg] == "-seed": + if iarg+2 > narg: error() + seed = int(args[iarg+1]) + if seed <= 0: error() + iarg += 2 + else: error() + +if not mdiarg: error() + +# initialize MDI Library + +mdi.MDI_Init(args[mdiarg]) + +# MPI communicator for just the driver + +world = mdi.MDI_MPI_get_world_comm() +me = world.Get_rank() +nprocs = world.Get_size() + +# connect to engine + +mdicomm = mdi.MDI_Accept_Communicator() + +# 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): + + # delete all atoms so can run a new calculation + + send_command("delete_atoms group all") + + # 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 = [xlo,ylo,zlo,xhi,yhi,zhi,0.0,0.0,0.0] + mdi.MDI_Send_command("RESET_BOX",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("CREATE_ATOM",mdicomm) + mdi.MDI_Send(natoms,1,mdi.MDI_INT,mdicomm) + mdi.MDI_Send_command("CREATE_TYPE",mdicomm) + mdi.MDI_Send(atypes,natoms,mdi.MDI_INT,mdicomm) + mdi.MDI_Send_command("CREATE_X",mdicomm) + mdi.MDI_Send(coords,3*natoms,mdi.MDI_DOUBLE,mdicomm) + mdi.MDI_Send_command("CREATE_V",mdicomm) + mdi.MDI_Send(vels,3*natoms,mdi.MDI_DOUBLE,mdicomm) + mdi.MDI_Send_command("CREATE_GO",mdicomm) + + # eval or run or minimize + + if mode == "eval": + mdi.MDI_Send_command("EVAL",mdicomm) + elif mode == "run": + send_command("run %d" % nsteps) + elif mode == "min": + send_command("minimize %g %g 1000 1000" % (tol,tol)) + + # request energy + + mdi.MDI_Send_command("tag_enable == 0) - error->all(FLERR, "Cannot use mdi engined without atom IDs"); + error->all(FLERR, "Cannot use MDI engine without atom IDs"); if (atom->natoms && atom->tag_consecutive() == 0) - error->all(FLERR, "mdi engine requires consecutive atom IDs"); + error->all(FLERR, "MDI engine requires consecutive atom IDs"); // confirm LAMMPS is being run as a driver diff --git a/src/MDI/mdi_engine.cpp b/src/MDI/mdi_engine.cpp index c720fa2198..5a02a36e4b 100644 --- a/src/MDI/mdi_engine.cpp +++ b/src/MDI/mdi_engine.cpp @@ -635,7 +635,7 @@ void MDIEngine::mdi_commands() // ------------------------------------ // custom commands and nodes which LAMMPS supports - // max length for a command is current 11 chars in MDI + // max length for a command is currently 11 chars in MDI // ------------------------------------ MDI_Register_command("@DEFAULT", "NBYTES"); @@ -1377,8 +1377,8 @@ void MDIEngine::evaluate() /* ---------------------------------------------------------------------- RESET_BOX command - 9 values = boxlo, boxhi, xy, yz, xz wrapper on library reset_box() method + 9 values = boxlo, boxhi, xy, yz, xz requires no atoms exist allows caller to define a new simulation box ---------------------------------------------------------------------- */