Job Types

Jobs in ASH are performed by calling functions that take some input (usually an ASH Fragment and an ASH Theory object).

The primary job-types available in ASH:

  • Single-point energy/property job

  • Geometry optimization

  • Saddlepoint search

  • Numerical frequencies

  • Analytic frequencies

  • Nudged elastic band optimization

  • Freezing string optimization

  • Molecular dynamics

  • Surface scan

These job-types are simple Python functions that are called with typically an ASH Theory and ASH Fragment as input.

Additionally ASH features various workflows that perform some combination of jobtypes above. The job-types can be used with any theory object available (with some exceptions), e.g. one of the QMTheories in QM Interfaces or using a QM/MM Theory object from QM/MM Theory

Output object of ASH Job-types

Almost all the main job types in ASH now return the same object. This differs from previous versions where either an energy, geometry, fragment or dictionary might have been returned.

The return object is a dataclass object of class ASH_Results. This object has various relevant attributes (energy, geometry, Hessian etc.) defined with are by default set to None, while the job functions will set the relevant attributes depending on what was calculated.

Keyword

Type

Default value

Details

label

string

None

A label that usually indicates what job-function created the object.

energy

float

None

The final energy. Set by Singlepoint, Optimizer, NEBTS.

gradient

Numpy array

None

A calculated gradient. Set by Singlepoint with Grad=True.

reaction_energy

float

None

A reaction energy in a chosen unit. Set by Singlepoint_reaction.

energy_contributions

dict

None

A dictionary of various energy contributions. Set by Singlepoint_reaction if a multistep theory like ORCA_CC_CBS_Theory was used.

energies

list of floats

None

A list of energies calculated. Set by Singlepoint_fragments, Singlepoint_theories, Singlepoint_fragments_and_theories and Singlepoint_reaction.

reaction_energies

list of floats

None

A list of reaction energies calculated. Set by Singlepoint_reaction.

gradients

List of numpy arrays.

None

A list of gradients calculated. Set by Singlepoint_parallel.

energies_dict

dict

None

Dictionary containing multiple energies for multiple single-point energy calculations. Set by Singlepoint_parallel.

gradients_dict

dict

None

Dictionary containing multiple gradients for multiple single-point energy calculations. Set by Singlepoint_parallel.

geometry

Numpy array

None

The final geometry from job. Set by Optimizer.

initial_geometry

Numpy array

None

The initial geometry from job. Set by Optimizer.

hessian

Numpy array

None

Hessian matrix. Set by NumFreq.

frequencies

List

None

List of vibrational frequencies in cm**-1. Set by NumFreq and AnFreq.

vib_eigenvectors

Numpy array

None

Eigenvectors from a mass-weighed Hessian diagonalization. Set by NumFreq.

normal_modes

Numpy array

None

Normal modes (unweighted eigenvectors). Set by NumFreq.

thermochemistry

dict

None

A dictionary containing various thermochemistry components ('ZPVE','Gcorr' etc.). Set by NumFreq and AnFreq.

surfacepoints

dict

None

Dictionary of energies of surfacepoints. Set by calc_surface and calc_surface_fromXYZ.

saddlepoint_fragment

ASH Fragment

None

An ASH fragment for the saddlepoint found. Set by NEB and NEBTS.

MEP_energies_dict

dict

None

Dictionary of total energies for each image. Set by NEB and NEBTS.

barrier_energy

float

None

The barrier height in kcal/mol (reactant->SP). Set by NEBTS.

If you are unsure what the Results object contains you can simply print it out and inspect

from ash import *

#Geometry optimization of HF using ORCA
HF_frag=Fragment(databasefile="hf.xyz", charge=0, mult=1)
ORCAcalc = ORCATheory(orcasimpleinput="! BP86 def2-SVP  tightscf")
result = Optimizer(fragment=HF_frag, theory=ORCAcalc, coordsystem='tric')

print(result) #Print whole object
print(result.print_defined()) #Print only defined attributes (i.e. not None)
ASH_Results(label='Optimizer', energy=-100.354499689476, gradient=None, reaction_energy=None, energy_contributions=None,
  energies=None, reaction_energies=None, gradients=None, energies_dict=None, gradients_dict=None,
  geometry=array([[ 2.41430696e-10,  2.39715804e-09, -7.96015314e-03],[-2.41430696e-10, -2.39715804e-09,  9.24960153e-01]]),
  initial_geometry=None, charge=None, mult=None, hessian=None, frequencies=None, normal_modes=None,
  vib_eigenvectors=None, thermochemistry=None, surfacepoints=None, reactant_geometry=None, product_geometry=None,
  saddlepoint_geometry=None, saddlepoint_fragment=None, MEP_energies_dict=None, barrier_energy=None)

Printing defined attributes of ASH_Results dataclass
label: Optimizer
energy: -100.354499689474
geometry: [[ 6.66989696e-10  3.31567055e-09 -7.96014574e-03]
[-6.66989696e-10 -3.31567055e-09  9.24960145e-01]]

Using ASH_Results object:

The ASH_results object can also be used for your own workflows

result = ASH_Results(label="MyLabel", energy=-100.354499689476)

Writing ASH_Results object to disk:

You can write the ASH_Results object to disk using a JSON format. Note that ASH usually does this automatically for all major jobtypes

result = ASH_Results(label="MyWorkflow", energy=-100.354499689476)
result.write_to_disk(filename="ASH_myworkflow.result")

Reading ASH_Results file :

You can also read a previously written ASH_Results file back into a ASH_Results dataclass object. This is a convenient option for reusing results from previous calculations.

result = ASH_Results(label="MyWorkflow", energy=-100.354499689476)
result.write_to_disk(filename="ASH_myworkflow.result")
read_result = read_results_from_file(filename="ASH_myworkflow.result")

Single-point calculation

The most basic jobtype. See Singlepoint In addition to the basic Singlepoint jobtype, there are also specialized functions: Singlepoint_fragments, Singlepoint_theories, Singlepoint_fragments_and_theories, Singlepoint_reaction and Singlepoint_parallel that are used to run single-point calculations on multiple fragments or with multiple theories.

Example:

from ash import *

HF_frag=Fragment(xyzfile="hf.xyz", charge=0, mult=1) #Fragment object creation
ORCAcalc = ORCATheory(orcasimpleinput="! BP86 def2-SVP  tightscf") #ORCATheory object creation

result = Singlepoint(fragment=HF_frag, theory=ORCAcalc)

Geometry optimization

Geometry optimizations in ASH can be performed in variety of ways. See Geometry optimization documentation for all options.

The geomeTRIC-Optimizer is called by simply calling the Optimizer function. This option allows efficient optimization in multiple coordinate systems: TRIC, HDLC, DLC, Cartesian, redundant internals. The optimizer supports constraints as well as frozen atoms natively. Additionaly, an active-region can be defined which enables efficient QM/MM optimizations of a part of large systems (where most atoms are frozen). ASH features a full-featured interface to geomeTRIC that allows flexible constraint input, QM/MM optimizations, relaxed and unrelaxed 1D/2D surface scans and more.

Example:

from ash import *

HF_frag=Fragment(xyzfile="hf.xyz", charge=0, mult=1) #Fragment object creation
ORCAcalc = ORCATheory(orcasimpleinput="! BP86 def2-SVP  tightscf") #ORCATheory object creation

#Geometry optimization of the ORCA using geomeTRIC optimizer
Optimizer(fragment=HF_frag, theory=ORCAcalc, coordsystem='tric')
#Optimizer and Opt are aliases for the geomeTRICOptimizer function name.

See Geometry optimization for information on other features of the geomeTRIC Optimizer as well as information on other options: such as DL-FIND, and the native Cartesian-based optimizer.

Numerical frequencies (Hessian)

Numerical frequencies can be performed with ASH using any QM, MM or QM/MM theory object. Parallelization is available. See Vibrational frequencies documentation for all options.

Example:

from ash import *

HF_frag=Fragment(xyzfile="hf.xyz", charge=0, mult=1) #Fragment object creation
ORCAcalc = ORCATheory(orcasimpleinput="! BP86 def2-SVP  tightscf") #ORCATheory object creation

NumFreq(fragment=HF_frag, theory=ORCAcalc)

Analytical frequencies (Hessian)

Analytical frequencies can be requested in some cases if supported by the theory-level interface as well as the Hamiltonian inside program. See Vibrational frequencies

Nudged Elastic Band Calculations

Through an interface to the external code Knarr, nudged elastic band (NEB) calculations are possible. This enables one to calculate minimum energy paths and locate approximate saddlepoints using any QM, MM or QM/MM Theory in ASH.

See Nudged Elastic Band for documentation

Example:

from ash import *

Reactant=Fragment(xyzfile="react.xyz", charge=0, mult=1)
Product=Fragment(xyzfile="prod.xyz", charge=0, mult=1)

#Calculator object without frag
xtbcalc = xTBTheory(xtbmethod='GFN2', runmode='library')

NEB(reactant=Reactant, product=Product, theory=xtbcalc, images=10, CI=True)

Surface scans

Potential Energy Surfaces can be conveniently scanned in ASH using the calc_surface function that uses the geometric optimization library. Both unrelaxed and relaxed scans be calculated, using either 1 and 2 reaction coordinates.

See Surface Scan

Freezing string optimization

The freezing string method is an alternative method to NEB for locating approximate saddlepoints. A variant of the growing string method (that like NEB can locate minimum energy paths), the freezing string method sacrifices computation of the MEP in favor of a more efficient optimization of the saddlepoint geometry.

See X

Saddle-point optimization

While NEB and freezing string methods as well as surface scans all work to locate approximate saddlepoint geometries, and can often come very close to the true saddlepoint, they ultimately suffer from not using curvature information (Hessian) and thus cannot be expected to locate the true saddlepoint geometry with high accuracy.

A truly accurate saddle-point optimization needs to be performed by an eigenvector-following algorithm (usually a PRFO algorithm) but requires as input:

    1. a reasonably accurate guess for the SP geometry

    1. information about the curvature (Hessian information)

ASH features a few different options of performing saddle-point optimizations.

  • The RS-P-RFO algorithm of the geomeTRIC Optimizer. See geomeTRIC Optimizer

  • The PRFO algorithm implemented in the DL-FIND library. See DL-FIND_interface

  • The iterative Hessian diagonalization algorithm Sella algorithm. See Sella Optimizer

A simple example of how to find a saddlepoint via the algorithm in geomeTRIC is shown below. The syntax is similar to regular geomeTRIC optimization, except one adds the TSOpt=True option and then makes a choice for the Hessian approxiatmion. Note that this option relies on the input geometry being a good guess for the saddlepoint geometry. A Hessian also needs to be available (default: numerical Hessian is calculated in the first step). See geomeTRIC Optimizer for further details.

Example:

from ash import *

HF_frag=Fragment(xyzfile="tsguess.xyz", charge=0, mult=1) #Fragment object creation
ORCAcalc = ORCATheory(orcasimpleinput="! BP86 def2-SVP  tightscf") #ORCATheory object creation

#TSOpt=True enables saddlepoint optimization in geomeTRIC. Note: Exact Hessian is calculated in the first step by default.
Optimizer(fragment=HF_frag, theory=ORCAcalc, coordsystem='tric', TSOpt=True)

NEB-TS

Generally, the combination of NEB, scan or frozen-string job followed by a saddlepoint optimization is an efficient way to locate saddlepoints.

A combination of the double-ended NEB strategy and a single-ended eigenvector-following method is also available in ASH in the form of the NEB-TS method. This is an efficient yet robust way of finding a saddlepoint as discussed in the article:

V. Ásgeirsson, B. Birgisson, R. Bjornsson, U. Becker, F. Neese, C: Riplinger, H. Jónsson, J. Chem. Theory Comput. 2021,17, 4929–4945. DOI: 10.1021/acs.jctc.1c00462

See Nudged Elastic Band for documentation on the NEB-TS function.

Example:

from ash import *

Reactant=Fragment(xyzfile="react.xyz", charge=0, mult=1)
Product=Fragment(xyzfile="prod.xyz", charge=0, mult=1)
ORCAcalc = ORCATheory(orcasimpleinput="! BP86 def2-SVP  tightscf") #ORCATheory object creation

#NEB-TS combines a CI-NEB job (note: looser thresholds than default CI-NEB) and a Optimizer(TSOpt=True) job.
result = NEBTS(reactant=Reactant, product=Product, theory=ORCAcalc, images=12, printlevel=0)

Molecular Dynamics

It is possible to perform molecular dynamics in ASH using the interface to OpenMM that can be used for MM, QM and QM/MM simulations.

See Molecular dynamics and also Biased sampling MD & Free energy simulations