From 25c623706f5726e01ceafe4c3e7609cf7e4b17cd Mon Sep 17 00:00:00 2001 From: Ankith Date: Mon, 15 Jul 2024 02:04:56 +0530 Subject: [PATCH] Port more inv_rotate tests --- backend/tests/test_rotations.py | 124 ++++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) diff --git a/backend/tests/test_rotations.py b/backend/tests/test_rotations.py index d97d4f37..e9646f03 100644 --- a/backend/tests/test_rotations.py +++ b/backend/tests/test_rotations.py @@ -35,3 +35,127 @@ def test_inv_rotate(inv_rotate_func): assert_allclose(test_axis_collection, correct_axis_collection) assert_allclose(test_angle, correct_angle) + + +@pytest.mark.parametrize("inv_rotate_func", [inv_rotate, inv_rotate_scalar]) +@pytest.mark.parametrize("blocksize", [32, 128, 512]) +@pytest.mark.parametrize("point_distribution", ["anticlockwise", "clockwise"]) +def test_inv_rotate_correctness_on_circle_in_two_dimensions( + inv_rotate_func, blocksize, point_distribution +): + """Construct a unit circle, which we know has constant curvature, + and see if inv_rotate gives us the correct axis of rotation and + the angle of change + + Do this when d3 = z and d3= -z to cover both cases + + Parameters + ---------- + blocksize + + Returns + ------- + + """ + # FSAL start at 0. and proceeds counter-clockwise + if point_distribution == "anticlockwise": + theta_collection = np.linspace(0.0, 2.0 * np.pi, blocksize) + elif point_distribution == "clockwise": + theta_collection = np.linspace(2.0 * np.pi, 0.0, blocksize) + else: + raise NotImplementedError + + # rate of change, should correspond to frame rotation angles + dtheta_di = np.abs(theta_collection[1] - theta_collection[0]) + + # +1 because last point should be same as first point + director_collection = np.zeros((3, 3, blocksize)) + + # First fill all d1 components + # normal direction + director_collection[0, 0, ...] = -np.cos(theta_collection) + director_collection[0, 1, ...] = -np.sin(theta_collection) + + # Then all d2 components + # tangential direction + director_collection[1, 0, ...] = -np.sin(theta_collection) + director_collection[1, 1, ...] = np.cos(theta_collection) + + # Then all d3 components + director_collection[2, 2, ...] = -1.0 + + # blocksize - 1 to account for end effects + if point_distribution == "anticlockwise": + axis_of_rotation = np.array([0.0, 0.0, -1.0]) + elif point_distribution == "clockwise": + axis_of_rotation = np.array([0.0, 0.0, 1.0]) + else: + raise NotImplementedError + + correct_axis_collection = np.tile(axis_of_rotation.reshape(3, 1), blocksize - 1) + + test_axis_collection = np.asarray(inv_rotate_func(Tensor(director_collection))) + test_scaling = np.linalg.norm(test_axis_collection, axis=0) + test_axis_collection /= test_scaling + + assert test_axis_collection.shape == (3, blocksize - 1) + assert_allclose(test_axis_collection, correct_axis_collection) + assert_allclose(test_scaling, 0.0 * test_scaling + dtheta_di) + + +@pytest.mark.parametrize("inv_rotate_func", [inv_rotate, inv_rotate_scalar]) +@pytest.mark.parametrize("blocksize", [32, 128]) +def test_inv_rotate_correctness_on_circle_in_two_dimensions_with_different_directors( + inv_rotate_func, + blocksize, +): + """Construct a unit circle, which we know has constant curvature, + and see if inv_rotate gives us the correct axis of rotation and + the angle of change + + Here d3 is not z axis, so the `inv_rotate` formula returns the + curvature but with components in the local axis, i.e. it gives + [K1, K2, K3] in kappa_l = K1 . d1 + K2 . d2 + K3 . d3 + + Parameters + ---------- + blocksize + + Returns + ------- + + """ + # FSAL start at 0. and proceeds counter-clockwise + theta_collection = np.linspace(0.0, 2.0 * np.pi, blocksize) + # rate of change, should correspond to frame rotation angles + dtheta_di = theta_collection[1] - theta_collection[0] + + # +1 because last point should be same as first point + director_collection = np.zeros((3, 3, blocksize)) + + # First fill all d3 components + # tangential direction + director_collection[2, 0, ...] = -np.sin(theta_collection) + director_collection[2, 1, ...] = np.cos(theta_collection) + + # Then all d2 components + # normal direction + director_collection[1, 0, ...] = -np.cos(theta_collection) + director_collection[1, 1, ...] = -np.sin(theta_collection) + + # Then all d1 components + # binormal = d2 x d3 + director_collection[0, 2, ...] = -1.0 + + # blocksize - 1 to account for end effects + # returned curvature is in local coordinates! + correct_axis_collection = np.tile( + np.array([-1.0, 0.0, 0.0]).reshape(3, 1), blocksize - 1 + ) + test_axis_collection = np.asarray(inv_rotate_func(Tensor(director_collection))) + test_scaling = np.linalg.norm(test_axis_collection, axis=0) + test_axis_collection /= test_scaling + + assert test_axis_collection.shape == (3, blocksize - 1) + assert_allclose(test_axis_collection, correct_axis_collection) + assert_allclose(test_scaling, 0.0 * test_scaling + dtheta_di)