From d963e45bed49b4c0dad8baccca84f6cd81057565 Mon Sep 17 00:00:00 2001 From: Tom Aldcroft Date: Tue, 28 Feb 2023 18:37:19 -0500 Subject: [PATCH] Change allowed_rolldev to use chandra_models --- ska_sun/sun.py | 42 +++++++++++++++++++++++++-------------- ska_sun/tests/test_sun.py | 40 +++++++++++++++++++++---------------- 2 files changed, 50 insertions(+), 32 deletions(-) diff --git a/ska_sun/sun.py b/ska_sun/sun.py index 1cd68b9..93b35d8 100755 --- a/ska_sun/sun.py +++ b/ska_sun/sun.py @@ -3,7 +3,6 @@ Utility for calculating sun position, pitch angle and values related to roll. """ from math import acos, asin, atan2, cos, degrees, pi, radians, sin -from pathlib import Path import numpy as np import Ska.quatutil @@ -12,14 +11,20 @@ from chandra_aca.transform import radec_to_eci from Quaternion import Quat from ska_helpers.utils import LazyVal +from ska_helpers import chandra_models + + +CHANDRA_MODELS_PITCH_ROLL_FILE = "chandra_models/pitch_roll/pitch_roll_constraint.csv" def load_roll_table(): - dat = Table.read(Path(__file__).parent / "data" / "pitch_roll.fits.gz") + """Load the pitch/roll table from the chandra_models repo.""" + dat = chandra_models.get_data( + CHANDRA_MODELS_PITCH_ROLL_FILE, read_func=Table.read + ) + # Sanity check that the pitch values are monotonically increasing. + assert np.all(np.diff(dat["pitch"]) > 0) - # Add a terminating row to the data such that for pitch at or greater - # than 180 the allowed roll deviation is defined as 0. - dat.add_row({"pitch": 180, "rolldev": 0}) return dat @@ -28,17 +33,24 @@ def load_roll_table(): def allowed_rolldev(pitch): """Get allowed roll deviation (off-nominal roll) for the given ``pitch``. - :param pitch: Sun pitch angle (deg) - :returns: Roll deviation (deg) + + This performs a linear interpolation of the values in the pitch/roll table in + the chandra_models repo in ``chandra_models/pitch_roll/pitch_roll_constraint.csv``. + + For pitch values outside the range of the table the returned rolldev is 0. + + :param pitch: float, ndarray + Sun pitch angle (deg) + :returns: float, ndarray + Roll deviation (deg) """ - idx1 = np.searchsorted(ROLL_TABLE.val["pitch"], pitch, side="right") - idx0 = idx1 - 1 - idx_max = len(ROLL_TABLE.val) - 1 - idx0 = np.clip(idx0, 0, idx_max) - idx1 = np.clip(idx1, 0, idx_max) - val0 = ROLL_TABLE.val["rolldev"][idx0] - val1 = ROLL_TABLE.val["rolldev"][idx1] - out = np.minimum(val0, val1) # works even for a vector input for `pitch` + out = np.interp( + x=pitch, + xp=ROLL_TABLE.val["pitch"], + fp=ROLL_TABLE.val["off_nom_roll"], + left=0, + right=0, + ) return out diff --git a/ska_sun/tests/test_sun.py b/ska_sun/tests/test_sun.py index 54d13f2..35d4ed1 100644 --- a/ska_sun/tests/test_sun.py +++ b/ska_sun/tests/test_sun.py @@ -1,6 +1,7 @@ # Licensed under a 3-clause BSD style license - see LICENSE.rst import numpy as np +import pytest from Quaternion import Quat from ..sun import ( @@ -13,30 +14,35 @@ from ..sun import pitch as sun_pitch from ..sun import position - -def test_allowed_rolldev(): - - # Test array of pitchs and allowed roll dev - testarr = [ - [135, 13.979], - [138, 14.516], +# Expected pitch, rolldev pairs +exp_pitch_rolldev = np.array( + [ [0, 0], [40, 0], - [179.9, 18.748772], - [179.997, 0], + [56.0, 0], + [85.49229, 4.95597], + [85.52, 4.9560848], + [124.99, 12.23652], + [125, 12.2380], + [135, 13.979], + [138, 14.516], + [179.9, 18.749], + [179.997, 18.749], [180, 0], [181, 0], - [85.49229, 13.677669], - [85.52, 18.756727], - [124.99, 18.748772], - [125, 17.0], ] - for pitch, rolldev in testarr: - assert np.isclose(allowed_rolldev(pitch), rolldev) +) + +@pytest.mark.parametrize("pitch, rolldev", exp_pitch_rolldev) +def test_allowed_rolldev(pitch, rolldev): + + # Test array of pitchs and allowed roll dev + assert np.isclose(allowed_rolldev(pitch), rolldev) + - # Also test with pitch as vector +def test_allowed_rolldev_vector(): assert np.allclose( - allowed_rolldev(np.array(testarr)[:, 0]), np.array(testarr)[:, 1] + allowed_rolldev(exp_pitch_rolldev[:, 0]), exp_pitch_rolldev[:, 1] )