From b65aa44af187d43bafdb14797b29261fdcf2a9bf Mon Sep 17 00:00:00 2001
From: Taya Snijder <snijder@astron.nl>
Date: Mon, 28 Aug 2023 07:55:23 +0000
Subject: [PATCH] Resolve L2SS-1455 "Change angle to radians"

---
 README.md                                     |  1 +
 tangostationcontrol/VERSION                   |  2 +-
 .../devices/test_device_digitalbeam.py        |  6 +--
 .../devices/test_device_observation.py        | 38 +++++++++++++------
 .../default/devices/test_device_tilebeam.py   | 18 +++++----
 .../test_digitalbeam_performance.py           |  2 +-
 .../test_tilebeam_performance.py              |  2 +-
 .../base_device_classes/beam_device.py        |  2 +-
 .../devices/observation.py                    |  9 ++---
 .../test/devices/test_observation_base.py     |  4 +-
 tangostationcontrol/test/beam/test_delays.py  | 33 +++++++++-------
 .../devices/sdp/test_digitalbeam_device.py    |  4 +-
 12 files changed, 72 insertions(+), 49 deletions(-)

diff --git a/README.md b/README.md
index bf330a2d0..48c5c8a8d 100644
--- a/README.md
+++ b/README.md
@@ -115,6 +115,7 @@ Next change the version in the following places:
 
 # Release Notes
 
+* 0.21.0 Use radians instead of degrees when interpreting pointings
 * 0.20.5 Manage both polarisations in RCU_band_select_R(W), Antenna_Loss_R, and Frequency_Band_RW
 * 0.20.4 Collapse AbstractHierarchyDevice and AbstractHierarchy into one class
 * 0.20.3 Fix application of Field_Attenuation_R
diff --git a/tangostationcontrol/VERSION b/tangostationcontrol/VERSION
index 1b619f348..885415662 100644
--- a/tangostationcontrol/VERSION
+++ b/tangostationcontrol/VERSION
@@ -1 +1 @@
-0.20.5
+0.21.0
diff --git a/tangostationcontrol/integration_test/default/devices/test_device_digitalbeam.py b/tangostationcontrol/integration_test/default/devices/test_device_digitalbeam.py
index 4316c829a..a152c5e10 100644
--- a/tangostationcontrol/integration_test/default/devices/test_device_digitalbeam.py
+++ b/tangostationcontrol/integration_test/default/devices/test_device_digitalbeam.py
@@ -136,7 +136,7 @@ class TestDeviceDigitalBeam(AbstractTestBases.TestDeviceBase):
         # Point to Zenith
         self.proxy.set_pointing(
             numpy.array(
-                [["AZELGEO", "0deg", "90deg"]] * self.proxy.nr_beamlets_R
+                [["AZELGEO", "0rad", "1.570796rad"]] * self.proxy.nr_beamlets_R
             ).flatten()
         )
 
@@ -180,7 +180,7 @@ class TestDeviceDigitalBeam(AbstractTestBases.TestDeviceBase):
         # Point to Zenith
         self.proxy.set_pointing(
             numpy.array(
-                [["AZELGEO", "0deg", "90deg"]] * self.proxy.nr_beamlets_R
+                [["AZELGEO", "0rad", "1.570796rad"]] * self.proxy.nr_beamlets_R
             ).flatten()
         )
         # Store values with first subband configuration
@@ -228,7 +228,7 @@ class TestDeviceDigitalBeam(AbstractTestBases.TestDeviceBase):
 
         self.proxy.set_pointing(
             numpy.array(
-                [["AZELGEO", "0deg", "90deg"]] * self.proxy.nr_beamlets_R
+                [["AZELGEO", "0rad", "1.570796rad"]] * self.proxy.nr_beamlets_R
             ).flatten()
         )
 
diff --git a/tangostationcontrol/integration_test/default/devices/test_device_observation.py b/tangostationcontrol/integration_test/default/devices/test_device_observation.py
index b36350447..a21df5d39 100644
--- a/tangostationcontrol/integration_test/default/devices/test_device_observation.py
+++ b/tangostationcontrol/integration_test/default/devices/test_device_observation.py
@@ -225,14 +225,14 @@ class TestDeviceObservation(AbstractTestBases.TestDeviceBase):
         saps_pointing = [
             (
                 pointing_direction["direction_type"],
-                f"{pointing_direction['angle1']}deg",
-                f"{pointing_direction['angle2']}deg",
+                f"{pointing_direction['angle1']}rad",
+                f"{pointing_direction['angle2']}rad",
             )
         ] * len(data["SAPs"][0]["subbands"])
         tile_beam = [
             str(data["tile_beam"]["direction_type"]),
-            f"{data['tile_beam']['angle1']}deg",
-            f"{data['tile_beam']['angle2']}deg",
+            f"{data['tile_beam']['angle1']}rad",
+            f"{data['tile_beam']['angle2']}rad",
         ]
         first_beamlet = data["first_beamlet"]
 
@@ -290,7 +290,7 @@ class TestDeviceObservation(AbstractTestBases.TestDeviceBase):
     def test_apply_pointing(self):
         """Test that attribute sap pointing is correctly applied"""
         digitalbeam_proxy = self.setup_digitalbeam_proxy()
-        default_pointing = [("AZELGEO", "0deg", "90deg")] * N_beamlets_ctrl
+        default_pointing = [("AZELGEO", "0rad", "1.570796rad")] * N_beamlets_ctrl
         digitalbeam_proxy.Pointing_direction_RW = default_pointing
         self.assertListEqual(
             list(digitalbeam_proxy.Pointing_direction_RW), default_pointing
@@ -299,26 +299,42 @@ class TestDeviceObservation(AbstractTestBases.TestDeviceBase):
         self.proxy.observation_settings_RW = self.VALID_JSON
         self.proxy.Initialise()
         self.proxy.On()
-        expected_pointing = [("J2000", "1.5deg", "0deg")] * 3 + [
-            ("AZELGEO", "0deg", "90deg")
+
+        expected_pointing = [("J2000", "0.0261799rad", "0rad")] * 3 + [
+            ("AZELGEO", "0rad", "1.570796rad")
+        ] * (N_beamlets_ctrl - 3)
+
+        digitalbeam_pointing = list(digitalbeam_proxy.Pointing_direction_RW[0])
+        digitalbeam_pointing[1] = digitalbeam_pointing[1][:9] + "rad"
+        digitalbeam_pointing = [tuple(digitalbeam_pointing)] * 3 + [
+            ("AZELGEO", "0rad", "1.570796rad")
         ] * (N_beamlets_ctrl - 3)
+
+        self.maxDiff = None
+
         self.assertListEqual(
-            list(digitalbeam_proxy.Pointing_direction_RW), expected_pointing
+            digitalbeam_pointing,
+            expected_pointing,
         )
 
     def test_apply_tilebeam(self):
         # failing
         """Test that attribute tilebeam is correctly applied"""
         tilebeam_proxy = self.setup_tilebeam_proxy()
-        pointing_direction = [("J2000", "0deg", "0deg")] * CS001_TILES
+        pointing_direction = [("J2000", "0rad", "0rad")] * CS001_TILES
         tilebeam_proxy.Pointing_direction_RW = pointing_direction
         self.assertListEqual(
-            list(tilebeam_proxy.Pointing_direction_RW[0]), ["J2000", "0deg", "0deg"]
+            list(tilebeam_proxy.Pointing_direction_RW[0]), ["J2000", "0rad", "0rad"]
         )
         self.proxy.off()
         self.proxy.observation_settings_RW = self.VALID_JSON
         self.proxy.Initialise()
         self.proxy.On()
+
+        tilebeam_directions = list(tilebeam_proxy.Pointing_direction_RW[0])
+        tilebeam_directions[1] = tilebeam_directions[1][:9] + "rad"
+
         self.assertListEqual(
-            list(tilebeam_proxy.Pointing_direction_RW[0]), ["J2000", "1.5deg", "0deg"]
+            tilebeam_directions,
+            ["J2000", "0.0261799rad", "0rad"],
         )
diff --git a/tangostationcontrol/integration_test/default/devices/test_device_tilebeam.py b/tangostationcontrol/integration_test/default/devices/test_device_tilebeam.py
index 2fc4edc79..5d644bb06 100644
--- a/tangostationcontrol/integration_test/default/devices/test_device_tilebeam.py
+++ b/tangostationcontrol/integration_test/default/devices/test_device_tilebeam.py
@@ -28,7 +28,7 @@ class NumpyEncoder(json.JSONEncoder):
 
 class TestDeviceTileBeam(AbstractTestBases.TestDeviceBase):
     POINTING_DIRECTION = numpy.array(
-        [["J2000", "0deg", "0deg"]] * CS001_TILES
+        [["J2000", "0rad", "0rad"]] * CS001_TILES
     ).flatten()
 
     def setUp(self):
@@ -124,7 +124,7 @@ class TestDeviceTileBeam(AbstractTestBases.TestDeviceBase):
 
         # Point to Zenith
         self.proxy.set_pointing(
-            numpy.array([["AZELGEO", "0deg", "90deg"]] * CS001_TILES).flatten()
+            numpy.array([["AZELGEO", "0rad", "1.570796rad"]] * CS001_TILES).flatten()
         )
 
         calculated_HBAT_delay_steps = numpy.array(
@@ -149,7 +149,7 @@ class TestDeviceTileBeam(AbstractTestBases.TestDeviceBase):
         self.proxy.Tracking_enabled_RW = False
 
         # point at north on the horizon
-        self.proxy.set_pointing(["AZELGEO", "0deg", "0deg"] * CS001_TILES)
+        self.proxy.set_pointing(["AZELGEO", "0rad", "0rad"] * CS001_TILES)
 
         # obtain delays of the X polarisation of all the elements of the first tile
         north_beam_delay_steps = antennafield_proxy.HBAT_BF_delay_steps_RW[0].reshape(
@@ -161,17 +161,19 @@ class TestDeviceTileBeam(AbstractTestBases.TestDeviceBase):
             north_beam_delay_steps.tolist(),
             numpy.rot90(north_beam_delay_steps).tolist(),
         )
-
-        for angle in (90, 180, 270):
+        # 90, 180 and 270 degrees
+        for angle in (1.570796, 3.141593, 4.712389):
             # point at angle degrees (90=E, 180=S, 270=W)
-            self.proxy.set_pointing(["AZELGEO", f"{angle}deg", "0deg"] * CS001_TILES)
+            self.proxy.set_pointing(["AZELGEO", f"{angle}rad", "0rad"] * CS001_TILES)
 
             # obtain delays of the X polarisation of all the elements of the first tile
             angled_beam_delay_steps = antennafield_proxy.HBAT_BF_delay_steps_RW[
                 0
             ].reshape(4, 4, 2)[:, :, 0]
 
-            expected_delay_steps = numpy.rot90(north_beam_delay_steps, k=-(angle / 90))
+            expected_delay_steps = numpy.rot90(
+                north_beam_delay_steps, k=-(int((angle * 180) / numpy.pi) / 90)
+            )
 
             self.assertListEqual(
                 expected_delay_steps.tolist(),
@@ -234,7 +236,7 @@ class TestDeviceTileBeam(AbstractTestBases.TestDeviceBase):
         self.assertTrue(self.proxy.Tracking_enabled_R)
 
         # point somewhere
-        new_pointings = [("J2000", f"{tile}deg", "0deg") for tile in range(CS001_TILES)]
+        new_pointings = [("J2000", f"{tile}rad", "0rad") for tile in range(CS001_TILES)]
         self.proxy.Pointing_direction_RW = new_pointings
 
         # check pointing
diff --git a/tangostationcontrol/integration_test/digitalbeam_performance/test_digitalbeam_performance.py b/tangostationcontrol/integration_test/digitalbeam_performance/test_digitalbeam_performance.py
index d2680a02f..4ed1e4e4a 100644
--- a/tangostationcontrol/integration_test/digitalbeam_performance/test_digitalbeam_performance.py
+++ b/tangostationcontrol/integration_test/digitalbeam_performance/test_digitalbeam_performance.py
@@ -21,7 +21,7 @@ logger = logging.getLogger()
 class TestDigitalbeamPerformance(base.IntegrationTestCase):
     # The AntennaField is setup with self.NR_TILES tiles in the test configuration
     POINTING_DIRECTION = numpy.array(
-        [["J2000", "0deg", "0deg"]] * N_beamlets_ctrl
+        [["J2000", "0rad", "0rad"]] * N_beamlets_ctrl
     ).flatten()
 
     def setUp(self):
diff --git a/tangostationcontrol/integration_test/tilebeam_performance/test_tilebeam_performance.py b/tangostationcontrol/integration_test/tilebeam_performance/test_tilebeam_performance.py
index 916ee37a8..f1dca1038 100644
--- a/tangostationcontrol/integration_test/tilebeam_performance/test_tilebeam_performance.py
+++ b/tangostationcontrol/integration_test/tilebeam_performance/test_tilebeam_performance.py
@@ -19,7 +19,7 @@ logger = logging.getLogger()
 class TestTilebeamPerformance(base.IntegrationTestCase):
     # The AntennaField is setup with self.NR_TILES tiles in the test configuration
     NR_TILES = 48
-    POINTING_DIRECTION = numpy.array([["J2000", "0deg", "0deg"]] * NR_TILES).flatten()
+    POINTING_DIRECTION = numpy.array([["J2000", "0rad", "0rad"]] * NR_TILES).flatten()
 
     def setUp(self):
         super(TestTilebeamPerformance, self).setUp()
diff --git a/tangostationcontrol/tangostationcontrol/devices/base_device_classes/beam_device.py b/tangostationcontrol/tangostationcontrol/devices/base_device_classes/beam_device.py
index 7a19a17fa..b7b370aa5 100644
--- a/tangostationcontrol/tangostationcontrol/devices/base_device_classes/beam_device.py
+++ b/tangostationcontrol/tangostationcontrol/devices/base_device_classes/beam_device.py
@@ -299,7 +299,7 @@ class BeamDevice(AsyncDevice):
             (num_pointings, N_point_prop), dtype="<U32"
         )
         self._beam_manager.new_pointing_direction = numpy.array(
-            [["AZELGEO", "0deg", "90deg"]] * num_pointings, dtype="<U32"
+            [["AZELGEO", "0rad", "1.570796rad"]] * num_pointings, dtype="<U32"
         )
 
         self._beam_manager.beam_tracking_application_offset = (
diff --git a/tangostationcontrol/tangostationcontrol/devices/observation.py b/tangostationcontrol/tangostationcontrol/devices/observation.py
index 471f0a1fc..d195f5480 100644
--- a/tangostationcontrol/tangostationcontrol/devices/observation.py
+++ b/tangostationcontrol/tangostationcontrol/devices/observation.py
@@ -141,8 +141,8 @@ class Observation(LOFARDevice):
                 saps_pointing.append(
                     (
                         sap.pointing.direction_type,
-                        f"{sap.pointing.angle1}deg",
-                        f"{sap.pointing.angle2}deg",
+                        f"{sap.pointing.angle1}rad",
+                        f"{sap.pointing.angle2}rad",
                     ),
                 )
         return saps_pointing
@@ -159,8 +159,8 @@ class Observation(LOFARDevice):
         pointing_direction = self._observation_settings.tile_beam
         return [
             str(pointing_direction.direction_type),
-            f"{pointing_direction.angle1}deg",
-            f"{pointing_direction.angle2}deg",
+            f"{pointing_direction.angle1}rad",
+            f"{pointing_direction.angle2}rad",
         ]
 
     @attribute(
@@ -309,7 +309,6 @@ class Observation(LOFARDevice):
     @log_exceptions()
     def _stop_observation(self):
         """Tear down station resources we used."""
-
         pass
 
     @fault_on_error()
diff --git a/tangostationcontrol/tangostationcontrol/test/devices/test_observation_base.py b/tangostationcontrol/tangostationcontrol/test/devices/test_observation_base.py
index b1f20f80b..03dc58103 100644
--- a/tangostationcontrol/tangostationcontrol/test/devices/test_observation_base.py
+++ b/tangostationcontrol/tangostationcontrol/test/devices/test_observation_base.py
@@ -13,11 +13,11 @@ class TestObservationBase:
               "SAPs": [{
                     "subbands": [10, 20, 30],
                     "pointing": {
-                        "angle1": 1.5, "angle2": 0, "direction_type": "J2000"
+                        "angle1": 0.0261799, "angle2": 0, "direction_type": "J2000"
                     }
               }],
               "tile_beam":
-                { "angle1": 1.5, "angle2": 0, "direction_type": "J2000" },
+                { "angle1": 0.0261799, "angle2": 0, "direction_type": "J2000" },
               "first_beamlet": 0
             }
         """
diff --git a/tangostationcontrol/test/beam/test_delays.py b/tangostationcontrol/test/beam/test_delays.py
index 683a96c73..7d4173c6f 100644
--- a/tangostationcontrol/test/beam/test_delays.py
+++ b/tangostationcontrol/test/beam/test_delays.py
@@ -41,11 +41,11 @@ class TestDelays(base.TestCase):
         d = Delays([0, 0, 0])
 
         # should accept base use cases
-        self.assertTrue(d.is_valid_direction(("J2000", "0deg", "0deg")))
-        self.assertTrue(d.is_valid_direction(("J2000", "270deg", "90deg")))
-        self.assertTrue(d.is_valid_direction(("AZELGEO", "0deg", "0deg")))
-        self.assertTrue(d.is_valid_direction(("AZELGEO", "270deg", "90deg")))
-        self.assertTrue(d.is_valid_direction(("SUN", "0deg", "0deg")))
+        self.assertTrue(d.is_valid_direction(("J2000", "0rad", "0rad")))
+        self.assertTrue(d.is_valid_direction(("J2000", "4.712389rad", "1.570796rad")))
+        self.assertTrue(d.is_valid_direction(("AZELGEO", "0rad", "0rad")))
+        self.assertTrue(d.is_valid_direction(("AZELGEO", "4.712389rad", "1.570796rad")))
+        self.assertTrue(d.is_valid_direction(("SUN", "0rad", "0rad")))
 
         # i dont get these either, but casacore accepts them
         self.assertTrue(d.is_valid_direction([]))
@@ -54,16 +54,16 @@ class TestDelays(base.TestCase):
             d.is_valid_direction(
                 (
                     "J2000",
-                    "0deg",
+                    "0rad",
                 )
             )
         )
-        self.assertTrue(d.is_valid_direction(("J2000", "0deg", "0deg", "0deg")))
+        self.assertTrue(d.is_valid_direction(("J2000", "0rad", "0rad", "0rad")))
 
         # should not throw, and return False, on bad uses
         self.assertFalse(d.is_valid_direction(("", "", "")))
         self.assertFalse(
-            d.is_valid_direction(("J2000", "0deg", "0deg", "0deg", "0deg"))
+            d.is_valid_direction(("J2000", "0rad", "0rad", "0rad", "0rad"))
         )
         self.assertFalse(d.is_valid_direction((1, 2, 3)))
         self.assertFalse(d.is_valid_direction("foo"))
@@ -80,7 +80,7 @@ class TestDelays(base.TestCase):
             d.set_measure_time(timestamp)
 
             # point to the sun
-            direction = "SUN", "0deg", "0deg"
+            direction = "SUN", "0rad", "0rad"
 
             # calculate the delays based on the set reference position, the set time and now the set direction and antenna positions.
             pointing = d.measure.direction(*direction)
@@ -121,7 +121,7 @@ class TestDelays(base.TestCase):
         # compute the delays for an antennas w.r.t. the reference position
 
         # # obtain the direction vector for a specific pointing
-        direction = "J2000", "0deg", "0deg"
+        direction = "J2000", "0rad", "0rad"
 
         # calculate the delays based on the set reference position, the set time and now the set direction and antenna positions.
         delays = d.delays(direction, antenna_itrf)
@@ -146,7 +146,7 @@ class TestDelays(base.TestCase):
         d.set_measure_time(timestamp)
 
         # # obtain the direction vector for a specific pointing
-        direction = "J2000", "0deg", "90deg"
+        direction = "J2000", "0rad", "1.570796rad"
 
         # calculate the delays based on the set reference position, the set time and now the set direction and antenna positions.
         delays = d.delays(direction, antenna_itrf)
@@ -176,7 +176,7 @@ class TestDelays(base.TestCase):
             2022, 3, 1, 0, 0, 0
         )  # timestamp does not actually matter, but casacore doesn't know that.
         d.set_measure_time(timestamp)
-        direction = "J2000", "0deg", "90deg"
+        direction = "J2000", "0rad", "1.570796rad"
 
         # calculate the delays based on the set reference position, the set time and now the set direction and antenna positions.
         delays = d.delays(direction, antenna_itrf)
@@ -192,7 +192,12 @@ class TestDelays(base.TestCase):
 
         # generate different positions and directions
         positions = numpy.array([[i, 2, 3] for i in range(5)])
-        directions = numpy.array([["J2000", f"{i}deg", f"{i}deg"] for i in range(90)])
+        directions = numpy.array(
+            [
+                ["J2000", f"{i*numpy.pi/180}rad", f"{i*numpy.pi/180}rad"]
+                for i in range(90)
+            ]
+        )
 
         bulk_result = d.delays_bulk(directions, positions)
 
@@ -218,7 +223,7 @@ class TestDelays(base.TestCase):
         d.set_measure_time(timestamp)
 
         positions = numpy.array([[1, 2, 3]] * MAX_ANTENNA)
-        directions = numpy.array([["J2000", "0deg", "0deg"]] * N_beamlets_ctrl)
+        directions = numpy.array([["J2000", "0rad", "0rad"]] * N_beamlets_ctrl)
 
         count = 10
         before = time.monotonic_ns()
diff --git a/tangostationcontrol/test/devices/sdp/test_digitalbeam_device.py b/tangostationcontrol/test/devices/sdp/test_digitalbeam_device.py
index 4088b7664..381b60fb7 100644
--- a/tangostationcontrol/test/devices/sdp/test_digitalbeam_device.py
+++ b/tangostationcontrol/test/devices/sdp/test_digitalbeam_device.py
@@ -41,7 +41,7 @@ class TestDigitalBeamDevice(device_base.DeviceTestCase):
         """Verify won't overwrite digitalbeam data if no input_selected"""
 
         input_data = numpy.array(
-            [["AZELGEO", "0deg", "90deg"]] * N_beamlets_ctrl
+            [["AZELGEO", "0rad", "1.570796rad"]] * N_beamlets_ctrl
         ).flatten()
         current_data = numpy.array([[16384] * (A_pn * N_beamlets_ctrl)] * N_pn)
 
@@ -81,7 +81,7 @@ class TestDigitalBeamDevice(device_base.DeviceTestCase):
         """Verify can overwrite digitalbeam data if input_selected"""
 
         input_data = numpy.array(
-            [["AZELGEO", "0deg", "90deg"]] * N_beamlets_ctrl
+            [["AZELGEO", "0rad", "1.570796rad"]] * N_beamlets_ctrl
         ).flatten()
         current_data = numpy.array([[16384] * (A_pn * N_beamlets_ctrl)] * N_pn)
 
-- 
GitLab