def add_hydrogens(atom): existing_bonds = list(atom.iter_bonds()) bond_length = bonds.get_length(atom.number, 1, BOND_SINGLE) num_hydrogens = self.parameters.num_hydrogens if len(existing_bonds) == 0: t = atom.transformation.t + numpy.array([0, bond_length, 0]) H = Atom(name="auto H", number=1, transformation=Translation(t)) primitive.Add(H, atom.parent) bond = Bond(name="aut H bond", targets=[atom, H]) primitive.Add(bond, atom.parent) existing_bonds.append(bond) num_hydrogens -= 1 main_direction = numpy.zeros(3, float) for bond in existing_bonds: shortest_vector = bond.shortest_vector_relative_to(atom.parent) if bond.children[1].target == atom: shortest_vector *= -1 main_direction += shortest_vector main_direction /= numpy.linalg.norm(main_direction) normal = random_orthonormal(main_direction) rotation = Rotation.from_properties( 2 * numpy.pi / float(num_hydrogens), main_direction, False) h_pos = bond_length * ( main_direction * numpy.cos(self.parameters.valence_angle) + normal * numpy.sin(self.parameters.valence_angle)) for i in range(num_hydrogens): t = atom.transformation.t + h_pos H = Atom(name="auto H", number=1, transformation=Translation(t)) primitive.Add(H, atom.parent) bond = Bond(name="aut H bond", targets=[atom, H]) primitive.Add(bond, atom.parent) h_pos = rotation * h_pos
def add_hydrogens(atom): existing_bonds = list(atom.iter_bonds()) bond_length = bonds.get_length(atom.number, 1, BOND_SINGLE) num_hydrogens = self.parameters.num_hydrogens if len(existing_bonds) == 0: t = atom.transformation.t + numpy.array([0,bond_length,0]) H = Atom(name="auto H", number=1, transformation=Translation(t)) primitive.Add(H, atom.parent) bond = Bond(name="aut H bond", targets=[atom, H]) primitive.Add(bond, atom.parent) existing_bonds.append(bond) num_hydrogens -= 1 main_direction = numpy.zeros(3, float) for bond in existing_bonds: shortest_vector = bond.shortest_vector_relative_to(atom.parent) if bond.children[1].target == atom: shortest_vector *= -1 main_direction += shortest_vector main_direction /= numpy.linalg.norm(main_direction) normal = random_orthonormal(main_direction) rotation = Rotation.from_properties(2*numpy.pi / float(num_hydrogens), main_direction, False) h_pos = bond_length*( main_direction*numpy.cos(self.parameters.valence_angle) + normal*numpy.sin(self.parameters.valence_angle) ) for i in range(num_hydrogens): t = atom.transformation.t + h_pos H = Atom(name="auto H", number=1, transformation=Translation(t)) primitive.Add(H, atom.parent) bond = Bond(name="aut H bond", targets=[atom, H]) primitive.Add(bond, atom.parent) h_pos = rotation * h_pos
def __init__(self, graph, unit_cell=None): """ Argument: | ``graph`` -- the molecular graph from which the force field terms are extracted. See :class:molmod.molecular_graphs.MolecularGraph Optional argument: | ``unit_cell`` -- periodic boundry conditions, see :class:`molmod.unit_cells.UnitCell` """ from molmod.bonds import bonds if unit_cell is None: self.matrix = None self.reciprocal = None else: self.matrix = unit_cell.matrix self.reciprocal = unit_cell.reciprocal self.dm = graph.distances.astype(numpy.int32) dm = self.dm.astype(float) self.dm0 = dm**2 self.dmk = (dm+0.1)**(-3) self.vdw_radii = numpy.array([periodic[number].vdw_radius for number in graph.numbers], dtype=float) self.covalent_radii = numpy.array([periodic[number].covalent_radius for number in graph.numbers], dtype=float) bond_edges = [] bond_lengths = [] for i, j in graph.edges: bond_edges.append((i, j)) bond_lengths.append(bonds.get_length(graph.numbers[i], graph.numbers[j])) self.bond_edges = numpy.array(bond_edges, numpy.int32) self.bond_lengths = numpy.array(bond_lengths, float) special_angles = SpecialAngles() span_edges = [] span_lengths = [] for i, neighbors in graph.neighbors.iteritems(): number_i = graph.numbers[i] if (number_i >= 5 and number_i <=8): valence = len(neighbors) + abs(number_i-6) elif number_i >= 13 and number_i <= 16: valence = len(neighbors) + abs(number_i-14) else: valence = -1 if valence < 2 or valence > 6: default_angle = numpy.pi/180.0*115.0 elif valence == 2: default_angle = numpy.pi elif valence == 3: default_angle = numpy.pi/180.0*125.0 elif valence == 4: default_angle = numpy.pi/180.0*109.0 elif valence == 5: default_angle = numpy.pi/180.0*100.0 elif valence == 6: default_angle = numpy.pi/180.0*90.0 for j in neighbors: number_j = graph.numbers[j] for k in neighbors: if j < k and not frozenset([j, k]) in graph.edges: number_k = graph.numbers[k] triplet = ( number_j, len(graph.neighbors[j]), number_i, len(graph.neighbors[i]), number_k, len(graph.neighbors[k]), ) angle = special_angles.get_angle(triplet) if angle is None: angle = default_angle dj = bonds.get_length(number_i, number_j) dk = bonds.get_length(number_i, number_k) d = numpy.sqrt(dj**2+dk**2-2*dj*dk*numpy.cos(angle)) span_edges.append((j, k)) span_lengths.append(d) self.span_edges = numpy.array(span_edges, numpy.int32) self.span_lengths = numpy.array(span_lengths, float) self.dm_quad = 0.0 self.dm_reci = 0.0 self.bond_quad = 0.0 self.span_quad = 0.0 self.bond_hyper = 0.0 self.bond_hyper_scale = 5.0
def add_hydrogens(atom): existing_bonds = list(atom.iter_bonds()) num_bonds = len(existing_bonds) bond_length = bonds.get_length(atom.number, 1, BOND_SINGLE) if num_bonds == 0: t = atom.transformation.t + numpy.array([0, bond_length, 0]) H = Atom(name="auto H", number=1, transformation=Translation(t)) primitive.Add(H, atom.parent) bond = Bond(name="aut H bond", targets=[atom, H]) primitive.Add(bond, atom.parent) existing_bonds.append(bond) num_bonds = 1 used_valence = 0 oposite_direction = numpy.zeros(3, float) for bond in existing_bonds: shortest_vector = bond.shortest_vector_relative_to(atom.parent) if bond.children[1].target == atom: shortest_vector *= -1 oposite_direction -= shortest_vector if bond.bond_type == BOND_SINGLE: used_valence += 1 elif bond.bond_type == BOND_DOUBLE: used_valence += 2 elif bond.bond_type == BOND_TRIPLE: used_valence += 3 oposite_direction /= numpy.linalg.norm(oposite_direction) num_hydrogens = valence_el( atom.number) - 2 * lone_pairs(atom.number) - used_valence if num_hydrogens <= 0: return hybride_count = num_hydrogens + lone_pairs( atom.number) + num_bonds - (used_valence - num_bonds) num_sites = num_hydrogens + lone_pairs(atom.number) rotation = Rotation.from_properties( 2 * numpy.pi / float(num_sites), oposite_direction, False) opening_key = (hybride_count, num_sites) opening_angle = self.opening_angles.get(opening_key) if opening_angle is None: return if num_bonds == 1: first_bond = existing_bonds[0] other_atom = first_bond.children[0].target if other_atom == atom: other_atom = first_bond.children[1].target other_bonds = [ bond for bond in other_atom.iter_bonds() if bond != first_bond ] if len(other_bonds) > 0: normal = other_bonds[0].shortest_vector_relative_to( atom.parent) normal -= numpy.dot(normal, oposite_direction) * oposite_direction normal /= numpy.linalg.norm(normal) if other_bonds[0].children[0].target == other_atom: normal *= -1 else: normal = random_orthonormal(oposite_direction) elif num_bonds == 2: normal = numpy.cross( oposite_direction, existing_bonds[0].shortest_vector_relative_to(atom.parent)) normal /= numpy.linalg.norm(normal) elif num_bonds == 3: normal = random_orthonormal(oposite_direction) else: return h_pos = bond_length * (oposite_direction * numpy.cos(opening_angle) + normal * numpy.sin(opening_angle)) for i in range(num_hydrogens): t = atom.transformation.t + h_pos H = Atom(name="auto H", number=1, transformation=Translation(t)) primitive.Add(H, atom.parent) bond = Bond(name="aut H bond", targets=[atom, H]) primitive.Add(bond, atom.parent) h_pos = rotation * h_pos
def replace(self, gl_object): if not gl_object.get_fixed(): new = self.get_new(gl_object.transformation.t) # select a target object, i.e. the one the will be connected with # the bonds/vectors/... of the replaced object if (self.current_object == "Fragment"): # fragments are inserted as frames # take atom with index 1 as target target_object = new.children[1] else: target_object = new # check if all connections to the replaced object are applicable # to the new object. if not, then do not perform the replacement # and return early. for reference in gl_object.references[::-1]: if not reference.check_target(target_object): return # add the new object parent = gl_object.parent primitive.Add(new, parent) if (self.current_object == "Fragment"): # Fix the rotation and translation of the molecular fragment. # Rotation Bond = context.application.plugins.get_node("Bond") if len(gl_object.references) == 1 and isinstance( gl_object.references[0].parent, Bond): bond1 = gl_object.references[0].parent direction1 = bond1.shortest_vector_relative_to(parent) if bond1.children[0].target != gl_object: direction1 *= -1 bond2 = new.children[0].references[0].parent direction2 = bond2.shortest_vector_relative_to(parent) if bond2.children[0].target != target_object: direction2 *= -1 axis = numpy.cross(direction2, direction1) if numpy.linalg.norm(axis) < 1e-8: axis = random_orthonormal(direction1) angle = compute_angle(direction1, direction2) rotation = Rotation.from_properties(angle, axis, False) primitive.Transform(new, rotation) else: bond1 = None # Tranlsation pos_old = new.children[1].get_frame_relative_to(parent).t pos_new = gl_object.transformation.t translation = Translation(pos_new - pos_old) primitive.Transform(new, translation) if bond1 != None: # bond length old_length = numpy.linalg.norm(direction1) new_length = bonds.get_length( new.children[1].number, bond1.get_neighbor(gl_object).number) translation = Translation(-direction1 / old_length * (new_length - old_length)) primitive.Transform(new, translation) # let the references to the replaced object point to the new object for reference in gl_object.references[::-1]: try: primitive.SetTarget(reference, target_object) except primitive.PrimitiveError: primitive.Delete(reference.parent) # delete the replaced object primitive.Delete(gl_object) if (self.current_object == "Fragment"): # Delete the first atom in the fragment primitive.Delete(new.children[0]) # Unframe the fragment UnframeAbsolute = context.application.plugins.get_action( "UnframeAbsolute") UnframeAbsolute([new])
def replace(self, gl_object): if not gl_object.get_fixed(): new = self.get_new(gl_object.transformation.t) # select a target object, i.e. the one the will be connected with # the bonds/vectors/... of the replaced object if(self.current_object == "Fragment"): # fragments are inserted as frames # take atom with index 1 as target target_object = new.children[1] else: target_object = new # check if all connections to the replaced object are applicable # to the new object. if not, then do not perform the replacement # and return early. for reference in gl_object.references[::-1]: if not reference.check_target(target_object): return # add the new object parent = gl_object.parent primitive.Add(new, parent) if(self.current_object == "Fragment"): # Fix the rotation and translation of the molecular fragment. # Rotation Bond = context.application.plugins.get_node("Bond") if len(gl_object.references) == 1 and isinstance(gl_object.references[0].parent, Bond): bond1 = gl_object.references[0].parent direction1 = bond1.shortest_vector_relative_to(parent) if bond1.children[0].target != gl_object: direction1 *= -1 bond2 = new.children[0].references[0].parent direction2 = bond2.shortest_vector_relative_to(parent) if bond2.children[0].target != target_object: direction2 *= -1 axis = numpy.cross(direction2, direction1) if numpy.linalg.norm(axis) < 1e-8: axis = random_orthonormal(direction1) angle = compute_angle(direction1, direction2) rotation = Rotation.from_properties(angle, axis, False) primitive.Transform(new, rotation) else: bond1 = None # Tranlsation pos_old = new.children[1].get_frame_relative_to(parent).t pos_new = gl_object.transformation.t translation = Translation(pos_new - pos_old) primitive.Transform(new, translation) if bond1 != None: # bond length old_length = numpy.linalg.norm(direction1) new_length = bonds.get_length(new.children[1].number, bond1.get_neighbor(gl_object).number) translation = Translation(-direction1/old_length*(new_length-old_length)) primitive.Transform(new, translation) # let the references to the replaced object point to the new object for reference in gl_object.references[::-1]: try: primitive.SetTarget(reference, target_object) except primitive.PrimitiveError: primitive.Delete(reference.parent) # delete the replaced object primitive.Delete(gl_object) if(self.current_object == "Fragment"): # Delete the first atom in the fragment primitive.Delete(new.children[0]) # Unframe the fragment UnframeAbsolute = context.application.plugins.get_action("UnframeAbsolute") UnframeAbsolute([new])
def __init__(self, graph, unit_cell=None): """ Argument: | ``graph`` -- the molecular graph from which the force field terms are extracted. See :class:molmod.molecular_graphs.MolecularGraph Optional argument: | ``unit_cell`` -- periodic boundry conditions, see :class:`molmod.unit_cells.UnitCell` """ from molmod.bonds import bonds if unit_cell is None: self.matrix = None self.reciprocal = None else: self.matrix = unit_cell.matrix self.reciprocal = unit_cell.reciprocal self.dm = graph.distances.astype(int) dm = self.dm.astype(float) self.dm0 = dm**2 self.dmk = (dm + 0.1)**(-3) self.vdw_radii = np.array( [periodic[number].vdw_radius for number in graph.numbers], dtype=float) self.covalent_radii = np.array( [periodic[number].covalent_radius for number in graph.numbers], dtype=float) bond_edges = [] bond_lengths = [] for i, j in graph.edges: bond_edges.append((i, j)) bond_lengths.append( bonds.get_length(graph.numbers[i], graph.numbers[j])) self.bond_edges = np.array(bond_edges, int) self.bond_lengths = np.array(bond_lengths, float) special_angles = SpecialAngles() span_edges = [] span_lengths = [] for i, neighbors in graph.neighbors.items(): number_i = graph.numbers[i] if (number_i >= 5 and number_i <= 8): valence = len(neighbors) + abs(number_i - 6) elif number_i >= 13 and number_i <= 16: valence = len(neighbors) + abs(number_i - 14) else: valence = -1 if valence < 2 or valence > 6: default_angle = np.pi / 180.0 * 115.0 elif valence == 2: default_angle = np.pi elif valence == 3: default_angle = np.pi / 180.0 * 125.0 elif valence == 4: default_angle = np.pi / 180.0 * 109.0 elif valence == 5: default_angle = np.pi / 180.0 * 100.0 elif valence == 6: default_angle = np.pi / 180.0 * 90.0 for j in neighbors: number_j = graph.numbers[j] for k in neighbors: if j < k and not frozenset([j, k]) in graph.edges: number_k = graph.numbers[k] triplet = ( number_j, len(graph.neighbors[j]), number_i, len(graph.neighbors[i]), number_k, len(graph.neighbors[k]), ) angle = special_angles.get_angle(triplet) if angle is None: angle = default_angle dj = bonds.get_length(number_i, number_j) dk = bonds.get_length(number_i, number_k) d = np.sqrt(dj**2 + dk**2 - 2 * dj * dk * np.cos(angle)) span_edges.append((j, k)) span_lengths.append(d) self.span_edges = np.array(span_edges, int) self.span_lengths = np.array(span_lengths, float) self.dm_quad = 0.0 self.dm_reci = 0.0 self.bond_quad = 0.0 self.span_quad = 0.0 self.bond_hyper = 0.0 self.bond_hyper_scale = 5.0
def add_hydrogens(atom): existing_bonds = list(atom.iter_bonds()) num_bonds = len(existing_bonds) bond_length = bonds.get_length(atom.number, 1, BOND_SINGLE) if num_bonds == 0: t = atom.transformation.t + numpy.array([0,bond_length,0]) H = Atom(name="auto H", number=1, transformation=Translation(t)) primitive.Add(H, atom.parent) bond = Bond(name="aut H bond", targets=[atom, H]) primitive.Add(bond, atom.parent) existing_bonds.append(bond) num_bonds = 1 used_valence = 0 oposite_direction = numpy.zeros(3, float) for bond in existing_bonds: shortest_vector = bond.shortest_vector_relative_to(atom.parent) if bond.children[1].target == atom: shortest_vector *= -1 oposite_direction -= shortest_vector if bond.bond_type == BOND_SINGLE: used_valence += 1 elif bond.bond_type == BOND_DOUBLE: used_valence += 2 elif bond.bond_type == BOND_TRIPLE: used_valence += 3 oposite_direction /= numpy.linalg.norm(oposite_direction) num_hydrogens = valence_el(atom.number) - 2*lone_pairs(atom.number) - used_valence if num_hydrogens <= 0: return hybride_count = num_hydrogens + lone_pairs(atom.number) + num_bonds - (used_valence - num_bonds) num_sites = num_hydrogens + lone_pairs(atom.number) rotation = Rotation.from_properties(2*numpy.pi / float(num_sites), oposite_direction, False) opening_key = (hybride_count, num_sites) opening_angle = self.opening_angles.get(opening_key) if opening_angle is None: return if num_bonds == 1: first_bond = existing_bonds[0] other_atom = first_bond.children[0].target if other_atom == atom: other_atom = first_bond.children[1].target other_bonds = [bond for bond in other_atom.iter_bonds() if bond != first_bond] if len(other_bonds) > 0: normal = other_bonds[0].shortest_vector_relative_to(atom.parent) normal -= numpy.dot(normal, oposite_direction) * oposite_direction normal /= numpy.linalg.norm(normal) if other_bonds[0].children[0].target == other_atom: normal *= -1 else: normal = random_orthonormal(oposite_direction) elif num_bonds == 2: normal = numpy.cross(oposite_direction, existing_bonds[0].shortest_vector_relative_to(atom.parent)) normal /= numpy.linalg.norm(normal) elif num_bonds == 3: normal = random_orthonormal(oposite_direction) else: return h_pos = bond_length*(oposite_direction*numpy.cos(opening_angle) + normal*numpy.sin(opening_angle)) for i in range(num_hydrogens): t = atom.transformation.t + h_pos H = Atom(name="auto H", number=1, transformation=Translation(t)) primitive.Add(H, atom.parent) bond = Bond(name="aut H bond", targets=[atom, H]) primitive.Add(bond, atom.parent) h_pos = rotation * h_pos