Beispiel #1
0
def add_bonds(gra, keys, ord_dct=None, ste_par_dct=None, check=True):
    """ add bonds to this molecular graph
    """
    bnd_keys = set(bond_keys(gra))
    bnd_ord_dct = bond_orders(gra)
    bnd_ste_par_dct = bond_stereo_parities(gra)

    keys = set(map(frozenset, keys))
    ord_dct = {} if ord_dct is None else ord_dct
    ste_par_dct = {} if ste_par_dct is None else ste_par_dct

    ord_dct = dict_.transform_keys(ord_dct, frozenset)
    ste_par_dct = dict_.transform_keys(ste_par_dct, frozenset)

    if check:
        assert not keys & bnd_keys, (
            '{} and {} have a non-empty intersection'.format(keys, bnd_keys))

    assert set(ord_dct.keys()) <= keys
    assert set(ste_par_dct.keys()) <= keys

    bnd_keys.update(keys)
    bnd_ord_dct.update(ord_dct)
    bnd_ste_par_dct.update(ste_par_dct)

    atm_dct = atoms(gra)
    bnd_dct = bonds_from_data(bnd_keys=bnd_keys,
                              bnd_ord_dct=bnd_ord_dct,
                              bnd_ste_par_dct=bnd_ste_par_dct)

    gra = from_atoms_and_bonds(atm_dct=atm_dct, bnd_dct=bnd_dct)
    return gra
Beispiel #2
0
def yaml_dictionary(gra, one_indexed=True):
    """ generate a YAML dictionary representing a given graph
    """
    if one_indexed:
        # shift to one-indexing when we print
        atm_key_dct = {atm_key: atm_key + 1 for atm_key in atom_keys(gra)}
        gra = relabel(gra, atm_key_dct)

    yaml_atm_dct = atoms(gra)
    yaml_bnd_dct = bonds(gra)

    # prepare the atom dictionary
    yaml_atm_dct = dict(sorted(yaml_atm_dct.items()))
    yaml_atm_dct = dict_.transform_values(
        yaml_atm_dct, lambda x: dict(zip(ATM_PROP_NAMES, x)))

    # perpare the bond dictionary
    yaml_bnd_dct = dict_.transform_keys(yaml_bnd_dct,
                                        lambda x: tuple(sorted(x)))
    yaml_bnd_dct = dict(sorted(yaml_bnd_dct.items()))
    yaml_bnd_dct = dict_.transform_keys(yaml_bnd_dct,
                                        lambda x: '-'.join(map(str, x)))
    yaml_bnd_dct = dict_.transform_values(
        yaml_bnd_dct, lambda x: dict(zip(BND_PROP_NAMES, x)))

    yaml_gra_dct = {'atoms': yaml_atm_dct, 'bonds': yaml_bnd_dct}
    return yaml_gra_dct
Beispiel #3
0
def relabel(gra, atm_key_dct):
    """ relabel the graph with new atom keys
    """
    orig_atm_keys = atom_keys(gra)
    assert set(atm_key_dct.keys()) <= orig_atm_keys, ('{}\n{}'.format(
        set(atm_key_dct.keys()), orig_atm_keys))

    new_atm_key_dct = dict(zip(orig_atm_keys, orig_atm_keys))
    new_atm_key_dct.update(atm_key_dct)

    _relabel_atom_key = new_atm_key_dct.__getitem__

    def _relabel_bond_key(bnd_key):
        return frozenset(map(_relabel_atom_key, bnd_key))

    atm_dct = dict_.transform_keys(atoms(gra), _relabel_atom_key)
    bnd_dct = dict_.transform_keys(bonds(gra), _relabel_bond_key)
    return from_atoms_and_bonds(atm_dct, bnd_dct)
Beispiel #4
0
def from_yaml_dictionary(yaml_gra_dct, one_indexed=True):
    """ read the graph from a yaml dictionary
    """
    atm_dct = yaml_gra_dct['atoms']
    bnd_dct = yaml_gra_dct['bonds']

    atm_dct = dict_.transform_values(
        atm_dct, lambda x: tuple(map(x.__getitem__, ATM_PROP_NAMES)))

    bnd_dct = dict_.transform_keys(bnd_dct,
                                   lambda x: frozenset(map(int, x.split('-'))))

    bnd_dct = dict_.transform_values(
        bnd_dct, lambda x: tuple(map(x.__getitem__, BND_PROP_NAMES)))

    gra = _create.from_atoms_and_bonds(atm_dct, bnd_dct)

    if one_indexed:
        # revert one-indexing if the input is one-indexed
        atm_key_dct = {atm_key: atm_key - 1 for atm_key in atom_keys(gra)}
        gra = relabel(gra, atm_key_dct)

    return gra
Beispiel #5
0
def distance_ranges_from_coordinates(gra, dist_dct, ang_dct=None, dih_dct=None,
                                     angstrom=True, degree=True,
                                     rings_keys=(), keys=None, check=False):
    """ generate a set of distance ranges from coordinate values

    :param gra: molecular graph
    atom keys specifying the order of indices in the matrix
    :param dist_dct: a dictionary of desired distances for certain atoms; the
        keys are pairs of atoms, the values are distances in angstroms
    :type dist_dct: dict[(int, int): float]
    :param ang_dct: a dictionary of desired angles for certain atoms; the keys
        are triples of atoms; if the first or last element in a triple is None,
        an appopriate neighboring atom will be found
    :param dih_dct: a dictionary of desired angles for certain atoms; the keys
        are quadruples of atoms; if the first or last element in a triple is
        None, an appopriate neighboring atom will be found
    :type dist_dct: dict[(int, int, int): float]
    :param rings_keys: keys for rings in the graph; angle ranges will
        automatically be set to allow ring formation
    :param keys: set of keys that can be used to fill in the angle keys; if
        None, all graph keys will be considered available for use
    :param check: check the angle keys to make sure they can all be filled in?
    """
    keys = atom_keys(gra) if keys is None else keys

    ang_dct = {} if ang_dct is None else ang_dct
    dih_dct = {} if dih_dct is None else dih_dct

    # Fill in angle keys
    ang_key_filler_ = angle_key_filler_(gra, keys, check=check)
    ang_dct = dict_.transform_keys(ang_dct, ang_key_filler_)
    if None in ang_dct:
        ang_dct.pop(None)

    # Fill in dihedral keys
    dih_dct = dict_.transform_keys(dih_dct, ang_key_filler_)
    if None in dih_dct:
        dih_dct.pop(None)

    # Convert angles into distances
    dist_dct = dict_.transform_keys(dist_dct, frozenset)
    for (key1, key2, key3), a123 in ang_dct.items():
        a123 *= phycon.DEG2RAD if degree else 1.

        k12 = frozenset({key1, key2})
        k23 = frozenset({key2, key3})
        k13 = frozenset({key1, key3})

        d12 = (dist_dct[k12] if k12 in dist_dct else
               heuristic_bond_distance(gra, key1, key2, angstrom=angstrom))
        d23 = (dist_dct[k23] if k23 in dist_dct else
               heuristic_bond_distance(gra, key2, key3, angstrom=angstrom))

        d13 = numpy.sqrt(d12**2 + d23**2 - 2*d12*d23*numpy.cos(a123))

        dist_dct[k13] = d13

    # Convert convert fixed distances into ranges
    dist_range_dct = {k: (d, d) for k, d in dist_dct.items()}

    # Convert dihedrals into distances
    for (key1, key2, key3, key4), val in dih_dct.items():
        # Allow user to leave dihedrals open-ended, as a lower or upper bound
        if isinstance(val, numbers.Number):
            d1234 = val
        else:
            assert hasattr(val, '__len__') and len(val) == 2
            d1234 = next(v for v in val if v is not None)

        d1234 *= phycon.DEG2RAD if degree else 1.

        k12 = frozenset({key1, key2})
        k23 = frozenset({key2, key3})
        k34 = frozenset({key3, key4})
        k13 = frozenset({key1, key3})
        k24 = frozenset({key2, key4})
        k14 = frozenset({key1, key4})

        d12 = (dist_dct[k12] if k12 in dist_dct else
               heuristic_bond_distance(gra, key1, key2, angstrom=angstrom))
        d23 = (dist_dct[k23] if k23 in dist_dct else
               heuristic_bond_distance(gra, key2, key3, angstrom=angstrom))
        d34 = (dist_dct[k34] if k34 in dist_dct else
               heuristic_bond_distance(gra, key3, key4, angstrom=angstrom))
        d13 = (dist_dct[k13] if k13 in dist_dct else
               heuristic_bond_distance(gra, key1, key3, angstrom=angstrom))
        d24 = (dist_dct[k24] if k24 in dist_dct else
               heuristic_bond_distance(gra, key2, key4, angstrom=angstrom))

        term1 = (d12**2 + d23**2 - d13**2)*(d23**2 + d34**2 - d24**2)
        term2 = 2*d23**2 * (d13**2 + d24**2 - d23**2)
        denom = numpy.sqrt(
            (4*d12**2 * d23**2 - (d12**2 + d23**2 - d13**2)**2) *
            (4*d23**2 * d34**2 - (d23**2 + d34**2 - d24**2)**2))

        d14 = numpy.sqrt((term1 + term2 - numpy.cos(d1234) * denom) /
                         (2 * d23**2))

        if isinstance(val, numbers.Number) or val[0] == val[1]:
            dist_range_dct[k14] = (d14, d14)
        elif val[0] is None:
            ld14 = closest_approach(gra, key1, key4)
            dist_range_dct[k14] = (ld14, d14)
        elif val[1] is None:
            ud14 = 999.
            dist_range_dct[k14] = (d14, ud14)
        else:
            raise ValueError("Invalid dih_dict: {}".format(str(dih_dct)))

    for rng_keys in rings_keys:
        assert hasattr(keys, '__iter__'), (
            "Please pass in rings keys as a list of lists")

        rsz = len(rng_keys)
        a123 = (rsz - 2.) * 180. / rsz
        la123 = (a123 - 10.) * phycon.DEG2RAD
        ua123 = (a123 + 10.) * phycon.DEG2RAD

        for key1, key2, key3 in mit.windowed(rng_keys + rng_keys[:2], 3):
            k12 = frozenset({key1, key2})
            k23 = frozenset({key2, key3})
            k13 = frozenset({key1, key3})

            d12 = (dist_dct[k12] if k12 in dist_dct else
                   heuristic_bond_distance(gra, key1, key2, angstrom=angstrom))
            d23 = (dist_dct[k23] if k23 in dist_dct else
                   heuristic_bond_distance(gra, key2, key3, angstrom=angstrom))

            ld13 = numpy.sqrt(d12**2 + d23**2 - 2*d12*d23*numpy.cos(la123))
            ud13 = numpy.sqrt(d12**2 + d23**2 - 2*d12*d23*numpy.cos(ua123))
            dist_range_dct[k13] = (ld13, ud13)

    return dist_range_dct