Example #1
0
def _values(val_dct, name_mat, angstrom, degree):
    ret_val_dct = {}

    name_set = set(numpy.ravel(name_mat)) - {None}
    assert set(val_dct) == name_set

    for name, val in val_dct.items():
        # make sure every entry in the value dictionary corresponds to a
        # coordinate
        assert numpy.any(numpy.equal(name_mat, name))

        # make sure coordinates with the same name are in the same column
        col_idxs = numpy.where(numpy.equal(name_mat, name))[1]
        col_idx_set = set(col_idxs)
        assert len(col_idx_set) == 1

        # get the column index
        col_idx, = col_idx_set

        # convert units according to which column the values come from
        if col_idx == 0:
            if angstrom:
                val *= qcc.conversion_factor('angstrom', 'bohr')
        else:
            if degree:
                val *= qcc.conversion_factor('degree', 'radian')

        ret_val_dct[name] = val

    return ret_val_dct
Example #2
0
def join(geo1,
         geo2,
         dist_cutoff=3. * qcc.conversion_factor('angstrom', 'bohr'),
         theta=0. * qcc.conversion_factor('degree', 'radian'),
         phi=0. * qcc.conversion_factor('degree', 'radian')):
    """ join two geometries together
    """
    orient_vec = numpy.array([
        numpy.sin(theta) * numpy.cos(phi),
        numpy.sin(theta) * numpy.sin(phi),
        numpy.cos(theta)
    ])

    # get the correct distance apart
    geo1 = mass_centered(geo1)
    geo2 = mass_centered(geo2)
    ext1 = max(numpy.vdot(orient_vec, xyz) for xyz in coordinates(geo1))
    ext2 = max(numpy.vdot(-orient_vec, xyz) for xyz in coordinates(geo2))

    cm_dist = ext1 + dist_cutoff + ext2
    dist_grid = numpy.arange(cm_dist, 0., -0.1)
    for dist in dist_grid:
        trans_geo2 = translated(geo2, orient_vec * dist)
        min_dist = minimum_distance(geo1, trans_geo2)
        if numpy.abs(min_dist - dist_cutoff) < 0.1:
            break

    geo2 = trans_geo2

    # now, join them together
    syms = symbols(geo1) + symbols(geo2)
    xyzs = coordinates(geo1) + coordinates(geo2)
    return from_data(syms, xyzs)
Example #3
0
    def get_contributed_values_column(self, key: str) -> 'Series':
        """Returns a Pandas column with the requested contributed values

        Parameters
        ----------
        key : str
            The ContributedValues object key.
        scale : None, optional
            All units are based in Hartree, the default scaling is to kcal/mol.

        Returns
        -------
        Series
            A pandas Series containing the request values.
        """
        data = self.get_contributed_values(key)

        # Annoying work around to prevent some pands magic
        if isinstance(next(iter(data.values.values())), (int, float)):
            values = data.values
        else:
            values = {k: [v] for k, v in data.values.items()}

        tmp_idx = pd.DataFrame.from_dict(values,
                                         orient="index",
                                         columns=[data.name])

        # Convert to numeric
        tmp_idx[tmp_idx.select_dtypes(
            include=['number']).columns] *= constants.conversion_factor(
                data.units, self.units)

        return tmp_idx
Example #4
0
def _frequency_analysis(geo, hess, project=True):
    """ Froms the mass-weighted Hessian and diagonalizes it to obtain
        the normal coordinates and harmonic vibrational frequencies.

        :param geo: cartesian or z-matrix geometry
        :type geo: tuple
        :param hess: Hessian correpsonding to the geometry
        :type hess: tuple(tuple(float))
        :param project: project out rotations and translations of Hessian
        :type project: bool
        :rtype: tuple(tuple(float))
    """

    mw_hess = mass_weighted_hessian(geo, hess, project=project)
    # print(mw_hess)
    fcs, mw_norm_coos = numpy.linalg.eigh(mw_hess)

    conv = qcc.conversion_factor("hartree", "wavenumber")
    freqs = numpy.sqrt(numpy.complex_(fcs)) * conv
    freqs_im = numpy.imag(freqs)
    freqs_re = numpy.real(freqs)

    mw_vec = mass_weighting_vector(geo)
    norm_coos = mw_norm_coos
    norm_coos = _normalize_columns(mw_vec * mw_norm_coos)

    return norm_coos, freqs_re, freqs_im
Example #5
0
File: d3.py Project: bast/d3
def d3(charges, coordinates, rs6, rs8, s6, s8, rab, rcov, r2r4, coefficients):
    bohr_to_angstrom = constants.conversion_factor("bohr", "angstrom")

    coordinates_angstrom = list(
        map(lambda x: x * bohr_to_angstrom, coordinates))
    coordination_numbers = compute_coordination_numbers(
        coordinates_angstrom, charges, rcov)

    result = 0.0
    for j, charge1 in enumerate(charges):
        for k, charge2 in enumerate(charges):
            if k > j:
                dx = coordinates[3 * j + 0] - coordinates[3 * k + 0]
                dy = coordinates[3 * j + 1] - coordinates[3 * k + 1]
                dz = coordinates[3 * j + 2] - coordinates[3 * k + 2]
                dist = jnp.sqrt(dx * dx + dy * dy + dz * dz)

                c6jk = get_c6jk(
                    coefficients[(charge1, charge2)],
                    coordination_numbers[j],
                    coordination_numbers[k],
                )

                rr = rab[(charge1, charge2)] / (dist * bohr_to_angstrom)
                r1 = (-s6 * c6jk / (jnp.power(dist, 6) *
                                    (1.0 + 6.0 * jnp.power(rs6 * rr, 14))))

                c8jk = 3.0 * c6jk * r2r4[charge1] * r2r4[charge2]
                r2 = (-s8 * c8jk / (jnp.power(dist, 8) *
                                    (1.0 + 6.0 * jnp.power(rs8 * rr, 16))))
                result += r1 + r2

    return result
Example #6
0
def _pairwise_potentials(geo, idx_pair, potential='exp6'):
    """ Calculate the sum of the pairwise potential for a
        given set of atom pairs
    """

    # Get the indexes and symbols
    idx1, idx2 = idx_pair
    if idx1 != idx2:

        # Get the symbols of the atoms
        symbs = symbols(geo)
        symb1, symb2 = symbs[idx1], symbs[idx2]

        # Calculate interatomic distance
        rdist = (distance(geo, idx1, idx2) *
                 qcc.conversion_factor('bohr', 'angstrom'))

        # Calculate the potential
        if potential == 'exp6':
            params = _read_params(EXP6_DCT, symb1, symb2)
            pot_val = exp6_potential(rdist, *params)
        elif potential == 'lj_12_6':
            params = _read_params(LJ_DCT, symb1, symb2)
            pot_val = lj_potential(rdist, *params)
        else:
            pot_val = None

    else:
        pot_val = 1e10

    return pot_val
Example #7
0
def run_kickoff_saddle(
        geo, disp_xyzs, spc_info, thy_level, run_fs, thy_run_fs,
        opt_script_str, kickoff_size=0.1, kickoff_backward=False,
        opt_cart=True, **kwargs):
    """ kickoff from saddle to find connected minima
    """
    print('kickoff from saddle')
    thy_run_fs.leaf.create(thy_level[1:4])
    thy_run_path = thy_run_fs.leaf.path(thy_level[1:4])
    run_fs = autofile.fs.run(thy_run_path)
    disp_len = kickoff_size * qcc.conversion_factor('angstrom', 'bohr')
    if kickoff_backward:
        disp_len *= -1
    disp_xyzs = numpy.multiply(disp_xyzs, disp_len)
    geo = automol.geom.displaced(geo, disp_xyzs)
    if opt_cart:
        geom = geo
    else:
        geom = automol.geom.zmatrix(geo)
    moldr.driver.run_job(
        job=elstruct.Job.OPTIMIZATION,
        script_str=opt_script_str,
        run_fs=run_fs,
        geom=geom,
        spc_info=spc_info,
        thy_level=thy_level,
        overwrite=True,
        **kwargs,
    )
    ret = moldr.driver.read_job(job=elstruct.Job.OPTIMIZATION, run_fs=run_fs)
    if ret:
        inf_obj, _, out_str = ret
        prog = inf_obj.prog
        geo = elstruct.reader.opt_geometry(prog, out_str)
    return geo
Example #8
0
def _polygon_coordinates(num):
    """ main formula: side / 2 = radius * sin(2 * pi / 2 / 2)
    """
    side = 1.5 * qcc.conversion_factor('angstrom', 'bohr')
    rad = side / 2. / numpy.sin(numpy.pi / num)
    angs = [2. * numpy.pi * idx / num for idx in range(num)]
    xyzs = [(rad * numpy.cos(ang), rad * numpy.sin(ang), 0.) for ang in angs]
    return tuple(xyzs)
Example #9
0
def rotational_constants(geo, amu=True):
    """ rotational constants (atomic units if amu=False)
    """
    moms = moments_of_inertia(geo, amu=amu)
    sol = (qcc.get('speed of light in vacuum') *
           qcc.conversion_factor('meter / second', 'bohr hartree / h'))
    cons = numpy.divide(1., moms) / 4. / numpy.pi / sol
    cons = tuple(cons)
    return cons
Example #10
0
def values(zma, angstrom=False, degree=False):
    """ coordinate values, by coordinate name
    """
    vma, val_dct = zma

    # post-processing for unit convertions
    dist_names = _v_.distance_names(vma)
    ang_names = _v_.angle_names(vma)
    orig_val_dct = val_dct

    val_dct = {}
    for name, val in orig_val_dct.items():
        if angstrom and name in dist_names:
            val *= qcc.conversion_factor('bohr', 'angstrom')
        if degree and name in ang_names:
            val *= qcc.conversion_factor('radian', 'degree')
        val_dct[name] = val
    return val_dct
Example #11
0
def _bond_distance(xgr, atm1_key, atm2_key, check=True):
    """ predicted bond distance

    (currently crude, but could easily be made more sophisticated
    """
    if check:
        atm_sym_dct = _atom_symbols(xgr)
        assert atm2_key in _atom_neighbor_keys(xgr)[atm1_key]

    atm1_sym = atm_sym_dct[atm1_key]
    atm2_sym = atm_sym_dct[atm2_key]

    if atm1_sym == 'H' or atm2_sym == 'H':
        dist = 1.1 * qcc.conversion_factor('angstrom', 'bohr')
    else:
        dist = 1.5 * qcc.conversion_factor('angstrom', 'bohr')

    return dist
Example #12
0
    def _query(self,
               indexer: str,
               query: Dict[str, Any],
               field: str = "return_result") -> 'Series':
        """
        Runs a query based on an indexer which is index : molecule_id

        Parameters
        ----------
        indexer : str
            The primary index of the query
        query : Dict[str, Any]
            A results query
        field : str, optional
            The field to pull from the ResultRecords
        scale : str, optional
            The scale of the computation

        Returns
        -------
        Series
            A Series of the data results
        """
        self._check_state()

        field = field.lower()

        ret = []
        for query_set in composition_planner(**query):

            query_set["molecule"] = set(indexer.values())

            query_set["projection"] = {"molecule": True, field: True}
            records = pd.DataFrame(self.client.query_results(**query_set),
                                   columns=["molecule", field])

            df = pd.DataFrame.from_dict(indexer,
                                        orient="index",
                                        columns=["molecule"])
            df.reset_index(inplace=True)
            df = df.merge(records, how="left", on="molecule")
            df.set_index("index", inplace=True)
            df.drop("molecule", axis=1, inplace=True)
            ret.append(df)

        if len(ret) == 1:
            retdf = ret[0]
        else:
            retdf = ret[0]
            for df in ret[1:]:
                retdf += df

        retdf[retdf.select_dtypes(
            include=['number']).columns] *= constants.conversion_factor(
                'hartree', self.units)

        return retdf
Example #13
0
def coordinates(geo, angstrom=False):
    """ atomic coordinates
    """
    if geo:
        _, xyzs = zip(*geo)
    else:
        xyzs = ()
    xyzs = xyzs if not angstrom else numpy.multiply(
        xyzs, qcc.conversion_factor('bohr', 'angstrom'))
    return xyzs
Example #14
0
def _bond_angle(sgr, atm1_key, atm2_key, atm3_key, check=True):
    """ predict the bond angles an atom makes with its neighbors
    """
    if check:
        atm_ngb_keys_dct = _atom_neighbor_keys(sgr)
        atm2_ngb_keys = atm_ngb_keys_dct[atm2_key]
        assert {atm1_key, atm3_key} <= atm2_ngb_keys

    atm_hyb_dct = _resonance_dominant_atom_hybridizations(sgr)
    atm2_hyb = atm_hyb_dct[atm2_key]

    if atm2_hyb == 3:
        ang = 109.5 * qcc.conversion_factor('degree', 'radian')
    elif atm2_hyb == 2:
        ang = 120.0 * qcc.conversion_factor('degree', 'radian')
    else:
        assert atm2_hyb == 1
        ang = 180.0 * qcc.conversion_factor('degree', 'radian')

    return ang
Example #15
0
def masses(geo, amu=True):
    """ return the atomic masses
    """
    syms = symbols(geo)
    amas = list(map(pt.to_mass, syms))

    if not amu:
        conv = qcc.conversion_factor("atomic_mass_unit", "electron_mass")
        amas = numpy.multiply(amas, conv)

    amas = tuple(amas)
    return amas
Example #16
0
def coordinates(geo, idxs=None, angstrom=False):
    """ atomic coordinates
    """
    idxs = list(range(count(geo))) if idxs is None else idxs
    if geo:
        _, xyzs = zip(*geo)
    else:
        xyzs = ()
    xyzs = xyzs if not angstrom else numpy.multiply(
        xyzs, qcc.conversion_factor('bohr', 'angstrom'))
    xyzs = tuple(xyz for idx, xyz in enumerate(xyzs) if idx in idxs)
    return xyzs
Example #17
0
def from_data(symbols, coordinates, angstrom=False):
    """ geometry data structure from symbols and coordinates
    """
    syms = list(map(pt.to_E, symbols))
    natms = len(syms)

    xyzs = numpy.array(coordinates, dtype=float)
    assert numpy.ndim(xyzs) == 2 and numpy.shape(xyzs) == (natms, 3)
    xyzs = (xyzs if not angstrom else numpy.multiply(
        xyzs, qcc.conversion_factor('angstrom', 'bohr')))
    xyzs = list(map(tuple, xyzs))
    geo = tuple(zip(syms, xyzs))
    return geo
Example #18
0
def rct1_x_join(rct1_zma, atm1_key, atm2_key, atm3_key):
    """ Build the R1+X matrix for bimol reactions
    """

    x_zma = ((('X', (None, None, None), (None, None, None)), ), {})

    x_join_val_dct = {
        'rx': 1. * qcc.conversion_factor('angstrom', 'bohr'),
        'ax': 90. * qcc.conversion_factor('degree', 'radian'),
        'dx': 180. * qcc.conversion_factor('degree', 'radian'),
    }

    x_join_keys = numpy.array([[atm1_key, atm2_key, atm3_key]])
    x_join_names = numpy.array([['rx', 'ax', 'dx']], dtype=numpy.object_)
    x_join_names[numpy.equal(x_join_keys, None)] = None
    x_join_name_set = set(numpy.ravel(x_join_names)) - {None}
    x_join_val_dct = {name: x_join_val_dct[name] for name in x_join_name_set}

    rct1_x_zma = automol.zmatrix.join(rct1_zma, x_zma, x_join_keys,
                                      x_join_names, x_join_val_dct)

    return rct1_x_zma
Example #19
0
def rct1x_rct2_join(rct1_x_zma,
                    rct2_zma,
                    dist_name,
                    dist_val,
                    jkey1,
                    jkey2,
                    jkey3,
                    join_vals=(85., 85., 170., 85., 170.)):
    """ Second join function
    """

    rct2_natms = automol.zmatrix.count(rct2_zma)

    join_val_dct = {
        dist_name: dist_val,
        'aabs1': 85. * qcc.conversion_factor('degree', 'radian'),
        'aabs2': 85. * qcc.conversion_factor('degree', 'radian'),
        'babs1': 170. * qcc.conversion_factor('degree', 'radian'),
        'babs2': 85. * qcc.conversion_factor('degree', 'radian'),
        'babs3': 170. * qcc.conversion_factor('degree', 'radian'),
    }

    join_keys = numpy.array([[jkey1, jkey2, jkey3], [None, jkey1, jkey2],
                             [None, None, jkey1]])[:rct2_natms]
    join_names = numpy.array([[dist_name, 'aabs1', 'babs1'],
                              [None, 'aabs2', 'babs2'],
                              [None, None, 'babs3']])[:rct2_natms]
    join_names[numpy.equal(join_keys, None)] = None

    join_name_set = set(numpy.ravel(join_names)) - {None}
    join_val_dct = {name: join_val_dct[name] for name in join_name_set}

    rct1_x_rct2_zma = automol.zmatrix.join(rct1_x_zma, rct2_zma, join_keys,
                                           join_names, join_val_dct)

    return rct1_x_rct2_zma
Example #20
0
def _frequency_analysis(geo, hess, project=True):
    """ harmonic frequency analysis
    """
    mw_hess = mass_weighted_hessian(geo, hess, project=project)
    # print(mw_hess)
    fcs, mw_norm_coos = numpy.linalg.eigh(mw_hess)

    conv = qcc.conversion_factor("hartree", "wavenumber")
    freqs = numpy.sqrt(numpy.complex_(fcs)) * conv
    freqs_im = numpy.imag(freqs)
    freqs_re = numpy.real(freqs)

    mw_vec = mass_weighting_vector(geo)
    norm_coos = mw_norm_coos
    norm_coos = _normalize_columns(mw_vec * mw_norm_coos)
    return norm_coos, freqs_re, freqs_im
Example #21
0
def is_linear(geo, tol=2. * qcc.conversion_factor('degree', 'radian')):
    """ is this geometry linear?
    """
    ret = True

    if len(geo) == 1:
        ret = False
    elif len(geo) == 2:
        ret = True
    else:
        keys = range(len(symbols(geo)))
        for key1, key2, key3 in mit.windowed(keys, 3):
            cangle = numpy.abs(central_angle(geo, key1, key2, key3))
            if cangle % numpy.pi > tol:
                ret = False
    return ret
Example #22
0
def _start_zmatrix_from_ring(gra, rng_atm_keys):
    """ generates a z-matrix for a ring
    """
    # the key dictionary can be constructed immediately
    zma_key_dct = {
        atm_key: zma_key
        for zma_key, atm_key in enumerate(rng_atm_keys)
    }

    # now, build the z-matrix
    natms = len(rng_atm_keys)
    atm_sym_dct = atom_symbols(gra)

    dist_val = 1.5 * qcc.conversion_factor('angstrom', 'bohr')
    ang_val = (natms - 2.) * numpy.pi / natms
    dih_val = 0.

    # 1. construct the z-matrix for a 3-atom system
    key_mat = [[None, None, None], [0, None, None], [1, 0, None]]

    name_mat = [[None, None, None], ['R1', None, None], ['R2', 'A2', None]]

    syms = dict_.values_by_key(atm_sym_dct, rng_atm_keys[:3])

    val_dct = {'R1': dist_val, 'R2': dist_val, 'A2': ang_val}

    zma = automol.zmatrix.from_data(syms, key_mat, name_mat, val_dct)

    # 2. append z-matrix rows for the remaining atoms
    for row, rng_atm_key in enumerate(rng_atm_keys):
        if row > 2:
            sym = atm_sym_dct[rng_atm_key]
            dist_name = automol.zmatrix.new_distance_name(zma)
            ang_name = automol.zmatrix.new_central_angle_name(zma)
            dih_name = automol.zmatrix.new_dihedral_angle_name(zma)

            zma = automol.zmatrix.append(zma, sym, [row - 1, row - 2, row - 3],
                                         [dist_name, ang_name, dih_name],
                                         [dist_val, ang_val, dih_val])

    return zma, zma_key_dct
Example #23
0
    fmls = list(map(_connected_formula, ichs))
    fml = functools.reduce(automol.formula.join, fmls)
    return fml


def _connected_formula(ich):
    fml = object_from_hardcoded_inchi_by_key('formula', ich)
    if fml is None:
        ich = automol.inchi.standard_form(ich)
        rdm = _rdkit.from_inchi(ich)
        fml = _rdkit.to_formula(rdm)
    return fml


# hardcoded inchis which neither RDKit nor Pybel can handle
ANG2BOHR = qcc.conversion_factor('angstrom', 'bohr')
HARDCODED_INCHI_DCT = {
    'InChI=1S/C': {
        'inchi': 'InChI=1S/C',
        'geom': (('C', (0., 0., 0.)),),
        'graph': ({0: ('C', 0, None)}, {}),
        'smiles': '[C]',
        'formula': {'C': 1},
    },
    'InChI=1S/B': {
        'inchi': 'InChI=1S/B',
        'geom': (('B', (0., 0., 0.)),),
        'graph': ({0: ('B', 0, None)}, {}),
        'smiles': '[B]',
        'formula': {'B': 1},
    },
Example #24
0
"""
Obtain information from VPT2 calculations
"""

from qcelemental import constants as qcc
import autoread as ar
import autoparse.pattern as app
import autoparse.find as apf

KJ2EH = qcc.conversion_factor('kJ/mol', 'hartree')


def anharmonic_frequencies_reader(output_string):
    """ Get the anharmonic vibrational frequencies
    """

    # block
    block = apf.last_capture(
        (app.escape('Fundamental Bands (DE w.r.t. Ground State)') +
         app.capturing(app.one_or_more(app.WILDCARD, greedy=False)) +
         app.escape('Overtones (DE w.r.t. Ground State)')), output_string)

    pattern = (app.INTEGER + app.escape('(1)') + app.SPACE +
               app.maybe(app.one_or_more(app.LOWERCASE_LETTER)) +
               app.one_or_more(app.SPACE) + app.FLOAT +
               app.one_or_more(app.SPACE) + app.capturing(app.FLOAT))
    # pattern2 = (
    # app.INTEGER +
    # app.escape('(1)') +
    # app.SPACE +
    # app.maybe(app.one_or_more(app.LOWERCASE_LETTER)) +
Example #25
0
"""
Sets up pivot point locations for a species
"""

import numpy as np
from qcelemental import constants as qcc

# Conversion factors
DEG2RAD = qcc.conversion_factor('degree', 'radian')
RAD2DEG = qcc.conversion_factor('radian', 'degree')


def find_xyzp(xyz1, xyz2, xyz3, pdist, pangle, pdihed):
    """ geometric approach for calculating the xyz coordinates of atom A
        when the xyz coordinates of the A B and C are known and
        the position is defined w/r to A B C with internal coordinates
    """
    # Set to numpy arrays
    xyz1 = np.array(xyz1)
    xyz2 = np.array(xyz2)
    xyz3 = np.array(xyz3)

    # Build initial coordinates
    # pangle *= DEG2RAD
    # pdihed *= DEG2RAD

    # if something:
    #     xyzp = _two_point(xyz1, xyz2, xyz3, pdist, pangle, pdihed)
    # else:
    #     xyzp = _three_point(xyz1, xyz2, pdist, pangle)
    xyzp = _three_point(xyz1, xyz2, xyz3, pdist, pangle, pdihed)
Example #26
0
    def visualize(
        self,
        relative: bool = True,
        units: str = "kcal / mol",
        digits: int = 3,
        use_measured_angle: bool = False,
        return_figure: Optional[bool] = None,
    ) -> "plotly.Figure":
        """
        Parameters
        ----------
        relative : bool, optional
            Shows relative energy, lowest energy per scan is zero.
        units : str, optional
            The units of the plot.
        digits : int, optional
            Rounds the energies to n decimal places for display.
        use_measured_angle : bool, optional
            If True, the measured final angle instead of the constrained optimization angle.
            Can provide more accurate results if the optimization was ill-behaved,
            but pulls additional data from the server and may take longer.
        return_figure : Optional[bool], optional
            If True, return the raw plotly figure. If False, returns a hosted iPlot. If None, return a iPlot display in Jupyter notebook and a raw plotly figure in all other circumstances.

        Returns
        -------
        plotly.Figure
            The requested figure.
        """

        # Pull energy dictionary apart
        min_energy = 1e12
        x = []
        y = []
        for k, v in self.get_final_energies().items():
            if len(k) >= 2:
                raise TypeError(
                    "TorsionDrive.visualize is currently only available for 1-D scans."
                )

            if use_measured_angle:
                # Recalculate the dihedral angle
                dihedral_indices = self.keywords.dihedrals[0]
                mol = self.get_final_molecules(k)
                x.append(mol.measure(dihedral_indices))

            else:
                x.append(k[0])

            y.append(v)

            # Update minimum energy
            if v < min_energy:
                min_energy = v

        x = np.array(x)
        y = np.array(y)

        # Sort by angle
        sorter = np.argsort(x)
        x = x[sorter]
        y = y[sorter]
        if relative:
            y -= min_energy

        cf = constants.conversion_factor("hartree", units)
        trace = {
            "mode": "lines+markers",
            "x": x,
            "y": np.around(y * cf, digits)
        }
        # "name": "something"

        title = "TorsionDrive 1-D Plot"

        if relative:
            ylabel = f"Relative Energy [{units}]"
        else:
            ylabel = f"Absolute Energy [{units}]"

        custom_layout = {
            "title": title,
            "yaxis": {
                "title": ylabel,
                "zeroline": True
            },
            "xaxis": {
                "title": "Dihedral Angle [degrees]",
                "zeroline": False,
                "range": [x.min() - 10, x.max() + 10]
            },
        }

        return scatter_plot([trace],
                            custom_layout=custom_layout,
                            return_figure=return_figure)
Example #27
0
    def _get_native_values(
        self,
        subset: Set[str],
        method: Optional[str] = None,
        basis: Optional[str] = None,
        keywords: Optional[str] = None,
        program: Optional[str] = None,
        stoich: Optional[str] = None,
        name: Optional[str] = None,
        force: bool = False,
    ) -> pd.DataFrame:
        self._validate_stoich(stoich, subset=subset, force=force)

        # So that datasets with no records do not require a default program and default keywords
        if len(self.list_records()) == 0:
            return pd.DataFrame(index=self.get_index(subset))

        queries = self._form_queries(method=method,
                                     basis=basis,
                                     keywords=keywords,
                                     program=program,
                                     stoich=stoich,
                                     name=name)

        if len(queries) == 0:
            return pd.DataFrame(index=self.get_index(subset))

        stoich_complex = queries.pop("stoichiometry").values[0]
        stoich_monomer = "".join(
            [x for x in stoich_complex if not x.isdigit()]) + "1"

        def _query_apply_coeffients(stoich, query):

            # Build the starting table
            indexer, names = self._molecule_indexer(stoich=stoich,
                                                    coefficients=True,
                                                    force=force)
            df = self._get_records(indexer,
                                   query,
                                   include=["return_result"],
                                   merge=True)
            df.index = pd.MultiIndex.from_tuples(df.index, names=names)
            df.reset_index(inplace=True)

            # Block out null values `groupby.sum()` will return 0 rather than NaN in all cases
            null_mask = df[["name", "return_result"]].copy()
            null_mask["return_result"] = null_mask["return_result"].isnull()
            null_mask = null_mask.groupby(["name"
                                           ])["return_result"].sum() != False

            # Multiply by coefficients and sum
            df["return_result"] *= df["coefficient"]
            df = df.groupby(["name"])["return_result"].sum()
            df[null_mask] = np.nan
            return df

        names = []
        new_queries = []
        new_data = pd.DataFrame(index=subset)

        for _, query in queries.iterrows():

            query = query.replace({np.nan: None}).to_dict()
            qname = query["name"]
            names.append(qname)

            if force or not self._subset_in_cache(qname, subset):
                self._column_metadata[qname] = query
                new_queries.append(query)

        if not self._use_view(force):
            units: Dict[str, str] = {}
            for query in new_queries:
                qname = query.pop("name")
                if self.data.ds_type == _ReactionTypeEnum.ie:
                    # This implements 1-body counterpoise correction
                    # TODO: this will need to contain the logic for VMFC or other method-of-increments strategies
                    data_complex = _query_apply_coeffients(
                        stoich_complex, query)
                    data_monomer = _query_apply_coeffients(
                        stoich_monomer, query)
                    data = data_complex - data_monomer
                elif self.data.ds_type == _ReactionTypeEnum.rxn:
                    data = _query_apply_coeffients(stoich_complex, query)
                else:
                    raise ValueError(
                        f"ReactionDataset ds_type is not a member of _ReactionTypeEnum. (Got {self.data.ds_type}.)"
                    )

                new_data[qname] = data * constants.conversion_factor(
                    "hartree", self.units)
                query["name"] = qname
                units[qname] = self.units
        else:
            for query in new_queries:
                query["native"] = True
            new_data, units = self._view.get_values(new_queries)
            for query in new_queries:
                qname = query["name"]
                new_data[
                    qname] = new_data[qname] * constants.conversion_factor(
                        units[qname], self.units)

        for query in new_queries:
            qname = query["name"]
            self._column_metadata[qname].update({
                "native": True,
                "units": units[qname]
            })

        self._update_cache(new_data)
        return self.df.loc[subset, names]
Example #28
0
"""
  Functions to write ProjRot input files
"""

import os
from qcelemental import constants as qcc
from ioformat import build_mako_str
from ioformat import remove_trail_whitespace
from projrot_io import util


# Conversion factors
BOHR2ANG = qcc.conversion_factor('bohr', 'angstrom')

# OBTAIN THE PATH TO THE DIRECTORY CONTAINING THE TEMPLATES #
SRC_PATH = os.path.dirname(os.path.realpath(__file__))
TEMPLATE_PATH = os.path.join(SRC_PATH, 'templates')


def rpht_input(geoms, grads, hessians,
               saddle_idx=1,
               rotors_str='',
               coord_proj='cartesian',
               proj_rxn_coord=False):
    """ Writes a string for the input file for ProjRot.

        :param geoms: geometry for single species or along a reaction path
        :type geoms: list(list(float))
        :param grads: gradient for single species or along a reaction path
        :type grads: list(list(float))
        :param hessians: Hessian for single species or along a reaction path
Example #29
0
Library of physical constants
"""

from qcelemental import constants as qcc


# physical constants
NAVO = 6.0221409e+23
RC = 1.98720425864083  # gas constant in cal/(mol.K)
RC_kcal = 1.98720425864083e-3  # gas constant in kcal/(mol.K)
RC2 = 82.0573660809596  # gas constant in cm^3.atm/(mol.K)
RC_cal = 1.98720425864083  # gas constant in cal/(mol.K)
RC_atm = 82.0573660809596  # gas constant in cm^3.atm/(mol.K)

# conversion factors
KCAL2CAL = qcc.conversion_factor('kcal/mol', 'cal/mol')
J2CAL = qcc.conversion_factor('J/mol', 'cal/mol')
KJ2CAL = qcc.conversion_factor('kJ/mol', 'cal/mol')
KEL2CAL = qcc.conversion_factor('kelvin', 'cal/mol')
ANG2BOHR = qcc.conversion_factor('angstrom', 'bohr')
BOHR2ANG = qcc.conversion_factor('bohr', 'angstrom')
DEG2RAD = qcc.conversion_factor('degree', 'radian')
RAD2DEG = qcc.conversion_factor('radian', 'degree')
WAVEN2KCAL = qcc.conversion_factor('wavenumber', 'kcal/mol')
KCAL2WAVEN = qcc.conversion_factor('kcal/mol', 'wavenumber')
EH2KCAL = qcc.conversion_factor('hartree', 'kcal/mol')
KCAL2EH = qcc.conversion_factor('kcal/mol', 'hartree')
KCAL2KJ = qcc.conversion_factor('kcal/mol', 'kJ/mol')
WAVEN2EH = qcc.conversion_factor('wavenumber', 'hartree')
EH2WAVEN = qcc.conversion_factor('hartree', 'wavenumber')
# AMU2KG = qcc.conversion_factor('atomic mass unit', 'kilogram')
    def visualize(self,
                  entries: Union[str, List[str]],
                  specs: Union[str, List[str]],
                  relative: bool = True,
                  units: str = "kcal / mol",
                  digits: int = 3,
                  use_measured_angle: bool = False,
                  return_figure: Optional[bool] = None) -> 'plotly.Figure':
        """
        Parameters
        ----------
        entries : Union[str, List[str]]
            A single or list of indices to plot.
        specs : Union[str, List[str]]
            A single or list of specifications to plot.
        relative : bool, optional
            Shows relative energy, lowest energy per scan is zero.
        units : str, optional
            The units of the plot.
        digits : int, optional
            Rounds the energies to n decimal places for display.
        use_measured_angle : bool, optional
            If True, the measured final angle instead of the constrained optimization angle.
            Can provide more accurate results if the optimization was ill-behaved,
            but pulls additional data from the server and may take longer.
        return_figure : Optional[bool], optional
            If True, return the raw plotly figure. If False, returns a hosted iPlot. If None, return a iPlot display in Jupyter notebook and a raw plotly figure in all other circumstances.

        Returns
        -------
        plotly.Figure
            The requested figure.
        """

        show_spec = True
        if isinstance(specs, str):
            specs = [specs]
            show_spec = False

        if isinstance(entries, str):
            entries = [entries]

        # Query all of the specs and make sure they are valid
        for spec in specs:
            self.query(spec)

        traces = []

        xmin = 1e12
        xmax = -1e12
        # Loop over specifications
        for spec in specs:
            # Loop over indices (groups colors by entry)
            for index in entries:

                record = self.get_entry(index)

                td = self.df.loc[index, spec]
                min_energy = 1e12

                # Pull the dict apart
                x = []
                y = []
                for k, v in td.get_final_energies().items():
                    if len(k) >= 2:
                        raise TypeError(
                            "Dataset.visualize is currently only available for 1-D scans."
                        )

                    if use_measured_angle:
                        # Recalculate the dihedral angle
                        dihedral_indices = record.td_keywords.dihedrals[0]
                        mol = td.get_final_molecules(k)
                        x.append(mol.measure(dihedral_indices))

                    else:
                        x.append(k[0])

                    y.append(v)

                    # Update minmum energy
                    if v < min_energy:
                        min_energy = v

                trace = {"mode": "lines+markers"}
                if show_spec:
                    trace["name"] = f"{index}-{spec}"
                else:
                    trace["name"] = f"{index}"

                x = np.array(x)
                y = np.array(y)

                # Sort by angle
                sorter = np.argsort(x)
                x = x[sorter]
                y = y[sorter]
                if relative:
                    y -= min_energy

                # Find the x dimension
                if x.max() > xmax:
                    xmax = x.max()
                if x.min() < xmin:
                    xmin = x.min()

                cf = constants.conversion_factor("hartree", units)
                trace["x"] = x
                trace["y"] = np.around(y * cf, digits)

                traces.append(trace)

        title = "TorsionDriveDataset 1-D Plot"
        if show_spec is False:
            title += f" [spec={specs[0]}]"

        if relative:
            ylabel = f"Relative Energy [{units}]"
        else:
            ylabel = f"Absolute Energy [{units}]"

        custom_layout = {
            "title": title,
            "yaxis": {
                "title": ylabel,
                "zeroline": True
            },
            "xaxis": {
                "title": "Dihedral Angle [degrees]",
                "zeroline": False,
                "range": [xmin - 10, xmax + 10]
            }
        }

        return scatter_plot(traces,
                            custom_layout=custom_layout,
                            return_figure=return_figure)