Skip to content

Commit

Permalink
update version number
Browse files Browse the repository at this point in the history
  • Loading branch information
jchate6 committed Nov 1, 2021
2 parents ce83048 + efa3950 commit cb94429
Show file tree
Hide file tree
Showing 7 changed files with 314 additions and 33 deletions.
55 changes: 50 additions & 5 deletions neoexchange/astrometrics/sources_subs.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,14 @@

import logging
import os
from copy import deepcopy
import urllib.request
import urllib.error
from urllib.parse import urljoin
import imaplib
import email
from re import sub, compile
from math import degrees
from math import degrees, sqrt, copysign
from time import sleep
from datetime import date, datetime, timedelta
from socket import error, timeout
Expand All @@ -50,6 +51,35 @@
logger = logging.getLogger(__name__)


def box_spiral_generator(dist, max_sep):
"""Create a box spiral of offsets (starting at 0 and resetting when it reaches the max seperation)
Result is a generator, that can be treated as an iterator.
:param dist: distance of single offset in RA or Dec in arcsec
:param max_sep: total distance from origin at which point the spiral resets
:return (ra_off, dec_off): Tuple for the current requested offsets
"""
ra_off = 0
dec_off = 0
n = 1
while True:
k = 0
while k < abs(n):
if sqrt(ra_off**2 + dec_off**2) >= max_sep:
ra_off = 0
dec_off = 0
n = 1
yield ra_off, dec_off
ra_off += copysign(dist, n)
k += 1
k = 0
while k < abs(n):
yield ra_off, dec_off
dec_off += copysign(dist, n)
k += 1
n += copysign(1, n)
n *= -1


def download_file(url, file_to_save):
"""Helper routine to download from a URL and save into a file with error trapping"""

Expand Down Expand Up @@ -1676,7 +1706,10 @@ def make_config(params, filter_list):
'guiding_config': {},
'instrument_configs': []
}
if params['exp_type'] == 'REPEAT_EXPOSE':

if params.get('add_dither', False):
dither_pattern = box_spiral_generator(params['dither_distance'], 120)
elif params['exp_type'] == 'REPEAT_EXPOSE':
# Remove overhead from slot_length so repeat_exposure matches predicted frames.
# This will allow a 2 hour slot to fit within a 2 hour window.
single_mol_overhead = cfg.molecule_overhead['filter_change'] + cfg.molecule_overhead['per_molecule_time']
Expand All @@ -1698,7 +1731,8 @@ def make_config(params, filter_list):

instrument_config = {'exposure_count': exp_count,
'exposure_time': params['exp_time'],
'optical_elements': {'filter': filt[0]}
'optical_elements': {'filter': filt[0]},
'extra_params': {}
}

if params.get('bin_mode', None) == '2k_2x2' and params['pondtelescope'] == '1m0':
Expand All @@ -1720,7 +1754,18 @@ def make_config(params, filter_list):
'diffuser_z_position': 'out'}

instrument_config['extra_params'] = extra_params
conf['instrument_configs'].append(instrument_config)

if params.get('add_dither', False):
exp = 0
while exp < exp_count:
offsets = next(dither_pattern)
instrument_config['exposure_count'] = 1
instrument_config['extra_params']["offset_ra"] = offsets[0]
instrument_config['extra_params']["offset_dec"] = offsets[1]
conf['instrument_configs'].append(deepcopy(instrument_config))
exp += 1
else:
conf['instrument_configs'].append(instrument_config)

return conf

Expand Down Expand Up @@ -1965,7 +2010,7 @@ def configure_defaults(params):
params['instrument'] = '1M0-SCICAM-SINISTRO'

# Perform Repeated exposures if many exposures compared to number of filter changes.
if params['exp_count'] <= 10 or params['exp_count'] < 10*len(list(filter(None, params['filter_pattern'].split(',')))):
if params['exp_count'] <= 10 or params['exp_count'] < 10*len(list(filter(None, params['filter_pattern'].split(',')))) or params.get('add_dither', False):
params['exp_type'] = 'EXPOSE'
else:
params['exp_type'] = 'REPEAT_EXPOSE'
Expand Down
148 changes: 138 additions & 10 deletions neoexchange/astrometrics/tests/test_sources_subs.py
Original file line number Diff line number Diff line change
Expand Up @@ -750,7 +750,9 @@ def setUp(self):
'end_time': dark_end,
'filter_pattern': 'w',
'group_name': self.body_elements['current_name'] + '_' + 'CPT' + '-' + datetime.strftime(utc_date, '%Y%m%d'),
'user_id': 'bsimpson'
'user_id': 'bsimpson',
'dither_distance': 10,
'add_dither': False
}

self.maxDiff = None
Expand Down Expand Up @@ -850,7 +852,6 @@ def test_submit_cadence(self, mock_post):
if block != blocks[2]:
self.assertNotEqual(block.block_end, block.superblock.block_end)


@patch('astrometrics.sources_subs.expand_cadence', mock_expand_cadence_novis)
@patch('astrometrics.sources_subs.requests.post')
def test_submit_cadence_novis(self, mock_post):
Expand Down Expand Up @@ -4600,6 +4601,7 @@ def setUp(self):
},
'muscat_sync': True,
'target': self.target,
'add_dither': False,
'constraints': {
'max_airmass': 2.0,
'min_lunar_distance': 30.0
Expand All @@ -4613,6 +4615,7 @@ def setUp(self):
'exp_count': 10,
'filter_pattern': 'w',
'target': self.target,
'add_dither': False,
'constraints': {
'max_airmass': 2.0,
'min_lunar_distance': 30.0
Expand All @@ -4626,6 +4629,7 @@ def setUp(self):
'exp_count': 10,
'filter_pattern': 'w',
'target': self.target,
'add_dither': False,
'constraints': {
'max_airmass': 2.0,
'min_lunar_distance': 30.0
Expand Down Expand Up @@ -4705,6 +4709,7 @@ def test_1m_imaging(self):
'instrument_configs': [{
'exposure_count': 10,
'exposure_time': 60.0,
'extra_params': {},
'optical_elements': {
'filter': 'w'
}
Expand Down Expand Up @@ -4734,6 +4739,7 @@ def test_0m4_imaging(self):
'instrument_configs': [{
'exposure_count': 10,
'exposure_time': 90.0,
'extra_params': {},
'optical_elements': {
'filter': 'w'
}
Expand Down Expand Up @@ -5019,6 +5025,7 @@ def setUp(self):
'zp_explength': 60,
},
'muscat_sync': True,
'add_dither': False,
'constraints': {
'max_airmass': 2.0,
'min_lunar_distance': 30.0
Expand All @@ -5028,10 +5035,11 @@ def setUp(self):
self.params_2m0_imaging['exp_type'])[0]

self.params_1m0_imaging = configure_defaults({ 'site_code': 'K92',
'exp_time' : 60.0,
'exp_count' : 10,
'filter_pattern' : 'w',
'target' : self.target,
'exp_time': 60.0,
'exp_count': 10,
'filter_pattern': 'w',
'target': self.target,
'add_dither': False,
'constraints': {
'max_airmass': 2.0,
'min_lunar_distance': 30.0
Expand All @@ -5041,11 +5049,12 @@ def setUp(self):
self.params_1m0_imaging['exp_count'],
self.params_1m0_imaging['exp_type'])[0]
self.params_0m4_imaging = configure_defaults({ 'site_code': 'Z21',
'exp_time' : 90.0,
'exp_count' : 18,
'exp_time': 90.0,
'exp_count': 18,
'slot_length': 220,
'filter_pattern' : 'w',
'target' : self.target,
'filter_pattern': 'w',
'target': self.target,
'add_dither': False,
'constraints': {
'max_airmass': 2.0,
'min_lunar_distance': 30.0
Expand Down Expand Up @@ -5087,6 +5096,103 @@ def test_1m_imaging(self):
self.assertEqual(expected_num_configurations, len(configurations))
self.assertEqual(expected_type, configurations[0]['type'])

def test_1m_dithering(self):

expected_num_configurations = 1
expected_type = 'EXPOSE'
expected_num_inst_configurations = 10
expected_exp_num = 1
params = self.params_1m0_imaging
params['dither_distance'] = 10
params['add_dither'] = True

configurations = make_configs(params)

self.assertEqual(expected_num_configurations, len(configurations))
self.assertEqual(expected_type, configurations[0]['type'])

inst_configs = configurations[0]['instrument_configs']
self.assertEqual(expected_num_inst_configurations, len(inst_configs))
self.assertEqual(inst_configs[0]['exposure_count'], expected_exp_num)
self.assertEqual(inst_configs[0]['extra_params'], {'offset_ra': 0.0, 'offset_dec': 0.0})
self.assertEqual(inst_configs[6]['extra_params'], {'offset_ra': -10.0, 'offset_dec': -10.0})

def test_multifilter_dithering(self):

expected_num_configurations = 1
expected_type = 'EXPOSE'
expected_num_inst_configurations = 10
expected_exp_num = 1
params = self.params_1m0_imaging
params['dither_distance'] = 10
params['add_dither'] = True
params['filter_pattern'] = 'w,r'
params['exp_count'] = 10

configurations = make_configs(params)

self.assertEqual(expected_num_configurations, len(configurations))
self.assertEqual(expected_type, configurations[0]['type'])

inst_configs = configurations[0]['instrument_configs']
self.assertEqual(expected_num_inst_configurations, len(inst_configs))
self.assertEqual(inst_configs[0]['exposure_count'], expected_exp_num)
self.assertEqual(inst_configs[0]['extra_params'], {'offset_ra': 0.0, 'offset_dec': 0.0})
self.assertEqual(inst_configs[6]['extra_params'], {'offset_ra': -10.0, 'offset_dec': -10.0})
self.assertEqual(inst_configs[0]['optical_elements']['filter'], 'w')
self.assertEqual(inst_configs[1]['optical_elements']['filter'], 'r')
self.assertEqual(inst_configs[2]['optical_elements']['filter'], 'w')

def test_longblock_dithering(self):

expected_num_configurations = 1
expected_type = 'EXPOSE'
expected_num_inst_configurations = 100
expected_exp_num = 1
params = self.params_1m0_imaging
params['dither_distance'] = 20
params['add_dither'] = True
params['exp_count'] = 100

configurations = make_configs(params)

self.assertEqual(expected_num_configurations, len(configurations))
self.assertEqual(expected_type, configurations[0]['type'])

inst_configs = configurations[0]['instrument_configs']
self.assertEqual(expected_num_inst_configurations, len(inst_configs))
self.assertEqual(inst_configs[0]['exposure_count'], expected_exp_num)
self.assertEqual(inst_configs[0]['extra_params'], {'offset_ra': 0.0, 'offset_dec': 0.0})
self.assertEqual(inst_configs[6]['extra_params'], {'offset_ra': -20.0, 'offset_dec': -20.0})
self.assertEqual(inst_configs[30]['extra_params'], {'offset_ra': 60.0, 'offset_dec': 60.0})
self.assertEqual(inst_configs[91]['extra_params'], {'offset_ra': 20.0, 'offset_dec': 0.0})

def test_muscat_dithering(self):

expected_num_configurations = 1
expected_type = 'EXPOSE'
expected_num_inst_configurations = 10
expected_exp_num = 1
params = self.params_2m0_imaging
params['dither_distance'] = 10
params['add_dither'] = True
params['exp_count'] = 10

configurations = make_configs(params)

self.assertEqual(expected_num_configurations, len(configurations))
self.assertEqual(expected_type, configurations[0]['type'])

inst_configs = configurations[0]['instrument_configs']
self.assertEqual(expected_num_inst_configurations, len(inst_configs))
self.assertEqual(inst_configs[0]['exposure_count'], expected_exp_num)
self.assertEqual(inst_configs[0]['extra_params']['offset_ra'], 0.0)
self.assertEqual(inst_configs[0]['extra_params']['offset_dec'], 0.0)
self.assertEqual(inst_configs[0]['extra_params']['exposure_mode'], 'SYNCHRONOUS')
self.assertEqual(inst_configs[0]['extra_params']['exposure_time_g'], 60)
self.assertEqual(inst_configs[6]['extra_params']['offset_ra'], -10.0)
self.assertEqual(inst_configs[6]['extra_params']['offset_dec'], -10.0)

def test_0m4_imaging(self):

expected_num_configurations = 1
Expand Down Expand Up @@ -5208,6 +5314,7 @@ def setUp(self):
'pondtelescope' : '0m4a',
'site_code' : 'Q59',
'target' : self.elements,
'add_dither': False,
'constraints' : {'max_airmass': 2.0, 'min_lunar_distance': 15}
}
self.ipp_value = 1.0
Expand Down Expand Up @@ -6040,3 +6147,24 @@ def test_store_stuff_comet_longperiod(self):
self.assertLessEqual(len(body.source_subtype_1), 2)
self.assertEqual(body.source_subtype_1, 'LP')


class TestBoxSpiral(TestCase):

def test_run_generator(self):
"""Test Box Spiral generator"""

b = box_spiral_generator(1, 3)
self.assertEqual((0, 0), next(b))
self.assertEqual((1, 0), next(b))
self.assertEqual((1, 1), next(b))
self.assertEqual((0, 1), next(b))
self.assertEqual((-1, 1), next(b))
self.assertEqual((-1, 0), next(b))
for k, b_next in enumerate(b):
if k == 23:
self.assertEqual((3, 2), b_next)
if k == 24:
self.assertEqual((0, 0), b_next)
if k == 25:
self.assertEqual((1, 0), b_next)
break
10 changes: 10 additions & 0 deletions neoexchange/core/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,12 +226,22 @@ class ScheduleBlockForm(forms.Form):
acceptability_threshold = forms.FloatField(widget=forms.NumberInput(attrs={'style': 'width: 75px;'}), required=False)
ag_exp_time = forms.FloatField(widget=forms.NumberInput(attrs={'style': 'width: 75px;'}), required=False)
edit_window = forms.BooleanField(initial=False, required=False, widget=forms.CheckboxInput(attrs={'class': 'window-switch'}))
add_dither = forms.BooleanField(initial=False, required=False, widget=forms.CheckboxInput(attrs={'class': 'dither-switch'}))
dither_distance = forms.FloatField(widget=forms.NumberInput(attrs={'style': 'width: 75px;'}), required=False)
gp_explength = forms.FloatField(required=False, widget=forms.NumberInput(attrs={'size': '5'}))
rp_explength = forms.FloatField(required=False, widget=forms.NumberInput(attrs={'size': '5'}))
ip_explength = forms.FloatField(required=False, widget=forms.NumberInput(attrs={'size': '5'}))
zp_explength = forms.FloatField(required=False, widget=forms.NumberInput(attrs={'size': '5'}))
muscat_sync = forms.BooleanField(initial=False, required=False)

def clean_dither_distance(self):
"""Limit dither distance to values between 0 and 60 arcsec."""
if not self.cleaned_data['dither_distance'] or self.cleaned_data['dither_distance'] < 0:
return 10
if self.cleaned_data['dither_distance'] > 60:
return 60
return self.cleaned_data['dither_distance']

def clean_exp_length(self):
if not self.cleaned_data['exp_length'] or self.cleaned_data['exp_length'] < 0.1:
return 0.1
Expand Down
Loading

0 comments on commit cb94429

Please sign in to comment.