diff --git a/setup.py b/setup.py index 0070739..580768b 100755 --- a/setup.py +++ b/setup.py @@ -9,11 +9,9 @@ packages = ["ska_sun", "ska_sun.tests"] package_dir = {name: name} -package_data = {name: ["data/*fits.gz"]} duplicate_package_info(packages, name, namespace) duplicate_package_info(package_dir, name, namespace) -duplicate_package_info(package_data, name, namespace) setup( name=name, @@ -25,7 +23,6 @@ zip_safe=False, package_dir=package_dir, packages=packages, - package_data=package_data, tests_require=["pytest"], cmdclass=cmdclass, ) diff --git a/ska_sun/data/pitch_roll.fits.gz b/ska_sun/data/pitch_roll.fits.gz deleted file mode 100644 index f74bc93..0000000 Binary files a/ska_sun/data/pitch_roll.fits.gz and /dev/null differ diff --git a/ska_sun/sun.py b/ska_sun/sun.py index 1cd68b9..a7776b0 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,18 @@ 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 +31,25 @@ 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 -1.0, + corresonding to a pitch angle outside of the planning limits. + + :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=-1.0, + right=-1.0, + ) return out diff --git a/ska_sun/tests/test_sun.py b/ska_sun/tests/test_sun.py index 1b770f1..a42cb01 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,29 +14,36 @@ from ..sun import pitch as sun_pitch from ..sun import position - -def test_allowed_rolldev(): - # Test array of pitchs and allowed roll dev - testarr = [ +# Expected pitch, rolldev pairs +exp_pitch_rolldev = np.array( + [ + [0, -1.0], + [40, -1.0], + [56.0, -1.0], + [85.49229, 4.95597], + [85.52, 4.9560848], + [124.99, 12.23652], + [125, 12.2380], [135, 13.979], [138, 14.516], - [0, 0], - [40, 0], - [179.9, 18.748772], - [179.997, 0], - [180, 0], - [181, 0], - [85.49229, 13.677669], - [85.52, 18.756727], - [124.99, 18.748772], - [125, 17.0], + [177.9, 18.749], + [177.997, 18.749], + [178.0, -1.0], + [180, -1.0], + [181, -1.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] )