Example #1
0
    def __init__(self):
        self.interaction_manager = get_interaction_manager(
            *get_twod_signal_manager().get_interaction_data())

        #TODO : REMOVE WEIRD POINTS
        for x in [[19, 6], [19, 7], [21, 6]]:
            print(self.interaction_manager.interaction_matrix[x])
            self.interaction_manager.interaction_matrix[x[0]][x[1]] = 0
            self.interaction_manager.interaction_matrix[x[1]][x[0]] = 0

        self.interaction_matrix = self.interaction_manager.interaction_matrix
        self.interaction_matrix[self.interaction_matrix == 9] = 0
        self.type_array = self.interaction_manager.type_array
        self.shift_data = self.interaction_manager.shift_data
        self.number_atoms = self.interaction_manager.number_atoms

        self.viewer = QtViewer()

        ac = np.random.rand(self.number_atoms, 3) * 3
        self.coordinate_manager = CoordinateManager(ac,
                                                    self.interaction_manager)

        self.renderer = self.viewer.add_renderer(
            BallAndStickRenderer, self.coordinate_manager.get_coordinates(),
            self.type_array, np.array([]))
 def __init__(self):
     self.file_manager = FileManager()
     system, self.atom_coordinates = self.read_coordinates()
     #  self.interaction_manager = get_interaction_manager(get_twod_signal_manager().get_interaction_matrix(), system.type_array.tolist(), np.zeros(shape=system.type_array.shape))
     self.interaction_manager = get_interaction_manager(*get_twod_signal_manager().get_interaction_data())
     self.viewer = QtViewer()
     self.best_response_value = 1000000.0
     self.best_atom_coordinates = np.copy(self.atom_coordinates)
     self.fragments = self.generate_fragments(system)
     self.atom_coordinates = self.fix_hydrogen_bond_lengths(system, self.atom_coordinates)
Example #3
0
class MolecularMinimizer:
    def __init__(self, molecules, interaction_manager):

        self.molecules = molecules
        for molecule in self.molecules:
            molecule.r_array *= 1.85
        self.v = QtViewer()
        self.renderers = {}
        for molecule in self.molecules:
            ar = self.v.add_renderer(BallAndStickRenderer, molecule.r_array, molecule.type_array, molecule.bonds)
            self.renderers[molecule] = ar
        self.best_response_value = 0
        self.best_atom_coordinates = None
        self.twod_signal_manager = get_twod_signal_manager()
        self.interaction_manager = interaction_manager

    def update(self):
        for molecule in self.molecules:
            if len(molecule.bonds)>=2:

                i = random.randrange(len(molecule.bonds))
                a = bond_bisect(molecule.bonds, molecule.bonds[i], True)

                r_old = np.copy(molecule.r_array)

                uf = a[1]
                point_a = np.copy(molecule.r_array[molecule.bonds[i][0]])
                point_b = np.copy(molecule.r_array[molecule.bonds[i][1]])
                M = rotation_matrix(np.pi/20, point_b-point_a)[:3, :3]

                molecule.r_array = np.array(molecule.export['vectors'])

                molecule.r_array -= point_a
                molecule.r_array[uf] = np.dot(molecule.r_array[uf], M.T)
                molecule.r_array += point_a
                self.set_vectors(molecule, molecule.r_array)
                new_response_value = calculate_response_value(molecule.r_array)
                if new_response_value < self.best_response_value:
                    self.best_response_value = new_response_value
                else:
                    molecule.r_array = r_old
                    self.set_vectors(r_old)
                self.renderers[molecule].update_positions(molecule.r_array)
                self.v.widget.repaint()

            else:
                None
    def set_vectors(self, molecule, arr):
        for i,vec in enumerate(arr):
            molecule.export['vectors'][i][:] = vec

    def run(self):
        self.v.schedule(self.update)
        self.v.run()
Example #4
0
    def __init__(self, molecules, interaction_manager):

        self.molecules = molecules
        for molecule in self.molecules:
            molecule.r_array *= 1.85
        self.v = QtViewer()
        self.renderers = {}
        for molecule in self.molecules:
            ar = self.v.add_renderer(BallAndStickRenderer, molecule.r_array, molecule.type_array, molecule.bonds)
            self.renderers[molecule] = ar
        self.best_response_value = 0
        self.best_atom_coordinates = None
        self.twod_signal_manager = get_twod_signal_manager()
        self.interaction_manager = interaction_manager
Example #5
0
    def __init__(self, coordinates, interaction_manager):
        self.viewer = QtViewer()
        self.selected_atom = 0
        self.active = True
        self.coordinates = None
        self.atoms = None
        self.bonds = None
        self.interaction_manager = interaction_manager

        self.viewer.widget.on_mouse.append(self.select)

        try:
            self.update(coordinates, interaction_manager)
            if len(coordinates) != len(self.atoms):
                raise Exception(
                    "Atom List does not correspond to coordinate array")

        except Exception as e:
            self.disable(e)
Example #6
0
    def __init__(self):
        self.interaction_manager = get_interaction_manager(
            *get_twod_signal_manager().get_interaction_data())
        im = self.interaction_manager.interaction_matrix
        im[19][6] = 0
        im[19][7] = 0
        """
        for x in [9,10,11,12,13,17,18,19,20,21]:
            for y in range(self.interaction_manager.number_atoms):
                if im[x][y] == 3:
                    im[x][y] = 0
                    im[y][x] = 0

        """

        self.interaction_matrix = self.interaction_manager.interaction_matrix
        self.type_array = self.interaction_manager.type_array
        self.shift_data = self.interaction_manager.shift_data
        self.number_atoms = self.interaction_manager.number_atoms
        self.global_bond_indices = self.interaction_manager.bonds
        self.bond_orders = self.interaction_manager.bond_orders
        self.viewer = QtViewer()
        self.best_response_value = 1000000.0
        ac = np.random.rand(self.number_atoms, 3) * 0.001
        #ac = FileManager().read_numpy_from_xyz('manual2.xyz') * 0.1
        self.iteration_number = 0
        self.coordinate_manager = CoordinateManager(self, ac,
                                                    self.interaction_manager)
        self.fragments = self.generate_fragments_list()
        print(self.coordinate_manager.calculate_response_value(True))
        self.interaction_manager.print_matrix()
        input("")

        self.delay = 0
        """
        for x in [0,1,2,3,4,5]:
            self.interaction_manager.interaction_matrix[self.interaction_manager.interaction_matrix==x] = 9
        """
        self.nullfrag = Fragment([], [], [], [], self.viewer,
                                 self.coordinate_manager,
                                 self.interaction_manager, [])
Example #7
0
import numpy as np
v1 = np.array([1.0, 0.0, -1.0/np.sqrt(2)])
v2 = np.array([-1.0, 0.0, -1.0/np.sqrt(2)])
v3 = np.array([0.0, 1.0, 1.0/np.sqrt(2)])
v4 = np.array([0.0, -1.0, 1.0/np.sqrt(2)])

from chemlab.graphics import QtViewer
from chemlab.graphics.renderers import PointRenderer
from chemlab.graphics.colors import black, green, blue, red

colors = [black, green, blue, red]
v = QtViewer()
v.add_renderer(PointRenderer, np.array([v1, v2, v3, v4]), colors)

from chemlab.graphics.renderers import TriangleRenderer

vertices = np.array([
    v1, v4, v3,
    v3, v4, v2,
    v1, v3, v2,
    v2, v4, v1
])

colors = [green] * 12

# Normals: cross-product for each face
n1 = -np.cross(v4 - v1, v3 - v1)
n1 /= np.linalg.norm(n1)

n2 = -np.cross(v4 - v3, v2 - v3)
n2 /= np.linalg.norm(n2)
Example #8
0
from chemlab.db import CirDB
from chemlab.graphics import QtViewer
from chemlab.graphics.renderers import AtomRenderer
from chemlab.graphics.postprocessing import FXAAEffect, SSAOEffect

# A series of compounds to display
compounds = ["methane", "ethane", "propane", "butane"]

db = CirDB()

# Prepare the viewer
v = QtViewer()
v.widget.initializeGL()
v.add_post_processing(SSAOEffect, kernel_size=128, kernel_radius=1.0)
v.add_post_processing(FXAAEffect)

for compound in compounds:
    mol = db.get("molecule", compound)
    rend = v.add_renderer(AtomRenderer, mol.r_array, mol.type_array)

    v.widget.camera.autozoom(mol.r_array)
    # Give some extra zoom
    v.widget.camera.mouse_zoom(1.0)

    v.widget.toimage(300, 300).save(compound + '.png')

    # Cleanup
    v.remove_renderer(rend)
Example #9
0
class ChemLabMinimiser:
    def __init__(self):
        self.interaction_manager = get_interaction_manager(
            *get_twod_signal_manager().get_interaction_data())

        #TODO : REMOVE WEIRD POINTS
        for x in [[19, 6], [19, 7], [21, 6]]:
            print(self.interaction_manager.interaction_matrix[x])
            self.interaction_manager.interaction_matrix[x[0]][x[1]] = 0
            self.interaction_manager.interaction_matrix[x[1]][x[0]] = 0

        self.interaction_matrix = self.interaction_manager.interaction_matrix
        self.interaction_matrix[self.interaction_matrix == 9] = 0
        self.type_array = self.interaction_manager.type_array
        self.shift_data = self.interaction_manager.shift_data
        self.number_atoms = self.interaction_manager.number_atoms

        self.viewer = QtViewer()

        ac = np.random.rand(self.number_atoms, 3) * 3
        self.coordinate_manager = CoordinateManager(ac,
                                                    self.interaction_manager)

        self.renderer = self.viewer.add_renderer(
            BallAndStickRenderer, self.coordinate_manager.get_coordinates(),
            self.type_array, np.array([]))

    def main(self):
        self.viewer.schedule(self.iteration)
        self.viewer.run()

    def iteration(self):
        self.force_step()

    def force_step(self):
        atom_coordinates = self.coordinate_manager.get_coordinates()
        for index, atom in enumerate(atom_coordinates):
            atom_coordinates[index] += self.get_force_vector(
                index, atom, atom_coordinates)
            self.renderer.update_positions(atom_coordinates)
        self.coordinate_manager.update(atom_coordinates)

    def get_force_vector(self, index, atom, atom_coordinates):
        vec = np.zeros(3)
        for i2, atom2 in enumerate(atom_coordinates):

            distance = np.linalg.norm(atom2 - atom)
            if distance == 0 or atom is atom2:
                continue
            #input((atom,atom2))

            subvec = 0.01 * (atom2 - atom) / distance

            minimum = minima[self.interaction_matrix[index][i2]]

            try:
                delta = abs(minimum - distance)
            except Exception as e:
                pass

            try:
                #print(delta, minimum, distance)
                subvec *= (delta * delta)
                vec += subvec
            except:
                pass

        return vec
Example #10
0
class MolecularGraphics:
    def __init__(self, coordinates, interaction_manager):
        self.viewer = QtViewer()
        self.selected_atom = 0
        self.active = True
        self.coordinates = None
        self.atoms = None
        self.bonds = None
        self.interaction_manager = interaction_manager

        self.viewer.widget.on_mouse.append(self.select)

        try:
            self.update(coordinates, interaction_manager)
            if len(coordinates) != len(self.atoms):
                raise Exception(
                    "Atom List does not correspond to coordinate array")

        except Exception as e:
            self.disable(e)

    def select(self, mouse_vector):
        closest_index = None
        closest_dist = 100
        for index, atom in enumerate(self.coordinates):
            dist = np.linalg.norm(mouse_vector[:2] - atom[:2])
            if dist < closest_dist:
                closest_index = index
                closest_dist = dist

        mouse_vector[2] = 0
        self.selected_atom = closest_index
        self.coordinates[0] = mouse_vector
        print(mouse_vector)
        self.update(self.coordinates, self.interaction_manager)

    """
    def scroll_atom(self):
        self.selected_atom += 1
        self.selected_atom %= len(self.interaction_manager.atoms)
        #print(self.selected_atom)
        self.update(self.coordinates, self.interaction_manager)
    """

    def update_coordinates(self, coordinates):
        self.coordinates = coordinates
        if self.active:
            try:

                self.renderer.update_positions(scale * coordinates)
                self.viewer.widget.update()
            except Exception as e:
                self.disable(e)

    def disable(self, e):
        raise e
        input(
            "Exception occured in graphics handler. Graphics will henceforth be disabled:"
        )
        self.active = False

    def run(self, iterfunction):
        if self.active:
            try:
                self.viewer.schedule(iterfunction)
                self.viewer.run()
            except Exception as e:
                self.disable(e)
        if not self.active:
            while True:
                iterfunction()

    def update(self, coordinates, interaction_manager):
        self.coordinates = coordinates
        self.interaction_manager = interaction_manager
        self.atoms = interaction_manager.atoms
        self.bonds = interaction_manager.bonds
        if self.active:
            try:
                bond_colors = np.array([
                    bond_colors_dict[bond.inferred_by] for bond in self.bonds
                ])
                interactions = []
                interaction_colors = []

                for x in [1, 3, 6]:
                    new_interaction_list = interaction_manager.get_all_interaction_atoms(
                        x)
                    new_interaction_indices = [[
                        y[0].index_value, y[1].index_value
                    ] for y in new_interaction_list]

                    interactions += new_interaction_indices
                    interaction_colors += [interaction_colors_dict[x]
                                           ] * len(new_interaction_indices)

                self.viewer.clear()

                type_array = [
                    atom.atom_type for atom in interaction_manager.atoms
                ]
                atom_colors = []
                for index, atom in enumerate(interaction_manager.atoms):
                    if atom.get_free_valency(
                    ) != 0 and atom.atom_type in atom_colors_dict and self.selected_atom != index:
                        atom_colors.append(atom_colors_dict[atom.atom_type])
                    elif index == self.selected_atom:
                        atom_colors.append([57, 255, 20, 255])
                    else:
                        atom_colors.append(default_atom_map[atom.atom_type])

                self.renderer = self.viewer.add_renderer(
                    MyBallAndStickRenderer, scale * coordinates,
                    np.array(type_array), np.array(atom_colors),
                    np.array([bond.get_indices() for bond in self.bonds]),
                    bond_colors, np.array(interactions),
                    np.array(interaction_colors))
            except Exception as e:
                self.disable(e)
class ChemLabMinimiser:
    def __init__(self):
        self.file_manager = FileManager()
        system, self.atom_coordinates = self.read_coordinates()
        #  self.interaction_manager = get_interaction_manager(get_twod_signal_manager().get_interaction_matrix(), system.type_array.tolist(), np.zeros(shape=system.type_array.shape))
        self.interaction_manager = get_interaction_manager(*get_twod_signal_manager().get_interaction_data())
        self.viewer = QtViewer()
        self.best_response_value = 1000000.0
        self.best_atom_coordinates = np.copy(self.atom_coordinates)
        self.fragments = self.generate_fragments(system)
        self.atom_coordinates = self.fix_hydrogen_bond_lengths(system, self.atom_coordinates)




    def generate_fragments(self, system):
        fragments = []
        groups = self.split_groups(system)
        for group in groups:
            new_bonds_reduced = np.array([[group[0].index(x[0]), group[0].index(x[1])] for x in group[1]])
            fragment = Fragment(group[0], system.type_array, np.array(group[1]),new_bonds_reduced, group[2], self.viewer, self.atom_coordinates, self.best_response_value, self.interaction_manager)
            fragments.append(fragment)
        return fragments

    def read_coordinates(self):
        infile = open('../outfile.mol', 'rb')
        mol_io = MolIO(infile)
        system = mol_io.read('molecule')
        atom_coordinates = system.r_array * 1.818

        return system, atom_coordinates

    def fix_hydrogen_bond_lengths(self, system, atom_coordinates):
        for bond in system.bonds:
            bond_types = [system.type_array[bond[0]], system.type_array[bond[1]]]
            if bond_types == ["C", "C"]:
                print("CC Bond: ", np.linalg.norm(atom_coordinates[bond[0]] - atom_coordinates[bond[1]]))
            if "H" in bond_types and "C" in bond_types:
                if bond_types[0] == "H":
                    h, c = bond
                else:
                    c, h = bond
                point_a = np.copy(atom_coordinates[c])
                point_b = np.copy(atom_coordinates[h])

                vec = (point_b-point_a)
                vec /= np.linalg.norm(vec)
                vec *= 0.109
                atom_coordinates[h][:] = point_a + vec
        return atom_coordinates

    def update(self):
        for x in [0, 1, 2]:
            self.atom_coordinates[:, x] -= min(self.atom_coordinates[:, x])
        for fragment in self.fragments:
            self.atom_coordinates, self.best_response_value = fragment.update(self.atom_coordinates, self.best_response_value)

    def main(self):
        self.interaction_manager.print_matrix()
        #self.interaction_manager.plot_all_interactions()
        for fragment in self.fragments:
            self.atom_coordinates = fragment.project_bond_lengths(self.atom_coordinates)
        """
        for fragment in self.fragments:
            self.atom_coordinates = fragment.reduce(self.atom_coordinates)
        """
        self.viewer.schedule(self.update, 1)
        self.viewer.run()
        raise SystemExit

    def split_groups(self, system):
        groups = []
        unselected = [x for x in range(system.n_atoms)]
        while len(unselected) > 0:
            new_atoms = set()
            new_atoms.add(unselected[0])
            atoms = []
            new_bonds = []
            new_bond_orders = []
            while len(new_atoms) > 0:
                a = list(new_atoms)[0]
                atoms.append(a)
                new_atoms.remove(a)

                for bond_index, bond in enumerate(system.bonds):
                    if atoms[-1] == bond[0] and bond[1] not in atoms:
                        new_atoms.add(bond[1])
                    if atoms[-1] == bond[1] and bond[0] not in atoms:
                        new_atoms.add(bond[0])
                    if a in bond and bond.tolist() not in new_bonds:
                        new_bonds.append(bond.tolist())
                        new_bond_orders.append(system.bond_orders[bond_index])
            atoms.sort()
            groups.append([atoms, new_bonds, new_bond_orders])
            unselected = [x for x in range(system.n_atoms) if x not in sum([y[0] for y in groups],[])]
        return groups
Example #12
0
import numpy as np

v1 = np.array([1.0, 0.0, -1.0 / np.sqrt(2)])
v2 = np.array([-1.0, 0.0, -1.0 / np.sqrt(2)])
v3 = np.array([0.0, 1.0, 1.0 / np.sqrt(2)])
v4 = np.array([0.0, -1.0, 1.0 / np.sqrt(2)])

from chemlab.graphics import QtViewer
from chemlab.graphics.renderers import PointRenderer
from chemlab.graphics.colors import black, green, blue, red

colors = [black, green, blue, red]
v = QtViewer()
v.add_renderer(PointRenderer, np.array([v1, v2, v3, v4]), colors)

from chemlab.graphics.renderers import TriangleRenderer

vertices = np.array([v1, v4, v3, v3, v4, v2, v1, v3, v2, v2, v4, v1])

colors = [green] * 12

# Normals: cross-product for each face
n1 = -np.cross(v4 - v1, v3 - v1)
n1 /= np.linalg.norm(n1)

n2 = -np.cross(v4 - v3, v2 - v3)
n2 /= np.linalg.norm(n2)

n3 = -np.cross(v3 - v1, v2 - v1)
n3 /= np.linalg.norm(n3)
Example #13
0
class ChemLabMinimiser:
    def __init__(self):
        self.interaction_manager = get_interaction_manager(
            *get_twod_signal_manager().get_interaction_data())
        im = self.interaction_manager.interaction_matrix
        im[19][6] = 0
        im[19][7] = 0
        """
        for x in [9,10,11,12,13,17,18,19,20,21]:
            for y in range(self.interaction_manager.number_atoms):
                if im[x][y] == 3:
                    im[x][y] = 0
                    im[y][x] = 0

        """

        self.interaction_matrix = self.interaction_manager.interaction_matrix
        self.type_array = self.interaction_manager.type_array
        self.shift_data = self.interaction_manager.shift_data
        self.number_atoms = self.interaction_manager.number_atoms
        self.global_bond_indices = self.interaction_manager.bonds
        self.bond_orders = self.interaction_manager.bond_orders
        self.viewer = QtViewer()
        self.best_response_value = 1000000.0
        ac = np.random.rand(self.number_atoms, 3) * 0.001
        #ac = FileManager().read_numpy_from_xyz('manual2.xyz') * 0.1
        self.iteration_number = 0
        self.coordinate_manager = CoordinateManager(self, ac,
                                                    self.interaction_manager)
        self.fragments = self.generate_fragments_list()
        print(self.coordinate_manager.calculate_response_value(True))
        self.interaction_manager.print_matrix()
        input("")

        self.delay = 0
        """
        for x in [0,1,2,3,4,5]:
            self.interaction_manager.interaction_matrix[self.interaction_manager.interaction_matrix==x] = 9
        """
        self.nullfrag = Fragment([], [], [], [], self.viewer,
                                 self.coordinate_manager,
                                 self.interaction_manager, [])

    def generate_fragments_list(self):
        """
        Creates a list of fragment objects
        """

        self.calculate_valencies()

        fragments = []
        fragment_data = self.generate_fragment_groups()
        for fragment_piece in fragment_data:
            global_indices = fragment_piece['global indices']
            global_bond_indices = fragment_piece['global bond indices']
            local_bond_indices = np.array(
                [[global_indices.index(x[0]),
                  global_indices.index(x[1])] for x in global_bond_indices])
            bond_orders = fragment_piece['bond orders']
            fragment = Fragment(global_indices, global_bond_indices,
                                local_bond_indices, bond_orders, self.viewer,
                                self.coordinate_manager,
                                self.interaction_manager, self.free_valencies)
            fragments.append(fragment)
        return fragments

    def calculate_valencies(self):
        valencies = {"H": 1, "C": 4, "N": 4}
        self.free_valencies = [
            valencies[x] for x in self.interaction_manager.type_array
        ]
        for bond in self.global_bond_indices:
            self.free_valencies[bond[0]] -= 1
            self.free_valencies[bond[1]] -= 1
        for i, shift in enumerate(self.shift_data):
            if 100 < shift < 160:
                self.free_valencies[i] -= 1
        self.fix_types()

    def fix_types(self):
        for index, type in enumerate(self.type_array):
            if self.free_valencies[index] == 0 and self.type_array[
                    index] == "C":
                self.type_array[index] = "N"

    def fix_renderers(self):
        self.viewer.clear()
        for fragment in self.fragments:
            fragment.set_renderer()

    def generate_fragment_groups(self):
        fragment_groups = []
        unselected = [x for x in range(self.number_atoms)]
        while len(unselected) > 0:
            new_atoms = set()
            new_atoms.add(unselected[0])
            atoms = []
            new_bonds = []
            new_bond_orders = []
            while len(new_atoms) > 0:
                a = list(new_atoms)[0]
                atoms.append(a)
                new_atoms.remove(a)
                for bond_index, bond in enumerate(self.global_bond_indices):
                    if atoms[-1] == bond[0] and bond[1] not in atoms:
                        new_atoms.add(bond[1])
                    if atoms[-1] == bond[1] and bond[0] not in atoms:
                        new_atoms.add(bond[0])
                    if a in bond and list(bond) not in new_bonds:
                        new_bonds.append(list(bond))
                        new_bond_orders.append(self.bond_orders[bond_index])
            atoms.sort()
            fragment_piece = dict()
            fragment_piece["global indices"] = atoms
            fragment_piece["global bond indices"] = new_bonds
            fragment_piece["bond orders"] = new_bond_orders
            fragment_groups.append(fragment_piece)
            unselected = [
                x for x in range(self.number_atoms)
                if x not in sum([y["global indices"]
                                 for y in fragment_groups], [])
            ]
        return fragment_groups

    def main(self):
        #self.interaction_manager.interaction_matrix[self.interaction_manager.interaction_matrix==1] = 0
        #self.interaction_manager.interaction_matrix[self.interaction_manager.interaction_matrix==2] = 0

        print(self.coordinate_manager.calculate_response_value(True))
        self.viewer.schedule(self.iteration2)
        self.viewer.run()

    def iteration2(self):
        atom_coordinates = self.coordinate_manager.get_coordinates()
        hmbcs = []
        for x1 in range(len(atom_coordinates)):
            for x2 in range(len(atom_coordinates)):
                if self.interaction_matrix[x1][x2] == 3:
                    hmbcs.append([x1, x2])
        for frag1 in self.fragments:
            for frag2 in self.fragments:
                for hmbc in hmbcs:
                    a = hmbc[0] in frag1.global_indices and hmbc[
                        1] in frag2.global_bond_indices
                    b = hmbc[1] in frag1.global_indices and hmbc[
                        0] in frag2.global_bond_indices
                    if not (a and b):
                        continue
                    hmbc.sort()
                    if self.type_array[hmbc[0]] == "H":
                        bond = [
                            x for x in self.global_bond_indices if hmbc[0] in x
                        ][0]
                        carbon_index = max(bond)
                        if self.free_valencies[carbon_index] != 0:
                            continue
                        else:
                            adjacent_carbons = [[
                                y for y in x if y != carbon_index
                                and self.free_valencies[y] != 0
                            ][0] for x in self.global_bond_indices
                                                if carbon_index in x]
                            if len(adjacent_carbons) == 1:
                                self.merge(
                                    frag1,
                                    frag2,
                                )

                                self.global_bond_indices.append(
                                    adjacent_carbons[0], hmbc[1])

    def iteration(self):
        self.iteration_number += 1
        if self.iteration_number < 2500:
            self.optimise_substructures()
        else:
            self.form_new_bonds()

    def optimise_substructures(self):
        for fragment in self.fragments:
            fragment.start_iter()
            fragment.rotate_bonds(sequence=1)
            fragment.rotate_bonds(sequence=1)
            fragment.verify()
            fragment.start_iter()
            fragment.translate()
            fragment.verify()

            fragment.update_graphics()

    def form_new_bonds(self):

        fragment1 = random.choice(self.fragments)

        shortest_bond = None
        closest_fragment = None
        shortest_distance = 1000

        atom_coordinates = self.coordinate_manager.get_coordinates()

        for fragment2 in self.fragments:
            if fragment1 != fragment2 or len(self.fragments) == 1:
                for i1 in fragment1.global_indices:
                    for i2 in fragment2.global_indices:
                        frag1_atom = atom_coordinates[i1]
                        frag2_atom = atom_coordinates[i2]
                        if np.linalg.norm(frag2_atom -
                                          frag1_atom) < shortest_distance:
                            if self.free_valencies[
                                    i1] > 0 and self.free_valencies[
                                        i2] > 0 and self.checkHMBC(
                                            i1, i2, fragment1, fragment2):
                                if not (fragment1.has_hydrogens[i1]
                                        and fragment1.has_hydrogens[i2]):
                                    shortest_bond = [i1, i2]
                                    shortest_distance = np.linalg.norm(
                                        frag2_atom - frag1_atom)
                                    closest_fragment = fragment2

        if closest_fragment == None:
            return
        else:
            self.iteration_number = 0
            self.coordinate_manager.reset()

        self.interaction_manager.interaction_matrix[i1][i2] = 4
        self.interaction_manager.interaction_matrix[i2][i1] = 4
        if len(self.fragments) > 1:
            self.merge(fragment1, closest_fragment, shortest_bond)
        else:

            self.merge(fragment1, self.nullfrag, shortest_bond)

        self.coordinate_manager.reset()
        for fragment in self.fragments:
            fragment.project_bond_lengths()

    def merge(self, fragment1, fragment2, shortest_bond):
        """
        Creates a list of fragment objects
        """

        global_indices = fragment1.global_indices + fragment2.global_indices
        self.global_bond_indices.append(shortest_bond)
        self.calculate_valencies()
        global_bond_indices = fragment1.global_bond_indices + fragment2.global_bond_indices + [
            shortest_bond
        ]
        local_bond_indices = np.array(
            [[global_indices.index(x[0]),
              global_indices.index(x[1])] for x in global_bond_indices])
        bond_orders = fragment1.bond_orders + fragment2.bond_orders

        self.fix_types()
        self.fix_renderers()

        fragment = Fragment(global_indices, global_bond_indices,
                            local_bond_indices, bond_orders, self.viewer,
                            self.coordinate_manager, self.interaction_manager,
                            self.free_valencies)
        self.viewer.clear()
        if fragment1 in self.fragments:
            self.fragments.remove(fragment1)
        if fragment2 in self.fragments:
            self.fragments.remove(fragment2)
        self.fragments.append(fragment)
        self.calculate_valencies()
        for fragment in self.fragments:
            fragment.set_renderer()

        return fragment

    def checkHMBC(self, i1, i2, frag1, frag2):
        return True

        all_bonds = frag1.global_bond_indices + frag2.global_bond_indices + [[
            i1, i2
        ]]

        all_indices = list(set(sum(all_bonds, [])))

        i1_hmbcs = [
            x for x in range(0, self.number_atoms)
            if self.interaction_matrix[i1][x] == 3 and x in all_indices
        ]

        one_bond_gap = []
        for bond in all_bonds:
            if i1 in bond:
                if i1 == bond[0]:
                    one_bond_gap.append(bond[1])
                else:
                    one_bond_gap.append(bond[0])

        two_bond_gap = []
        for index in one_bond_gap:
            for bond in all_bonds:
                if index in bond and index not in one_bond_gap and index != i1:
                    if index == bond[0]:
                        two_bond_gap.append(bond[1])
                    else:
                        two_bond_gap.append(bond[0])

        three_bond_gap = []
        for index in two_bond_gap:
            for bond in all_bonds:
                if index in bond and index not in one_bond_gap and index not in two_bond_gap and index != i1:
                    if index == bond[0]:
                        three_bond_gap.append(bond[1])
                    else:
                        three_bond_gap.append(bond[0])

        delta_indices = [
            x for x in i1_hmbcs if x not in two_bond_gap + three_bond_gap
        ]
        if len(delta_indices) > 0:
            print(delta_indices)
            return False
        else:
            return True

        i2_hmbcs = [
            x for x in range(0, self.number_atoms)
            if self.interaction_matrix[i2][x] == 3 and x in all_indices
        ]