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()
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
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
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 ]