Gaussian input/output treatments

using pymatgen library

import used modules and objects

Load some pymatgen specific classes and module


In [1]:
import pymatgen as mg
from pymatgen.io.gaussianio import GaussianInput, GaussianOutput

Image class of IPython for rendering pictures.


In [2]:
from IPython.display import Image

Generate gaussian inputs

Hereafter is the docstring of the GaussianInput class.


In [3]:
help(GaussianInput)


Help on class GaussianInput in module pymatgen.io.gaussianio:

class GaussianInput(builtins.object)
 |  An object representing a Gaussian input file.
 |  
 |  Args:
 |      mol: Input molecule. If molecule is a single string, it is used as a
 |          direct input to the geometry section of the Gaussian input
 |          file.
 |      charge: Charge of the molecule. If None, charge on molecule is used.
 |          Defaults to None. This allows the input file to be set a
 |          charge independently from the molecule itself.
 |      spin_multiplicity: Spin multiplicity of molecule. Defaults to None,
 |          which means that the spin multiplicity is set to 1 if the
 |          molecule has no unpaired electrons and to 2 if there are
 |          unpaired electrons.
 |      title: Title for run. Defaults to formula of molecule if None.
 |      functional: Functional for run.
 |      basis_set: Basis set for run.
 |      route_parameters: Additional route parameters as a dict. For example,
 |          {'SP':"", "SCF":"Tight"}
 |      input_parameters: Additional input parameters for run as a dict. Used
 |          for example, in PCM calculations.  E.g., {"EPS":12}
 |      link0_parameters: Link0 parameters as a dict. E.g., {"%mem": "1000MW"}
 |  
 |  Methods defined here:
 |  
 |  __init__(self, mol, charge=None, spin_multiplicity=None, title=None, functional='HF', basis_set='6-31G(d)', route_parameters=None, input_parameters=None, link0_parameters=None)
 |  
 |  __str__(self)
 |  
 |  as_dict(self)
 |  
 |  get_cart_coords(self)
 |      Return the cartesian coordinates of the molecule
 |  
 |  get_zmatrix(self)
 |      Returns a z-matrix representation of the molecule.
 |  
 |  to_string(self, cart_coords=False)
 |      Return GaussianInput string
 |      
 |      Option: whe cart_coords sets to True return the cartesian coordinates instead of the z-matrix
 |  
 |  write_file(self, filename, cart_coords=False)
 |      Write the input string into a file
 |      
 |      Option: see __str__ method
 |  
 |  ----------------------------------------------------------------------
 |  Class methods defined here:
 |  
 |  from_dict(d) from builtins.type
 |  
 |  ----------------------------------------------------------------------
 |  Static methods defined here:
 |  
 |  from_file(filename)
 |      Creates GaussianInput from a file.
 |      
 |      Args:
 |          filename: Gaussian input filename
 |      
 |      Returns:
 |          GaussianInput object
 |  
 |  from_string(contents)
 |      Creates GaussianInput from a string.
 |      
 |      Args:
 |          contents: String representing an Gaussian input file.
 |      
 |      Returns:
 |          GaussianInput object
 |  
 |  parse_coords(coord_lines)
 |      Helper method to parse coordinates.
 |  
 |  ----------------------------------------------------------------------
 |  Data descriptors defined here:
 |  
 |  __dict__
 |      dictionary for instance variables (if defined)
 |  
 |  __weakref__
 |      list of weak references to the object (if defined)
 |  
 |  molecule
 |      Returns molecule associated with this GaussianInput.
 |  
 |  ----------------------------------------------------------------------
 |  Data and other attributes defined here:
 |  
 |  xyz_patt = re.compile('^(\\w+)[\\s,]+([\\d\\.eE\\-]+)[\\s,]...\\-]+)[\...
 |  
 |  zmat_patt = re.compile('^(\\w+)*([\\s,]+(\\w+)[\\s,]+(\\w+))*[\\-\\.\\...

Examples

In this example, we get a $PO_2N^{2-}$ molecule and look for the best place for two Li atoms in the plane of the molecule. This example shows how to set up a Gaussian input file for all possible combinations. Coordinates of this molecule are available in xyz format :


In [4]:
mol = mg.Molecule.from_file("PO2N.xyz")
print(mol.to("xyz"))
Image("PO2N.png")


4
P1 N1 O2
P -2.714301 0.000003 0.056765
O -1.926896 -1.284476 0.128633
O -1.925428 1.283516 0.129485
N -4.181288 0.000879 -0.079861
Out[4]:

First we set up the three guessed positions for Li atoms in the plane of the molecule. Each position is along the bissector of two PO or PN bonds. We build a list of pymatgen.Site object which represent an atom with its symbol, coordinates ....


In [5]:
posLi = [mg.Site("Li", [-0.424, -0.001,  0.267]),
         mg.Site("Li", [-3.789, -2.031, -0.046]),
         mg.Site("Li", [-3.787,  2.032, -0.044])]
print(posLi)


[Site: Li (-0.4240, -0.0010, 0.2670), Site: Li (-3.7890, -2.0310, -0.0460), Site: Li (-3.7870, 2.0320, -0.0440)]

Now for each combinaison of two Li atoms among three possibilities we will write a gaussian input file. Look at the combinations method of itertools module.


In [6]:
from itertools import combinations
for sites in combinations(posLi, 2):
    print(sites, "\t indices : ", [posLi.index(site) for site in sites])


(Site: Li (-0.4240, -0.0010, 0.2670), Site: Li (-3.7890, -2.0310, -0.0460)) 	 indices :  [0, 1]
(Site: Li (-0.4240, -0.0010, 0.2670), Site: Li (-3.7870, 2.0320, -0.0440)) 	 indices :  [0, 2]
(Site: Li (-3.7890, -2.0310, -0.0460), Site: Li (-3.7870, 2.0320, -0.0440)) 	 indices :  [1, 2]

Hereafter is the loop over combinations which will write all input files.


In [7]:
# Gaussian keywords
route_parms = {"opt": "tight", "Freq": ""}
link0 = {"%Nproc":"5"}
DFT = "B3LYP"

# the loop
for sites in combinations(posLi, 2):
    # load the molecule
    mol = mg.Molecule.from_file("PO2N.xyz")
    
    # set up a label according to the combination
    title = "combination_" + "".join([str(posLi.index(site)) for site in sites])
    print(title)
    
    # add the two Li atoms to the molecule
    for site in sites:
        mol.append(site.specie, site.coords)
        
    # set up the calculation
    gau = GaussianInput(mol, charge=0, spin_multiplicity=1, title=title, 
                        functional=DFT, route_parameters=route_parms, link0_parameters=link0)
    gau.write_file(title + ".com", cart_coords=True)


combination_01
combination_02
combination_12

We can also load an input file and get some information.


In [8]:
gau = GaussianInput.from_file("combination_01.com")
print(gau.basis_set, gau.functional)


6-31G(d) B3LYP

In [9]:
print(gau.to_string(cart_coords=True))


%Nproc=5
#P B3LYP/6-31G(d) Freq Test opt=tight Test

combination_01

0 1
P -2.714301 0.000003 0.056765
O -1.926896 -1.284476 0.128633
O -1.925428 1.283516 0.129485
N -4.181288 0.000879 -0.079861
Li -0.424000 -0.001000 0.267000
Li -3.789000 -2.031000 -0.046000




Post-treatments of Gaussian outputs

Docstring of the GaussianOutput class


In [10]:
help(GaussianOutput)


Help on class GaussianOutput in module pymatgen.io.gaussianio:

class GaussianOutput(builtins.object)
 |  Parser for Gaussian output files.
 |  
 |  Args:
 |      filename: Filename of Gaussian output file.
 |  
 |  .. note::
 |  
 |      Still in early beta.
 |  
 |  Attributes:
 |  
 |  .. attribute:: structures
 |  
 |      All structures from the calculation.
 |  
 |  .. attribute:: energies
 |  
 |      All energies from the calculation.
 |  
 |  .. attribute:: properly_terminated
 |  
 |      True if run has properly terminated
 |  
 |  .. attribute:: is_pcm
 |  
 |      True if run is a PCM run.
 |  
 |  .. attribute:: stationary_type
 |  
 |      If it is a relaxation run, indicates whether it is a minimum (Minimum)
 |      or a saddle point ("Saddle").
 |  
 |  .. attribute:: corrections
 |  
 |      Thermochemical corrections if this run is a Freq run as a dict. Keys
 |      are "Zero-point", "Thermal", "Enthalpy" and "Gibbs Free Energy"
 |  
 |  .. attribute:: functional
 |  
 |      Functional used in the run.
 |  
 |  .. attribute:: basis_set
 |  
 |      Basis set used in the run
 |  
 |  .. attribute:: charge
 |  
 |      Charge for structure
 |  
 |  .. attribute:: spin_mult
 |  
 |      Spin multiplicity for structure
 |  
 |  .. attribute:: num_basis_func
 |  
 |      Number of basis functions in the run.
 |  
 |  .. attribute:: pcm
 |  
 |      PCM parameters and output if available.
 |  
 |  .. attribute:: errors
 |  
 |      error if not properly terminated (list to be completed in error_defs)
 |  
 |  .. attribute:: Mulliken_charges
 |  
 |      Mulliken atomic charges
 |  
 |  Methods defined here:
 |  
 |  __init__(self, filename)
 |  
 |  as_dict(self)
 |      Json-serializable dict representation.
 |  
 |  ----------------------------------------------------------------------
 |  Data descriptors defined here:
 |  
 |  __dict__
 |      dictionary for instance variables (if defined)
 |  
 |  __weakref__
 |      list of weak references to the object (if defined)
 |  
 |  final_energy
 |  
 |  final_structure

Examples :

Used the GaussianOutput class to read a Gaussian output file.


In [11]:
logfile = GaussianOutput("O3P-O-PO3/config_0123.log")

Is termination Normal ?


In [12]:
logfile.properly_terminated


Out[12]:
True

Display final energy or mulliken charges :


In [13]:
logfile.final_energy


Out[13]:
-1239.01264675

In [14]:
logfile.Mulliken_charges


Out[14]:
{1: ['P', 1.751758],
 2: ['P', 1.203271],
 3: ['O', -0.722993],
 4: ['O', -0.771242],
 5: ['O', -0.804145],
 6: ['O', -0.771148],
 7: ['O', -0.633752],
 8: ['O', -0.633729],
 9: ['O', -0.519418],
 10: ['Li', 0.528585],
 11: ['Li', 0.528596],
 12: ['Li', 0.421974],
 13: ['Li', 0.422242]}

You can extract the coordinates of the final structure. All structures are pymatgen.Molecule objects, see here or the reference guide. You can do lot of stuff with this object such as : neighbors list, compute distances or the distance matrix, symmetry operation, atomic substitution ...


In [15]:
print(logfile.final_structure.to(fmt="xyz"))


13
Li4 P2 O7
P 1.803152 -0.000062 -0.074603
P -2.714301 0.000003 0.056765
O 0.711492 0.000020 -1.166577
O 1.626159 1.347642 0.712312
O 3.338973 -0.000234 -0.476901
O 1.625851 -1.347548 0.712612
O -1.926896 -1.284476 0.128633
O -1.925428 1.283516 0.129485
O -4.181288 0.000879 -0.079861
Li 3.387513 1.698635 0.310029
Li 3.387174 -1.698958 0.310641
Li -0.135176 -1.487921 -0.211882
Li -0.134065 1.489076 -0.212137

You would prefer a gaussian input format with a z-matrix of the 42th geometrical optimization step.


In [16]:
print(logfile.structures[41].to(fmt="gjf"))


#P HF/6-31G(d)  Test

Li4 P2 O7

0 1
P
P 1 B1
O 1 B2 2 A2
O 1 B3 3 A3 2 D3
O 1 B4 4 A4 3 D4
O 1 B5 5 A5 3 D5
O 2 B6 3 A6 6 D6
O 2 B7 7 A7 3 D7
O 2 B8 7 A8 8 D8
Li 4 B9 5 A9 1 D9
Li 6 B10 5 A10 1 D10
Li 7 B11 3 A11 6 D11
Li 8 B12 4 A12 3 D12

B1=4.376288
B2=1.543372
A2=36.067295
B3=1.572484
A3=105.757762
D3=-63.587256
B4=1.587877
A4=103.530048
D4=127.302261
B5=1.570339
A5=103.613837
D5=118.342854
B6=1.509599
A6=70.094274
D6=-30.800762
B7=1.509898
A7=116.635764
D7=-54.758827
B8=1.474749
A8=121.618553
D8=-179.642556
B9=1.844669
A9=48.464768
D9=-173.301681
B10=1.844418
A10=48.529403
D10=176.422774
B11=1.836204
A11=36.882001
D11=-26.625480
B12=1.836768
A12=14.624477
D12=-64.000507




You can plot the geometrical convergence (here using plotly).


In [17]:
import plotly.plotly as py
import plotly.graph_objs as go

In [21]:
fig = go.Figure(
    data=go.Data([
        go.Scatter(x=[i for i in range(len(logfile.energies))], y=logfile.energies)
    ]),
    layout=go.Layout(xaxis=go.XAxis(title="step"), yaxis=go.YAxis(title="Energy (ua)"))
)
py.image.ishow(fig)