From 92116f14860980326f4fe4361f2f00163a6afcd2 Mon Sep 17 00:00:00 2001 From: Amy Stamile <astamile@usgs.gov> Date: Thu, 25 Apr 2024 19:14:33 -0700 Subject: [PATCH] fixed tests. --- knoten/sensor_utils.py | 4 +- knoten/shape.py | 6 ++- knoten/utils.py | 1 + tests/test_csm.py | 10 +--- tests/test_illuminator.py | 24 +++++++++ tests/test_sensorutils.py | 108 +++++++++++++++++++++++--------------- tests/test_shape.py | 28 ++++++++++ 7 files changed, 127 insertions(+), 54 deletions(-) create mode 100644 tests/test_illuminator.py create mode 100644 tests/test_shape.py diff --git a/knoten/sensor_utils.py b/knoten/sensor_utils.py index cfadaee..be985aa 100644 --- a/knoten/sensor_utils.py +++ b/knoten/sensor_utils.py @@ -34,7 +34,7 @@ def phase_angle(image_pt, sensor, shape, illuminator): sensor_state = csm.get_state(sensor, image_pt) ground_pt = shape.intersect_surface(sensor_state["sensorPos"], sensor_state["lookVec"]) - + illum_pos = illuminator.get_position_from_csm_sensor(sensor, ground_pt) vec_a = utils.Point(sensor_state["sensorPos"].x - ground_pt.x, @@ -44,7 +44,7 @@ def phase_angle(image_pt, sensor, shape, illuminator): vec_b = utils.Point(illum_pos.x - ground_pt.x, illum_pos.y - ground_pt.y, illum_pos.z - ground_pt.z) - + return np.rad2deg(utils.sep_angle(vec_a, vec_b)) def emission_angle(image_pt, sensor, shape): diff --git a/knoten/shape.py b/knoten/shape.py index 509e15d..441ab06 100644 --- a/knoten/shape.py +++ b/knoten/shape.py @@ -8,7 +8,7 @@ class Ellipsoid: A biaxial ellipsoid shape model. """ - def __init__(self, semi_major, semi_minor = None): + def __init__(self, semi_major, semi_minor=None, median=None): """ Create an ellipsoid shape model from a set of radii @@ -23,9 +23,13 @@ class Ellipsoid: self.b = semi_major self.c = semi_major + if median is not None: + self.b = median + if semi_minor is not None: self.c = semi_minor + @classmethod def from_csm_sensor(cls, sensor): semi_major, semi_minor = csm.get_radii(sensor) diff --git a/knoten/utils.py b/knoten/utils.py index cde4fe5..1165b85 100644 --- a/knoten/utils.py +++ b/knoten/utils.py @@ -29,6 +29,7 @@ def sep_angle(a_vec, b_vec): : np.ndarray """ dot_prod = a_vec.x * b_vec.x + a_vec.y * b_vec.y + a_vec.z * b_vec.z + print(dot_prod) dot_prod /= magnitude(a_vec) * magnitude(b_vec) if(dot_prod >= 1.0): return 0.0 diff --git a/tests/test_csm.py b/tests/test_csm.py index ede5308..b31e9b9 100644 --- a/tests/test_csm.py +++ b/tests/test_csm.py @@ -85,12 +85,4 @@ def test_get_state(mock_sensor, pt): "imagePoint": pt } - assert state == expected - - -@mock.patch.object(csm, 'get_radii', return_value=(10, 10)) -def test_get_surface_normal(mock_sensor): - ground_pt = utils.Point(1, 0, 0) - normal = csm.get_surface_normal(mock_sensor, ground_pt) - - assert normal == (1.0, 0.0, 0.0) \ No newline at end of file + assert state == expected \ No newline at end of file diff --git a/tests/test_illuminator.py b/tests/test_illuminator.py new file mode 100644 index 0000000..e7d8688 --- /dev/null +++ b/tests/test_illuminator.py @@ -0,0 +1,24 @@ +import unittest +from unittest import mock + +import csmapi + +from knoten import utils +from knoten.illuminator import Illuminator + +class TestIlluminator(unittest.TestCase): + + def test_get_position_from_csm_sensor(self): + mock_sensor = mock.MagicMock(spec=csmapi.RasterGM) + mock_sensor.getIlluminationDirection.return_value = utils.Point(1.0, 10.0, 0.0) + + test_illum = Illuminator() + + ground_pt = utils.Point(10.0, 10.0, 0.0) + + position = test_illum.get_position_from_csm_sensor(mock_sensor, ground_pt) + + self.assertEqual(position, (9.0, 0.0, 0.0)) + + def tearDown(self): + pass \ No newline at end of file diff --git a/tests/test_sensorutils.py b/tests/test_sensorutils.py index c7be63a..b6731c2 100644 --- a/tests/test_sensorutils.py +++ b/tests/test_sensorutils.py @@ -3,7 +3,7 @@ import pytest import numpy as np import csmapi -from knoten import csm, sensor_utils, utils, bundle +from knoten import csm, sensor_utils, utils, bundle, shape, illuminator @pytest.fixture def mock_sensor(): @@ -14,32 +14,46 @@ def mock_sensor(): def pt(): return csmapi.ImageCoord(0.0, 0.0) -@mock.patch.object(csm, 'get_state', return_value={'sensorPos': utils.Point(100.0, 0.0, 0.0)}) -@mock.patch.object(csm, 'generate_ground_point', return_value=utils.Point(0,0,0)) -def test_phase_angle(mock_sensor, pt): - mock_sensor.getIlluminationDirection.return_value = utils.Point(100.0, 100.0, 0.0) - phase_angle = sensor_utils.phase_angle(pt, mock_sensor) +@pytest.fixture +def test_shape(): + return shape.Ellipsoid(0, 0) - np.testing.assert_array_equal(phase_angle, 135.0) +@pytest.fixture +def test_illuminator(): + return illuminator.Illuminator(0, 0) -@mock.patch.object(csm, 'get_state', return_value={'sensorPos': utils.Point(100.0, 0.0, 0.0)}) -@mock.patch.object(csm, 'generate_ground_point', return_value=utils.Point(0,0,0)) -def test_emission_angle(mock_sensor, pt): - with mock.patch.object(csm, 'get_surface_normal', return_value=utils.Point(-1,0,0)) as mock_normal: - emission_angle = sensor_utils.emission_angle(pt, mock_sensor) +def test_phase_angle(mock_sensor, pt, test_shape, test_illuminator): + with ( + mock.patch.object(illuminator.Illuminator, 'get_position_from_csm_sensor', return_value=utils.Point(100.0, 100.0, 0.0)), + mock.patch.object(csm, 'get_state', return_value={'sensorPos': utils.Point(100.0, 0.0, 0.0), 'lookVec': utils.Point(-1.0, 0.0, 0.0)}), + mock.patch.object(shape.Ellipsoid, 'intersect_surface', return_value=utils.Point(0,0,0)) + ): + phase_angle = sensor_utils.phase_angle(pt, mock_sensor, test_shape, test_illuminator) - mock_normal.assert_called() + np.testing.assert_allclose(phase_angle, 45.0) - np.testing.assert_array_equal(emission_angle, 180.0) +def test_emission_angle(mock_sensor, pt, test_shape): + with ( + mock.patch.object(shape.Ellipsoid, 'get_surface_normal', return_value=utils.Point(-1,0,0)), + mock.patch.object(shape.Ellipsoid, 'intersect_surface', return_value=utils.Point(0,0,0)), + mock.patch.object(csm, 'get_state', return_value={'sensorPos': utils.Point(100.0, 0.0, 0.0), 'lookVec': utils.Point(-1.0, 0.0, 0.0)}), + mock.patch.object(illuminator.Illuminator, 'get_position_from_csm_sensor', return_value=utils.Point(100.0, 100.0, 0.0)) + ): + emission_angle = sensor_utils.emission_angle(pt, mock_sensor, test_shape) -@mock.patch.object(csm, 'get_state', return_value={'sensorPos': utils.Point(-100.0, 0.0, 0.0)}) -@mock.patch.object(csm, 'generate_ground_point', return_value=utils.Point(0,0,0)) -def test_slant_distance(mock_sensor, pt): - slant_distance = sensor_utils.slant_distance(pt, mock_sensor) + np.testing.assert_array_equal(emission_angle, 180.0) - np.testing.assert_array_equal(slant_distance, 100.0) + +def test_slant_distance(mock_sensor, pt, test_shape): + with ( + mock.patch.object(csm, 'get_state', return_value={'sensorPos': utils.Point(100.0, 0.0, 0.0), 'lookVec': utils.Point(-1.0, 0.0, 0.0)}), + mock.patch.object(shape.Ellipsoid, 'intersect_surface', return_value=utils.Point(0,0,0)) + ): + slant_distance = sensor_utils.slant_distance(pt, mock_sensor, test_shape) + + np.testing.assert_array_equal(slant_distance, 100.0) @mock.patch.object(csm, 'get_state', return_value={'sensorPos': utils.Point(-100.0, 0.0, 0.0)}) @@ -56,18 +70,18 @@ def test_sub_spacecraft_point(mock_sensor, pt): np.testing.assert_array_equal(sub_spacecraft_point, [90.0, 0.0]) -@mock.patch.object(csm, 'get_state', return_value={'sensorPos': utils.Point(100.0, 0.0, 0.0)}) -@mock.patch.object(csm, 'generate_ground_point', return_value=utils.Point(10.0, 0.0, 0.0)) -def test_local_radius_intersection(mock_sensor, pt): - local_radius = sensor_utils.local_radius(pt, mock_sensor) +@mock.patch.object(csm, 'get_state', return_value={'sensorPos': utils.Point(100.0, 0.0, 0.0), 'lookVec': utils.Point(-1.0, 0.0, 0.0)}) +@mock.patch.object(shape.Ellipsoid, 'intersect_surface', return_value=utils.Point(10.0, 0.0, 0.0)) +def test_local_radius_intersection(mock_sensor, pt, test_shape): + local_radius = sensor_utils.local_radius(pt, mock_sensor, test_shape) np.testing.assert_array_equal(local_radius, 10.0) -@mock.patch.object(csm, 'get_state', return_value={'sensorPos': utils.Point(-1000.0, 0.0, 0.0)}) -@mock.patch.object(csm, 'generate_ground_point', return_value=utils.Point(10.0, 0.0, 0.0)) -def test_local_radius_ground(mock_sensor, pt): - local_radius = sensor_utils.local_radius(pt, mock_sensor) +@mock.patch.object(csm, 'get_state', return_value={'sensorPos': utils.Point(1000.0, 0.0, 0.0), 'lookVec': utils.Point(-1000.0, 0.0, 0.0)}) +@mock.patch.object(shape.Ellipsoid, 'intersect_surface', return_value=utils.Point(10.0, 0.0, 0.0)) +def test_local_radius_ground(mock_sensor, pt, test_shape): + local_radius = sensor_utils.local_radius(pt, mock_sensor, test_shape) np.testing.assert_array_equal(local_radius, 10.0) @@ -79,25 +93,35 @@ def test_right_ascension_declination(mock_sensor, pt): np.testing.assert_array_equal(right_ascension_declination, [180.0, 0.0]) -@mock.patch.object(csm, 'generate_ground_point', return_value=utils.Point(0.0, 0.0, 0.0)) -@mock.patch.object(bundle, 'compute_image_partials', return_value=np.array([2, 1, 4, 4, 4, 8])) -def test_line_resolution(mock_sensor, pt): - line_resolution = sensor_utils.line_resolution(pt, mock_sensor) +def test_line_resolution(mock_sensor, pt, test_shape): + with ( + mock.patch.object(bundle, 'compute_image_partials', return_value=np.array([2, 1, 4, 4, 4, 8])), + mock.patch.object(shape.Ellipsoid, 'intersect_surface', return_value=utils.Point(0,0,0)), + mock.patch.object(csm, 'get_state', return_value={'sensorPos': utils.Point(100.0, 0.0, 0.0), 'lookVec': utils.Point(-1.0, 0.0, 0.0)}) + ): + line_resolution = sensor_utils.line_resolution(pt, mock_sensor, test_shape) + + np.testing.assert_array_equal(line_resolution, 6.0) - np.testing.assert_array_equal(line_resolution, 6.0) -@mock.patch.object(csm, 'generate_ground_point', return_value=utils.Point(0.0, 0.0, 0.0)) -@mock.patch.object(bundle, 'compute_image_partials', return_value=np.array([2, 1, 4, 4, 4, 8])) -def test_sample_resolution(mock_sensor, pt): - sample_resolution = sensor_utils.sample_resolution(pt, mock_sensor) +def test_sample_resolution(mock_sensor, pt, test_shape): + with ( + mock.patch.object(bundle, 'compute_image_partials', return_value=np.array([2, 1, 4, 4, 4, 8])), + mock.patch.object(shape.Ellipsoid, 'intersect_surface', return_value=utils.Point(0,0,0)), + mock.patch.object(csm, 'get_state', return_value={'sensorPos': utils.Point(100.0, 0.0, 0.0), 'lookVec': utils.Point(-1.0, 0.0, 0.0)}) + ): + sample_resolution = sensor_utils.sample_resolution(pt, mock_sensor, test_shape) - np.testing.assert_array_equal(sample_resolution, 9.0) + np.testing.assert_array_equal(sample_resolution, 9.0) -@mock.patch.object(csm, 'generate_ground_point', return_value=utils.Point(0.0, 0.0, 0.0)) -@mock.patch.object(bundle, 'compute_image_partials', return_value=np.array([2, 1, 4, 4, 4, 8])) -def test_pixel_resolution(mock_sensor, pt): - pixel_resolution = sensor_utils.pixel_resolution(pt, mock_sensor) +def test_pixel_resolution(mock_sensor, pt, test_shape): + with ( + mock.patch.object(bundle, 'compute_image_partials', return_value=np.array([2, 1, 4, 4, 4, 8])), + mock.patch.object(shape.Ellipsoid, 'intersect_surface', return_value=utils.Point(0,0,0)), + mock.patch.object(csm, 'get_state', return_value={'sensorPos': utils.Point(100.0, 0.0, 0.0), 'lookVec': utils.Point(-1.0, 0.0, 0.0)}) + ): + pixel_resolution = sensor_utils.pixel_resolution(pt, mock_sensor, test_shape) - np.testing.assert_array_equal(pixel_resolution, 7.5) \ No newline at end of file + np.testing.assert_array_equal(pixel_resolution, 7.5) \ No newline at end of file diff --git a/tests/test_shape.py b/tests/test_shape.py new file mode 100644 index 0000000..07cb559 --- /dev/null +++ b/tests/test_shape.py @@ -0,0 +1,28 @@ +import unittest +from unittest import mock + +from knoten import shape, utils + +class TestEllipsoid(unittest.TestCase): + + def test_get_surface_normal(self): + test_shape = shape.Ellipsoid(10, 10) + + ground_pt = utils.Point(1, 0, 0) + normal = test_shape.get_surface_normal(ground_pt) + + self.assertEqual(normal, (1.0, 0.0, 0.0)) + + def test_intersect_surface(self): + test_shape = shape.Ellipsoid(10, 10) + sensor_pos = utils.Point(100, 0, 0) + look_vec = utils.Point(-1, 0, 0) + + intersection = test_shape.intersect_surface(sensor_pos, look_vec) + + self.assertEqual(intersection.x, 10.0) + self.assertEqual(intersection.y, 0.0) + self.assertEqual(intersection.z, 0.0) + + def tearDown(self): + pass \ No newline at end of file -- GitLab