Source code for schrodinger.application.jaguar.results

"""
Classes for parsing Jaguar output files and accessing output properties
programmatically.

Copyright Schrodinger, LLC. All rights reserved.

"""

import copy
import functools
import math
import textwrap
from past.builtins import cmp
import warnings

import numpy as np

import schrodinger.utils.units as units
from schrodinger import structure
from schrodinger.application.jaguar import constants
from schrodinger.application.jaguar import jaguar_diff as diff
from schrodinger.application.jaguar import utils
from schrodinger.application.jaguar.exceptions import JaguarRuntimeError
from schrodinger.infra import mm

#-----------------------------------------------------------------------------


[docs]class IncompleteOutput(RuntimeError): """Indicators that the output is incomplete."""
#----------------------------------------------------------------------------- @functools.total_ordering class _Attribute(object): """ A medium utility class to automate and regularize handling of attributes. _Attributes typically live within other classes, such as JaguarResults/Output, as members of a self._attributes list. For ease of access, _Attribute.name is programatically placed within the containing objects __dict__. Many of the __init__ variables of _Attribute have special significance in the context of qm_descriptors/descriptors.py, described in the __init__ docstring. """ def __init__(self, name, description="", datatype="NotPrimitive", units=None, init=lambda: None, comparison=diff._SIMPLE, precision=None, component_names=None, val=None, pretty_name=None): """ Arguments name (str) Attribute name. Placed in __dict__ of containing class. Also the handle by which qm_descriptors.py accesses specific _Attributes. description (str) A description of the attribute appropriate for inclusion in the class docstring. Also the phrase that is generated for the help msg describing options one can pass to qm_descriptors.py pretty_name (str) A name shorter than .description, but longer than .name. Used to generate informative strings for keys when placing _Attribute's in dictionaries as part of qm_descriptors.py. Ends up being the str tied to a property in the files output by qm_descriptors.py (i.e. Maestro property keys). If .pretty_name undefined, is set equal to .description. val (scalar or list of any type in descriptors.PRIMITIVES, or None) Value associated with _Attribute, first stored in containing class' __dict__[_Attribute.name]. qm_descriptors.py workflow places the value in here (val), thus allowing an _Attribute to be a standalone object that contains both information and the value of the given property it refers to. component_names (str) Used only in qm_descriptors.py. Specifically, used for generating keys when adding _Attributes that have lists in their .val, and each member of the list has a specific name. Currently only used in two class' self._attributes, Dipole and JaguarAtomicResults. datatype (str) An indication of the data type, also for inclusion in the class docstring. Used extensively in descriptors.py for logic pathing when harvesting _Attributes from Jaguar .out files. Currently follows these conventions: - if scalar: 'name_of_type' Ex: 'float' - if list: 'list of name_of_type' Ex: 'list of floats' - if object: don't define, defaults to 'NotPrimitive' units (str) The units of the attribute; included in the docstring. Appended to end of string in make_mae_key(). init (function) A function returning the initial value for the attribute. This must be a function so that things like empty lists and dictionaries aren't shared across multiple instances of JaguarOutputs. Note that for _Attribute's linked to classes, such as dipole_qm and Dipole, we init a dummy instance of the class to allow the inner self._attributes list to be exposed. comparison (object) The type of comparison to use for this attribute. If None, no comparison will be made. precision (str) The name of the class attribute to use for the precision value in _LIST_PRECISION or _FLOAT_PRECISION comparisons. """ self.name = name self.description = description self.datatype = datatype self.units = units self.init = init self.comparison = comparison self.precision = precision self.component_names = component_names self.val = val if pretty_name: self.pretty_name = pretty_name else: self.pretty_name = self.description def __lt__(self, other): """ Provide for sorting based on the name. """ return self.name < other.name def __eq__(self, other): return self.name == other.name def summary(self, indent=0): """ Provide a summary of the attribute suitable for a class docstring. """ if not self.description or not self.datatype: raise Exception("Attribute '%s' is missing a description and/or" " datatype." % self.name) prefix = " " * indent desc_indent = prefix + " " description = textwrap.fill(self.description, initial_indent=desc_indent, subsequent_indent=desc_indent) if self.units: units = ", %s" % self.units else: units = "" return "%s%s (%s%s)\n%s\n" % (prefix, self.name, self.datatype, units, description) def __repr__(self): return '<%s: %s>' % (type(self).__name__, self.name) #Functions for outputting attributes in human-readable formats - mae/sdf def make_mae_key(self, curr_key): """ Convert curr_key to be compliant with Maestro property format. :type curr_key: string :param curr_key: Descriptive name of _Attribute. """ #We need to use base_datatype to deal with _Attributes with datatype='list of XX' base_datatype = self.datatype.split()[-1] if base_datatype in ('bool', 'bools'): prefix = 'b_j_' elif base_datatype in ('int', 'ints'): prefix = 'i_j_' elif base_datatype in ('float', 'floats'): prefix = 'r_j_' elif base_datatype in ('string', 'strings'): prefix = 's_j_' else: msg = f'For mae files, cannot output base datatypes of type "{base_datatype}". Found for key: {curr_key}' raise JaguarRuntimeError(msg) suffix = '' if self.units: suffix = '_' + self.units mae_key = (prefix + curr_key + suffix).replace(' ', '_') return mae_key #at this point, should only be called by an attr with attr.val = primitive data, a list of prim, or None def add_as_mae(self, destination, appending=False): """ Adds property with key as self.pretty_name+self.units (if defined), modified to fit Maestro property name conventions. :type destination: dictionary :param destination: Dictionary to put this _Attribute's values into :type appending: bool :param appending: Flag to allow appending _Attribute values to values under an existing key. Mainly used for atomic _Attributes. """ #split into components if a list if isinstance(self.val, list): count = 0 for val in self.val: if self.component_names: name = self.component_names[count] else: #default to numbering if component_names not defined name = self.pretty_name + f" {count}" mae_key = self.make_mae_key(name) if appending: destination[mae_key].append(val) else: destination[mae_key] = val count += 1 else: mae_key = self.make_mae_key(self.pretty_name) if appending: destination[mae_key].append(self.val) else: destination[mae_key] = self.val #-----------------------------------------------------------------------------
[docs]class FukuiIndices(object): """ A class to store Atomic Fukui indices. """ precision = 1.0e-2
[docs] def __init__(self, index, atom_name, homo_nn, homo_ns, homo_sn, homo_ss, lumo_nn, lumo_ns, lumo_sn, lumo_ss): """ Initialization requires all N/S combinations for both the HOMO and the LUMO. """ #should choose either index or atom_name self.index = index #1-based index self.atom_name = atom_name self._attributes = [ _Attribute("homo_nn", datatype="float", pretty_name='Atom Fukui Index f_NN HOMO', description="Atomic Fukui Indices, f_NN HOMO"), _Attribute("homo_ns", datatype="float", pretty_name='Atom Fukui Index f_NS HOMO', description="Atomic Fukui Indices, f_NS HOMO"), _Attribute("homo_sn", datatype="float", pretty_name='Atom Fukui Index f_SN HOMO', description="Atomic Fukui Indices, f_SN HOMO"), _Attribute("homo_ss", datatype="float", pretty_name='Atom Fukui Index f_SS HOMO', description="Atomic Fukui Indices, f_SS HOMO"), _Attribute("lumo_nn", datatype="float", pretty_name='Atom Fukui Index f_NN LUMO', description="Atomic Fukui Indices, f_NN LUMO"), _Attribute("lumo_ns", datatype="float", pretty_name='Atom Fukui Index f_NS LUMO', description="Atomic Fukui Indices, f_NS LUMO"), _Attribute("lumo_sn", datatype="float", pretty_name='Atom Fukui Index f_SN LUMO', description="Atomic Fukui Indices, f_SN LUMO"), _Attribute("lumo_ss", datatype="float", pretty_name='Atom Fukui Index f_SS LUMO', description="Atomic Fukui Indices, f_SS LUMO") ] # Programmatically assign all the args to the corresponding # attribute names. locals_ = locals() for attr in self._attributes: setattr(self, attr.name, locals_[attr.name])
def __eq__(self, other): for attr in self._attributes: self_val = getattr(self, attr.name) other_val = getattr(other, attr.name) if self_val is None or other_val is None: if diff.compare_a_none(self_val, other_val) != 0: return False else: if diff.compare_float(self_val, other_val, self.precision) != 0: return False return True def __ne__(self, other): return not (self == other) def __repr__(self): template = "FukuiIndices(" + \ ", ".join(["%s=%%(%s)s" % (attr.name, attr.name) for attr in self._attributes]) + \ ")" return template % self.__dict__
#-----------------------------------------------------------------------------
[docs]class JaguarAtomicResults(object): """ A class for holding atomic level properties. Attributes forces (list of floats, Hartree/Bohr) Atomic forces. charge_esp (float) Electrostatic potential charge. charge_nbo (float) NBO charge. charge_stockholder (float) Stockholder charge. charge_lowdin (float) Lowdin charge. spin_lowdin (float) Lowdin spin density. charge_mulliken (float) Mulliken charge. spin_mulliken (float) Mulliken spin density. fukui_indices (FukuiIndices) Fukui indices. nmr_shielding (float) NMR shielding. nmr_abs_shift (float) NMR absolute shifts nmr_rel_shift (float) NMR relative shifts, defined only for C/H. nmr_h_avg_shift (float) NMR relative shifts, with the shifts of H's bonded to the same atom averaged. nmr_2d_avg_shift (float) NMR relative shifts, with 2D equivalent sites shifts averaged. maxat_esp (float) Max atomic ESP value on molecular surface. minat_esp (float) Min atomic ESP value on molecular surface. maxat_alie (float) Max atomic ALIE value on molecular surface. minat_alie (float) Min atomic ALIE value on molecular surface. epn (float) Electrostatic potential at the nucleus. isotope (string) Atomic isotope. nuclear_spin (float) Nuclear spin of atom. nuclear_magnetic_dipole_moment (float) Nuclear magnetic dipole moment of atom. """ forces_precision = 1.0e-4 charge_precision = 5.0e-5 nmr_precision = 1.0e-2 esp_precision = 1.0e-2 alie_precision = 1.0e-2 epn_precision = 1.0e-2 nuclear_spin_precision = 1.0e-4 nuclear_magnetic_dipole_moment_precision = 1.0e-4
[docs] def __init__(self, index, atom_name): """ index (integer) The 1-based index of the atom in the structure. atom_name (str) The name of the atom. The name can have a trailing '@' to indicate it's a counterpoise atom. """ self.index = index if atom_name.endswith("@"): self.counterpoise = True self.atom_name = atom_name[:-1] else: self.counterpoise = False self.atom_name = atom_name self._attributes = [ #fukui_indices doesn't need description, which is defined in FukuiIndices class #init is NECESSARY for descriptors.fill_val to propagate through to homo_nn,etc attributes _Attribute("fukui_indices", init=lambda: FukuiIndices("self.index", f"{self.atom_name}", None, None, None, None, None, None, None, None)), _Attribute("atom_name", description="Atom Name", pretty_name="Atom Name", datatype="string", init=lambda: self.atom_name), _Attribute("forces", description="Atomic Forces", pretty_name="Atom Forces", datatype="list of float", comparison=diff._LIST_PRECISION, precision="forces_precision", component_names=('Atom Force X', 'Atom Force Y', 'Atom Force Z'), init=list), _Attribute("charge_nbo", description="Atomic Charges from NBO", pretty_name="Atom Charge from NBO", datatype="float", comparison=diff._FLOAT_PRECISION, precision="charge_precision"), _Attribute("charge_esp", description="Atomic Charges from ESP", pretty_name="Atom Charge from ESP", datatype="float", comparison=diff._FLOAT_PRECISION, precision="charge_precision"), _Attribute("charge_stockholder", description="Stockholder Atomic Charges", pretty_name="Stockholder Atom Charge", datatype="float", comparison=diff._FLOAT_PRECISION, precision="charge_precision"), _Attribute("charge_lowdin", description="Lowdin Atomic Charges", pretty_name="Lowdin Atom Charge", datatype="float", comparison=diff._FLOAT_PRECISION, precision="charge_precision"), _Attribute("spin_lowdin", description="Lowdin Spin Densities", pretty_name="Lowdin Spin Density", datatype="float", comparison=diff._FLOAT_PRECISION, precision="charge_precision"), _Attribute("charge_mulliken", description="Mulliken Atomic Charges", pretty_name="Mulliken Atom Charge", datatype="float", comparison=diff._FLOAT_PRECISION, precision="charge_precision"), _Attribute("spin_mulliken", description="Mulliken Spin Densities", pretty_name="Mulliken Spin Density", datatype="float", comparison=diff._FLOAT_PRECISION, precision="charge_precision"), _Attribute("nmr_shielding", description="NMR Isotropic Shielding per Atom", pretty_name="Atom NMR Isotropic Shielding", datatype="float", comparison=diff._FLOAT_PRECISION, precision="nmr_precision"), _Attribute("nmr_abs_shift", description="NMR Atomic Absolute Shifts", pretty_name="NMR Atomic Absolute Shifts", datatype="float", comparison=diff._FLOAT_PRECISION, precision="nmr_precision"), _Attribute( "nmr_rel_shift", description="NMR Atomic Relative Shifts", pretty_name="NMR Atomic Relative Shifts for Carbon/Hydrogen", datatype="float", comparison=diff._FLOAT_PRECISION, precision="nmr_precision"), _Attribute( "nmr_h_avg_shift", description="NMR H-Averaged Relative Shifts", pretty_name="NMR Relative Shifts for Equivalent Hydrogens", datatype="float", comparison=diff._FLOAT_PRECISION, precision="nmr_precision"), _Attribute("nmr_2d_avg_shift", description="NMR 2D-Averaged Relative Shifts", pretty_name= "NMR Relative Shifts for 2D-Equivalent Carbon/Hydrogen", datatype="float", comparison=diff._FLOAT_PRECISION, precision="nmr_precision"), _Attribute("maxat_esp", description="Max Atomic ESP Values", pretty_name="Atom Max Atomic ESP Value", datatype="float", comparison=diff._FLOAT_PRECISION, precision="esp_precision"), _Attribute("minat_esp", description="Min Atomic ESP Values", pretty_name="Atom Min Atomic ESP Value", datatype="float", comparison=diff._FLOAT_PRECISION, precision="esp_precision"), _Attribute("maxat_alie", description="Max Atomic ALIE Values", pretty_name="Atom Max Atomic ALIE Value", datatype="float", comparison=diff._FLOAT_PRECISION, precision="alie_precision"), _Attribute("minat_alie", description="Min Atomic ALIE Value", pretty_name="Atom Min Atomic ALIE Value", datatype="float", comparison=diff._FLOAT_PRECISION, precision="alie_precision"), _Attribute("epn", description="Electrostatic Potential at Atomic Nuclei", pretty_name="Atom Electrostatic Potential at Nucleus", datatype="float", comparison=diff._FLOAT_PRECISION, precision="epn_precision"), _Attribute("isotope", description="Isotope of Atom", pretty_name="Atom Isotope", datatype="string"), _Attribute("nuclear_spin", description="Nuclear Spin of Atom", pretty_name="Atom Nuclear Spin", datatype="float", comparison=diff._FLOAT_PRECISION, precision="nuclear_spin_precision"), _Attribute("nuclear_magnetic_dipole_moment", description="Nuclear Magnetic Dipole Moment of Atom", pretty_name="Atom Nuclear Magnetic Dipole Moment", datatype="float", comparison=diff._FLOAT_PRECISION, precision="nuclear_magnetic_dipole_moment_precision"), ] for attr in self._attributes: self.__dict__[attr.name] = attr.init()
def __str__(self): return self.atom_name def __repr__(self): return "JaguarAtomicResults(%d, %s)" % (self.index, self.atom_name)
[docs] def diff(self, other, short_circuit=False, factor=1.0): """ Return a list of differing attributes. """ return diff._diff(self, other, short_circuit=short_circuit, factor=factor)
def __eq__(self, other): if self.diff(other, short_circuit=True): return False else: return True def __ne__(self, other): return not (self == other)
#-----------------------------------------------------------------------------
[docs]@functools.total_ordering class BondCharge(object): """ A class to store bond-midpoint charges calculated in ESP fitting. """ precision = JaguarAtomicResults.charge_precision
[docs] def __init__(self, name, charge): self.name = name self.charge = charge self.bond_midpoint_charge = self.charge #only necessary for _attributes to be able to access self._attributes = [ _Attribute( "bond_midpoint_charge", description="Bond-Midpoint Charges Calculated in ESP Fitting", pretty_name=f"{self.name} Bond-Midpoint Charge", datatype="float"), ]
def __eq__(self, other): if self.cmp(other) == 0: return True else: return False def __ne__(self, other): return not (self == other) def __lt__(self, other): if self.cmp(other) < 0: return True else: return False def __repr__(self): if self.charge is None: #for dummy initialization return f"BondCharge('{self.name}', {self.charge})" else: return f"BondCharge('{self.name}', {self.charge:.5f})"
[docs] def cmp(self, other): if self.charge is None or other.charge is None: return diff.compare_a_none(self.charge, other.charge) else: return diff.compare_float(self.charge, other.charge, self.precision)
#-----------------------------------------------------------------------------
[docs]@functools.total_ordering class Orbital(object): """ A class for storing orbital information. Attributes energy (float, Hartrees) symmetry (str) """ precision = 1.0e-4 _special_equiv = { "Pi_u_1": "Pi_u_2", "Pi_u_2": "Pi_u_1", "Pi_g_1": "Pi_g_2", "Pi_g_2": "Pi_g_1", }
[docs] def __init__(self, type_, index, energy, symmetry=None): if type_ is None: type_ = 'rhf' #make type_ more meaningful than 'None' self.type_ = type_.lower() #transform 'Alpha|Beta' to 'alpha|beta' ener_handle = 'orb_ener_' + self.type_ symm_handle = 'orb_symm_' + self.type_ setattr(self, ener_handle, energy) setattr(self, symm_handle, symmetry) self.index = index #Map *_handles to old names to allow consistent access self.energy = getattr(self, ener_handle) self.symmetry = getattr(self, symm_handle) desc_prefix = 'Placeholder Prefix' desc_suffix = 'PlaceHolder Suffix' if self.type_ == 'rhf': desc_prefix = '' desc_suffix = 'for RHF calculations' elif self.type_ == 'alpha': desc_prefix = 'Alpha ' desc_suffix = 'for UHF calculations' elif self.type_ == 'beta': desc_prefix = 'Beta ' desc_suffix = 'for UHF calculations' self._attributes = [ _Attribute( ener_handle, description=f"{desc_prefix}Orbital Energies {desc_suffix}", pretty_name=f"{type_} Orbital {self.index} Energy", datatype="float", units='Hartrees'), _Attribute( symm_handle, description=f"{desc_prefix} Orbital Energies {desc_suffix}", pretty_name=f"{type_} Orbital {self.index} Symmetry", datatype="string") ]
def __eq__(self, other): if self.cmp(other) == 0: return True else: return False def __ne__(self, other): return not (self == other) def __lt__(self, other): if self.cmp(other) < 0: return True else: return False def __str__(self): if self.symmetry: return f"{self.energy} ({self.symmetry})" #return "%s (%s)" % (self.energy, self.symmetry) else: return f"{self.energy}" #return "%s" % self.energy def __repr__(self): if self.symmetry: return f"Orbital({self.energy}, '{self.symmetry}')" #return "Orbital(%s, '%s')" % (self.energy, self.symmetry) else: return f"Orbital({self.energy})" #return "Orbital(%s)" % self.energy def __sub__(self, other): if self.symmetry != other.symmetry: return Orbital(self.energy - other.energy, str(self.symmetry) + " vs " + str(other.symmetry)) else: return Orbital(self.energy - other.energy)
[docs] def cmp(this, that): """ Compare on orbital energy and the non-reduced symmetry. """ #For init case, which is just a dummy version of Orbital if this.energy is None or that.energy is None: energy_cmp = diff.compare_a_none(this.energy, that.energy) else: energy_cmp = diff.compare_float(this.energy, that.energy, this.precision) if energy_cmp: return energy_cmp # If the orbital energy is degenerate, we have no guarantee of the # symmetry ordering. Therefore, compare only on the nonreduced # symmetry (i.e. before the slash). See salcdir/findclasses.c for # details on reducing symmetry. if this.symmetry and that.symmetry: symmetry_cmp = cmp( this.symmetry.split("/")[0], that.symmetry.split("/")[0]) if not symmetry_cmp: return symmetry_cmp elif this.symmetry == Orbital._special_equiv.get(that.symmetry): return 0 return symmetry_cmp # If only one orbital has symmetry, return non-zero. elif this.symmetry: return 1 elif that.symmetry: return -1 # Otherwise fall back to energy comparison else: return energy_cmp
#-----------------------------------------------------------------------------
[docs]class ConvCriteria(object): """ A simple storage class for storing info about the progress of convergence criteria for geometry optimizations. May add SCF convergence criterion later (but maybe that belongs in SCFIteration class) """ # Based off of geometry optimization default thresholds energy_prec = 1e-5 grad_prec = 1e-4 displacement_prec = 1e-3 thresh_prec = 0.0
[docs] def __init__(self, deltaE, deltaE_thresh, gmax, gmax_thresh, grms, grms_thresh, dmax, dmax_thresh, drms, drms_thresh): """ Initialize. """ self.deltaE = deltaE self.deltaE_thresh = deltaE_thresh self.gmax = gmax self.gmax_thresh = gmax_thresh self.grms = grms self.grms_thresh = grms_thresh self.dmax = dmax self.dmax_thresh = dmax_thresh self.drms = drms self.drms_thresh = drms_thresh # Note "comparison"/"precision" kwargs not used by jaguar_diff.py. # Filled out here only so __eq__ can be programmatically implemented self._attributes = [ _Attribute("deltaE", description="Geopt DeltaE", pretty_name="Geopt DeltaE (Hartree)", datatype="float", precision="energy_prec", units="Hartrees"), _Attribute( "deltaE_thresh", description="DeltaE Geopt Convergence Threshold", pretty_name="DeltaE Geopt Convergence Threshold (Hartree)", datatype="float", precision="thresh_prec", units="Hartrees"), _Attribute("gmax", description="Geopt Max Gradient", pretty_name="Geopt Max Gradient", precision="grad_prec", datatype="float"), _Attribute("gmax_thresh", description="Geopt Max Gradient Convergence Threshold", pretty_name="Geopt Max Gradient Convergence Threshold", precision="thresh_prec", datatype="float"), _Attribute("grms", description="Geopt Gradient RMS", pretty_name="Geopt Gradient RMS", precision="grad_prec", datatype="float"), _Attribute("grms_thresh", description="Geopt Gradient RMS Convergence Threshold", pretty_name="Geopt Gradient RMS Convergence Threshold", precision="thresh_prec", datatype="float"), _Attribute("dmax", description="Geopt Max Displacement", pretty_name="Geopt Max Displacement", precision="displacement_prec", datatype="float"), _Attribute( "dmax_thresh", description="Geopt Max Displacement Convergence Threshold", pretty_name="Geopt Max Displacement Convergence Threshold", precision="thresh_prec", datatype="float"), _Attribute("drms", description="Geopt Displacement RMS", pretty_name="Geopt Displacement RMS", precision="displacement_prec", datatype="float"), _Attribute( "drms_thresh", description="Geopt Displacement RMS Convergence Threshold", pretty_name="Geopt Displacement RMS Convergence Threshold", precision="thresh_prec", datatype="float"), ]
def __eq__(self, other): if not isinstance(other, ConvCriteria): raise TypeError( f"Comparison of ConvCriteria with {type(other)} is not supported." ) for attr in self._attributes: self_val = getattr(self, attr.name) other_val = getattr(other, attr.name) precision = getattr(ConvCriteria, attr.precision) if self_val is None or other_val is None: if diff.compare_a_none(self_val, other_val) != 0: return False else: if diff.compare_float(self_val, other_val, precision) != 0: return False return True def __ne__(self, other): return not (self == other) def __repr__(self): return f"ConvCriteria({self.deltaE}, {self.deltaE_thresh}, {self.gmax}, {self.gmax_thresh}, {self.grms}, {self.grms_thresh}, {self.dmax}, {self.dmax_thresh}, {self.drms}, {self.drms_thresh})"
#-----------------------------------------------------------------------------
[docs]class ScfIteration(object): """ A simple storage class for storing info on an SCF iteration. """ header = """ i u d i g t p i c r RMS maximum e d i u i energy density DIIS r t s t d total energy change change error """
[docs] def __init__(self, updt, diis, icut, grid, energy, energy_change, rms_density_change, max_diis_error): """ Initialize. """ self.updt = updt self.diis = diis self.icut = icut self.grid = grid self.energy = energy self.energy_change = energy_change self.rms_density_change = rms_density_change self.max_diis_error = max_diis_error #empty since we don't want any of this info...yet self._attributes = [] return
[docs] @staticmethod def fromEtotString(etot_string): """ Create an instance from a standard etot string. """ field = etot_string.split() if len(field) == 9: field.insert(7, "0.0") scfiter = ScfIteration(updt=field[2], diis=field[3], icut=int(field[4]), grid=field[5], energy=float(field[6]), energy_change=float(field[7]), rms_density_change=float(field[8]), max_diis_error=float(field[9])) return scfiter
[docs] def toString(self, iter=0): """ Render as a string, with optional iteration number. """ str_ = "etot %2d %s %s %d %s %19.11f %8.1e %8.1e %8.1e" % ( iter, self.updt, self.diis, self.icut, self.grid, self.energy, self.energy_change, self.rms_density_change, self.max_diis_error) return str_
#-----------------------------------------------------------------------------
[docs]class ZVariables(dict, object): """ A class to store Z-variables and their values, generated in scan jobs. The class is basically a dictionary with added attributes indicating the length and angle units. Attributes: length_unit (str) Either Angstrom or Bohr. (The value is equal to one of the module level constants unAngstrom or unBohr.) angle_unit (str) Either degree or radian. (The values is equal to one of the module level constants unDegree or unRadian.) """ precision = 0.01
[docs] def __init__(self, length_unit, angle_unit): self.length_unit = length_unit self.angle_unit = angle_unit dict.__init__(self) #empty placeholder for now. Fill if you want information inside to be exposed self._attributes = []
def __eq__(self, other): try: if self.length_unit != other.length_unit: return False if self.angle_unit != other.angle_unit: return False for k, v in self.items(): if k[0] == 'd': # We assume angle variables in the ZVariables object # are indicated with a 'd' prefix. This should be # true almost universally. if diff.compare_angle(v, other.get(k), ZVariables.precision): return False elif diff.compare_float(v, other.get(k), ZVariables.precision): return False return True except AttributeError: return False def __ne__(self, other): return not (self == other)
#-----------------------------------------------------------------------------
[docs]@functools.total_ordering class ThermoProp(object): """ A class to store the components of calculated thermodynamic properties. Attributes :ivar str `type_`: Descriptive string indicating which thermodynamic property (U/Cv/S/H/G/lnQ) this instance refers to :ivar float temp: The temperature at which the properties were calculated. :ivar str energy_units: Units of provided values :ivar float total: The total calculated thermodynamic property. :ivar float translational: The translational contribution to the calculated property. :ivar float rotational: The rotational contribution to the calculated property. :ivar float vibrational: The vibrational contribution to the calculated property. :ivar float electronic: The electronic contribution to the calculated property. """ precision = 1.0e-3
[docs] def __init__(self, type_, temp, press, energy_units, total, trans=None, rot=None, vib=None, elec=None): self.type_ = type_ self.temp = temp self.press = press self.energy_units = energy_units total_handle = f"{self.type_.lower().replace(' ','_')}" trans_handle = f"{self.type_.lower().replace(' ','_')}_trans" rot_handle = f"{self.type_.lower().replace(' ','_')}_rot" vib_handle = f"{self.type_.lower().replace(' ','_')}_vib" elec_handle = f"{self.type_.lower().replace(' ','_')}_elec" setattr(self, total_handle, total) setattr(self, trans_handle, trans) setattr(self, rot_handle, rot) setattr(self, vib_handle, vib) setattr(self, elec_handle, elec) #Map *_handles to old names to allow access from older scripts, if any self.total = getattr(self, total_handle) self.translational = getattr(self, trans_handle) self.rotational = getattr(self, rot_handle) self.vibrational = getattr(self, vib_handle) self.electronic = getattr(self, elec_handle) self._attributes = [ _Attribute(total_handle, description=f"Total Calculated {type_}", pretty_name=f"{self.type_} {self.temp}K {self.press}atm", units=self.energy_units, datatype="float"), _Attribute( trans_handle, description=f"Translational Contribution to {type_}", pretty_name= f"Translational {self.type_} {self.temp}K {self.press}atm", units=self.energy_units, datatype="float"), _Attribute(rot_handle, description=f"Rotational Contribution to {type_}", pretty_name= f"Rotational {self.type_} {self.temp}K {self.press}atm", units=self.energy_units, datatype="float"), _Attribute(vib_handle, description=f"Vibrational Contribution to {type_}", pretty_name= f"Vibrational {self.type_} {self.temp}K {self.press}atm", units=self.energy_units, datatype="float"), _Attribute(elec_handle, description=f"Electronic Contribution to {type_}", pretty_name= f"Electronic {self.type_} {self.temp}K {self.press}atm", units=self.energy_units, datatype="float") ]
def __eq__(self, other): if self.cmp(other) == 0: return True else: return False def __ne__(self, other): return not (self == other) def __lt__(self, other): if self.cmp(other) < 0: return True else: return False
[docs] def cmp(self, other): if self.total is None or other.total is None: return diff.compare_a_none(self.total, other.total) else: return diff.compare_float(self.total, other.total, self.precision)
def __str__(self): if self.translational is not None: return f"{self.total} (tr={self.translational}, rot={self.rotational}, vib={self.vibrational}, e={self.electronic})" else: return f"{self.total}" def __sub__(self, other): if self.translational is not None: return ThermoProp(self.total - other.total, self.translational - other.translational, self.rotational - other.rotational, self.vibrational - other.vibrational, self.electronic - other.electronic) else: return ThermoProp(self.total - other.total)
#-----------------------------------------------------------------------------
[docs]class ThermoCollection(object): """ A class to store a full set of calculated thermodynamic properties at a given temperature. Attributes: temp (float) The temperature at which the properties were calculated. press (float) The pressure at which the properties were calculated. (in atm units) units (str) Units that the energy values are in (if not in Hartrees) total (list of floats) The total calculated thermodynamic properties for, in order, U/Cv/S/H/G trans (list of floats) The translational contribution for, in order, U/Cv/S/H/G rot (list of floats) The rotational contribution for, in order, U/Cv/S/H/G vib (list of floats) The vibrational contribution for, in order, U/Cv/S/H/G elec (list of floats) The electronic contribution for, in order, U/Cv/S/H/G UTotal (float, Hartrees) Total internal energy (SCFE + ZPE + U) HTotal (float, Hartrees) Total enthalpy (UTotal + pV) GTotal (float, Hartrees) Total Gibbs free energy (HTotal - T*S) """ precision = 1.0e-6
[docs] def __init__(self, temp, press, units, total, trans, rot, vib, elec, UTotal, HTotal, GTotal): self.temp = temp self.press = press self.units = units self.UTotal = UTotal self.HTotal = HTotal self.GTotal = GTotal #set units energy_unit = None k_energy_unit = None if units == 'joules': energy_unit = 'J/(mol K)' k_energy_unit = 'kJ/mol' elif units == 'calories': energy_unit = 'cal/(mol K)' k_energy_unit = 'kcal/mol' #create ThermoProp's self.U = ThermoProp('Internal Energy', temp, press, k_energy_unit, total[0], trans[0], rot[0], vib[0], elec[0]) self.Cv = ThermoProp('Heat Capacity', temp, press, energy_unit, total[1], trans[1], rot[1], vib[1], elec[1]) self.S = ThermoProp('Entropy', temp, press, energy_unit, total[2], trans[2], rot[2], vib[2], elec[2]) self.H = ThermoProp('Enthalpy', temp, press, k_energy_unit, total[3], trans[3], rot[3], vib[3], elec[3]) self.G = ThermoProp('Gibbs Free Energy', temp, press, k_energy_unit, total[4], trans[4], rot[4], vib[4], elec[4]) self.lnQ = ThermoProp('lnQ', temp, press, None, total[5], trans[5], rot[5], vib[5], elec[5]) self._attributes = [ #U,Cv,S,H,G,lnQ don't need description's since those will #be defined in ThermoProp class _Attribute("U"), _Attribute("Cv"), _Attribute("S"), _Attribute("H"), _Attribute("G"), _Attribute("lnQ"), _Attribute("UTotal", description="Total Internal Energy (SCFE + ZPE + U)", pretty_name= f"Total Internal Energy {self.temp}K {self.press}atm", datatype="float", units="Hartrees"), _Attribute( "HTotal", description="Total Enthalpy (UTotal + pV)", pretty_name=f"Total Enthalpy {self.temp}K {self.press}atm", datatype="float", units="Hartrees"), _Attribute("GTotal", description="Total Gibbs Free Energy (HTotal - T*S)", pretty_name= f"Total Gibbs Free Energy {self.temp}K {self.press}atm", datatype="float", units="Hartrees") ]
def __eq__(self, other): try: for attr in ("U", "Cv", "S", "H", "G"): if getattr(self, attr) != getattr(other, attr): return False for attr in ("UTotal", "HTotal", "GTotal"): self_val = getattr(self, attr) other_val = getattr(other, attr) if self_val is None or other_val is None: if diff.compare_a_none(self_val, other_val) != 0: return False else: if diff.compare_float(self_val, other_val, self.precision) != 0: return False return True except AttributeError: return False def __ne__(self, other): return not (self == other) def __str__(self): return f"{self.temp}K {self.press}atm U={self.U.total} Cv={self.Cv.total} S={self.S.total}, H={self.H.total}, G={self.G.total} UTotal={self.UTotal} HTotal={self.HTotal} GTotal={self.GTotal}" def __sub__(self, other): if (self.temp != other.temp) or (self.press != other.press) or ( self.units != other.units): return None return ThermoCollection(self.temp, self.press, self.units, self.U - other.U, self.Cv - other.Cv, self.S - other.S, self.H - other.H, self.G - other.G, self.UTotal - other.UTotal, self.HTotal - other.HTotal, self.GTotal - other.GTotal)
#-----------------------------------------------------------------------------
[docs]class NormalMode(object): # When defining a docstring as anything other than a bare string, it's # necessary to explicitly assign it to __doc__. __doc__ = """ A class for storing normal mode results. Attributes frequency (float, %s) symmetry (str) The symmetry type (Mulliken symbol) of the normal mode; None if symmetry is not present or used. ir_intensity (float, %s) The IR intensity; set to None if not calculated. raman_activity (float, %s) The Raman activity; set to None if not calculated. raman_intensity (float, %s) The Raman intensity; set to None if not calculated. reduced_mass (float, %s) force_constant (float, %s) dipole_strength (float, %s) The dipole strength; set to None if not calculated. rotational_strength (float, %s) The rotational strength; set to None if not calculated. displacement (float array) The atomic displacements, as an array with x, y, z columns for each atom row. """ % (constants.unInverseCentimeter, constants.unKilometersPerMol, constants.unAngstrom4, constants.unAngstrom4, constants.unAtomicMassUnit, constants.unMDynePerAngstrom, constants.unDipoleStrength, constants.unRotationalStrength) frequency_precision = 1.0e-1 ir_intensity_precision = 1.0e-1 raman_activity_precision = 1.0e-1 raman_intensity_precision = 1.0e-1 reduced_mass_precision = 1.0e-1 force_constant_precision = 1.0e-1 dipole_strength_precision = 1.0e-1 rotational_strength_precision = 1.0e-1
[docs] def __init__(self, frequency, t_atoms, index): """ Arguments frequency (float) The frequency of the normal mode. t_atoms (int) The number of atoms in the molecule. """ self.index = index self.frequency = frequency self.symmetry = None self.ir_intensity = None self.reduced_mass = None self.force_constant = None self.dipole_strength = None self.rotational_strength = None self.displacement = np.array([[0, 0, 0]] * t_atoms, np.float_) self.raman_activity = None self.raman_intensity = None self._attributes = [ _Attribute("frequency", description="Frequencies of Normal Modes", pretty_name=f"Mode {self.index} Frequency", precision=self.frequency_precision, datatype="float", units="cm-1"), _Attribute("symmetry", description="Symmetries of Normal Modes", datatype="string", pretty_name=f"Mode {self.index} Symmetry"), _Attribute("ir_intensity", datatype="float", description="IR Intensities of Normal Modes", pretty_name=f"Mode {self.index} IR Intensity", precision=self.ir_intensity_precision), _Attribute("reduced_mass", datatype="float", description="Reduced Masses of Normal Modes", pretty_name=f"Mode {self.index} Reduced Mass", precision=self.reduced_mass_precision), _Attribute("force_constant", datatype="float", description="Force Constants of Normal Modes", pretty_name=f"Mode {self.index} Force Constant", precision=self.force_constant_precision), _Attribute("dipole_strength", datatype="float", pretty_name=f"Mode {self.index} Dipole Strength", description="Dipole Strengths of Normal Modes", precision=self.dipole_strength_precision), _Attribute("rotational_strength", datatype="float", description="Rotational Strengths of Normal Modes", pretty_name=f"Mode {self.index} Rotational Strength", precision=self.rotational_strength_precision), _Attribute("raman_activity", datatype="float", description="Raman Activities of Normal Modes", pretty_name=f"Mode {self.index} Raman Activity", precision=self.raman_activity_precision), _Attribute("raman_intensity", datatype="float", pretty_name=f"Mode {self.index} Raman Intensity", description="Raman Intensities of Normal Modes", precision=self.raman_intensity_precision), ]
def __eq__(self, other): """ Check normal mode properties for equality. """ try: for attr in self._attributes: self_val = getattr(self, attr.name) other_val = getattr(other, attr.name) if self_val is None or other_val is None: if diff.compare_a_none(self_val, other_val) != 0: return False else: if attr.datatype == 'float': if diff.compare_float(self_val, other_val, attr.precision) != 0: return False elif attr.datatype == 'string': if self_val != other_val: return False return True except AttributeError: return False def __ne__(self, other): return not (self == other) def __str__(self): s = f"{self.frequency} {constants.unInverseCentimeter}" if self.symmetry: s += f" ({self.symmetry})" if self.reduced_mass: s += f" {self.reduced_mass:.2f} ({constants.unAtomicMassUnit})" if self.force_constant: s += f" {self.force_constant:.2f} ({constants.unMDynePerAngstrom})" if self.ir_intensity: s += f" {self.ir_intensity:.2f} ({constants.unKilometersPerMol})" if self.dipole_strength: s += f" {self.dipole_strength:.2f} ({constants.unDipoleStrength})" if self.rotational_strength: s += f" {self.rotational_strength:.2f} ({constants.unRotationalStrength})" if self.raman_intensity: s += f" {self.raman_intensity:.2f} ({constants.unAngstrom4})" if self.raman_activity: s += f" {self.raman_activity:.2f} ({constants.unAngstrom4})" return s def __sub__(self, other): """ Return the difference between two NormalMode objects. This is really only useful for printing the resulting NormalMode object to easily see the difference between them. """ nm = NormalMode(self.frequency - other.frequency, self.displacement.shape[0]) nm.reduced_mass = self.reduced_mass - other.reduced_mass nm.force_constant = self.force_constant - other.force_constant nm.symmetry = "%s/%s" % (self.symmetry, other.symmetry) if (self.ir_intensity is not None and other.ir_intensity is not None): nm.ir_intensity = (self.ir_intensity - other.ir_intensity) if (self.raman_activity is not None and other.raman_activity is not None): nm.raman_activity = (self.raman_activity - other.raman_activity) if (self.raman_intensity is not None and other.raman_intensity is not None): nm.raman_intensity = (self.raman_intensity - other.raman_intensity) if (self.dipole_strength is not None and other.dipole_strength is not None): nm.dipole_strength = (self.dipole_strength - other.dipole_strength) if (self.rotational_strength is not None and other.rotational_strength is not None): nm.rotational_strength = (self.rotational_strength - other.rotational_strength) return nm
#-----------------------------------------------------------------------------
[docs]class JaguarOptions(object): """ A class for keeping track of specific calculation options. Attributes ip (list of int) The values of all ip flags, indexed from 1 pseudospectral (bool) True if the user did not enter `nops=1` in their input. This attribute tracks the users settings for the overall job, in contrast to `JaguarResults.nops_on` which reports whether nops was used for various stages of the calculation (e.g. each step of a geometry optimization) solvation (bool) whether the calculation used solvation analytic_gradients (bool) True if analytic gradients, False if calculated by finite difference. Is only meaningful when gradients are actually being calculated (i.e. when 'forces' of JaguarResults object is defined). analytic_frequencies (bool) True if analytic second derivatives are used, False if calculated by finite difference. Is only meaningful when frequencies are being calculated (i.e. when the JaguarResults normal_mode list attribute is non-empty). esp_fit (int) If no electrostatic potential fit is being done, this will be set to JaguarOutputs.ESP_NONE. If ESP atom centered fitting is being done, it will be set to JaguarOutputs.ESP_ATOMS. If ESP fitting is being done with atom centers and bond midpoints, esp_fit will be set to JaguarOptions.ESP_ATOMS_AND_BOND_MIDPOINTS. """ ip_default = 1 ESP_NONE = 0 ESP_ATOMS = 1 ESP_ATOMS_AND_BOND_MIDPOINTS = 2
[docs] def __init__(self): self.ip = 500 * [JaguarOptions.ip_default] # Insert dummy value at 0 to allow 1 based indexing. self.ip.insert(0, None) self.pseudospectral = True # Added to provide a simple means of checking for solvation # calculations; necessary for modifying end_geometry() behavior, # among other things. self.solvation = False self.analytic_gradients = True self.analytic_frequencies = True self.esp_fit = self.ESP_NONE #empty placeholder for now. Fill if you want information inside to be exposed self._attributes = []
def __str__(self): attrs = set([k for k in list(self.__dict__) if not k.startswith("_")]) lines = [] attrs.remove("ip") for ix in range(1, len(self.ip)): if self.ip[ix] != JaguarOptions.ip_default: lines.append("ip%d = %d" % (ix, self.ip[ix])) ref = JaguarOptions() attrs = list(attrs) attrs.sort() for attr in attrs: if getattr(self, attr, None) != getattr(ref, attr, None): lines.append("%s = %s" % (attr, getattr(self, attr, None))) return "\n".join(lines)
#-----------------------------------------------------------------------------
[docs]class DerivedAttrs(object): """ A class for building and holding properties derived from other _Attributes in JaguarResults. Designed only with single primitive valued _Attribute's in mind (no lists). By its nature this class will be pretty manual, since every derived property will have its own logic. Class method buildDerivedAttrs called by JaguarOutput parent at end of init (after textparsing) energy_aposteri0 (float, Hartrees) Uncorrected energy in the case of a posteri-corrected calculations (energy-energy_aposteri) homo_lumo_gap (float, Hartrees) HOMO-LUMO Gap energy. Calculated as lower of same-spin orbital differences in unrestricted calcs lambdamax_ev (float, eV) Excitation energy (ev) of state with highest oscillator strength lambdamax_nm (float, nm) Excitation energy (nm) of state with highest oscillator strength """ #precision must be placed here based on how jaguar_diff._diff works. energy_precision_hartree = 1e-6 #same as JaguarResults.energy_precision exc_energy_precision_ev = 6e-4 #same as JaguarResults.exc_energy exc_energy_precision_nm = 20 #this is arbitrarily large since nm has reciprocal relation with eV. Any sigificant diffs should be caught by exc_energy_precision_ev orbe_precision = Orbital.precision osc_precision = 1e-3 #same as in JaguarResults.osc_precision
[docs] def __init__(self): """ Create the _attributes list and define precisions so that _diff can be used. """ self._attributes = [ _Attribute( "energy_aposteri0", description= 'Uncorrected energy in the case of a posteri-corrected calculations (energy-energy_aposteri)', pretty_name='Uncorrected a posteriori energy', datatype='float', units='Hartree', comparison=diff._FLOAT_PRECISION, precision='energy_precision_hartree'), _Attribute( "homo_lumo_gap", description= 'HOMO-LUMO Gap energy. Calculated as lower of same-spin orbital differences in unrestricted calcs', pretty_name='HOMO-LUMO Gap', datatype='float', units='Hartree', comparison=diff._FLOAT_PRECISION, precision='orbe_precision'), _Attribute( "lambdamax_ev", description= 'Excitation energy (eV) of state with highest oscillator strength', pretty_name='Lambda Max eV', datatype='float', units='eV', comparison=diff._FLOAT_PRECISION, precision='exc_energy_precision_ev'), _Attribute( "lambdamax_nm", description= 'Excitation energy (nm) of state with highest oscillator strength', pretty_name='Lambda Max nm', datatype='float', units='nm', comparison=diff._FLOAT_PRECISION, precision='exc_energy_precision_nm') ] for attr in self._attributes: if attr.name in self.__dict__: raise RuntimeError('Attribute is redefined!') self.__dict__[attr.name] = attr.init()
[docs] def buildDerivedAttrs(self, jresults, joutput): """ Fill in the values of self._attributes if ingredients exist jresults is parent JaguarResults, use to obtain ingredients joutput is parent JaguarOutput, use to obtain job options needed for logic (ie - homo_lumo_gap) """ # These attributes are not directly available from the output file, # but can be simply computed from output quantities if jresults.energy_aposteri is not None: if jresults.energy is not None: self.energy_aposteri0 = jresults.energy - jresults.energy_aposteri if jresults.homo is not None: if jresults.lumo is not None: self.homo_lumo_gap = jresults.lumo - jresults.homo #account for UHF calcs elif jresults.homo_alpha is not None: if jresults.lumo_alpha is not None: #assume beta's also exist at this point alpha_gap = jresults.lumo_alpha - jresults.homo_alpha beta_gap = jresults.lumo_beta - jresults.homo_beta if alpha_gap > beta_gap: gap = beta_gap else: gap = alpha_gap self.homo_lumo_gap = gap if len(jresults.excitation_energies) > 0: high_osc = 0.000 high_osc_indx = 0 for indx, osc in enumerate(jresults.oscillator_strengths): #only compare to third decimal, replace if osc higher than high_osc if osc - high_osc > self.osc_precision: high_osc = osc high_osc_indx = indx self.lambdamax_ev = jresults.excitation_energies[high_osc_indx] self.lambdamax_nm = units.NM_X_EV * (1.0 / self.lambdamax_ev) # This makes gas_phase_energy extraction backwards compatible. # It reverts to the old (2015-3) behavior for output files made before # 2015-4 if jresults.gas_phase_energy is None: jresults.gas_phase_energy = jresults.energy
[docs] def diff(self, other, short_circuit=False, factor=1.0): """ Return a list of differing attributes. """ return diff._diff(self, other, short_circuit=short_circuit, factor=factor)
def __eq__(self, other): if self.diff(other): return False else: return True def __ne__(self, other): return not (self == other)
#-----------------------------------------------------------------------------
[docs]class JaguarResults(object): """ A class for holding results for a specific geometry. Attributes scf_energy (float, Hartrees) SCF energy external_program_energy (float, Hartrees) Energy produced by an external program nn_gas_energy (float, Hartrees) Neural network potential energy nn_sol_energy (float, Hartrees) Neural network potential energy nn_energy (float, Hartrees) Neural network potential energy nn_stddev (float, Hartrees) Neural network potential energy std deviation across models rimp2_ss_energy (float, Hartrees) RI-MP2 same-spin energy rimp2_os_energy (float, Hartrees) RI-MP2 opposite-spin energy rimp2_corr_energy (float, Hartrees) RI-MP2 correlation energy rimp2_energy (float, Hartrees) RI-MP2 energy gas_phase_energy (float, Hartrees) Gas phase total energy conv_crit (ConvCriteria) Details on convergence criterion for a geopt step scf_iter (list of ScfIterations) Details on the scf iterations lmp2_energy (float, Hartrees) LMP2 energy solvation_energy (float, Hartrees) Solvation energy solution_phase_energy (float, Hartrees) Solution phase energy energy_one_electron (float, Hartrees) Total one-electron energy (component (E) in SCF summary) energy_two_electron (float, Hartrees) Total two-electron energy (component (I) in SCF summary) energy_electronic (float, Hartrees) Total electronic energy (component (L) in SCF summary) energy_aposteri (float, Hartrees) a posteriori correction to the total energy (component (N0) in SCF summary) energy_aposteri0 (float, Hartrees) Uncorrected energy in the case of a posteri-corrected calculations (derived quantity not in output file) nuclear_repulsion (float, Hartrees) Nuclear repulsion energy homo (float, Hartrees) HOMO energy (set to None for open shell calcs) homo_alpha (float, Hartrees) Alpha HOMO energy (set to None for closed shell calcs) homo_beta (float, Hartrees) Beta HOMO energy (set to None for closed shell calcs) lumo (float, Hartrees) LUMO energy (set to None for open shell calcs) lumo_alpha (float, Hartrees) Alpha LUMO energy (set to None for closed shell calcs) lumo_beta (float, Hartrees) Beta LUMO energy (set to None for closed shell calcs) zero_point_energy (float, kcal/mol) Zero point from a frequency calculation canonical_orbitals (int) Number of canonical orbitals for a given job doubted_geom (bool) Indicates that the Jaguar output contained an indication that this was a bad step geopt_step_num (int) Nominal geometry optimization step according to Jaguar, which is not necessarily monontonic because Jaguar sometimes restarts optimzations nops_on (bool) True if this stage of the calculation is not using pseudospectral methods. sm_point (integer) Number of point along string method string. sm_iter (integer) Iteration number of string method. S_min_eval (float) Minimum eigenvalue of S (overlap matrix) orbital (list of Orbitals) Orbitals (defined for closed shell only) orbital_alpha (list of Orbitals) Alpha orbitals (defined for open shell only) orbital_beta (list of Orbitals) Beta orbitals (defined for open shell only) zvar (ZVariables) A mapping of scan variable names to values; ZVariables is a dict subclass. thermo (list of ThermoCollection) A list of ThermoCollection objects, each representing thermochemical properties at a given temperature reaction_coord (float) transition_state_components (list of floats) vetted_ts_vector_index (integer) Index eigenvector of TS geometry that has been vetted with vet_ts != 0 vetted_ts_vector (NormalMode instance) NormalMode instance representing eigenvector of TS geometry that has been vetted with vet_ts != 0 dipole_qm (Dipole) Dipole calculated from the wavefunction dipole_esp (Dipole) Dipole calculated from the electrostatic potential charges dipole_mulliken (Dipole) Dipole calculated from the Mulliken charges charge_bond_midpoint (list of BondCharge) ESP charges for bond midpoints atom (list of JaguarAtomicResults) Atom based properties for this JaguarResults object normal_mode (list of NormalMode objects) Normal mode information spin_spin_couplings (list of SpinSpinCoupling objects) Spin-spin coupling information scan_value (dict of floats) A dictionary with zvar keys and float values indicating the scan coordinate values for this geometry fdpolar_alpha1 (float) Frequency-dependent polarizability, first frequency fdpolar_freq1 (float) Frequency used for fdpolar_alpha1 fdpolar_alpha2 (float) Frequency-dependent polarizability, second frequency fdpolar_freq2 (float) Frequency used for fdpolar_alpha2 fdpolar_beta (float) frequency-dependent first-order hyperpolarizability, reported as mean of beta-tensor orientations fdpolar_freq3 (float) third frequency used for frequency-dependent hyperpolarizability calcs polar_alpha (float) Polarizability polar_beta (float) First-order hyperpolarizability polar_gamma (float) Second-order hyperpolarizability et_S_if (float) Overlap of initial and final state wfns in electron transfer et_H_ii (float) Hamiltonian of initial state in electron transfer et_H_if (float) Hamiltonian of initial->final state in electron transfer et_T_if (float) Electron transfer transition energy min_esp (float) Minimum ESP value on isodensity surface max_esp (float) Maximum ESP value on isodensity surface mean_esp (float) Mean ESP value on isodensity surface mean_pos_esp (float) Mean positive ESP value on isodensity surface mean_neg_esp (float) Mean negative ESP value on isodensity surface sig_pos_esp (float) Variance of positive ESP values on isodensity surface sig_neg_esp (float) Variance of negative ESP values on isodensity surface sig_tot_esp (float) Total ESP variance on isodensity surface balance_esp (float) ESP balance on isodensity surface local_pol_esp (float) Local polarity on isodensity surface min_alie (float) Minimum ALIE value on isodensity surface max_alie (float) Maximum ALIE value on isodensity surface mean_alie (float) Mean ALIE value on isodensity surface mean_pos_alie (float) Mean positive ALIE value on isodensity surface mean_neg_alie (float) Mean negative ALIE value on isodensity surface sig_pos_alie (float) Variance of positive ALIE values on isodensity surface sig_neg_alie (float) Variance of negative ALIE values on isodensity surface sig_tot_alie (float) Total ALIE variance on isodensity surface balance_alie (float) ALIE balance on isodensity surface local_pol_alie (float) Average deviation from mean ALIE on isodensity surface excitation_energies (list of floats) Electronic excitation energies singlet_excitation_energies (list of floats) Restricted singlet electronic excitation energies triplet_excitation_energies (list of floats) Restricted triplet electronic excitation energies oscillator_strengths (list of floats) Excitation energy oscillator strengths singlet_oscillator_strengths (list of floats) Singlet excitation energy oscillator strengths triplet_oscillator_strengths (list of floats) Triplet excitation energy oscillator strengths opt_excited_state_energy_1 (float) Energy of first excited state geometry optimization total_lo_correction (float, kcal/mol) Total localized orbital energy correction spin_splitting_score (float) Ligand field spin-splitting score for DBLOC calculations s2 (float) Spin: <S**2> sz2 (float) Spin: Sz*<Sz+1> derived_attrs (DerivedAttrs object) Container for simple attributes derived from ones explicitly found in output file """ _attributes = [ _Attribute("scf_energy", description='SCF Energy', datatype='float', units='Hartree', comparison=diff._FLOAT_PRECISION, precision="energy_precision"), _Attribute("external_program_energy", description='Energy produced by external program', pretty_name='External Program Energy', datatype='float', units='Hartree', comparison=diff._FLOAT_PRECISION, precision="energy_precision"), _Attribute("nn_gas_energy", description='neural network gas-phase energy', pretty_name='NN gas-phase energy', datatype='float', units='Hartree', comparison=diff._FLOAT_PRECISION, precision="energy_precision"), _Attribute("nn_sol_energy", description='neural network solution-phase energy', pretty_name='NN solution-phase energy', datatype='float', units='Hartree', comparison=diff._FLOAT_PRECISION, precision="energy_precision"), _Attribute("nn_energy", description='neural network potential energy', pretty_name='NN energy', datatype='float', units='Hartree', comparison=diff._FLOAT_PRECISION, precision="energy_precision"), _Attribute("nn_stddev", description= 'standard deviation in prediction of neural network energy', pretty_name='NN standard deviation', datatype='float', units='Hartree', comparison=diff._FLOAT_PRECISION, precision="energy_precision"), _Attribute("rimp2_ss_energy", description='RI-MP2 Same-Spin Energy', pretty_name='RI-MP2 Same-Spin Energy', datatype='float', units='Hartree', comparison=diff._FLOAT_PRECISION, precision="energy_precision"), _Attribute("rimp2_os_energy", description='RI-MP2 Opposite-Spin Energy', pretty_name='RI-MP2 Opposite-Spin Energy', datatype='float', units='Hartree', comparison=diff._FLOAT_PRECISION, precision="energy_precision"), _Attribute("rimp2_corr_energy", description='RI-MP2 Correlation Energy', pretty_name='RI-MP2 Correlation Energy', datatype='float', units='Hartree', comparison=diff._FLOAT_PRECISION, precision="energy_precision"), _Attribute("rimp2_energy", description='RI-MP2 Energy', pretty_name='RI-MP2 Energy', datatype='float', units='Hartree', comparison=diff._FLOAT_PRECISION, precision="energy_precision"), _Attribute("gas_phase_energy", description='Gas Phase Energy', datatype='float', units='Hartree', comparison=diff._FLOAT_PRECISION, precision="energy_precision"), _Attribute("conv_crit", description='Geometry Optimization Convergence Criterion', init=lambda: ConvCriteria(None, None, None, None, None, None, None, None, None, None)), _Attribute("lmp2_energy", description='LMP2 Energy', datatype='float', units='Hartree', comparison=diff._FLOAT_PRECISION, precision="energy_precision"), _Attribute("solvation_energy", description='Solvation Energy', datatype='float', units='Hartree', comparison=diff._FLOAT_PRECISION, precision="energy_precision"), _Attribute("solution_phase_energy", description='Solution Phase Energy', datatype='float', units='Hartree', comparison=diff._FLOAT_PRECISION, precision="energy_precision"), _Attribute("energy_one_electron", description= 'Total one-electron energy (component (E) in SCF summary)', pretty_name='One Electron Energy', datatype='float', units='Hartree', comparison=diff._FLOAT_PRECISION, precision="energy_precision"), _Attribute("energy_two_electron", description= 'Total two-electron energy (component (I) in SCF summary)', pretty_name='Two-electron Energy', datatype='float', units='Hartree', comparison=diff._FLOAT_PRECISION, precision="energy_precision"), _Attribute( "energy_electronic", description='Total electronic energy (component (L) in SCF summary)', pretty_name='Total Electronic Energy', datatype='float', units='Hartree', comparison=diff._FLOAT_PRECISION, precision="energy_precision"), _Attribute( "energy_aposteri", description= 'a posteriori correction to the total energy (component (N0) in SCF summary)', pretty_name='A Posteriori Energy Correction', datatype='float', units='Hartree', comparison=diff._FLOAT_PRECISION, precision="energy_precision"), _Attribute("nuclear_repulsion", description='Nuclear Repulsion Energy', datatype='float', units='Hartree', comparison=diff._FLOAT_PRECISION, precision="nucrep_precision"), _Attribute("homo", description='HOMO energy (set to None for open-shell calcs)', pretty_name='HOMO Energy', datatype='float', units='Hartree', comparison=diff._FLOAT_PRECISION, precision="_orbe_precision"), _Attribute( "homo_alpha", description='Alpha HOMO energy (set to None for closed-shell calcs)', pretty_name='Alpha HOMO Energy', datatype='float', units='Hartree', comparison=diff._FLOAT_PRECISION, precision="_orbe_precision"), _Attribute( "homo_beta", description='Beta HOMO energy (set to None for closed-shell calcs)', pretty_name='Beta HOMO Energy', datatype='float', units='Hartree', comparison=diff._FLOAT_PRECISION, precision="_orbe_precision"), _Attribute("lumo", description='LUMO energy (set to None for open-shell calcs)', pretty_name='LUMO Energy', datatype='float', units='Hartree', comparison=diff._FLOAT_PRECISION, precision="_orbe_precision"), _Attribute( "lumo_alpha", description='Alpha LUMO energy (set to None for closed-shell calcs)', pretty_name='Alpha LUMO Energy', datatype='float', units='Hartree', comparison=diff._FLOAT_PRECISION, precision="_orbe_precision"), _Attribute( "lumo_beta", description='Beta LUMO energy (set to None for closed-shell calcs)', pretty_name='Beta LUMO Energy', datatype='float', units='Hartree', comparison=diff._FLOAT_PRECISION, precision="_orbe_precision"), _Attribute("zero_point_energy", description='Zero Point Energy', datatype='float', units='Hartree', comparison=diff._FLOAT_PRECISION, precision="zpe_precision"), _Attribute("canonical_orbitals", description="Number of canonical orbitals", pretty_name='Number of canonical orbitals', datatype="int"), _Attribute( "doubted_geom", description="Indicates a geometry step was not expected to be good", pretty_name='Unreliable geometry', datatype="bool", init=lambda: False), _Attribute( "geopt_step_num", description= "Geometry optimization step number according to Jaguar (not necessarily monotonic since Jaguar sometimes restarts)", pretty_name='Geometry step number', datatype="int"), _Attribute("nops_on", description="Indicates a NOPS calculation", pretty_name='NOPS on', datatype="bool", init=lambda: False), _Attribute("sm_point", description="Num of points along string method string", pretty_name='Num String Method Points', datatype="int"), _Attribute("sm_iter", description="Iteration number of string method", pretty_name='String Method Iter', datatype="int"), _Attribute("reaction_coord", description="Reaction coordinate Number", pretty_name='Rxn Coord Num', datatype="float", comparison=diff._FLOAT_PRECISION, precision="rxn_coord_precision"), _Attribute("S_min_eval", description="Minimum value of S (overlap matrix)", pretty_name='Min Elem Overlap Matrix', datatype="float"), _Attribute( "orbital", #attrs defined in Orbital init=lambda: Orbital('RHF', 999, None)), _Attribute( "orbital_alpha", #attrs defined in Orbital init=lambda: Orbital('Alpha', 998, None)), _Attribute( "orbital_beta", #attrs defined in Orbital init=lambda: Orbital('Beta', 997, None)), _Attribute("zvar", description='a mapping of scan variable names to values'), _Attribute( "thermo", #attrs defined in ThermoCollection/Prop init=lambda: ThermoCollection("Fake_Temp", "Fake_Press", None, [ None, None, None, None, None, None ], [None, None, None, None, None, None], [ None, None, None, None, None, None ], [None, None, None, None, None, None ], [None, None, None, None, None, None], None, None, None)), _Attribute( "dipole_qm", #attrs defined in Dipole init=lambda: Dipole('qm')), _Attribute( "dipole_esp", #attrs defined in Dipole init=lambda: Dipole('esp')), _Attribute( "dipole_mulliken", #attrs defined in Dipole init=lambda: Dipole('mulliken')), _Attribute( "normal_mode", #attrs defined in NormalMode init=lambda: NormalMode(None, 0, None)), _Attribute( "spin_spin_couplings", #attrs defined in SpinSpinCoupling init=lambda: []), _Attribute( "charge_bond_midpoint", #attrs defined in BondCharge init=lambda: BondCharge('N/A', None)), _Attribute("transition_state_components", description='Transition State Components', comparison=diff._LIST_PRECISION, precision="ts_component_precision"), _Attribute( "vetted_ts_vector_index", description= 'index eigenvector of TS geometry that has been vetted with vet_ts != 0 - NOT CURRENTLY SUPPORTED' ), _Attribute( "vetted_ts_vector", description= 'NormalMode instance representing eigenvector of TS geometry that has been vetted with vet_ts != 0 - NOT CURRENTLY SUPPORTED' ), _Attribute("fdpolar_alpha1", description="Frequency-Dependent Polarizability 1", datatype="float", comparison=diff._FLOAT_PRECISION, precision="alpha_polar_precision"), _Attribute("fdpolar_freq1", description="Frequency of 'Freq-Dependent Polarizability 1'", datatype="float", comparison=diff._FLOAT_PRECISION, precision="alpha_polar_precision", units="eV"), _Attribute("fdpolar_alpha2", description="Frequency-Dependent Polarizability 2", datatype="float", comparison=diff._FLOAT_PRECISION, precision="alpha_polar_precision"), _Attribute("fdpolar_freq2", description="Frequency of 'Freq-Dependent Polarizability 2'", datatype="float", comparison=diff._FLOAT_PRECISION, precision="alpha_polar_precision", units="eV"), _Attribute( "fdpolar_beta", description="Frequency-Dependent First-Order Hyperpolarizability", datatype="float", comparison=diff._FLOAT_PRECISION, precision="beta_polar_precision"), _Attribute( "fdpolar_freq3", description= "Frequency used to calculate 'Frequency-Dependent First-Order Hyperpolarizability'", datatype="float", comparison=diff._FLOAT_PRECISION, precision="alpha_polar_precision", units="eV"), _Attribute("polar_alpha", description="Polarizability", datatype="float", comparison=diff._FLOAT_PRECISION, precision="alpha_polar_precision"), _Attribute("polar_beta", description="First-Order Hyperpolarizability", datatype="float", comparison=diff._FLOAT_PRECISION, precision="beta_polar_precision"), _Attribute("polar_gamma", description="Second-Order Hyperpolarizability", datatype="float", comparison=diff._FLOAT_PRECISION, precision="gamma_polar_precision"), _Attribute( "et_S_if", description="Overlap of initial and final state wfns in e- transfer", pretty_name='et_S_if', datatype="float", ), _Attribute( "et_H_ii", description="Hamiltonian of initial state in e- transfer", pretty_name='et_H_ii', datatype="float", ), _Attribute( "et_H_if", description="Hamiltonian of initial to final state in e- transfer", pretty_name='et_H_if', datatype="float", ), _Attribute( "et_T_if", description="e- transfer transition energy", pretty_name='et_T_if', datatype="float", ), _Attribute("min_esp", description="Minimum ESP value on isodensity surface", pretty_name='Min ESP Val', datatype="float", comparison=diff._FLOAT_PRECISION, precision="esp_analysis_precision"), _Attribute("max_esp", description="Maximum ESP value on isodensity surface", pretty_name='Max ESP Val', datatype="float", comparison=diff._FLOAT_PRECISION, precision="esp_analysis_precision"), _Attribute("mean_esp", description="Mean ESP value on isodensity surface", pretty_name='Mean ESP Val', datatype="float", comparison=diff._FLOAT_PRECISION, precision="esp_analysis_precision"), _Attribute("mean_pos_esp", description="Mean positive ESP value on isodensity surface", pretty_name='Mean Positive ESP Val', datatype="float", comparison=diff._FLOAT_PRECISION, precision="esp_analysis_precision"), _Attribute("mean_neg_esp", description="Mean negative ESP value on isodensity surface", pretty_name='Mean Negative ESP Val', datatype="float", comparison=diff._FLOAT_PRECISION, precision="esp_analysis_precision"), _Attribute("sig_pos_esp", description="Variance of positive ESP on isodensity surface", pretty_name='Variance of Positive ESP', datatype="float", comparison=diff._FLOAT_PRECISION, precision="esp_analysis_precision"), _Attribute("sig_neg_esp", description="Variance of negative ESP on isodensity surface", pretty_name='Variance of Negative ESP', datatype="float", comparison=diff._FLOAT_PRECISION, precision="esp_analysis_precision"), _Attribute("sig_tot_esp", description="Total ESP variance on isodensity surface", pretty_name='Variance of Total ESP', datatype="float", comparison=diff._FLOAT_PRECISION, precision="esp_analysis_precision"), _Attribute("balance_esp", description="ESP balance on isodensity surface", pretty_name='ESP Balance', datatype="float", comparison=diff._FLOAT_PRECISION, precision="balance_esp_precision"), _Attribute("local_pol_esp", description="Local polarity on isodensity surface", pretty_name="Local ESP Polarity", datatype="float", comparison=diff._FLOAT_PRECISION, precision="esp_analysis_precision"), _Attribute("min_alie", description="Minimum ALIE value on isodensity surface", pretty_name="Min ALIE Val", datatype="float", comparison=diff._FLOAT_PRECISION, precision="alie_analysis_precision"), _Attribute("max_alie", description="Maximum ALIE value on isodensity surface", pretty_name="Max ALIE Val", datatype="float", comparison=diff._FLOAT_PRECISION, precision="alie_analysis_precision"), _Attribute("mean_alie", description="Mean ALIE value on isodensity surface", pretty_name="Mean ALIE Val", datatype="float", comparison=diff._FLOAT_PRECISION, precision="alie_analysis_precision"), _Attribute("mean_pos_alie", description="Mean positive ALIE value on isodensity surface", pretty_name="Mean Positive ALIE Val", datatype="float", comparison=diff._FLOAT_PRECISION, precision="alie_analysis_precision"), _Attribute("mean_neg_alie", description="Mean negative ALIE value on isodensity surface", pretty_name="Mean Negative ALIE Val", datatype="float", comparison=diff._FLOAT_PRECISION, precision="alie_analysis_precision"), _Attribute( "sig_pos_alie", description="Variance of positive ALIE on isodensity surface", pretty_name="Variance Positive ALIE", datatype="float", comparison=diff._FLOAT_PRECISION, precision="alie_analysis_precision"), _Attribute( "sig_neg_alie", description="Variance of negative ALIE on isodensity surface", pretty_name="Variance Negative ALIE", datatype="float", comparison=diff._FLOAT_PRECISION, precision="alie_analysis_precision"), _Attribute("sig_tot_alie", description="Total ALIE variance on isodensity surface", pretty_name="Variance Total ALIE", datatype="float", comparison=diff._FLOAT_PRECISION, precision="alie_analysis_precision"), _Attribute("balance_alie", description="ALIE balance on isodensity surface", pretty_name="ALIE Balance", datatype="float", comparison=diff._FLOAT_PRECISION, precision="balance_alie_precision"), _Attribute( "local_pol_alie", description="Avg deviation from mean ALIE on isodensity surface", pretty_name='Avg Deviation from Mean ALIE', datatype="float", comparison=diff._FLOAT_PRECISION, precision="alie_analysis_precision"), _Attribute("excitation_energies", description="Excitation energies", datatype="float", comparison=diff._LIST_PRECISION, precision="exc_precision", units='eV', init=list), _Attribute( "singlet_excitation_energies", description="Restricted Singlet Electronic excitation energies", pretty_name="Restricted Singlet Exc Ener", datatype="float", comparison=diff._LIST_PRECISION, precision="exc_precision", units='eV', init=list), _Attribute( "triplet_excitation_energies", description="Restricted triplet electronic excitation energies", pretty_name="Restricted Triplet Exc Ener", datatype="float", comparison=diff._LIST_PRECISION, precision="exc_precision", units='eV', init=list), _Attribute("transition_dipole_moments", description="Transition dipole moments", pretty_name="Transition Dipole Moment", datatype="list of Dipole", comparison=diff._LIST_OBJECTS, units='debye', init=list), _Attribute("singlet_transition_dipole_moments", description="Restricted singlet transition dipole moments", pretty_name="Restricted Singlet TDM", datatype="list of Dipole", comparison=diff._LIST_OBJECTS, units='debye', init=list), _Attribute("triplet_transition_dipole_moments", description="Restricted triplet transition dipole moments", pretty_name="Restricted Triplet TDM", datatype="list of Dipole", comparison=diff._LIST_OBJECTS, units='debye', init=list), _Attribute("excited_dipole_moments", description="Excited state dipole moments", pretty_name="Excited State Dipole Moments", datatype="list of Dipole", comparison=diff._LIST_OBJECTS, units='debye', init=list), _Attribute( "singlet_excited_dipole_moments", description="Restricted singlet excited state dipole moments", pretty_name="Restricted Singlet Excited State Dipole Moments", datatype="list of Dipole", comparison=diff._LIST_OBJECTS, units='debye', init=list), _Attribute( "triplet_excited_dipole_moments", description="Restricted triplet excited state dipole moments", pretty_name="Restricted Triplet Excited State Dipole Moments", datatype="list of Dipole", comparison=diff._LIST_OBJECTS, units='debye', init=list), _Attribute("excited_esp_dipole_moments", description="Excited state ESP dipole moments", pretty_name="Excited State ESP Dipole Moments", datatype="list of Dipole", comparison=diff._LIST_OBJECTS, units='debye', init=list), _Attribute( "singlet_excited_esp_dipole_moments", description="Restricted singlet ESP excited state dipole moments", pretty_name="Restricted Singlet ESP Excited State Dipole Moments", datatype="list of Dipole", comparison=diff._LIST_OBJECTS, units='debye', init=list), _Attribute( "triplet_excited_esp_dipole_moments", description="Restricted triplet excited ESP state dipole moments", pretty_name="Restricted Triplet Excited ESP State Dipole Moments", datatype="list of Dipole", comparison=diff._LIST_OBJECTS, units='debye', init=list), _Attribute("oscillator_strengths", description="Excited state oscillator strengths", pretty_name='Oscillator Str', datatype="float", comparison=diff._LIST_PRECISION, precision="osc_precision", init=list), _Attribute("singlet_oscillator_strengths", description="Singlet excited state oscillator strengths", pretty_name='Singlet Oscillator Str', datatype="float", comparison=diff._LIST_PRECISION, precision="osc_precision", init=list), _Attribute("triplet_oscillator_strengths", description="Triplet excitation energy oscillator strengths", pretty_name='Triplet Oscillator Str', datatype="float", comparison=diff._LIST_PRECISION, precision="osc_precision", init=list), _Attribute( "opt_excited_state_energy_1", description="Energy of first excited state geometry optimization", pretty_name="", datatype="float", comparison=diff._FLOAT_PRECISION, precision="energy_precision"), _Attribute("total_lo_correction", description="Total localized orbital energy correction", pretty_name="Total LO Correction", datatype="float", comparison=diff._FLOAT_PRECISION, precision="lo_precision"), _Attribute("spin_splitting_score", description= "Ligand field spin-splitting score for DBLOC calculations", pretty_name="Spin Splitting Score", datatype="float", comparison=diff._FLOAT_PRECISION, precision="spin_splitting_precision"), _Attribute("s2", description="Spin: <S**2>", pretty_name='s2 Spin', datatype="float"), _Attribute("sz2", description="Spin: Sz*<Sz+1>", pretty_name='sz2 Spin', datatype="float"), _Attribute("rotational_constants", description="Rotational constants of molecule", datatype="float", comparison=diff._LIST_PRECISION, precision="osc_precision", init=list), _Attribute("symmetry_number", description="symmetry number for molecule", datatype="int", init=lambda: 1), _Attribute("derived_attrs", init=lambda: DerivedAttrs()) ] # The following "precision" constants are used in comparisons and # should be considered good defaults that you can modify. # For SCF, LMP2 etc energies energy_precision = 1.e-6 nucrep_precision = 1.e-8 zpe_precision = 1.e-2 lo_precision = 1.e-2 spin_splitting_precision = 1.e-2 rxn_coord_precision = 1.e-3 ts_component_precision = 1.e-1 # The alpha polarizability precision should be tighter, but Jaguar # only prints it out to 3 decimal places. alpha_polar_precision = 1.0e-3 beta_polar_precision = 1.0e-3 gamma_polar_precision = 1.0e-1 esp_analysis_precision = 1.e-2 balance_esp_precision = 1.e-3 alie_analysis_precision = 1.e-2 balance_alie_precision = 1.e-3 # Electronic excitation energies are in eV # (Default TDDFT energy convergence is 1e-5 hartree == 0.00027 eV) exc_precision = 6.0e-4 # Oscillator strengths osc_precision = 1.0e-3 # The oscillator strength is derived from the transition moment and the # moment is typically about 10-20X higher, so set the moment precision 20X higher. tdm_precision = osc_precision * 20
[docs] def __init__(self): """ Create a JaguarResults object. """ self._attributes = copy.deepcopy(JaguarResults._attributes) # A list of atomic properties for this JaguarResults object. self.atom = [] # An mmjag handle that is used to access the geometry parsed for # this object. self._mmjag_handle = None # A list of convergence categories. Because a PBF geometry optimization # might involve a preliminary gas phase geometry optimization, there may # be more than one convergence categories, and so we need a list self.convergence_category = [] self.scan_value = {} self.scf_iter = [] # See the class docstring for descriptions of all the attributes # that are present in a JaguarOutput instance. for attr in self._attributes: if attr.name in self.__dict__: raise RuntimeError('Attribute is redefined!') self.__dict__[attr.name] = attr.init()
@property def _orbe_precision(self): "A property that provides the precision for orbital energy comparisons." return Orbital.precision def _getEnergy(self): # See energy property doc. # overwrites gas phase energy if external program is being used energies = (self.rimp2_energy, self.nn_energy, self.external_program_energy, self.solution_phase_energy, self.lmp2_energy, self.scf_energy) ener = None for e in energies: if e is not None: ener = e break return ener energy = property(_getEnergy, doc=""" The overall/final energy for the calculation. Meant to be a simple handle for one to get the energy of a calculation, since there are many different types of energies in JaguarResults. The energy types range from general to method-specific - energy, solution_phase_energy, gas_phase energy, scf_energy, RI-MP2, LMP2, Neural Net (NN), external. More general energy types can be assigned the value of other energy types depending on the calculation. For instance, a gas-phase HF job has energy = scf_energy. But a gas-phase RI-MP2 job has energy = rimp2_energy, since that is the "final" energy of the calculation. Solution-phase calculations have more layers. The code that assigns values to the various energy types is split between _getEnergy() and the various functions in textparser.py. For instance see the rimp2_energies, nn_gas/sol_energy fxns. """) def _getForces(self): # See forces property doc. if not self.atom or not self.atom[0].forces: return None forces = np.zeros((len(self.atom), 3), np.float_) for ix, a in enumerate(self.atom): forces[ix] = np.array(a.forces, np.float_) return forces forces = property(_getForces, doc=""" Convenient access to forces for all atoms as a numpy array. """)
[docs] def getAtomTotal(self): # See atom_total property doc. return len(self.atom)
atom_total = property(getAtomTotal, doc=""" Return the number of atoms in the structure geometry. """)
[docs] def getStructure(self, properties=None): """ Get a schrodinger.Structure object for a specific geometry. property_names (list of tuples of (string, object)) A list of properties names and values belonging to the overall job these results are a part of. """ #FIXME: this function is too complex. if self._mmjag_handle is None: raise IncompleteOutput( "No geometry specification was found for these results.") st = structure.Structure( mm.mmjag_ct_from_zmat(self._mmjag_handle, mm.MMJAG_ZMAT1)) if properties: props = properties[:] else: props = [] def addprop(name, value): """ A utility function to simplify the following code. """ if value is not None: props.append((name, value)) return addprop('i_j_Number_of_canonical_orbitals', self.canonical_orbitals) if self.external_program_energy is not None: addprop('r_j_Gas_Phase_Energy', self.external_program_energy) elif self.nn_gas_energy is not None: addprop('r_j_Gas_Phase_Energy', self.nn_gas_energy) elif self.nn_sol_energy is not None: addprop('r_j_Solution_Phase_Energy', self.nn_sol_energy) else: addprop('r_j_Gas_Phase_Energy', self.gas_phase_energy) addprop('r_j_Solvation_Energy', self.solvation_energy) if self.nn_sol_energy is None: addprop('r_j_Solution_Phase_Energy', self.solution_phase_energy) addprop('r_j_Final_Energy', self.energy) addprop('r_j_HOMO', self.homo) addprop('r_j_alpha_HOMO', self.homo_alpha) addprop('r_j_beta_HOMO', self.homo_beta) addprop('r_j_LUMO', self.lumo) addprop('r_j_alpha_LUMO', self.lumo_alpha) addprop('r_j_beta_LUMO', self.lumo_beta) addprop('r_j_Zero_Point_Energy', self.zero_point_energy) addprop('i_j_SM_Iter', self.sm_iter) addprop('i_j_SM_Point', self.sm_point) if self.doubted_geom: addprop('b_j_doubt_geom', self.doubted_geom) if self.geopt_step_num is not None: addprop('i_j_geopt_step_num', self.geopt_step_num) if self.dipole_qm: addprop('r_j_QM_Dipole_(debye)', self.dipole_qm.dipolemag_qm) addprop('r_j_QM_Dipole_X_(debye)', self.dipole_qm.x) addprop('r_j_QM_Dipole_Y_(debye)', self.dipole_qm.y) addprop('r_j_QM_Dipole_Z_(debye)', self.dipole_qm.z) addprop('r_j_Rxn_Coord', self.reaction_coord) if self.zvar: keys = list(self.zvar) keys.sort() # The r_j_zvar property name seems like a bad idea, but this is # necessary to mimic the backend behavior. for k in keys: addprop('r_j_' + k, self.zvar[k]) if isinstance( self.thermo, list): #because dummy is not a list, but a real one will be for t in self.thermo: if 298.14 < t.temp < 298.16: addprop('r_j_Entropy_(298K)', t.S.total) addprop('r_j_Enthalpy_(298K)', t.H.total) addprop('r_j_Free_Energy_(298K)', t.G.total) addprop(utils.gibbs_energy_property_string(298.15), t.GTotal) else: addprop('r_j_Entropy_(%.2fK)' % t.temp, t.S.total) addprop('r_j_Enthalpy_(%.2fK)' % t.temp, t.H.total) addprop('r_j_Free_Energy_(%.2fK)' % t.temp, t.G.total) addprop(utils.gibbs_energy_property_string(t.temp), t.GTotal) for k, v in props: if v is not None: st.property[k] = v if len(self.atom): if self.atom[0].charge_esp is not None: for st_atom, self_atom in zip(st.atom, self.atom): st_atom.partial_charge = self_atom.charge_esp st_atom.solvation_charge = self_atom.charge_esp attr_name = ["charge", "spin"] prop_name = ["Charges", "Spin_Populations"] pop_type = ["Mulliken", "Lowdin"] for pop in pop_type: for attr, prop in zip(attr_name, prop_name): full_attr = attr + "_" + pop.lower() full_prop = "r_j_" + pop + "_" + prop if getattr(self.atom[0], full_attr) is not None: for st_atom, self_atom in zip(st.atom, self.atom): st_atom.property[full_prop] = getattr( self_atom, full_attr) return st
[docs] def diff(self, other, short_circuit=False, factor=1.0): """ Return a set of attributes that differ. :param JaguarResults other: The instance to compare against. :param bool short_circuit: If True, return immediately upon finding a difference. :param float factor: A fudge factor to apply to most comparison precision values. The allowed difference between values is multiplied by factor. """ differing = diff._diff(self, other, short_circuit=short_circuit, factor=factor) # Unfortunately, the .atom[:] attributes must be diff'd additionally if self.atom_total == other.atom_total: for ix, at in enumerate(self.atom): atomdiffs = self.atom[ix].diff(other.atom[ix], short_circuit=short_circuit) for atomprop in atomdiffs: if isinstance(atomprop, tuple): differing.add( ((('atom', ix), atomprop[0]), atomprop[1])) elif atomprop: differing.add((('atom', ix), atomprop)) if short_circuit and differing: return differing else: differing.add("atom_total") return differing
def __eq__(self, other): if self.diff(other, short_circuit=True): return False else: return True def __ne__(self, other): return not (self == other)
#-----------------------------------------------------------------------------
[docs]@functools.total_ordering class Dipole(object): """ A class for storing dipole information. Attributes: source (string) Descriptor of what set of charges or wavefunction were used to compute the dipole magnitude (float, Debye) The magnitude of the dipole moment. x, y, z (float, Debye) The x, y, z components of the dipole moment. """ precision = 1.0e-4 tdm_precision = JaguarResults.tdm_precision
[docs] def __init__(self, source, x=None, y=None, z=None, magnitude=None): # Use setattr to create different handles for Dipoles # from different sources (qm,esp,mulliken) mag_handle = 'dipolemag_' + source comp_handle = 'dipolecomp_' + source # Allow default values of None if x is None or y is None or z is None: setattr(self, mag_handle, None) setattr(self, comp_handle, None) else: setattr(self, comp_handle, [x, y, z]) if magnitude is not None: setattr(self, mag_handle, magnitude) else: #allows both real and complex component values calc_mag = math.sqrt((x * x.conjugate() + y * y.conjugate() + z * z.conjugate()).real) setattr(self, mag_handle, calc_mag) self.source = source.lower() self.x = x self.y = y self.z = z #Map mag_handle to old name to allow consistent access self.magnitude = getattr(self, mag_handle) # Set description desc_prefix = '' if self.source == 'qm': desc_prefix = 'Wavefunction' elif 'esp' in self.source: desc_prefix = 'ESP' if "excited" in self.source: desc_prefix = 'Excited ' + desc_prefix else: desc_prefix = self.source.capitalize() # Set precision self._diff_precision = Dipole.precision # More lax precision for trans/excited dipoles, as in JaguarResults if any(x in source for x in ('excited', 'transition', 'so-transition')): self._diff_precision = Dipole.tdm_precision self._attributes = [ _Attribute( mag_handle, description=f"{desc_prefix} Dipole Moment Magnitude Calc'd", pretty_name=f'{desc_prefix} Dipole Moment Magnitude', units="Debye", comparison=None, datatype="float"), _Attribute( comp_handle, description=f"{desc_prefix} Dipole Moment Components Calc'd", pretty_name=f'{desc_prefix} Dipole Components', component_names=(f'{desc_prefix} Dipole Component X', f'{desc_prefix} Dipole Component Y', f'{desc_prefix} Dipole Component Z'), units="Debye", comparison=None, datatype="list of float") ]
def __eq__(self, other): if not isinstance(other, Dipole): return False return self.cmp(other) == 0 def __ne__(self, other): return not (self == other) def __lt__(self, other): return self.cmp(other) < 0
[docs] def cmp(self, other): # Provide a stable ordering, only compare equal if magnitudes are equal. # Would need molecular geometry to know if orientations matched if self.source != other.source: warnings.warn( f"Comparing a {self.source} dipole with a {other.source} dipole" ) if self.magnitude is None or other.magnitude is None: #for comparing dummy inits cmp_ = diff.compare_a_none(self.magnitude, other.magnitude) else: cmp_ = diff.compare_float(self.magnitude, other.magnitude, self._diff_precision) if cmp_: return cmp_ return 0
def __repr__(self): if any(xyz is None for xyz in (self.x, self.y, self.z)): #for instantiating dummies with None's return f"Dipole({self.source}, x={self.x}, y={self.y}, z={self.z})" else: return f"Dipole({self.source}, x={self.x:.4f}, y={self.y:.4f}, z={self.z:.4f})"
#-----------------------------------------------------------------------------
[docs]class SpinSpinCoupling: # When defining a docstring as anything other than a bare string, it's # necessary to explicitly assign it to __doc__. __doc__ = """ A class for storing Spin-Spin Coupling results. Attributes atom_pair (list(JaguarAtomicResults)) The atom pair used to calculate the spin-spin coupling constants total_spin_spin (np.array(float), Hz) The total spin-spin coupling tensor (3x3 matrix) total_spin_spin_isotropic (float, Hz) The isotropic value of the spin-spin coupling tensor fermi_contact (np.array(float), Hz) The Fermi-Contact Matrix (3x3 matrix) fermi_contact_isotropic (float, Hz) The isotropic value of the Fermi-Contact Matrix spin_dipole (np.array(float), Hz) The Spin-Dipole Matrix (3x3 matrix) spin_dipole_isotropic (float, Hz) The isotropic value of the Spin-Dipole Matrix fermi_contact_spin_dipole (np.array(float), Hz) The Fermi-Contact / Spin-Dipole Matrix (3x3 matrix) fermi_contact_spin_dipole_isotropic (float, Hz) The isotropic value of the Fermi-Contact / Spin-Dipole Matrix paramag_spin_orbit (np.array(float), Hz) The Paramagnetic Spin-Orbit Matrix (3x3 matrix) paramag_spin_orbit_isotropic (float, Hz) The isotropic value of the Paramagnetic Spin-Orbit Matrix diamag_spin_orbit (np.array(float), Hz) The Diamagnetic Spin-Orbit Matrix (3x3 matrix) diamag_spin_orbit_isotropic (float, Hz) The isotropic value of the Diamagnetic Spin-Orbit Matrix """
[docs] def __init__(self, atom_pair, total_spin_spin=None, total_spin_spin_isotropic=None, fermi_contact=None, fermi_contact_isotropic=None, spin_dipole=None, spin_dipole_isotropic=None, fermi_contact_spin_dipole=None, fermi_contact_spin_dipole_isotropic=None, paramag_spin_orbit=None, paramag_spin_orbit_isotropic=None, diamag_spin_orbit=None, diamag_spin_orbit_isotropic=None): """ Arguments :param np.array(JaguarAtomicResults) atom_pair: The atom pair used to calculate the spin-spin coupling constants :param np.array(float) total_spin_spin: The total spin-spin coupling tensor (3x3 matrix) in Hz units :param float total_spin_spin_isotropic: The isotropic value of the spin-spin coupling tensor in Hz units :param np.array(float) fermi_contact: The Fermi-Contact Matrix in Hz units :param float fermi_contact_isotropic: The isotropic value of the Fermi-Contact Matrix in Hz units :param np.array(float) spin_dipole: The Spin-Dipole Matrix in Hz units :param float spin_dipole_isotropic: The isotropic value of the Spin-Dipole Matrix in Hz units :param np.array(float) fermi_contact_spin_dipole: The Fermi-Contact and Spin-Dipole symmetric combination Matrix in Hz units :param float fermi_contact_spin_dipole_isotropic: The isotropic value of the Fermi-Contact and Spin-Dipole symmetric combination Matrix in Hz units :param np.array(float) paramag_spin_orbit: The Paramagnetic Spin-Orbit Matrix in Hz units :param float paramag_spin_orbit_isotropic: The isotropic value of the Paramagnetic Spin-Orbit Matrix in Hz units :param np.array(float) diamag_spin_orbit: The Diamagnetic Spin-Orbit Matrix in Hz units :param float diamag_spin_orbit_isotropic: The isotropic value of the Diamagnetic Spin-Orbit Matrix in Hz units """ self._attributes = [ _Attribute("atom_pair", description="Atom Pair", pretty_name="Atom Pair", init=lambda: atom_pair), _Attribute( "total_spin_spin", description="Total Spin-Spin Matrix of Atom Pair", pretty_name= f"Total Spin-Spin Matrix of {atom_pair[0].atom_name} and {atom_pair[1].atom_name}", precision=1.0e-4, init=lambda: total_spin_spin), _Attribute( "total_spin_spin_isotropic", description="Total Spin-Spin Isotropic Value of Pairs", pretty_name= f"Total Spin-Spin Isotropic Value of {atom_pair[0].atom_name} and {atom_pair[1].atom_name}", precision=1.0e-4, datatype="float", init=lambda: total_spin_spin_isotropic), _Attribute( "fermi_contact", description="Fermi Contact Matrix of Atom Pair", pretty_name= f"Fermi-Contact Matrix of {atom_pair[0].atom_name} and {atom_pair[1].atom_name}", precision=1.0e-4), _Attribute( "fermi_contact_isotropic", description="Fermi-Contact Isotropic Value of Pairs", pretty_name= f"Fermi-Contact Isotropic Value of {atom_pair[0].atom_name} and {atom_pair[1].atom_name}", precision=1.0e-4, datatype="float"), _Attribute( "spin_dipole", description="Spin-Dipole Matrix of Atom Pair", pretty_name= f"Spin-Dipole Matrix of {atom_pair[0].atom_name} and {atom_pair[1].atom_name}", precision=1.0e-4), _Attribute( "spin_dipole_isotropic", description="Spin-Dipole Isotropic Value of Pairs", pretty_name= f"Spin-Dipole Isotropic Value of {atom_pair[0].atom_name} and {atom_pair[1].atom_name}", precision=1.0e-4, datatype="float"), _Attribute( "fermi_contact_spin_dipole", description= "Symmetric Combination of Fermi Contact Matrix and Spin Dipole Matrix of Atom Pair", pretty_name= f"Symmetric combination of Fermi-Contact Matrix and Spin-Dipole Matrix of {atom_pair[0].atom_name} and {atom_pair[1].atom_name}", precision=1.0e-4), _Attribute( "fermi_contact_spin_dipole_isotropic", description= "Isotropic value of Symmetric Combination of Fermi Contact Matrix and Spin Dipole Matrix of Atom Pair", pretty_name= f"Isotropic value of Symmetric Combination of Fermi Contact Matrix and Spin Dipole Matrix of {atom_pair[0].atom_name} and {atom_pair[1].atom_name}", precision=1.0e-4, datatype="float"), _Attribute( "paramag_spin_orbit", description="Paramagnetic Spin-Orbit Matrix of Atom Pair", pretty_name= f"Paramagnetic Spin-Orbit Matrix of {atom_pair[0].atom_name} and {atom_pair[1].atom_name}", precision=1.0e-4), _Attribute( "paramag_spin_orbit_isotropic", description="Paramagnetic Spin-Orbit Isotropic Value of Pairs", pretty_name= f"Paramagnetic Spin-Orbit Isotropic Value of {atom_pair[0].atom_name} and {atom_pair[1].atom_name}", precision=1.0e-4, datatype="float"), _Attribute( "diamag_spin_orbit", description="Diamagnetic Spin-Orbit Matrix of Atom Pair", pretty_name= f"Diamagnetic Spin-Orbit Matrix of {atom_pair[0].atom_name} and {atom_pair[1].atom_name}", precision=1.0e-4), _Attribute( "diamag_spin_orbit_isotropic", description="Diamagnetic Spin-Orbit Isotropic Value of Pairs", pretty_name= f"Diamagnetic Spin-Orbit Isotropic Value of {atom_pair[0].atom_name} and {atom_pair[1].atom_name}", precision=1.0e-4, datatype="float"), ] for attr in self._attributes: self.__dict__[attr.name] = attr.init()
def __eq__(self, other): """ Check spin-spin coupling properties for equality. """ try: for attr in self._attributes: self_val = getattr(self, attr.name) other_val = getattr(other, attr.name) if self_val is None or other_val is None: if diff.compare_a_none(self_val, other_val) != 0: return False else: if attr.datatype == 'float': if diff.compare_float(self_val, other_val, attr.precision) != 0: return False elif attr.name == 'atom_pair': if False in (self_val == other_val): return False else: if self_val.shape != other_val.shape: return False elif not np.allclose( self_val, other_val, atol=attr.precision): return False return True except AttributeError: return False def __ne__(self, other): return not (self == other) def __repr__(self): for attr in self._attributes: print(attr.name) template = "SpinSpinCoupling(" + \ ", ".join(["%s=%%(%s)s" % (attr.name, attr.name) for attr in self._attributes if attr.name in ['atom_pair','total_spin_spin','total_spin_spin_isotropic']]) + \ ")" return template % self.__dict__
#add_attribute_aliases(JaguarResults)