def test_torsions(): from pyxmolpp2.polymer import TorsionAngleFactory, OutOfRangeResidue from pyxmolpp2.pdb import PdbFile from pyxmolpp2.geometry import Degrees import glob filenames = sorted(glob.glob("tests_dataset/pdb/rcsb/*.pdb")) for filename in filenames: frame = PdbFile(filename).get_frame() for r in frame.asResidues: try: angles = [ TorsionAngleFactory.phi(r), TorsionAngleFactory.psi(r), TorsionAngleFactory.omega(r), TorsionAngleFactory.chi1(r), TorsionAngleFactory.chi2(r), TorsionAngleFactory.chi3(r), TorsionAngleFactory.chi4(r), TorsionAngleFactory.chi5(r), ] for angle in angles: if angle: try: value = angle.value() angle.set(value + Degrees(30), Degrees(0)) except Exception: pass except OutOfRangeResidue: pass
def test_vectorXYZ_transformations(): v = VectorXYZ([XYZ(0, 0, 0), XYZ(1, 1, 1)]) v.transform(Translation3d(XYZ(2, 2, 2))) for (a, b) in zip(v, VectorXYZ([XYZ(2, 2, 2), XYZ(3, 3, 3)])): assert (a - b).len() == 0 v.transform(Translation3d(XYZ(2, 2, 2))) v.transform( Transformation3d(Rotation3d(XYZ(1, 1, 1), Degrees(30)), Translation3d(XYZ(2, 2, 2)))) v.transform(Rotation3d(XYZ(1, 1, 1), Degrees(30))) v.transform(UniformScale3d(5))
def test_calc_alignment(): from pyxmolpp2.geometry import calc_alignment, XYZ, VectorXYZ, calc_rmsd, Rotation3d, Translation3d, Degrees a = VectorXYZ([XYZ(1, 2, 3), XYZ(1, 2, 5), XYZ(4, 2, 7), XYZ(8, 1, 4)]) G = Rotation3d(XYZ(7, 6, 5), Degrees(12)) * Translation3d(XYZ(8, -9, 1)) b = VectorXYZ([G.transform(x) for x in a]) G2 = calc_alignment(a, b) assert calc_rmsd(a, b) > 1 assert calc_rmsd(a, b, G2) == pytest.approx(0)
def test_conversions(): from pyxmolpp2.geometry import Degrees, Radians, radians_to_degrees, degrees_to_radians deg = Degrees(10) rad = Radians(100) assert rad.radians == pytest.approx(100) assert deg.degrees == pytest.approx(10) assert rad.degrees == pytest.approx(radians_to_degrees(100)) assert deg.radians == pytest.approx(degrees_to_radians(10))
def test_shorthands(): import numpy as np from pyxmolpp2.geometry import Rotation3d, Translation3d, XYZ, Degrees, calc_alignment frame = make_polyglycine([("A", 20)]) for a in frame.asAtoms: a.r = XYZ(*np.random.random(3)) frame2 = frame.copy() asel = frame.asAtoms asel2 = frame2.asAtoms asel.geom_center() asel.mass_center([1.0] * asel.size) asel.inertia_tensor([1.0] * asel.size) asel.geom_inertia_tensor() T = Translation3d(XYZ(1, 0, 0)) asel2.transform(T) assert np.isclose(asel.rmsd(asel2), 1.0) assert np.isclose(asel.rmsd(asel2.toCoords), 1.0) assert np.isclose(asel.rmsd(asel2.toCoords.transform(T.inverted())), 0.0) T = Translation3d(XYZ(1, 0, 0)) * Rotation3d(XYZ(1, 1, 1), Degrees(45)) asel.align_to(asel2) assert np.isclose(asel.rmsd(asel2), 0) asel2.transform(T) asel.align_to(asel2.toCoords) assert np.isclose(asel.rmsd(asel2), 0) T = Translation3d(XYZ(1, 0, 0)) * Rotation3d(XYZ(1, 1, 1), Degrees(45)) asel2.transform(T) assert np.allclose(T.matrix3d(), calc_alignment(asel2.toCoords, asel.toCoords).matrix3d()) assert np.allclose(T.matrix3d(), asel.alignment_to(asel2).matrix3d()) assert np.allclose(T.matrix3d(), asel.alignment_to(asel2.toCoords).matrix3d())
def test_composition(): from pyxmolpp2.geometry import calc_alignment, XYZ, VectorXYZ, calc_rmsd, Rotation3d, Translation3d, Degrees, UniformScale3d R = Rotation3d(XYZ(1, 1, 1), Degrees(39)) T = Translation3d(XYZ(7, 1, 2)) S = UniformScale3d(1.5) G = R * T * S * R * T def check(G): r = XYZ(5, 6, 4) assert ((G * G.inverted()).transform(r) - r).len() == pytest.approx(0) check(R) check(T) check(S) check(G) for a in [R, T, S, G]: for b in [R, T, S, G]: check(a * b)
def test_transformation_3d(): import numpy as np from pyxmolpp2.geometry import calc_alignment, XYZ, VectorXYZ, calc_rmsd, Rotation3d, Translation3d, Degrees, UniformScale3d R = Rotation3d(XYZ(1, 0, 0), Degrees(45)) T = Translation3d(XYZ(1, 2, 5)) G = T * R m = G.matrix3d() v = G.vector3d() assert pytest.approx(m[0, 0]) == 1 assert pytest.approx(m[0, 1]) == 0 assert pytest.approx(m[0, 2]) == 0 assert pytest.approx(np.sqrt(2) / 2) == m[2, 1] assert v.x == 1 assert v.y == 2 assert v.z == 5
def test_rotation_decomposition(): import numpy as np from pyxmolpp2.geometry import XYZ, Rotation3d, Degrees for ax, theta in [ (XYZ(0, 0, 1), Degrees(30)), (XYZ(0, 0, 1), Degrees(70)), (XYZ(0, 1, 0), Degrees(70)), (XYZ(1, 0, 0), Degrees(70)), (XYZ(1, 1, 0), Degrees(70)), (XYZ(1, 1, 1), Degrees(70)), (XYZ(1, 0, 1), Degrees(0)), (XYZ(1, 1, 1), Degrees(0)), ]: R = Rotation3d(ax, theta) ax1, theta1 = R.axis(), R.theta() R2 = Rotation3d(ax1, theta1) assert np.allclose(R.matrix3d(), R2.matrix3d()), ("\n".join( map(lambda x: "%25.18e" % x, (R.matrix3d() - R2.matrix3d()).flatten())))
Protect yourself from missing 2pi/180.0 """ from pyxmolpp2.geometry import Degrees, Radians, cos, sin, tan, fabs import numpy as np ############################################################################## # To avoid accidental errors user is forced to use :py:class:`~pyxmolpp2.geometry.AngleValue` instead of raw float numbers # # :py:class:`~pyxmolpp2.geometry.AngleValue` can be constructed via :py:class:`~pyxmolpp2.geometry.Degrees` # or :py:class:`~pyxmolpp2.geometry.Radians`: angle_value_1 = Degrees(45) angle_value_2 = Radians(np.pi) ############################################################################## # It can be casted back to float as degrees or radians: print(angle_value_1.degrees, angle_value_1.radians) print(angle_value_2.degrees, angle_value_2.radians) ############################################################################## # AngleValue supports all basic arithmetic operations: print((angle_value_1*2 + angle_value_2/3).degrees) ############################################################################## # :py:mod:`pyxmolpp2.geometry` also defines :py:func:`~pyxmolpp2.geometry.cos`, :py:func:`~pyxmolpp2.geometry.sin`, :py:func:`~pyxmolpp2.geometry.tan`, :py:func:`~pyxmolpp2.geometry.fabs` for convenience:
residue48 = frame.asChains[0][48] print(residue48) psi_48 = TorsionAngleFactory.psi(residue48) print(psi_48) print(psi_48.value().degrees) ############################################################################## # Note: Factory may return ``None`` if such angle does not exist: print(TorsionAngleFactory.omega(frame.asResidues[0])) ############################################################################## # Torsion angle allows to set a new one: # All residues 49-76 are affected by this rotation psi_48.set(Degrees(150)) print(psi_48.value().degrees) ############################################################################## # Construction # ^^^^^^^^^^^^ # Torsion angle constructor allow two forms: # 1. Read-only torsion angle # 2. Read-write torsion angle from pyxmolpp2.polymer import TorsionAngle, AtomName, Atom r1 = frame.asResidues[1] r2 = frame.asResidues[2] # Let's create a read-only phi of residue 2