Skip to content

Commit

Permalink
Add support for dynamic limits via effective t_ccd
Browse files Browse the repository at this point in the history
  • Loading branch information
taldcroft committed Feb 14, 2019
1 parent 1b329bd commit 6b4125c
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 3 deletions.
54 changes: 54 additions & 0 deletions proseco/catalog.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from .acq import get_acq_catalog, AcqTable
from .fid import get_fid_catalog, FidTable
from . import characteristics_acq as ACQ
from . import characteristics as ACA


def get_aca_catalog(obsid=0, **kwargs):
Expand Down Expand Up @@ -96,6 +97,14 @@ def _get_aca_catalog(**kwargs):
aca.call_args = kwargs.copy()
aca.set_attrs_from_kwargs(**kwargs)

# Override t_ccd related inputs with effective temperatures for downstream
# action by AcqTable, GuideTable, FidTable. See set_attrs_from_kwargs()
# method for more details.
if 't_ccd' in kwargs:
del kwargs['t_ccd']
kwargs['t_ccd_acq'] = aca.t_ccd_eff_acq
kwargs['t_ccd_guide'] = aca.t_ccd_eff_guide

# Get stars (typically from AGASC) and do not filter for stars near
# the ACA FOV. This leaves the full radial selection available for
# later roll optimization. Use aca.stars or aca.acqs.stars from here.
Expand Down Expand Up @@ -144,6 +153,22 @@ def _get_aca_catalog(**kwargs):
return aca


def get_effective_t_ccd(t_ccd):
"""Return the effective T_ccd used for selection and catalog evaluation.
For details see Dynamic ACA limits in baby steps section in:
https://occweb.cfa.harvard.edu/twiki/bin/view/Aspect/StarWorkingGroupMeeting2019x02x13
:param t_ccd:
:return:
"""
t_limit = ACA.aca_t_ccd_planning_limit
if t_ccd > t_limit:
return t_ccd + 1 + (t_ccd - t_limit)
else:
return t_ccd


class ACATable(ACACatalogTable):
"""Container ACACatalogTable class that has merged guide / acq / fid catalogs
as attributes and other methods relevant to the merged catalog.
Expand All @@ -156,6 +181,11 @@ class ACATable(ACACatalogTable):
# catalog in the ACATable meta.
starcheck_catalog = MetaAttribute(is_kwarg=False)

# Effective T_ccd used for dynamic ACA limits (see updates_for_t_ccd_effective()
# method below).
t_ccd_eff_acq = MetaAttribute(is_kwarg=False)
t_ccd_eff_guide = MetaAttribute(is_kwarg=False)

@property
def t_ccd(self):
if self.t_ccd_acq != self.t_ccd_guide:
Expand All @@ -181,6 +211,30 @@ def thumbs_up(self):
self.fids.thumbs_up &
self.guides.thumbs_up)

def set_attrs_from_kwargs(self, **kwargs):
"""Set object attributes from kwargs.
After calling the base class method which does all the real work, then
compute the effective T_ccd temperatures.
In this ACATable object:
- t_ccd_eff_{acq,guide} are the effective T_ccd values which are adjusted
if the actual t_ccd{acq,guide} values are above ACA.aca_t_ccd_planning_limit.
- t_ccd_{acq,guide} are the actual (or predicted) values from the call
The downstream AcqTable, GuideTable, and FidTable are initialized with the
*effective* values as t_ccd. Those classes do not have the concept of effective
temperature.
:param kwargs: dict of input kwargs
:return: dict
"""
super().set_attrs_from_kwargs(**kwargs)

self.t_ccd_eff_acq = get_effective_t_ccd(self.t_ccd_acq)
self.t_ccd_eff_guide = get_effective_t_ccd(self.t_ccd_guide)


def get_review_table(self):
"""Get ACAReviewTable object based on self.
Expand Down
3 changes: 3 additions & 0 deletions proseco/characteristics.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@
col_spoiler_mag_diff = 4.5
col_spoiler_pix_sep = 10 # pixels

# ACA T_ccd planning limit (degC)
aca_t_ccd_planning_limit = -9.5

# Dark current that corresponds to a 5.0 mag star in a single pixel. Apply
# this value to the region specified by bad_pixels.
bad_pixel_dark_current = 700_000
Expand Down
70 changes: 67 additions & 3 deletions proseco/tests/test_catalog.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 matplotlib

matplotlib.use('agg')

import pickle
Expand All @@ -16,7 +17,6 @@
from ..fid import get_fid_catalog
from .. import characteristics as ACA


HAS_SC_ARCHIVE = Path(mica.starcheck.starcheck.FILES['data_root']).exists()
TEST_COLS = 'slot idx id type sz yang zang dim res halfw'.split()

Expand Down Expand Up @@ -56,7 +56,6 @@ def test_get_aca_catalog_20603():
' 7 9 116791744 ACQ 6x6 985.38 -1210.19 20 1 140',
' 0 10 40108048 ACQ 6x6 2.21 1619.17 20 1 140']


repr(aca) # Apply default formats
assert aca[TEST_COLS].pformat(max_width=-1) == exp

Expand Down Expand Up @@ -242,6 +241,71 @@ def test_big_sim_offset():
assert all(name in aca.fids.colnames for name in names)


def test_calling_with_t_ccd():
"""Test that calling get_aca_catalog with t_ccd arg sets all the
CCD attributes correctly in the nominal case of a temperature
below the planning limit.
"""
dark = DARK40.copy()
stars = StarsTable.empty()
stars.add_fake_constellation(mag=8.0, n_stars=8)
t_ccd = ACA.aca_t_ccd_planning_limit - 1.0

kwargs = mod_std_info(stars=stars, dark=dark, t_ccd=t_ccd)
aca = get_aca_catalog(**kwargs)
assert np.isclose(aca.t_ccd, t_ccd)
assert np.isclose(aca.t_ccd_acq, t_ccd)
assert np.isclose(aca.t_ccd_guide, t_ccd)

assert np.isclose(aca.t_ccd_eff_acq, t_ccd)
assert np.isclose(aca.t_ccd_eff_guide, t_ccd)

assert np.isclose(aca.acqs.t_ccd, t_ccd)
assert np.isclose(aca.guides.t_ccd, t_ccd)


t_ccd_cases = [(-0.5, 0, 0),
(0, 0, 0),
(0.5, 1.5, 1.4)]


@pytest.mark.parametrize('t_ccd_case', t_ccd_cases)
def test_t_ccd_effective_acq_guide(t_ccd_case):
"""Test setting of effective T_ccd temperatures for cases above and
below the planning limit.
"""
dark = DARK40.copy()
stars = StarsTable.empty()
stars.add_fake_constellation(mag=8.0, n_stars=8)

t_limit = ACA.aca_t_ccd_planning_limit

t_offset, t_penalty_acq, t_penalty_guide = t_ccd_case
# Set acq and guide temperatures different
t_ccd_acq = t_limit + t_offset
t_ccd_guide = t_ccd_acq - 0.1

kwargs = mod_std_info(stars=stars, dark=dark,
t_ccd_acq=t_ccd_acq, t_ccd_guide=t_ccd_guide)
aca = get_aca_catalog(**kwargs)

with pytest.raises(ValueError):
# Cannot access this attribute if acq and guide temps are different
aca.t_ccd

assert np.isclose(aca.t_ccd_acq, t_ccd_acq)
assert np.isclose(aca.t_ccd_guide, t_ccd_guide)

# t_ccd + 1 + (t_ccd - t_limit) from proseco.catalog.get_effective_t_ccd()
assert np.isclose(aca.t_ccd_eff_acq, t_ccd_acq + t_penalty_acq)
assert np.isclose(aca.t_ccd_eff_guide, t_ccd_guide + t_penalty_guide)

assert np.isclose(aca.t_ccd_eff_acq, aca.acqs.t_ccd)
assert np.isclose(aca.t_ccd_eff_guide, aca.guides.t_ccd)


def test_call_args_attr():
aca = get_aca_catalog(**mod_std_info(optimize=False, n_guide=0, n_acq=0, n_fid=0))
assert aca.call_args == {'att': (0, 0, 0),
Expand Down Expand Up @@ -502,7 +566,7 @@ def test_report_from_objects(tmpdir):
obsdir = rootdir / f'obs{obsid:05}'
for subdir in 'acq', 'guide':
outdir = obsdir / subdir
assert(outdir / 'index.html').exists()
assert (outdir / 'index.html').exists()
assert len(list(outdir.glob('*.png'))) > 0


Expand Down

0 comments on commit 6b4125c

Please sign in to comment.