def test_dihedral_special_cases(self): a = Position(random(), random(), random()) # not sure what it should be in such undefined cases #self.assertTrue(isnan(gemmi.calculate_dihedral(a, a, a, a))) self.assertEqual(gemmi.calculate_dihedral(a, a, a, a), 0.0) # Special cases from scitbx tst_math.py # atan2 is guaranteed to give exact values (I think) p000 = Position(0, 0, 0) p100 = Position(1, 0, 0) p010 = Position(0, 1, 0) def xy_dihedral(last_point): return gemmi.calculate_dihedral(p100, p000, p010, last_point) self.assertEqual(xy_dihedral(Position(1, 1, 0)), 0.0) self.assertEqual(xy_dihedral(Position(-1, 1, 0)), pi) p01_ = Position(0, 1, -1) self.assertEqual(xy_dihedral(p01_), pi/2) p01_.z = 1 self.assertEqual(xy_dihedral(p01_), -pi/2)
def calculate_dihedral_angles(seq1: SequenceVariant, seq2: SequenceVariant, atom_names_seq1: [str], atom_names_seq2: [str]): """ calculates a dihedral angles of given points from two following sequences. The arrays may be empty, but it should be 4 points all together :param seq1: dict structure of the first sequence :param seq2: dict structure of the first sequence :param atom_names_seq1: the atoms that are needed from the first sequence :param atom_names_seq2: the atoms that are needed from the second sequence :return: an dihedral angle """ points = [make_gemmi_position_format_from_coords(seq1.atoms[atom_name].coords) for atom_name in atom_names_seq1] + \ [make_gemmi_position_format_from_coords(seq2.atoms[atom_name].coords) for atom_name in atom_names_seq2] if len(points) == 4: result = degrees(gemmi.calculate_dihedral(points[0], points[1], points[2], points[3])) return round(result, 1) if result >= 0 else round(360 + result, 1) # angles should be > 0 else: raise WrongNumberOfArgumentsException(len(points))
def check_dihedral(a, b, c, d, angle): deg = gemmi.calculate_dihedral(a, b, c, d) * 180 / pi self.assertAlmostEqual(deg, angle, places=4)
def xy_dihedral(last_point): return gemmi.calculate_dihedral(p100, p000, p010, last_point)