def rotate_residue(mol, bond_number, angle): # --- Identify rotatable bonds --- rotatable_bonds = struc.find_rotatable_bonds(mol.bonds) # --- do not rotate about backbone bonds --- for atom_name in BACKBONE: index = np.where(mol.atom_name == atom_name)[0][0] rotatable_bonds.remove_bonds_to(index) # --- init coordinates for new model --- coord = mol.coord.copy() # --- get bond axis --- atom_i, atom_j, _ = rotatable_bonds.as_array()[bond_number] axis = coord[atom_j] - coord[atom_i] # --- get support atom --- support = coord[atom_i] # --- need to get atoms only on one side of the bond --- bond_list_without_axis = mol.bonds.copy() bond_list_without_axis.remove_bond(atom_i, atom_j) rotated_atom_indices = struc.find_connected(bond_list_without_axis, root=atom_j) # --- rotate atoms --- coord[rotated_atom_indices] = struc.rotate_about_axis( coord[rotated_atom_indices], axis, angle, support) atom_list = [] for i, atom_i in enumerate(mol): atom_new = struc.Atom(coord[i], atom_name=atom_i.atom_name, element=atom_i.element) atom_list.append(atom_new) new_mol = struc.array(atom_list) new_mol.res_id[:] = mol.res_id new_mol.res_name[:] = mol.res_name new_mol.bonds = mol.bonds.copy() return new_mol
def test_find_rotatable_bonds(res_name, expected_bonds): """ Check the :func:`find_rotatable_bonds()` function based on known examples. """ molecule = info.residue(res_name) ref_bond_set = { tuple(sorted((name_i, name_j))) for name_i, name_j in expected_bonds } rotatable_bonds = struc.find_rotatable_bonds(molecule.bonds) test_bond_set = set() for i, j, _ in rotatable_bonds.as_array(): test_bond_set.add( tuple(sorted((molecule.atom_name[i], molecule.atom_name[j])))) # Compare with reference bonded atom names assert test_bond_set == ref_bond_set # All rotatable bonds must be single bonds assert np.all(rotatable_bonds.as_array()[:, 2] == struc.BondType.SINGLE)
import biotite.structure as struc import biotite.structure.io as strucio import biotite.structure.info as info import biotite.structure.graphics as graphics # 'CA' is not in backbone, # as we want to include the rotation between 'CA' and 'CB' BACKBONE = ["N", "C", "O", "OXT"] LIBRARY_SIZE = 9 # Get the structure (including bonds) from the standard RCSB compound residue = info.residue("TYR") bond_list = residue.bonds ### Identify rotatable bonds ### rotatable_bonds = struc.find_rotatable_bonds(residue.bonds) # Do not rotate about backbone bonds, # as these are irrelevant for a amino rotamer library for atom_name in BACKBONE: index = np.where(residue.atom_name == atom_name)[0][0] rotatable_bonds.remove_bonds_to(index) print("Rotatable bonds in tyrosine:") for atom_i, atom_j, _ in rotatable_bonds.as_array(): print(residue.atom_name[atom_i] + " <-> " + residue.atom_name[atom_j]) ### VdW radii of each atom, required for the next step ### vdw_radii = np.zeros(residue.array_length()) for i, element in enumerate(residue.element): vdw_radii[i] = info.vdw_radius_single(element) # The Minimum required distance between two atoms is mean of their # VdW radii