Contents
AMH: DFT calculations with NWChem
We now re-visit the AMH dimers (both of them) using density functional theory.
We already know from the Ar$_2$ examples we have done that most density functionals are rather poor for van der Waals dimers. The AMH system is not quite a van der Waals system, but it has a strong dispersion contribution, so any density functional we use will need to be corrected for the missing dispersion energy.
Further, according to Griffiths et al., there is a problem with PBE: it overbinds the //P4/nmm// phase due to a charge-transfer problem that manifests in an overbinding at long range.
You will need to test PBE for both of these issues and propose fixes.
You will need to decide on
- Which functional to use: PBE or PBE0 or some other? Remember you need to justify your choice.
- Dispersion correction or no dispersion correction?
- Explain the observations highlighted on the previous lab page using these calculations.
- The goal of this report is to use your calculations to best explain the main results of the paper - particularly those I have highlighted in the previous laboratory page.
Scripts
The script on the AMH laboratory page can be modified to do a DFT calculation. I've included an example here.
Here's a script for the molecular dimer. This one does a PBE+D calculation. It's provided only as a template. You will need to decide just which calculation you need.
import argparse, numpy, subprocess, re, sys, os
import numpy, re, sys, subprocess
#import matplotlib.pyplot as plt
# Parse command-line arguments
parser = argparse.ArgumentParser(description = """
Create a set of NWChem input files for the Ar2 dimer, run NWChem on them, and
parse the output for interaction energy.
""")
parser.add_argument("-m", "--min", dest="minR", type=float, default=1.,
help="minimum Ar separation in A")
parser.add_argument("-M", "--max", dest="maxR", type=float, default=5.,
help="maximum Ar separation in A")
parser.add_argument("-d", "--delta", dest="deltaR", type=float, default=0.5,
help="step size for Ar separation in A")
parser.add_argument("-o", "--output", dest="output", type=str, default="output.txt",
help="output text file")
parser.add_argument("-np", "--nproc", dest="nproc", type=int, default=1,
help="Number of processors to be used.")
parser.add_argument("-b", "--basis", dest="basis", type=str, default="aug-cc-pvtz",
help="basis set used in calculation")
args = parser.parse_args()
nwchem_dir = os.environ["NWCHEM_TOP"]
username = os.environ["USER"]
nproc = args.nproc
# I have commented out the uniform grid:
#positions = numpy.arange(args.minR, args.maxR + 0.00001, args.deltaR)
# Instead, use a non-uniform grid specific to your system:
positions = numpy.array([1.7,2.1,2.3,2.5,2.7,3.1,4.0,5.0,10.0,20.0])
print "Basis set ",args.basis
print "positions = ", positions
print "Output to : ",args.output
print "Number of processors : ",nproc
output = open(args.output,'w')
# Conversion factor:
au2cm = 219474.631371
au2kJ = 2625.499
# Construct input files
input_file_template = """
title "NH3..H2O BSSE corrected DFT interaction energy"
scratch_dir /scratch/HDD_2T/{user}/nwchem
geometry units angstrom "NH3+H2O"
N 0.00000 0.00000 0.00000
H1 0.98601 0.00000 -0.30465
H2 -0.46058 0.84108 -0.38142
H3 -0.46058 -0.84108 -0.38142
O 0.00000 0.00000 {RzO}
H4 0.00000 0.00000 {RzH4}
H5 -0.96568 -0.00000 {RzH5}
end
geometry units angstrom "NH3+ghost"
N 0.00000 0.00000 0.00000
H1 0.98601 0.00000 -0.30465
H2 -0.46058 0.84108 -0.38142
H3 -0.46058 -0.84108 -0.38142
BqO 0.00000 0.00000 {RzO}
BqH 0.00000 0.00000 {RzH4}
BqH -0.96568 -0.00000 {RzH5}
end
geometry units angstrom "ghost+H2O"
BqN 0.00000 0.00000 0.00000
BqH 0.98601 0.00000 -0.30465
BqH -0.46058 0.84108 -0.38142
BqH -0.46058 -0.84108 -0.38142
O 0.00000 0.00000 {RzO}
H4 0.00000 0.00000 {RzH4}
H5 -0.96568 -0.00000 {RzH5}
end
basis
N library {basis}
H1 library {basis}
H2 library {basis}
H3 library {basis}
O library {basis}
H4 library {basis}
H5 library {basis}
BqN library N {basis}
BqH library H {basis}
BqO library O {basis}
end
dft
xc xpbe96 cpbe96
iterations 200
disp
direct
end
set geometry "NH3+H2O"
charge 0
task dft
unset geometry "NH3+H2O"
dft; vectors hcore; end
set geometry "NH3+ghost"
charge 0
task dft
unset geometry "NH3+ghost"
dft; vectors hcore; end
set geometry "ghost+H2O"
charge 0
task dft
unset geometry "ghost+H2O"
"""
# z coordinates for O, H4 and H5 : H2O will be translated along the z-axis
# Units: Angstrom
zO = 0.0
zH4 = -1.03900
zH5 = 0.27836
# Regular expressions to find the right lines in the file
dft_re = re.compile("Total DFT energy =\s+(-?[0-9]+.[0-9]+)")
# Dictionary to store the energies we find
energies = {}
# Main loop through different position values
for delta_z in positions:
print "Current position = ",delta_z
input_file_name = "in-R{0:5.3f}.nw".format(delta_z)
output_file_name = "out-R{0:5.3f}.out".format(delta_z)
# Write input file
Rz_O = zO + delta_z
Rz_H4 = zH4 + delta_z
Rz_H5 = zH5 + delta_z
RzO = """{0:10.6f}""".format(Rz_O)
RzH4 = """{0:10.6f}""".format(Rz_H4)
RzH5 = """{0:10.6f}""".format(Rz_H5)
input_file = open(input_file_name, "w")
input_file.write(input_file_template.format(RzO=RzO,RzH4=RzH4,RzH5=RzH5,user=username,basis=args.basis))
input_file.close()
# Run NWChem
output_file = open(output_file_name, "w")
subprocess.call(["mpirun.mpich","-np",str(nproc),"nwchem", input_file_name],
stdout=output_file, stderr=subprocess.STDOUT)
output_file.close()
# Read output file back in
output_file = open(output_file_name, "r")
dft_energies = []
for line in output_file:
dft_match = dft_re.search(line)
if dft_match:
dft_energies.append(float(dft_match.group(1)))
output_file.close()
if not (len(dft_energies) == 3):
print "Apparent error in output file! {0:d} DFT energies found.".format(len(dft_energies))
sys.exit(1)
energies[delta_z] = dft_energies
dft_dimer = energies[delta_z][0]
dft_monomerA = energies[delta_z][1]
dft_monomerB = energies[delta_z][2]
dft_interaction = dft_dimer - dft_monomerA - dft_monomerB
print "Eint[DFT] = ",dft_interaction*au2kJ
# prepare plots
dft_dimer = numpy.array([energies[p][0] for p in positions])
dft_monomerA = numpy.array([energies[p][1] for p in positions])
dft_monomerB = numpy.array([energies[p][2] for p in positions])
dft_interaction = dft_dimer - dft_monomerA - dft_monomerB
# convert to kJ/mol
dft_interaction = au2kJ*dft_interaction
output.write(('%10s '*5 + '\n') %
(" R ","DFT monoA","DFT monoB","DFT dimr","DFT int "))
for i in range(len(positions)):
output.write(('%10.6f '*5 + '\n') %
(positions[i],
dft_monomerA[i], dft_monomerB[i], dft_dimer[i], dft_interaction[i]))
output.close()Important
Start with the calculations used in by Griffiths et al.
- PBE
- PBE0
- PBE+D
- PBE0+D
Then consider using the LC functionals you used on Ar$_2$. Do these improve on PBE0+D?
Remember that you need to do this for both dimers.
