tweaks to src files, added examples dir

This commit is contained in:
Steve Plimpton
2022-03-11 09:33:34 -07:00
parent faf9c1532a
commit 8ba4e7e897
9 changed files with 491 additions and 4 deletions

View File

@ -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

113
examples/mdi/README Normal file
View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

21
examples/mdi/in.series Normal file
View File

@ -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

View File

@ -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("<ENERGY",mdicomm)
energy = mdi.MDI_Recv(1,mdi.MDI_DOUBLE,mdicomm)
energy = world.bcast(energy,root=0)
# request pressure tensor
mdi.MDI_Send_command("<PTENSOR",mdicomm)
ptensor = mdi.MDI_Recv(6,mdi.MDI_DOUBLE,mdicomm)
ptensor = world.bcast(ptensor,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
aveeng = energy/natoms
pressure = (ptensor[0] + ptensor[1] + ptensor[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 press %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

@ -42,10 +42,10 @@ FixMDIAimd::FixMDIAimd(LAMMPS *lmp, int narg, char **arg) :
// check requirements for LAMMPS to work with MDI as an engine
if (atom->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

View File

@ -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
---------------------------------------------------------------------- */