/test/transformations.py

https://github.com/woutersmet/Molmodsummer
Python | 145 lines | 90 code | 21 blank | 34 comment | 16 complexity | 0b547f6e4067c2e593194626e89b29d7 MD5 | raw file
  1. # MolMod is a collection of molecular modelling tools for python.
  2. # Copyright (C) 2007 - 2008 Toon Verstraelen <Toon.Verstraelen@UGent.be>
  3. #
  4. # This file is part of MolMod.
  5. #
  6. # MolMod is free software; you can redistribute it and/or
  7. # modify it under the terms of the GNU General Public License
  8. # as published by the Free Software Foundation; either version 3
  9. # of the License, or (at your option) any later version.
  10. #
  11. # MolMod is distributed in the hope that it will be useful,
  12. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. # GNU General Public License for more details.
  15. #
  16. # You should have received a copy of the GNU General Public License
  17. # along with this program; if not, see <http://www.gnu.org/licenses/>
  18. #
  19. # --
  20. from common import BaseTestCase
  21. from molmod.transformations import Complete, superpose
  22. from molmod.vectors import random_unit
  23. import numpy, copy, random, math
  24. import unittest
  25. __all__ = ["TransformationsTestCase"]
  26. class TransformationsTestCase(BaseTestCase):
  27. def setUp(self):
  28. self.test_transformations = []
  29. for i in xrange(20):
  30. test_transformation = Complete()
  31. test_transformation.set_rotation_properties(random.random()*math.pi*2, numpy.random.uniform(-3, 3, 3), random.sample([True, False], 1)[0])
  32. test_transformation.t = numpy.random.uniform(-3, 3, 3)
  33. self.test_transformations.append(test_transformation)
  34. def test_apply_after(self):
  35. for tt1 in self.test_transformations:
  36. for tt2 in self.test_transformations:
  37. temp = copy.deepcopy(tt1)
  38. temp.apply_after(tt2)
  39. r = numpy.dot(tt2.r, tt1.r)
  40. rotation_error = numpy.sum(numpy.ravel((r - temp.r)**2))/9.0
  41. self.assertAlmostEqual(rotation_error, 0)
  42. t = numpy.dot(tt2.r, tt1.t) + tt2.t
  43. translation_error = numpy.sum((t - temp.t)**2)/3.0
  44. self.assertAlmostEqual(translation_error, 0)
  45. def test_apply_before(self):
  46. for tt1 in self.test_transformations:
  47. for tt2 in self.test_transformations:
  48. temp = copy.deepcopy(tt1)
  49. temp.apply_before(tt2)
  50. r = numpy.dot(tt1.r, tt2.r)
  51. rotation_error = numpy.sum(numpy.ravel((r - temp.r)**2))/9.0
  52. self.assertAlmostEqual(rotation_error, 0)
  53. t = numpy.dot(tt1.r, tt2.t) + tt1.t
  54. translation_error = numpy.sum((t - temp.t)**2)/3.0
  55. self.assertAlmostEqual(translation_error, 0)
  56. def test_apply_inverse_after(self):
  57. for tt1 in self.test_transformations:
  58. for tt2 in self.test_transformations:
  59. temp = copy.deepcopy(tt1)
  60. temp.apply_inverse_after(tt2)
  61. r = numpy.dot(numpy.transpose(tt2.r), tt1.r)
  62. rotation_error = numpy.sum(numpy.ravel((r - temp.r)**2))/9.0
  63. self.assertAlmostEqual(rotation_error, 0)
  64. t = numpy.dot(numpy.transpose(tt2.r), tt1.t - tt2.t)
  65. translation_error = numpy.sum((t - temp.t)**2)/3.0
  66. self.assertAlmostEqual(translation_error, 0)
  67. def test_apply_inverse_before(self):
  68. for tt1 in self.test_transformations:
  69. for tt2 in self.test_transformations:
  70. temp = copy.deepcopy(tt1)
  71. temp.apply_inverse_before(tt2)
  72. r = numpy.dot(tt1.r, numpy.transpose(tt2.r))
  73. rotation_error = numpy.sum(numpy.ravel((r - temp.r)**2))/9.0
  74. self.assertAlmostEqual(rotation_error, 0)
  75. t = numpy.dot(tt1.r, -numpy.dot(numpy.transpose(tt2.r), tt2.t)) + tt1.t
  76. translation_error = numpy.sum((t - temp.t)**2)/3.0
  77. self.assertAlmostEqual(translation_error, 0)
  78. def test_superpose(self):
  79. # create a few test sets with random data points, including degenerate
  80. # situations. (e.g. one point, two points, linear points)
  81. references = [ # a list of 2-tuples: (points, degenerate)
  82. (numpy.random.normal(0, 5, (n, 3)), False) for n in xrange(4, 40)
  83. ] + [
  84. #(numpy.array([[0,0,1]], float), True),
  85. #(numpy.array([[0,0,0],[0,0,1]], float), True),
  86. #(numpy.array([[0,0,0],[0,0,1],[0,0,2]], float), True),
  87. #(numpy.array([[0,0,0],[0,0,1],[0,0,2],[0,0,4]], float), True),
  88. #(numpy.random.normal(0, 5, (3, 3)), True)
  89. ]
  90. # Do a random transformation on the points
  91. randomized = []
  92. for points, degenerate in references:
  93. #points[:] -= points.mean(axis=0)
  94. axis = random_unit(3)
  95. angle = numpy.random.uniform(0, numpy.pi*2)
  96. transformation = Complete()
  97. transformation.set_rotation_properties(angle, axis, False)
  98. transformation.t[:] = numpy.random.normal(0, 5, 3)
  99. randomized.append((
  100. numpy.array([transformation.vector_apply(p) for p in points]),
  101. transformation
  102. ))
  103. for (ref_points, degenerate), (tr_points, transf) in zip(references, randomized):
  104. check_transf = superpose(ref_points, tr_points)
  105. # check whether the rotation matrix is orthogonal
  106. self.assertArraysAlmostEqual(numpy.dot(check_transf.r, check_transf.r.transpose()), numpy.identity(3, float), 1e-5)
  107. # first check whether check_transf brings the tr_points back to the ref_points
  108. check_points = numpy.dot(tr_points, check_transf.r.transpose()) + check_transf.t
  109. self.assertArraysAlmostEqual(ref_points, check_points, 1e-5, doabs=True)
  110. if not degenerate:
  111. # if the set of points is not degenerate, check whether transf and check_transf
  112. # are each other inverses
  113. tmp = Complete()
  114. tmp.apply_before(transf)
  115. tmp.apply_before(check_transf)
  116. self.assertArraysAlmostEqual(numpy.dot(transf.r, check_transf.r), numpy.identity(3, float), 1e-5)
  117. self.assertArrayAlmostZero(tmp.t, 1e-5)
  118. # Add some distortion to the transformed points
  119. randomized = []
  120. for tr_points, transf in randomized:
  121. tr_points[:] += numpy.random.normal(0, 1.0, len(tr_points))
  122. # Do a blind test
  123. for (ref_points, degenerate), (tr_points, transf) in zip(references, randomized):
  124. superpose(ref_points, tr_points)