Optimizations and the PES

Here we will learn how to use NWChem for geometry optimizations and to generate the PES of a dimer.

Geometry Optimization

This is a common task: you have a system and want to obtain an optimized structure. How do you do it? Here's an example:

Memory 500 mb

charge 0
Geometry units bohr
  O     0.0000000000    0.0000000000    0.0000000000
  H1   -1.4536519600    0.0000000000   -1.1216873200
  H2    1.4536519600    0.0000000000   -1.1216873200
End

Basis "ao basis" spherical
  H  library  STO-3G
  O  library  STO-3G
End

Title "H2O STO-3G Geometry Optimization"

scf
  Singlet
end
task scf optimize

Put these commands in a file titled h2o-sto3g-scf-opt.nw. Run it the usual way:

$ mpirun.mpich -np 1 nwchem h2o-sto3g-scf-opt.nw >& h2o-sto3g-scf-opt.out

Towards the bottom of the output you will find the lines:

                Final and change from initial internal coordinates
                --------------------------------------------------



                                Z-matrix (autoz)
                                --------

 Units are Angstrom for bonds and degrees for angles

      Type          Name      I     J     K     L     M      Value       Change
      ----------- --------  ----- ----- ----- ----- ----- ---------- ----------
    1 Stretch                  1     2                       0.98941    0.01778
    2 Stretch                  1     3                       0.98941    0.01778
    3 Bend                     2     1     3               100.02684   -4.66316

 ======
                                internuclear distances
 ------------------------------------------------------------------------------
       center one      ||      center two      || atomic units ||       a.u.
 ------------------------------------------------------------------------------
    2 H1               ||   1 O                ||     1.86971  ||     1.86971
    3 H2               ||   1 O                ||     1.86971  ||     1.86971
 ------------------------------------------------------------------------------
                         number of included internuclear distances:          2
 ======



 ======
                                 internuclear angles
 ------------------------------------------------------------------------------
        center 1       ||       center 2       ||       center 3       ||  degrees
 ------------------------------------------------------------------------------
    2 H1               ||   1 O                ||   3 H2               ||   100.03
 ------------------------------------------------------------------------------
                            number of included internuclear angles:          1
 ======

This bit contains the final (optimised) bond lengths and angles. The reference O-H bond length is 0.095639 nm (Halkier et al, Chem. Phys. Lett. 274, 235-241 (1997)) and H-O-H bond angle (from the same reference) is 104.54 degrees. These results here are quite different from these.

Important

The STO-3G basis is quite small, so let's now converge the geometry with basis by repeating the above calculations with the

  • cc-pVDZ
  • cc-pVTZ
  • aug-cc-pVDZ
  • aug-cc-pVTZ

basis sets. Use separate files for each basis as you will need to keep track of your results. Make a table of your results. Do you see any trend? Does the geometry converge to the reference results? Is there a basis set where you see an apparent convergence?

Optimisation at the MP2 level

It will not, and the reason is that Hartree-Fock is after all, approximate. We will use a higher level of theory to repeat the above task, this time using second-order perturbation theory: MP2. We will learn about this next week, but for now all you need to know is that MP2 is the next level up from HF.

Here's the input file for an MP2 optimization:

Memory 500 mb

charge 0
Geometry units bohr
  O     0.0000000000    0.0000000000    0.0000000000
  H1   -1.4536519600    0.0000000000   -1.1216873200
  H2    1.4536519600    0.0000000000   -1.1216873200
End

Basis "ao basis" spherical
  H  library  STO-3G
  O  library  STO-3G
End

Title "H2O STO-3G MP2 Geometry Optimization"

scf
  Singlet
end
task mp2 optimize

Save this as h2o-sto3g-mp2-opt.nw.

Important

Repeat the above exercise with MP2. Include these new geometries in your table. Do you see a better agreement with the reference results?

Important

By the end of this exercise you should have a table of the form:

Basis set

RHF

MP2

$R$ (O-H)

$\theta$ (H-O-H)

$R$ (O-H)

$\theta$ (H-O-H)

STO-3G

cc-pVDZ

cc-pVTZ

aug-cc-pVDZ

aug-cc-pVTZ

Reference values

What are the trends you have observed? How well do they correlate with the material covered in the lecture?

You may use the data in the paper by Mas and Szalewicz (http://aip.scitation.org/doi/pdf/10.1063/1.471469) for your reference values. They report the experimental geometry of water on page 4. These data have been taken from Ref 30 of that paper.

Interaction Energies

The interaction energy is the energy of stabilization when two of more species come together and form some sort of bond.

For two Ar atoms separated by distance R this takes the simple form \begin{equation} E_{\rm int}(R) = E[\mbox{Ar}\cdots\mbox{Ar}](R) - 2*E[\mbox{Ar}] \end{equation} where $E[\mbox{Ar}\cdots\mbox{Ar}](R)$ is the energy of the complex of two Ar atoms separated by distance $R$. And $E[\mbox{Ar}]$ is the energy of a single argon atom. So this looks easy to compute.

An example input file to do this calculation is:

title "Ar dimer no BSSE correction : MP2 interaction energy"

scratch_dir /scratch/HDD_2T/esm/<YOUR USER NAME>/nwchem

geometry units angstrom "Ar+Ar"
  Ar1 0 0 0
  Ar2 0 0 3.76
end

geometry units angstorm "Ar"
  Ar1 0 0 0
end

basis
  Ar1 library aug-cc-pvtz
  Ar2 library aug-cc-pvtz
end

set geometry "Ar+Ar"
task mp2
unset geometry "Ar+Ar"

set geometry "Ar"
task mp2
unset geometry "Ar"

Save this in file Ar2-noCPcorr-atz.nw. The noCPcorr stands for no counterpoise (CP) correction - I will explain what this means soon.

More about the above file:

Warning

First of all, we are now performing significant calculations so we cannot use the home directory to run our jobs. Instead we use a scratch directory. This is done by defining scratch_dir in the input file. Please change this directory path to include your own user name!!!

I have asked our administrators to create scratch directories for each of you. to check to see if you have one type:

  • $ ls /scratch/HDD_2T/esm/

Is your user name listed there? If so, type:

  • $ mkdir /scratch/HDD_2T/esm/${USER}/nwchem

This should create a directory for your NWChem scratch files. If it fails that means we have a problem. Let me know.

From now on we will NOT run any job on /home/${USER}!!!

OK, now to the other parts of this file:

Tip

For more on the set and unset command see the NWChem Wiki SET/UNSET

Run the job using

  $ mpirun.mpich -np 1 nwchem Ar2-noCPcorr-atz.nw >& Ar2-noCPcorr-atz.out

Run it to get the energies (in a.u. unless specified):

Basis: aug-cc-pVTZ
Method    E(Ar...Ar)             E(Ar)           Eint (cm-1)
====
HF       -1053.627091087923  -526.813754874704     +91.88
MP2      -1054.148750447087  -527.074074460254    -132.02
====

Here I have used the separation of R = 3.76 Angstrom Reference $E_{\rm int}$ at a separation of $R=3.75$ Angstrom is: -99.47 cm-1 (Ref: Patkowski, Murdachaew, Fou, and Szalewicz, Mol. Phys., 103, 10-20 (2005) Have a look at this paper as it contains a lot more data.)

Tip

Conversion factor: 1 Hartree = 219474.631 cm-1

Points to note:

Important

Repeat the calculation using the aug-cc-pVDZ basis. This time you should get

  • $E_{\rm int}({\rm HF}) = 82.575$ cm$^{-1}$, and

  • $E_{\rm int}({\rm MP2}) = -103.24$ cm$^{-1}$

Amazing! MP2 is now in better agreement with the reference energy. But how can this be when we have reduced the basis size?

Let's try and understand this. Make a calculation of $E_{\rm int}$ at the HF and MP2 levels of theory using a range of basis sets:

Important

Plot these energies (both the HF and MP2) as a function of basis set. Use the basis size on the $x$-axis - you will find the size printed in the NWChem output.

Q: Is there a pattern that will allow you to make a reasonable guess at the complete basis limit?

Put your data in a table of the form. Your interaction energies (in cm$^{-1}$) go in the columns labeled 'NoCP' = no counterpoise correction. We will fill in the CP columns next.

Basis set

Basis size

RHF

MP2

RHF

MP2

NoCP

NoCP

CP

CP

cc-pVDZ

cc-pVTZ

cc-pVQZ

aug-cc-pVDZ

aug-cc-pVTZ

aug-cc-pVQZ

Basis Set Superposition Error (BSSE)

There is a problem with these calculations. It's called the Basis set superposition error (BSSE). Here's how it goes:

BSSE: We always use finite basis sets for our calculations of energies. These are incomplete and introduce an inconsistency in the calculations of the energies of the dimer (Ar...Ar) and monomer (Ar). In the former the effective basis space is larger than the latter. If the energy method was variational, this would mean that E(Ar) would not be as low as it should be compared with E(Ar...Ar). The resulting error in Eint is called the basis set superposition error.

Resolution of the problem: Boys and Bernardi proposed using the dimer basis for both calculations. We calculate E(Ar...Ar) as before. But calculate E(Ar) using additionally the basis of the partner. This method of correcting the BSSE is called the counterpoise of CP correction.

In file Ar2/Ar2-CPcorr-atz.nw is an example of how the CP correction can be applied:

title "Ar dimer BSSE corrected MP2 interaction energy" 

scratch_dir /scratch/HDD_2T/esm/{YOUR USER NAME}/nwchem

geometry units angstrom "Ar+Ar" 
  Ar1 0 0 0 
  Ar2 0 0 3.76
end

geometry units angstrom "Ar+ghost" 
  Ar1 0 0 0 
  Bq2 0 0 3.76
end

basis 
  Ar1 library aug-cc-pvtz 
  Ar2 library aug-cc-pvtz 
  Bq2 library Ar aug-cc-pvtz 
end

set geometry "Ar+Ar"
task mp2
unset geometry "Ar+Ar"

scf; vectors atomic; end

set geometry "Ar+ghost"
task mp2
unset geometry "Ar+ghost"

atom doesn't contain any electrons. All it contains is the basis set of the missing partner.

Let's now repeat the above set of calculations for Eint with the CP correction. Use all 6 basis sets specified above.

Important

Include these new energies on your plot of interaction energy versus basis size.

Q: Can you see a pattern this time? Is it clearer or less clear than last time?

Put your data in the table we began in the previous step.

Python code to perform an Ar$_2$ scan

If you wish to calculate the interaction energy for a set of argon separations, the above procedure will be tedious. Instead we can use a script like the one given here:

 
import argparse, numpy, subprocess, re, sys
import os
#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("-b", "--basis", dest="basis", type=str, default="aug-cc-pvtz",
                    help="basis set used in calculation")
parser.add_argument("-o", "--output", dest="output", type=str, default="output.txt",
                    help="output text file")

args = parser.parse_args()
 
nwchem_dir = os.environ["NWCHEM_TOP"]
username = os.environ["USER"]
scratch = os.environ["SCRATCH"]
nproc = "1"

#usage = 'Usage: %s minR maxR dR output' % sys.argv[0]
#try:
#        minR   = float(sys.argv[1])
#        maxR   = float(sys.argv[2])
#        deltaR = float(sys.argv[3])
#        file   = sys.argv[4]
#except:
#        print usage; sys.exit(1)
 
 
positions = numpy.arange(args.minR, args.maxR + 0.00001, args.deltaR)
#positions = numpy.arange(minR, maxR + 0.00001, deltaR)
#positions = numpy.array([ 3.0, 3.3, 3.4, 3.5, 3.6, 3.7, 3.75, 3.8, 3.9, 4.0, 4.25, 4.5, 4.75, 5.0, 5.5, 6.0 ])
print "Basis set ",args.basis
print "positions = ", positions
print "Output to : ",args.output
output = open(args.output,'w')
 
 
# Conversion factor:
au2cm = 219474.631371
 
# Construct input files
 
input_file_template = """
title "Ar dimer BSSE corrected MP2 interaction energy"
 
scratch_dir {scratch}/nwchem
 
geometry units angstrom "Ar+Ar"
 Ar1 0 0 0
 Ar2 0 0 {R}
end
 
geometry units angstrom "Ar+ghost"
 Ar1 0 0 0
 Bq2 0 0 {R}
end
 
basis
 Ar1 library    {basis}
 Ar2 library    {basis}
 Bq2 library Ar {basis}
end
 
set geometry "Ar+Ar"
task mp2
unset geometry "Ar+Ar"
 
scf; vectors atomic; end
 
set geometry "Ar+ghost"
task mp2
unset geometry "Ar+ghost"
"""
 
# Regular expressions to find the right lines in the file
 
scf_re = re.compile("SCF energy\s+(-?[0-9]+.[0-9]+)")
mp2_re = re.compile("Total MP2 energy\s+(-?[0-9]+.[0-9]+)")
 
# Dictionary to store the energies we find
 
energies = {}
 
# Main loop through different position values
 
for ar_position in positions:
    print "Current position = ",ar_position
    input_file_name = "in-R{0:5.3f}.nw".format(ar_position)
    output_file_name = "out-R{0:5.3f}.out".format(ar_position)
 
    # Write input file
    with open(input_file_name,"w") as INP:
        INP.write(input_file_template.format(R=ar_position, basis=args.basis,
                    user=username, scratch=scratch))

    # Run NWChem
    output_file = open(output_file_name, "w")
    #subprocess.call(["mpirun.mpich","-np 1",os.path.join(nwchem_dir,"bin/nwchem"), input_file_name],
    subprocess.call(["mpirun.mpich","-np",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")
    scf_energies = []
    mp2_energies = []
    for line in output_file:
        scf_match = scf_re.search(line)
        if scf_match:
            scf_energies.append(float(scf_match.group(1)))
        else:
            mp2_match = mp2_re.search(line)
            if mp2_match:
                mp2_energies.append(float(mp2_match.group(1)))
    output_file.close()
 
    if not (len(scf_energies) == 2 and len(mp2_energies) == 2):
        print "Apparent error in output file! {:d} SCF energies and {:d} MP2 energies found.".format(
            len(scf_energies), len(mp2_energies))
        sys.exit(1)
 
    energies[ar_position] = scf_energies + mp2_energies
    scf_dimer   = energies[ar_position][0]
    scf_monomer = energies[ar_position][1]
    mp2_dimer   = energies[ar_position][2]
    mp2_monomer = energies[ar_position][3]
    scf_interaction = scf_dimer - 2*scf_monomer
    mp2_interaction = mp2_dimer - 2*mp2_monomer
    print "Eint[SCF] = ",scf_interaction*au2cm
    print "Eint[MP2] = ",mp2_interaction*au2cm
 
# prepare plots
 
scf_dimer = numpy.array([energies[p][0] for p in positions])
scf_monomer = numpy.array([energies[p][1] for p in positions])
mp2_dimer = numpy.array([energies[p][2] for p in positions])
mp2_monomer = numpy.array([energies[p][3] for p in positions])
 
scf_interaction = scf_dimer - 2*scf_monomer
mp2_interaction = mp2_dimer - 2*mp2_monomer
 
# convert to cm-1
scf_interaction = au2cm*scf_interaction
mp2_interaction = au2cm*mp2_interaction
 
output.write(('%10s '*7 + '\n') % 
             ("   R    ","SCF mono","SCF dimr",
              "SCF int ","MP2 mono","MP2 dimr","MP2 int "))
 
for i in range(len(positions)):
    output.write(('%10.6f '*7 + '\n') %
    (positions[i],
    scf_monomer[i], scf_dimer[i], scf_interaction[i],
    mp2_monomer[i], mp2_dimer[i], mp2_interaction[i]))
 
output.close()
 
 
#args.output.write(("{:>10s},  "*6 + "\n").format(
#    "SCF mono", "SCF di", "SCF int",
#    "MP2 mono", "MP2 di", "MP2 int"))
#
#for i in range(len(positions)):
#    args.output.write(("{:10.6f},  "*6 + "\n").format(
#        scf_monomer[i], scf_dimer[i], scf_interaction[i],
#        mp2_monomer[i], mp2_dimer[i], mp2_interaction[i]))
#
#args.output.close()
 
## Plot:
#
#fig = plt.figure(figsize=(9,9))
#ax = fig.add_subplot(111)
#
## edit this to change which lines plotted
#
#lines_to_plot = [scf_interaction, mp2_interaction]
#
#for line in lines_to_plot:
#    ax.plot(positions, line)
#
#plt.show()

This is a rather long code, but it contains a number of python2.7 lines that have been commented out and replaced by python2.6-compatible lines. You need to make a change to the input_file_template and change the scratch_dir to be the one relevant to you. Otherwise no further change should be needed.

Save the above commands in a file called nwchem_batch_comanche.py and make it executable using

  $ chmod +x nwchem_batch_comanche.py

To see the usage use:

  $ ./nwchem_batch_comanche.py --help

you should get:

usage: nwchem_batch_comanche.py [-h] [-m MINR] [-M MAXR] [-d DELTAR] [-b BASIS]
                           [-o OUTPUT]

Create a set of NWChem input files for the Ar2 dimer, run NWChem on them, and
parse the output for interaction energy.

optional arguments:
  -h, --help            show this help message and exit
  -m MINR, --min MINR   minimum Ar separation in A
  -M MAXR, --max MAXR   maximum Ar separation in A
  -d DELTAR, --delta DELTAR
                        step size for Ar separation in A
  -b BASIS, --basis BASIS
                        basis set used in calculation
  -o OUTPUT, --output OUTPUT
                        output text file

Now you should be able to run it using, for example,

  $ ./nwchem_batch_comanche.py -m 3.0 -M 6.0 -d 0.5 -b aug-cc-pVDZ -o Ar2_adz_hf_mp2_scan.txt

This will calculate interaction energies at the HF and MP2 levels of theory for the argon dimer at separations 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4.0, 4.5, 5.0, 5.5 and 6.0 Angstrom and save the results in file Ar2_adz_hf_mp2_scan.txt.

Important

Tasks:

  • Calculate the interaction energies using the aug-cc-pVDZ, aug-cc-pVTZ, and aug-cc-pVQZ basis sets.
  • Plot these using Gnuplot. Make sure you include the data points and use smooth csplines to draw a smooth line between the data points.

  • What pattern do you see?
  • Include data from the paper linked above. These data will be your reference values.
  • How close are your results to these reference values?

Important

Sometimes it is good to do a calculation another way to see what happens:

  • Modify the python code to calculate the interaction energies without the CP correction.
  • Calculate the interaction energies without this correction and plot them as above.
  • What do you conclude?

AJMPublic/teaching/electronic-structure/practical3 (last edited 2021-04-14 13:55:35 by apw109)