def test_dihedral(): coord1 = struc.coord([-0.5, -1, 0]) coord2 = struc.coord([0, 0, 0]) coord3 = struc.coord([1, 0, 0]) coord4 = struc.coord([0, 0, -1]) assert struc.dihedral(coord1, coord2, coord3, coord4) \ == pytest.approx(0.5*np.pi)
def test_index_functions(): """ The `index_xxx()` functions should give the same result as the corresponding `xxx` functions. """ stack = strucio.load_structure(join(data_dir, "1l2y.mmtf")) array = stack[0] # Test for atom array, stack and raw coordinates samples = (array, stack, struc.coord(array), struc.coord(stack)) # Generate random indices random.seed(42) indices = random.randint(array.array_length(), size=(100, 4), dtype=int) for sample in samples: if isinstance(sample, np.ndarray): atoms1 = sample[..., indices[:, 0], :] atoms2 = sample[..., indices[:, 1], :] atoms3 = sample[..., indices[:, 2], :] atoms4 = sample[..., indices[:, 3], :] else: atoms1 = sample[..., indices[:, 0]] atoms2 = sample[..., indices[:, 1]] atoms3 = sample[..., indices[:, 2]] atoms4 = sample[..., indices[:, 3]] assert np.allclose(struc.displacement(atoms1, atoms2), struc.index_displacement(sample, indices[:, :2]), atol=1e-5) assert np.allclose(struc.distance(atoms1, atoms2), struc.index_distance(sample, indices[:, :2]), atol=1e-5) assert np.allclose(struc.angle(atoms1, atoms2, atoms3), struc.index_angle(sample, indices[:, :3]), atol=1e-5) assert np.allclose(struc.dihedral(atoms1, atoms2, atoms3, atoms4), struc.index_dihedral(sample, indices[:, :4]), atol=1e-5)
def detect_disulfide_bonds(structure, distance=2.05, distance_tol=0.05, dihedral=90, dihedral_tol=10): # Array where detected disulfide bonds are stored disulfide_bonds = [] # A mask that selects only S-gamma atoms of cysteins sulfide_mask = (structure.res_name == "CYS") & \ (structure.atom_name == "SG") # sulfides in adjacency to other sulfides are detected in an # efficient manner via a cell list cell_list = struc.CellList(structure, cell_size=distance + distance_tol, selection=sulfide_mask) # Iterate over every index corresponding to an S-gamma atom for sulfide_i in np.where(sulfide_mask)[0]: # Find indices corresponding to other S-gamma atoms, # that are adjacent to the position of structure[sulfide_i] # We use the faster 'get_atoms_in_cells()' instead of # `get_atoms()`, as precise distance measurement is done # afterwards anyway potential_bond_partner_indices = cell_list.get_atoms_in_cells( coord=structure.coord[sulfide_i]) # Iterate over every index corresponding to an S-gamma atom # as bond partner for sulfide_j in potential_bond_partner_indices: if sulfide_i == sulfide_j: # A sulfide cannot create a bond with itself: continue # Create 'Atom' instances # of the potentially bonds S-gamma atoms sg1 = structure[sulfide_i] sg2 = structure[sulfide_j] # For dihedral angle measurement the corresponding # C-beta atoms are required, too cb1 = structure[(structure.chain_id == sg1.chain_id) & (structure.res_id == sg1.res_id) & (structure.atom_name == "CB")] cb2 = structure[(structure.chain_id == sg2.chain_id) & (structure.res_id == sg2.res_id) & (structure.atom_name == "CB")] # Measure distance and dihedral angle and check criteria bond_dist = struc.distance(sg1, sg2) bond_dihed = np.abs(np.rad2deg(struc.dihedral(cb1, sg1, sg2, cb2))) if bond_dist > distance - distance_tol and \ bond_dist < distance + distance_tol and \ bond_dihed > dihedral - dihedral_tol and \ bond_dihed < dihedral + dihedral_tol: # Atom meet criteria -> we found a disulfide bond # -> the indices of the bond S-gamma atoms # are put into a tuple with the lower index first bond_tuple = sorted((sulfide_i, sulfide_j)) # Add bond to list of bonds, but each bond only once if bond_tuple not in disulfide_bonds: disulfide_bonds.append(bond_tuple) return np.array(disulfide_bonds, dtype=int)
print("Adjacent CA distances") print(struc.distance(array[:-1], array[1:])) ######################################################################## # Like some other functions in :mod:`biotite.structure`, we are able to # pick any combination of an atom, atom array or stack. Alternatively # :class:`ndarray` objects containing the coordinates can be provided. # # Furthermore, we can measure bond angles and dihedral angles. # Calculate angle between first 3 CA atoms in first frame # (in radians) print("Angle:", struc.angle(array[0], array[1], array[2])) # Calculate dihedral angle between first 4 CA atoms in first frame # (in radians) print("Dihedral angle:", struc.dihedral(array[0], array[1], array[2], array[4])) ######################################################################## # .. note:: The :func:`distance()`, :func:`angle()` and # :func:`dihedral()` functions all have their :func:`pair_...()` # counterparts, that take can atom array (stack) and # pairs/triplets/quadruplets of atoms, of which distance/angle should # be calculated. # Both variants can be setup to consider periodic boundary conditions # by setting the `box` or `periodic` parameter, respectively. # # In some cases one is interested in the dihedral angles of the peptide # backbone, :math:`\phi`, :math:`\psi` and :math:`\omega`. # In the following code snippet we measure these angles and create a # simple Ramachandran plot for the first frame of *TC5b*.