Bond Class

This tutorial is meant to illustrate some of the properties and functionality available within the Bond class.

[111]:
# Imports necessary packages and checks the version of molli.
import molli as ml
ml.aux.assert_molli_version_min("1.0a")

#Loads in the dendrobine molecule
mol = ml.load(ml.files.benzene_mol2)

Each Molecule has a list of bonds in a defined order. Individual bonds can be retrieved in a fashion similar in how to retrieve an Atom:

[112]:
ex_bond1 = mol.get_bond(0)
ex_bond1
[112]:
Bond(a1=Atom(element=C, isotope=None, label='C', formal_charge=0, formal_spin=0), a2=1, label=None, btype=Aromatic, stereo=Unknown, f_order=1.0)

Bonds have quite a few important properties

[113]:
ex_bond1.as_dict()
[113]:
{'a1': {'element': C,
  'isotope': None,
  'label': 'C',
  'atype': <AtomType.Aromatic: 2>,
  'stereo': <AtomStereo.Unknown: 0>,
  'geom': <AtomGeom.Unknown: 0>,
  'formal_charge': 0,
  'formal_spin': 0,
  'attrib': {},
  '_parent': <weakref at 0x7fd77b19a0c0; to 'Molecule' at 0x7fd77afedb50>},
 'a2': {'element': C,
  'isotope': None,
  'label': 'C',
  'atype': <AtomType.Aromatic: 2>,
  'stereo': <AtomStereo.Unknown: 0>,
  'geom': <AtomGeom.Unknown: 0>,
  'formal_charge': 0,
  'formal_spin': 0,
  'attrib': {},
  '_parent': <weakref at 0x7fd77b19a0c0; to 'Molecule' at 0x7fd77afedb50>},
 'label': None,
 'btype': <BondType.Aromatic: 20>,
 'stereo': <BondStereo.Unknown: 0>,
 'f_order': 1.0,
 'attrib': {},
 '_parent': <weakref at 0x7fd77b19a0c0; to 'Molecule' at 0x7fd77afedb50>}

Here’s an example of individual atoms of the bond can be quickly called upon

[114]:
#This calls Atom 1 of the bond
atom1 = ex_bond1.a1

#This calls Atom2 of a bond
atom2 = ex_bond1.a2
atom2
[114]:
Atom(element=C, isotope=None, label='C', formal_charge=0, formal_spin=0)

An important note about bonds is that a1 (atom 1) and a2 (atom2) are somewhat arbitrary depending on how the molecule was constructed/read in. Another option that can be come useful when looking is using the modulus (%) operator.

[115]:
#This finds the other atom a part of the bond
other_atom = ex_bond1 % atom2

#This checks if atom1 is equal to the other_atom
atom1 == other_atom
[115]:
True

molli implements that functionality to find atoms connected other atoms quickly

[116]:
#This finds the atoms also connected to atom2
connected_atoms = [a for a in mol.connected_atoms(atom2)]
connected_atoms
[116]:
[Atom(element=C, isotope=None, label='C', formal_charge=0, formal_spin=0),
 Atom(element=C, isotope=None, label='C', formal_charge=0, formal_spin=0),
 Atom(element=H, isotope=None, label='H', formal_charge=0, formal_spin=0)]

molli also implements functionality to find the bonds associated with other atoms

[117]:
n_bonds_atom2 = mol.n_bonds_with_atom(atom2)
print(f'The number of bonds with Atom 2 = {n_bonds_atom2}')

bonds_from_atom = [b for b in mol.bonds_with_atom(atom2)]
bonds_from_atom
The number of bonds with Atom 2 = 3
[117]:
[Bond(a1=Atom(element=C, isotope=None, label='C', formal_charge=0, formal_spin=0), a2=1, label=None, btype=Aromatic, stereo=Unknown, f_order=1.0),
 Bond(a1=1, a2=2, label=None, btype=Aromatic, stereo=Unknown, f_order=1.0),
 Bond(a1=1, a2=7, label=None, btype=Single, stereo=Unknown, f_order=1.0)]

Bond Deletion

Bonds can also be quickly deleted either through the direct deletion of atoms or bonds

[118]:
# Prints the index of the bond and the bond itself
for i, b in enumerate(mol.bonds):
    print(format(i, "<5"), b)
0     Bond(a1=Atom(element=C, isotope=None, label='C', formal_charge=0, formal_spin=0), a2=1, label=None, btype=Aromatic, stereo=Unknown, f_order=1.0)
1     Bond(a1=1, a2=2, label=None, btype=Aromatic, stereo=Unknown, f_order=1.0)
2     Bond(a1=2, a2=3, label=None, btype=Aromatic, stereo=Unknown, f_order=1.0)
3     Bond(a1=3, a2=4, label=None, btype=Aromatic, stereo=Unknown, f_order=1.0)
4     Bond(a1=4, a2=5, label=None, btype=Aromatic, stereo=Unknown, f_order=1.0)
5     Bond(a1=5, a2=Atom(element=C, isotope=None, label='C', formal_charge=0, formal_spin=0), label=None, btype=Aromatic, stereo=Unknown, f_order=1.0)
6     Bond(a1=Atom(element=C, isotope=None, label='C', formal_charge=0, formal_spin=0), a2=6, label=None, btype=Single, stereo=Unknown, f_order=1.0)
7     Bond(a1=1, a2=7, label=None, btype=Single, stereo=Unknown, f_order=1.0)
8     Bond(a1=2, a2=8, label=None, btype=Single, stereo=Unknown, f_order=1.0)
9     Bond(a1=3, a2=9, label=None, btype=Single, stereo=Unknown, f_order=1.0)
10    Bond(a1=4, a2=10, label=None, btype=Single, stereo=Unknown, f_order=1.0)
11    Bond(a1=5, a2=11, label=None, btype=Single, stereo=Unknown, f_order=1.0)

Deleting an Atom will delete both the Atom and the bonds associated with that `Atom

[119]:
# Deletes the first atom in the molecule
mol.del_atom(0)

# Prints the updated bond list
for i, b in enumerate(mol.bonds):
    print(format(i, "<5"), b)
0     Bond(a1=Atom(element=C, isotope=None, label='C', formal_charge=0, formal_spin=0), a2=1, label=None, btype=Aromatic, stereo=Unknown, f_order=1.0)
1     Bond(a1=1, a2=2, label=None, btype=Aromatic, stereo=Unknown, f_order=1.0)
2     Bond(a1=2, a2=3, label=None, btype=Aromatic, stereo=Unknown, f_order=1.0)
3     Bond(a1=3, a2=4, label=None, btype=Aromatic, stereo=Unknown, f_order=1.0)
4     Bond(a1=Atom(element=C, isotope=None, label='C', formal_charge=0, formal_spin=0), a2=6, label=None, btype=Single, stereo=Unknown, f_order=1.0)
5     Bond(a1=1, a2=7, label=None, btype=Single, stereo=Unknown, f_order=1.0)
6     Bond(a1=2, a2=8, label=None, btype=Single, stereo=Unknown, f_order=1.0)
7     Bond(a1=3, a2=9, label=None, btype=Single, stereo=Unknown, f_order=1.0)
8     Bond(a1=4, a2=10, label=None, btype=Single, stereo=Unknown, f_order=1.0)

Deleting a Bond will ONLY delete the `Bond`` and still maintain the same number of atoms

[120]:
print(f'The number of atoms before deleting a bond = {mol.n_atoms}')

#This gets the first bond in the list
ex_bond = mol.get_bond(0)

# Deletes the first bond in the molecule
mol.del_bond(ex_bond)
print(f'The number of atoms after deleting a bond = {mol.n_atoms}')

# Prints the updated bond list
for i, b in enumerate(mol.bonds):
    print(format(i, "<5"), b)
The number of atoms before deleting a bond = 11
The number of atoms after deleting a bond = 11
0     Bond(a1=1, a2=2, label=None, btype=Aromatic, stereo=Unknown, f_order=1.0)
1     Bond(a1=2, a2=3, label=None, btype=Aromatic, stereo=Unknown, f_order=1.0)
2     Bond(a1=3, a2=4, label=None, btype=Aromatic, stereo=Unknown, f_order=1.0)
3     Bond(a1=Atom(element=C, isotope=None, label='C', formal_charge=0, formal_spin=0), a2=6, label=None, btype=Single, stereo=Unknown, f_order=1.0)
4     Bond(a1=1, a2=7, label=None, btype=Single, stereo=Unknown, f_order=1.0)
5     Bond(a1=2, a2=8, label=None, btype=Single, stereo=Unknown, f_order=1.0)
6     Bond(a1=3, a2=9, label=None, btype=Single, stereo=Unknown, f_order=1.0)
7     Bond(a1=4, a2=10, label=None, btype=Single, stereo=Unknown, f_order=1.0)

Other Miscellaneous Properties of Bonds

Bond coordinates can be retrieved as follows

[121]:
#This gets the first bond in the list
ex_bond = mol.get_bond(0)

# These are the coordinates of the atoms attached to the bond
mol.bond_coords(ex_bond)
[121]:
array([[-3.8438, -0.82  , -0.    ],
       [-2.7152, -1.6396, -0.    ]])

The Bond length can be retrieved as follows

[122]:
#This gets the length of a bond
mol.bond_length(ex_bond)
[122]:
1.3948054057824697

Bonds can also be found using atoms and indexed

[123]:
#This finds the bond whose atoms 5 and 11 are associated with the bond
ex_bond = mol.lookup_bond(3, 9)

#This finds the index of the bond found
mol.index_bond(ex_bond)
[123]:
6

The vector created by the bond can also be called

[124]:
mol.bond_vector(ex_bond)
[124]:
array([ 0.8793, -0.6386,  0.    ])

Much like the Atom class, the Bond class allows for storage of arbitrary objects. Here is an example

[125]:
#Gets the first bond
ex_bond = mol.get_bond(0)

print(f'Current attribute list for an Example Bond')
ex_bond.attrib["List"] = [0,1,2]
ex_bond.attrib["Tuple"] = ('a','b','c')
ex_bond.attrib["Dictionary"] = {"Data": (0.1, 0.2, 0.3)}

ex_bond.attrib
Current attribute list for an Example Bond
[125]:
{'List': [0, 1, 2],
 'Tuple': ('a', 'b', 'c'),
 'Dictionary': {'Data': (0.1, 0.2, 0.3)}}