Skip to content

Commit

Permalink
Merge pull request #27 from sot/pitch-roll-constraint
Browse files Browse the repository at this point in the history
Change allowed_rolldev to use chandra_models
  • Loading branch information
taldcroft authored Mar 1, 2023
2 parents 389ea43 + 7f587bb commit e43f1e1
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 36 deletions.
3 changes: 0 additions & 3 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -25,7 +23,6 @@
zip_safe=False,
package_dir=package_dir,
packages=packages,
package_data=package_data,
tests_require=["pytest"],
cmdclass=cmdclass,
)
Binary file removed ska_sun/data/pitch_roll.fits.gz
Binary file not shown.
41 changes: 26 additions & 15 deletions ska_sun/sun.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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


Expand All @@ -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


Expand Down
44 changes: 26 additions & 18 deletions ska_sun/tests/test_sun.py
Original file line number Diff line number Diff line change
@@ -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 (
Expand All @@ -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]
)


Expand Down

0 comments on commit e43f1e1

Please sign in to comment.