# MDI driver to perform an AIMD simulation # using one instance of LAMMPS as the MD timestepper # using second instance of LAMMPS as a QM surrogate to compute forces # NOTE: this script is derived from the MDI_AIMD_Driver.cpp code # included in the MDI distribution # it alters the timestepping to match a velocity Verlet algorithm # forces are computed once before timestepping beings # both the @COORDS and @FORCES nodes are triggered in the MM code # as the appropriate places to extract COORDS and provide FORCES # Syntax: python3 aimd_driver.py switch arg switch arg ... # possible switches: # -mdi "-role DRIVER ..." # 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 # -nsteps 5 # number of timesteps, default = 5 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 aimd_driver.py switch arg switch arg ...") # run an AIMD simulation def perform_aimd(world,mm_comm,qm_comm): me = world.Get_rank() nprocs = world.Get_size() # receive number of atoms from the MM engine mdi.MDI_Send_command("COORDS",qm_comm) mdi.MDI_Send(coords,3*natoms,mdi.MDI_DOUBLE,qm_comm) # get QM potential energy mdi.MDI_Send_command("FORCES",mm_comm) mdi.MDI_Send(forces,3*natoms,mdi.MDI_DOUBLE,mm_comm) # get MM kinetic energy mdi.MDI_Send_command("COORDS",qm_comm) mdi.MDI_Send(coords,3*natoms,mdi.MDI_DOUBLE,qm_comm) # get QM potential energy mdi.MDI_Send_command("FORCES",mm_comm) mdi.MDI_Send(forces,3*natoms,mdi.MDI_DOUBLE,mm_comm) # MM engine proceeds to @ENDSTEP node # so that KE will be for fully updated velocity mdi.MDI_Send_command("@ENDSTEP",mm_comm) # get MM kinetic energy mdi.MDI_Send_command(" narg: error() 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 elif args[iarg] == "-nsteps": if iarg+2 > narg: error() nsteps = int(args[iarg+1]) if nsteps < 0: error() iarg += 2 else: error() if not mdiarg: error() # LAMMPS engines are stand-alone codes # world = MPI communicator for just this driver # invoke perform_tasks() directly if not plugin: mdi.MDI_Init(mdiarg) world = mdi.MDI_MPI_get_world_comm() # connect to 2 engines, determine which is MM vs QM mdicomm1 = mdi.MDI_Accept_Communicator() mdicomm2 = mdi.MDI_Accept_Communicator() mdi.MDI_Send_command("