Coding with Theory Objects#

AaronTools.theory.Theory() keeps much of the code for writing quantum chemistry input files similar across different software packages. Here, we will cover the basics of creating and using a Theory.

Creation#

Several objects or variables must be passed to Theory to make it usable. Each of the necessary objects are found in the AaronTools.theory package. We’ll briefly cover each of these.

Method Class#

AaronTools.theory.Method() is used to keep method keywords the same across different formats. As an example:

from AaronTools.theory import Method

pbe0 = Method("PBE0")

When used with a Gaussian input file, this Method will use the Gaussian keyword for PBE0 (PBE1PBE).

Method also takes a is_semiempirical argument:

rm1 = Method("RM1", is_semiempirical=True)

For Gaussian and ORCA input files, using a semi-empirical method will cause basis set information to be omitted.

SAPTMethod#

AaronTools.theory.SAPTMethod() is a subclass of Method that is specific for SAPT jobs. When used to make a Psi4 input file, the molecule will be split into monomers, which are specified by the components attribute of the Geometry instance.

sapt0 = SAPTMethod("sapt0")

Basis Sets

The AaronTools.theory.BasisSet() object is a collection of AaronTools.theory.Basis() and AaronTools.theory.ECP() objects.

from AaronTools.theory import Basis, ECP, BasisSet
from AaronTools.finders import AnyTransitionMetal, AnyNonTransitionMetal

basis = BasisSet(
    [
        Basis("cc-pVTZ", AnyNonTransitionMetal()),
        Basis("cc-pVTZ", AnyNonTransitionMetal(), aux_type='C'),
        Basis("cc-pVTZ-PP", AnyTransitionMetal()),
        Basis("cc-pVTZ-PP", AnyTransitionMetal(), aux_type='C')
    ],
    [ECP("SK-MCDHF-RSC")]
)

The second argument given to each Basis determines which elements that basis applies to. By default, a Basis applies to all elements. An ECP applies to any transition metal. These elements will be overridden if another argument is supplied when creating an ECP or Basis (i.e. list of elements or AaronTools.finders.Finders()).

The aux_type keyword is used for ORCA and Psi4 input files to specify auxiliary basis sets. A list of elements or an appropriate Finder that use that basis set can be given to a Basis or ECP.

Empirical Dispersion#

:py:meth`AaronTools.theory.emp_dispersion.EmpiricalDispersion` keeps specifying dispersion corrections consistent across different formats.

from AaronTools.theory import EmpiricalDispersion

disp = EmpiricalDispersion("Grimme D2")

The following are equivalent:

disp = EmpiricalDispersion("Grimme D2")
disp = EmpiricalDispersion("GD2")
disp = EmpiricalDispersion("D2")
disp = EmpiricalDispersion("-D2")

Some dispersion methods are not available in all QM software programs. Check the get_gaussian, get_orca, etc. methods of the EmpiricalDispersion class (or the respective manuals) for acceptable dispersion methods.

Integration Grid#

As with other objects in the AaronTools.theory package, the AaronTools.theory.IntegrationGrid() object is a way to specify grids in a similar manner across different file formats.

It’s important to note that different programs use different types of grids. This, combined with varied grid pruning algorithms, mean that grids will usually have to be approximated if you use a keyword from one program to make an input file for a different program.

from AaronTools.theory import IntegrationGrid

grid = IntegrationGrid("SuperFineGrid")

Gaussian, ORCA, and Psi4 all have different ways of specifying integration grids. Gaussian and ORCA have grid keywords. When using an ORCA grid keyword to write a Gaussian input file, IntegrationGrid will try to approximate the ORCA grid’s density. Psi4 specifies grid density by supplying a number of radial and angular points. Gaussian allows a similar specification. These can be specified as a string of the format "(radial, angular)". As an example,

grid = IntegrationGrid("(99, 590)")

This grid can be used with Gaussian and Psi4, and should give similar results (down to grid pruning and other algorithmic differences). If you’re going to write and ORCA input file with this grid, the number of radial points is set indirectly with the IntAcc option. IntAcc will be set for the number of radial points in the 2nd row of the periodic table.

Job Types#

There are six job types in the theory package:

A single JobType can be given to a Theory. If multiple JobType instances are given as list, the job-related information will appear in the order it appears in the list. For example:

jobs = [FrequencyJob(), OptimizationJob()]

A Psi4 input file that uses this list will specify frequency before optimize, but many programs are not sensitive to the order these jobs will appear in the input file.

Other Options#

  • charge - overall charge

  • multiplicity - multiplicity

  • processors - allocated cores

  • memory - allocated RAM

When writing an input file, additional keywords can be passed to AaronTools.geometry.Geometry.write() that specify any other options. The keywords for the dictionary are listed in Theory parameters.

Examples#

Below are examples of writing roughly equivalent input files for Gaussian, ORCA, and Psi4.

from AaronTools.geometry import Geometry
from AaronTools.theory import *

geom = Geometry('tnt.xyz')

fun = Method("B3LYP")
basis_set = BasisSet([Basis("def2-SVP")])
int_grid = IntegrationGrid("(99, 590)")
disp = EmpiricalDispersion("D2")

jobs = [OptimizationJob(), FrequencyJob()]

b3lyp_def2svp = Theory(
    method=fun,
    basis=basis_set,
    grid=int_grid,
    empirical_dispersion=disp,
    job_type=jobs,
)

geom.write(
    outfile="tnt_freq.com",
    theory=b3lyp_def2svp,
    GAUSSIAN_ROUTE={'freq':['HPModes', 'NoRaman']}
)

geom.write(
    outfile="tnt_freq.inp",
    theory=b3lyp_def2svp
)

geom.write(
    outfile="tnt_freq.in",
    theory=b3lyp_def2svp
)

Note that Method, BasisSet, IntegrationGrid, and EmpiricalDispersion objects can be created automatically when creating a Theory object just by passing strings:

b3lyp_def2svp = Theory(
    method="B3LYP",
    basis="def2-SVP",
    grid="(99, 590)",
    empirical_dispersion="D2",
    job_type=jobs,
)