mirror of
https://github.com/biopython/biopython.git
synced 2025-10-21 23:38:51 +08:00
Addresses a bug in the code that caused the Newton-Raphson optimization to quit earlier than it should, resulting in poorer alignments.
112 lines
3.5 KiB
Python
112 lines
3.5 KiB
Python
# Copyright 2022 by Joao Rodrigues. All rights reserved.
|
|
#
|
|
# This file is part of the Biopython distribution and governed by your
|
|
# choice of the "Biopython License Agreement" or the "BSD 3-Clause License".
|
|
# Please see the LICENSE file that should have been included as part of this
|
|
# package.
|
|
"""Unit tests for the Bio.PDB.CEAligner module."""
|
|
|
|
import unittest
|
|
|
|
try:
|
|
import numpy as np
|
|
except ImportError:
|
|
from Bio import MissingPythonDependencyError
|
|
|
|
raise MissingPythonDependencyError(
|
|
"Install NumPy if you want to use Bio.PDB."
|
|
) from None
|
|
|
|
from Bio.PDB import CEAligner
|
|
from Bio.PDB import MMCIFParser
|
|
|
|
|
|
class CEAlignerTests(unittest.TestCase):
|
|
"""Test CEAligner class."""
|
|
|
|
@staticmethod
|
|
def _get_ca_coords_as_array(structure):
|
|
xyz_list = [a.coord for a in structure.get_atoms() if a.name == "CA"]
|
|
return np.asarray(xyz_list, dtype=np.float64)
|
|
|
|
def test_cealigner(self):
|
|
"""Test aligning 7CFN on 6WQA."""
|
|
ref = "PDB/6WQA.cif"
|
|
mob = "PDB/7CFN.cif"
|
|
result = "PDB/7CFN_aligned.cif"
|
|
|
|
parser = MMCIFParser(QUIET=1)
|
|
s1 = parser.get_structure("6wqa", ref)
|
|
s2 = parser.get_structure("7cfn", mob)
|
|
|
|
aligner = CEAligner()
|
|
aligner.set_reference(s1)
|
|
aligner.align(s2, final_optimization=False)
|
|
|
|
self.assertAlmostEqual(aligner.rms, 3.83, places=2)
|
|
|
|
# Assert the transformation was done right by comparing
|
|
# the moved coordinates to a 'ground truth' reference.
|
|
# Reference obtained with Pymol's CEAlign code.
|
|
refe = parser.get_structure("7cfn_aligned", result)
|
|
refe_coords = self._get_ca_coords_as_array(refe)
|
|
s2_f_coords = self._get_ca_coords_as_array(s2)
|
|
|
|
diff = refe_coords - s2_f_coords
|
|
rmsd = np.sqrt((diff * diff).sum() / len(refe_coords))
|
|
self.assertAlmostEqual(rmsd, 0.0, places=2)
|
|
|
|
def test_cealigner_no_transform(self):
|
|
"""Test aligning 7CFN on 6WQA without transforming 7CFN."""
|
|
ref = "PDB/6WQA.cif"
|
|
mob = "PDB/7CFN.cif"
|
|
|
|
parser = MMCIFParser(QUIET=1)
|
|
s1 = parser.get_structure("6wqa", ref)
|
|
s2 = parser.get_structure("7cfn", mob)
|
|
|
|
s2_original_coords = [list(a.coord) for a in s2.get_atoms()]
|
|
|
|
aligner = CEAligner()
|
|
aligner.set_reference(s1)
|
|
aligner.align(s2, transform=False, final_optimization=False)
|
|
s2_coords_final = [list(a.coord) for a in s2.get_atoms()]
|
|
|
|
self.assertAlmostEqual(aligner.rms, 3.83, places=2)
|
|
self.assertEqual(s2_original_coords, s2_coords_final)
|
|
|
|
def test_ce_aligner_final_optimization(self):
|
|
"""Test aligning 7CFN on 6WQA with the final optimization."""
|
|
ref = "PDB/6WQA.cif"
|
|
mob = "PDB/7CFN.cif"
|
|
|
|
parser = MMCIFParser(QUIET=1)
|
|
s1 = parser.get_structure("6wqa", ref)
|
|
s2 = parser.get_structure("7cfn", mob)
|
|
|
|
aligner = CEAligner()
|
|
aligner.set_reference(s1)
|
|
aligner.align(s2)
|
|
|
|
self.assertAlmostEqual(aligner.rms, 3.75, places=2)
|
|
|
|
def test_cealigner_nucleic(self):
|
|
"""Test aligning 1LCD on 1LCD."""
|
|
ref = "PDB/1LCD.cif"
|
|
mob = "PDB/1LCD.cif"
|
|
|
|
parser = MMCIFParser(QUIET=1)
|
|
s1 = parser.get_structure("1lcd_ref", ref)
|
|
s2 = parser.get_structure("1lcd_mob", mob)
|
|
|
|
aligner = CEAligner()
|
|
aligner.set_reference(s1)
|
|
aligner.align(s2)
|
|
|
|
self.assertAlmostEqual(aligner.rms, 0.0, places=3)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
runner = unittest.TextTestRunner(verbosity=2)
|
|
unittest.main(testRunner=runner)
|