Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ Portal for scheduling observations of NEOs (and other Solar System objects) usin

## History

### 3.17.1
* Add MPC codes for the new ELP 0.35m Delta Rho telescopes in Aqawan B.
* Update MPC strings for telescope design and detector for the Delta Rho + QHY600 telescope + camera (Reported by @carrholt)
* Specify and allow minimum elevation for the JPL SBObs frontend, which eliminates the non-visible objects previously returned (The default min_elev specified in the JPL API docs doesn't seem to be actually applied)
* Fix `neox/tests/base.by` for removal of Numpy `long` which was breaking all the functional tests

### 3.17.0
* Long-term maintenance update to Rocky Linux 9 for the base Docker container image, Python 3.11 and Astropy 5.3.x.

Expand Down
20 changes: 16 additions & 4 deletions neoexchange/astrometrics/ephem_subs.py
Original file line number Diff line number Diff line change
Expand Up @@ -1118,7 +1118,7 @@ def get_mag_mapping(site_code):
# Disabled by TAL 2018/8/10 after mirror recoating
# bad_onem_site_codes = ['Q63', 'Q64']
bad_onem_site_codes = ['BAD1M']
point4m_site_codes = ['Z21', 'Z17', 'W89', 'W79', 'T04', 'T03', 'Q58', 'Q59', 'V38', 'L09', '0M4']
point4m_site_codes = ['Z21', 'Z17', 'W89', 'W79', 'T04', 'T03', 'Q58', 'Q59', 'V38', 'V45', 'V47', 'L09', '0M4']

# Magnitudes represent upper bin limits
site_code = site_code.upper()
Expand Down Expand Up @@ -1460,6 +1460,18 @@ def get_sitepos(site_code, dbg=False):
site_long = -site_long
site_hgt = 2027.0
site_name = 'LCO ELP Node 0m4a Aqawan A at McDonald Observatory'
elif site_code == 'ELP-AQWB-0M4A' or site_code == 'V45':
(site_lat, status) = S.sla_daf2r(30, 40, 47.88)
(site_long, status) = S.sla_daf2r(104, 0., 54.1287)
site_long = -site_long
site_hgt = 2042.08
site_name = 'LCO ELP Node 0m4a Aqawan B at McDonald Observatory'
elif site_code == 'ELP-AQWB-0M4B' or site_code == 'V47':
(site_lat, status) = S.sla_daf2r(30, 40, 47.88)
(site_long, status) = S.sla_daf2r(104, 0., 54.06)
site_long = -site_long
site_hgt = 2042.08
site_name = 'LCO ELP Node 0m4b Aqawan B at McDonald Observatory'
elif site_code == 'BPL':
(site_lat, status) = S.sla_daf2r(34, 25, 57)
(site_long, status) = S.sla_daf2r(119, 51, 46)
Expand Down Expand Up @@ -1899,7 +1911,7 @@ def get_mountlimits(site_code_or_name):
ha_pos_limit = 4.5 * 15.0
ha_neg_limit = -4.5 * 15.0
alt_limit = 30.0
elif '-AQWA' in site or '-AQWB' in site or 'CLMA-0M4' in site or site in ['Z17', 'Z21', 'Q58', 'Q59', 'T03', 'T04', 'W89', 'W79', 'V38', 'L09']:
elif '-AQWA' in site or '-AQWB' in site or 'CLMA-0M4' in site or site in ['Z17', 'Z21', 'Q58', 'Q59', 'T03', 'T04', 'W89', 'W79', 'V38', 'V45', 'V47', 'L09']:
ha_pos_limit = 4.46 * 15.0
ha_neg_limit = -4.5 * 15.0
alt_limit = 15.0
Expand Down Expand Up @@ -1950,7 +1962,7 @@ def get_sitecam_params(site, bin_mode=None):
unrecognized site."""

valid_site_codes = LCOGT_site_codes()
valid_point4m_codes = ['W89', 'W79', '0M4', 'Z17', 'Z21', 'T04', 'T03', 'Q58', 'Q59', 'V38', 'L09']
valid_point4m_codes = ['W89', 'W79', '0M4', 'Z17', 'Z21', 'T04', 'T03', 'Q58', 'Q59', 'V38', 'V45', 'V47', 'L09']

site = site.upper()
if site == '2M0':
Expand Down Expand Up @@ -2080,7 +2092,7 @@ def determine_sites_to_schedule(sched_date=datetime.utcnow()):
S_point4m_sites = ['L09', ]
S_onem_sites = ['K93', 'K92', 'K91']
elif sched_date.hour >= 23 or (0 <= sched_date.hour < 8):
N_point4m_sites = ['T04', 'T03', 'V38']
N_point4m_sites = ['T04', 'T03', 'V38', 'V45', 'V47']
N_onem_sites = ['V37', ]
S_point4m_sites = ['W89', 'W79']
S_onem_sites = ['W87', 'W85']
Expand Down
4 changes: 4 additions & 0 deletions neoexchange/astrometrics/site_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@
'LSC-AQWA-0M4A' : 'W89',
'LSC-AQWB-0M4A' : 'W79',
'ELP-AQWA-0M4A' : 'V38',
'ELP-AQWB-0M4A' : 'V45',
'ELP-AQWB-0M4B' : 'V47',
'CPT-AQWA-0M4A' : 'L09',
'SQA-DOMA-0M8A' : 'G51',
'XXX-XXXX-1M0X' : '1M0',
Expand Down Expand Up @@ -113,6 +115,8 @@
'0m409' : 'W89',
'0m412' : 'W79',
'0m411' : 'V38',
'0m400' : 'V45', # LCOGT elp-aqwb-0m4a (sq44)
'0m473' : 'V47', # LCOGT elp-aqwb-0m4b (sq46)
'0m407' : 'L09', # LCOGT cpt-aqwa-0m4a
'0m420' : 'XXX' # ASAS-SN cpt-aqwa-0m4b
}
Expand Down
35 changes: 31 additions & 4 deletions neoexchange/astrometrics/sources_subs.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
from re import sub, compile
from math import degrees, sqrt, copysign, ceil
from time import sleep
from datetime import date, datetime, timedelta
from datetime import datetime, timedelta
from socket import error, timeout
from random import randint
import requests
Expand Down Expand Up @@ -1729,6 +1729,12 @@ def make_location(params):
elif params['site_code'] == 'V39':
location['telescope'] = '1m0a'
location['enclosure'] = 'domb'
elif params['site_code'] == 'V45':
location['telescope'] = '0m4a'
location['enclosure'] = 'aqwb'
elif params['site_code'] == 'V47':
location['telescope'] = '0m4b'
location['enclosure'] = 'aqwb'
elif params['site_code'] == 'Z31':
location['telescope'] = '1m0a'
location['enclosure'] = 'doma'
Expand Down Expand Up @@ -2214,7 +2220,9 @@ def configure_defaults(params):
'T04' : 'OGG',
'Q58' : 'COJ', # Code for 0m4a
'Q59' : 'COJ',
'V38' : 'ELP',
'V38' : 'ELP', # Code for aqwa-0m4a
'V45' : 'ELP', # Code for aqwb-0m4a
'V47' : 'ELP', # Code for aqwb-0m4b
'L09' : 'CPT'} # Code for 0m4a

params['pondtelescope'] = '1m0'
Expand All @@ -2239,7 +2247,7 @@ def configure_defaults(params):
if params.get('filter', None):
del(params['filter'])
params['spectra_slit'] = 'slit_6.0as'
elif params['site_code'] in ['Z17', 'Z21', 'T04', 'T03', 'Q58', 'Q59', 'V38', 'L09', 'W89', 'W79', '0M4']:
elif params['site_code'] in ['Z17', 'Z21', 'T04', 'T03', 'Q58', 'Q59', 'V38', 'V45', 'V47', 'L09', 'W89', 'W79', '0M4']:
params['instrument'] = '0M4-SCICAM-QHY600'
params['pondtelescope'] = '0m4'
params['binning'] = 1
Expand All @@ -2252,6 +2260,12 @@ def configure_defaults(params):
if params['site_code'] == 'V38':
# elp-aqwa-0m4a kb80
params['observatory'] = 'aqwa'
elif params['site_code'] == 'V45':
# elp-aqwb-0m4a sq44
params['observatory'] = 'aqwb'
elif params['site_code'] == 'V47':
# elp-aqwb-0m4b sq46
params['observatory'] = 'aqwb'
elif params.get('bin_mode', None) == '2k_2x2':
params['binning'] = 2

Expand Down Expand Up @@ -3189,9 +3203,18 @@ def translate_constraints(constraints):
elif ">" in c:
field, value = c.split(">")
translated.append(f"{field.strip()}|GT|{value.strip()}")
elif "==" in c:
field, value = c.split("==")
translated.append(f"{field.strip()}|EQ|{value.strip()}")
elif "!=" in c:
field, value = c.split("!=")
translated.append(f"{field.strip()}|NE|{value.strip()}")
elif "IS DEFINED" in c:
field, value = c.split("IS DEFINED")
translated.append(f"{field.strip()}|DF")
elif "NOT DEFINED" in c:
field, value = c.split("NOT DEFINED")
translated.append(f"{field.strip()}|ND")
else:
raise ValueError(f"Unsupported constraint format: {c}")

Expand All @@ -3200,7 +3223,7 @@ def translate_constraints(constraints):

return quote(json_str)

def make_jpl_sbobs_query(obs_date, site_code='W86', max_objects=100, min_obs_time=30, min_Vmag=None, max_Vmag=None, max_rotper=None):
def make_jpl_sbobs_query(obs_date, site_code='W86', max_objects=100, min_obs_time=30, min_elev=30, min_Vmag=None, max_Vmag=None, max_rotper=None):
"""
Make a query URL for the JPL SBobs API (https://ssd-api.jpl.nasa.gov/doc/sbwobs.html). The following constraints are
applied in addition to those from the passed parameters:
Expand All @@ -3223,6 +3246,8 @@ def make_jpl_sbobs_query(obs_date, site_code='W86', max_objects=100, min_obs_tim
Maximum number of objects to return
min_obs_time : int/float
Minimum number of minutes needed for observing (truncated to integer)
min_elev : int/float
Minimum altitude/elevation that the object must reach (default: 30)
min_Vmag : float or None
Objects must be fainter than this V band magnitude
max_Vmag : float or None
Expand All @@ -3245,6 +3270,8 @@ def make_jpl_sbobs_query(obs_date, site_code='W86', max_objects=100, min_obs_tim
url += "&sb-group=neo&elong-min=45&glat-min=10"
# Need to be visible for at least time time (in minutes)
url += f"&time-min={int(min_obs_time)}"
# Need to be above this altitude
url += f"&elev-min={min_elev}"
# Try and decode the site code into a LCO telescope class and then use
# this to set mag limits
if min_Vmag is None or max_Vmag is None:
Expand Down
18 changes: 16 additions & 2 deletions neoexchange/astrometrics/tests/test_ephem_subs.py
Original file line number Diff line number Diff line change
Expand Up @@ -2715,7 +2715,7 @@ def test_CA_afternoon1(self):
should be schedulable for Northern targets, OGG for bright targets'''
d = datetime(2017, 3, 9, 23, 27, 5)

expected_sites = { 'north' : { '0m4' : ['T04', 'T03', 'V38'], '1m0' : ['V37',] },
expected_sites = { 'north' : { '0m4' : ['T04', 'T03', 'V38', 'V45', 'V47'], '1m0' : ['V37',] },
'south' : { '0m4' : ['W89', 'W79'], '1m0' : ['W87', 'W85'] }
}

Expand All @@ -2729,7 +2729,7 @@ def test_CA_afternoon2(self):

d = datetime(2017, 3, 10, 00, 2, 5)

expected_sites = { 'north' : { '0m4' : ['T04', 'T03', 'V38'], '1m0' : ['V37',] },
expected_sites = { 'north' : { '0m4' : ['T04', 'T03', 'V38', 'V45', 'V47'], '1m0' : ['V37',] },
'south' : { '0m4' : ['W89', 'W79'] , '1m0' : ['W87', 'W85'] }
}

Expand Down Expand Up @@ -3822,6 +3822,20 @@ def test_elp_aqwa_0m4b(self):

self.assertEqual(expected_sitecode, sitecode)

def test_elp_aqwb_0m4a(self):

expected_sitecode = 'V45'
sitecode = LCOGT_telserial_to_site_codes('0m4-00')

self.assertEqual(expected_sitecode, sitecode)

def test_elp_aqwb_0m4b(self):

expected_sitecode = 'V47'
sitecode = LCOGT_telserial_to_site_codes('0m4-73')

self.assertEqual(expected_sitecode, sitecode)

def test_lsc_aqwa_0m4a(self):

expected_sitecode = 'W89'
Expand Down
38 changes: 37 additions & 1 deletion neoexchange/astrometrics/tests/test_sources_subs.py
Original file line number Diff line number Diff line change
Expand Up @@ -4416,6 +4416,35 @@ def test_elp_point4m(self):

params = configure_defaults(test_params)

def test_elp_point4m_num2(self):
test_params = self.obs_params
test_params['site_code'] = 'V45'

expected_params = { 'instrument': '0M4-SCICAM-QHY600',
'pondtelescope': '0m4',
'observatory': 'aqwb',
'site': 'ELP',
'binning': 1}
expected_params.update(test_params)

params = configure_defaults(test_params)

self.assertEqual(expected_params, params)


def test_elp_point4m_num3(self):
test_params = self.obs_params
test_params['site_code'] = 'V47'

expected_params = { 'instrument': '0M4-SCICAM-QHY600',
'pondtelescope': '0m4',
'observatory': 'aqwb',
'site': 'ELP',
'binning': 1}
expected_params.update(test_params)

params = configure_defaults(test_params)

self.assertEqual(expected_params, params)

def test_lsc_point4m_num1(self):
Expand Down Expand Up @@ -7283,7 +7312,7 @@ def setUp(self):
# Split the very long string; Python will automatically concatenate all within the ()s
self.base_url = ('https://ssd-api.jpl.nasa.gov/sbwobs.api?mpc-code=K92&obs-time=2025-09-03&maxoutput=100'
'&output-sort=vmag&fmt-ra-dec=false&mag-required=true&sb-group=neo&elong-min=45&glat-min=10'
'&time-min=30&vmag-min=12.0&vmag-max=19.0')
'&time-min=30&elev-min=30&vmag-min=12.0&vmag-max=19.0')
self.obs_date = datetime(2025, 9, 3, 20, 0, 0)

self.maxDiff = None
Expand All @@ -7309,6 +7338,13 @@ def test_K92(self):

self.assertEqual(expected_url, url)

def test_K92_lower_alt_limit(self):
expected_url = self.base_url.replace('elev-min=30', 'elev-min=20')

url = make_jpl_sbobs_query(self.obs_date, 'K92', min_elev=20)

self.assertEqual(expected_url, url)

def test_K92_10objs(self):
expected_url = self.base_url.replace('100', '10')

Expand Down
4 changes: 2 additions & 2 deletions neoexchange/core/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
('Z24', 'TFN 1.0m - Z31,Z24; (Tenerife, Spain)'),
('0M4', '------------ Any 0.4m ------------'),
('W89', 'LSC 0.4m - W89,W79; (CTIO, Chile)'),
('V38', 'ELP 0.4m - V38; (McDonald, Texas)'),
('V38', 'ELP 0.4m - V38,V45,V47; (McDonald, Texas)'),
('T04', 'OGG 0.4m - T03-04; (Maui, Hawaii)'),
('Q58', 'COJ 0.4m - Q58-59; (Siding Spring, Aust.)'),
('L09', 'CPT 0.4m - L09; (Sutherland, S. Africa)'),
Expand All @@ -61,7 +61,7 @@
('D', 'Dark'))

SITES_1M0 = ('W86', 'V37', 'Q63', 'K92', 'Z24', '1M0')
SITES_0M4 = ('W89', 'V38', 'T04', 'Q58', 'L09', 'Z21', '0M4')
SITES_0M4 = ('W89', 'V38', 'V45', 'V47', 'T04', 'Q58', 'L09', 'Z21', '0M4')

BIN_MODES = {'0M4' :
(('central30_1x1', "Central 30'x30', 1x1"),
Expand Down
15 changes: 10 additions & 5 deletions neoexchange/core/models/frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,21 +187,24 @@ def return_site_string(self):
'W89' : 'LCO LSC Node Aqawan A 0m4a at Cerro Tololo, Chile',
'W79' : 'LCO LSC Node Aqawan B 0m4a at Cerro Tololo, Chile',
'V38' : 'LCO ELP Node Aqawan A 0m4a at McDonald Observatory, Texas',
'V45' : 'LCO ELP Node Aqawan B 0m4a at McDonald Observatory, Texas',
'V47' : 'LCO ELP Node Aqawan B 0m4b at McDonald Observatory, Texas',
'L09' : 'LCO CPT Node Aqawan A 0m4a at Sutherland, South Africa',
'G51' : 'LCO Byrne Observatory at Sedgwick Reserve'
}
return site_strings.get(self.sitecode, 'Unknown LCO site')

def return_tel_string(self):

detector = 'CCD'
point4m_aperture = 0.4
point4m_fRatio = 8.0
point4m_design = 'Schmidt-Cassegrain'
point4m_string = '{:.1f}-m f/{:1d} {} + {}'.format(point4m_aperture, int(point4m_fRatio), point4m_design, detector)
detector = 'CMOS'
point4m_aperture = 0.35
point4m_fRatio = 3.0
point4m_design = 'Corrected Dall-Kirkham'
point4m_string = '{:.2f}-m f/{:1d} {} + {}'.format(point4m_aperture, int(point4m_fRatio), point4m_design, detector)
point4m_dict = {'full' : point4m_string, 'design' : point4m_design,
'aperture' : point4m_aperture, 'fRatio' : point4m_fRatio, 'detector' : detector }

detector = 'CCD'
onem_aperture = 1.0
onem_fRatio = 8.0
onem_design = 'Ritchey-Chretien'
Expand Down Expand Up @@ -240,6 +243,8 @@ def return_tel_string(self):
'W89' : point4m_dict,
'W79' : point4m_dict,
'V38' : point4m_dict,
'V45' : point4m_dict,
'V47' : point4m_dict,
'L09' : point4m_dict,
}
tel_string = tels_strings.get(self.sitecode, {'full:' : 'Unknown LCO telescope'})
Expand Down
6 changes: 3 additions & 3 deletions neoexchange/core/tests/test_forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ def test_ephem_form_has_all_sites(self):
self.assertIn('value="T04"', form.as_p())
self.assertIn('LSC 0.4m - W89,W79; (CTIO, Chile)', form.as_p())
self.assertIn('value="W89"', form.as_p())
self.assertIn('ELP 0.4m - V38; (McDonald, Texas)', form.as_p())
self.assertIn('ELP 0.4m - V38,V45,V47; (McDonald, Texas)', form.as_p())
self.assertIn('value="V38"', form.as_p())
self.assertIn('------------ Non LCO ------------', form.as_p())
self.assertIn('value="non"', form.as_p())
Expand Down Expand Up @@ -258,7 +258,7 @@ def test_sched_form_has_all_sites(self):
self.assertIn('value="T04"', form.as_p())
self.assertIn('LSC 0.4m - W89,W79; (CTIO, Chile)', form.as_p())
self.assertIn('value="W89"', form.as_p())
self.assertIn('ELP 0.4m - V38; (McDonald, Texas)', form.as_p())
self.assertIn('ELP 0.4m - V38,V45,V47; (McDonald, Texas)', form.as_p())
self.assertIn('value="V38"', form.as_p())
self.assertIn('CPT 0.4m - L09; (Sutherland, S. Africa)', form.as_p())
self.assertIn('value="L09"', form.as_p())
Expand Down Expand Up @@ -377,7 +377,7 @@ def test_sched_form_has_all_sites(self):
self.assertIn('value="T04"', form.as_p())
self.assertIn('LSC 0.4m - W89,W79; (CTIO, Chile)', form.as_p())
self.assertIn('value="W89"', form.as_p())
self.assertIn('ELP 0.4m - V38; (McDonald, Texas)', form.as_p())
self.assertIn('ELP 0.4m - V38,V45,V47; (McDonald, Texas)', form.as_p())
self.assertIn('value="V38"', form.as_p())
self.assertIn('CPT 0.4m - L09; (Sutherland, S. Africa)', form.as_p())
self.assertIn('value="L09"', form.as_p())
Expand Down
Loading