Skip to content

Commit

Permalink
Merge branch 'issue-155'
Browse files Browse the repository at this point in the history
  • Loading branch information
talister committed Jan 7, 2019
2 parents 7ce1ae6 + ec9386f commit 18b1f11
Show file tree
Hide file tree
Showing 7 changed files with 4,366 additions and 18 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ Portal for scheduling observations of NEOs using Las Cumbres Observatory.

## History

### 2.7.8
Comet elements are now selected based on nearest in time.

### 2.7.7
Several patches for tests and minor issue fixes

Expand Down
58 changes: 42 additions & 16 deletions neoexchange/astrometrics/sources_subs.py
Original file line number Diff line number Diff line change
Expand Up @@ -676,30 +676,56 @@ def fetch_mpcdb_page(asteroid, dbg=False):
return page


def parse_mpcorbit(page, dbg=False):
def parse_mpcorbit(page, epoch_now=None, dbg=False):
"""Parses a page of elements tables return from the Minor Planet Center (MPC)
database search page and returns an element set as a dictionary.
In the case of multiple element sets (normally comets), the closest in time
to [epoch_now] is returned."""
if epoch_now is None:
epoch_now = datetime.utcnow()

data = []
# Find the table of elements and then the subtables within it
elements_table = page.find('table', {'class' : 'nb'})
if elements_table is None:
if dbg:
logger.debug("No element tables found")
elements_tables = page.find_all('table', {'class' : 'nb'})
if elements_tables is None or len(elements_tables) == 0:
logger.warning("No element tables found")
return {}
data_tables = elements_table.find_all('table')
for table in data_tables:
rows = table.find_all('tr')
for row in rows:
cols = row.find_all('td')
cols = [elem.text.strip() for elem in cols]
data.append([elem for elem in cols if elem])

elements = dict(clean_element(elem) for elem in data)

min_elements_dt = timedelta.max
best_elements = {}
for elements_table in elements_tables:
data_tables = elements_table.find_all('table')
for table in data_tables:
rows = table.find_all('tr')
for row in rows:
cols = row.find_all('td')
cols = [elem.text.strip() for elem in cols]
data.append([elem for elem in cols if elem])

elements = dict(clean_element(elem) for elem in data)
# Look for nearest element set in time
epoch = elements.get('epoch', None)
if dbg: print(epoch)
if epoch is not None:
try:
epoch_datetime = datetime.strptime(epoch, "%Y-%m-%d.0")
epoch_dt = epoch_now - epoch_datetime
if epoch_dt < min_elements_dt:
# Closer match found, update best elements and minimum time
# separation
if dbg: print("Found closer element match", epoch_dt, min_elements_dt, epoch)
best_elements = elements
min_elements_dt = abs(epoch_dt)
else:
if dbg: print("No closer match found")
except ValueError:
msg = "Couldn't parse epoch: " + epoch
logger.warning(msg)
name_element = page.find('h3')
if name_element is not None:
elements['obj_id'] = name_element.text.strip()
best_elements['obj_id'] = name_element.text.strip()

return elements
return best_elements


class PackedError(Exception):
Expand Down
4,070 changes: 4,070 additions & 0 deletions neoexchange/astrometrics/tests/test_mpcdb_Comet243P.html

Large diffs are not rendered by default.

180 changes: 180 additions & 0 deletions neoexchange/astrometrics/tests/test_sources_subs.py
Original file line number Diff line number Diff line change
Expand Up @@ -1598,6 +1598,10 @@ def setUp(self):
self.test_mpcdb_page = BeautifulSoup(test_fh, "html.parser")
test_fh.close()

test_fh = open(os.path.join('astrometrics', 'tests', 'test_mpcdb_Comet243P.html'), 'r')
self.test_multiple_epochs_page = BeautifulSoup(test_fh, "html.parser")
test_fh.close()

# Set to None to show all differences
self.maxDiff = None

Expand Down Expand Up @@ -1645,6 +1649,182 @@ def test_fetch_2014UR(self):
elements = parse_mpcorbit(self.test_mpcdb_page)
self.assertEqual(expected_elements, elements)

def test_fetch_243P_post2018Aug_epoch(self):

epoch = datetime(2018, 9, 5, 18, 0, 0)

expected_elements = {'epoch': '2018-08-30.0',
'epoch JD': '2458360.5',
'perihelion date': '2018-08-26.00689',
'perihelion JD': '2458356.50689',
'argument of perihelion': '283.55482',
'ascending node': '87.65877',
'inclination': '7.64145',
'eccentricity': '0.3593001',
'perihelion distance': '2.4544438',
'radial non-grav. param.': None,
'transverse non-grav. param.': None,
'semimajor axis': '3.8308789',
'mean anomaly': '0.52489',
'mean daily motion': '0.13144867',
'aphelion distance': '5.207',
'period': '7.5',
'P-vector [x]': '0.97228322',
'P-vector [y]': '0.23016404',
'P-vector [z]': '-0.04110774',
'Q-vector [x]': '-0.19238738',
'Q-vector [y]': '0.88749145',
'Q-vector [z]': '0.41874339',
'recip semimajor axis orig': None,
'recip semimajor axis future': None,
'recip semimajor axis error': None,
'reference': 'MPC 111774',
'observations used': '334',
'residual rms': '0.60',
'perturbers coarse indicator': 'M-v',
'perturbers precise indicator': '0038h',
'first observation date used': '2003-08-01.0',
'last observation date used': '2018-09-19.0',
'computer name': 'MPCW',
'orbit quality code': None,
'obj_id': '243P/NEAT'}

elements = parse_mpcorbit(self.test_multiple_epochs_page, epoch)
self.assertEqual(expected_elements, elements)

def test_fetch_243P_pre2018Aug_epoch(self):

# Set epoch to 1 second after the 160/2=80 days between the 2018-03-23
# and 2018-08-30 elements sets
epoch = datetime(2018, 6, 11, 0, 0, 1)

expected_elements = {'epoch': '2018-08-30.0',
'epoch JD': '2458360.5',
'perihelion date': '2018-08-26.00689',
'perihelion JD': '2458356.50689',
'argument of perihelion': '283.55482',
'ascending node': '87.65877',
'inclination': '7.64145',
'eccentricity': '0.3593001',
'perihelion distance': '2.4544438',
'radial non-grav. param.': None,
'transverse non-grav. param.': None,
'semimajor axis': '3.8308789',
'mean anomaly': '0.52489',
'mean daily motion': '0.13144867',
'aphelion distance': '5.207',
'period': '7.5',
'P-vector [x]': '0.97228322',
'P-vector [y]': '0.23016404',
'P-vector [z]': '-0.04110774',
'Q-vector [x]': '-0.19238738',
'Q-vector [y]': '0.88749145',
'Q-vector [z]': '0.41874339',
'recip semimajor axis orig': None,
'recip semimajor axis future': None,
'recip semimajor axis error': None,
'reference': 'MPC 111774',
'observations used': '334',
'residual rms': '0.60',
'perturbers coarse indicator': 'M-v',
'perturbers precise indicator': '0038h',
'first observation date used': '2003-08-01.0',
'last observation date used': '2018-09-19.0',
'computer name': 'MPCW',
'orbit quality code': None,
'obj_id': '243P/NEAT'}

elements = parse_mpcorbit(self.test_multiple_epochs_page, epoch)
self.assertEqual(expected_elements, elements)

def test_fetch_243P_post2018Mar_epoch(self):

# Set epoch to 1 second before the 160/2=80 days between the 2018-03-23
# and 2018-08-30 elements sets
epoch = datetime(2018, 6, 10, 23, 59, 59)

expected_elements = {'epoch': '2018-03-23.0',
'epoch JD': '2458200.5',
'perihelion date': '2018-08-26.04162',
'perihelion JD': '2458356.54162',
'argument of perihelion': '283.56217',
'ascending node': '87.66076',
'inclination': '7.64150',
'eccentricity': '0.3591386',
'perihelion distance': '2.4544160',
'radial non-grav. param.': None,
'transverse non-grav. param.': None,
'semimajor axis': '3.8298701',
'mean anomaly': '339.48043',
'mean daily motion': '0.13150061',
'aphelion distance': '5.205',
'period': '7.5',
'P-vector [x]': '0.97225165',
'P-vector [y]': '0.23030922',
'P-vector [z]': '-0.04104137',
'Q-vector [x]': '-0.19254615',
'Q-vector [y]': '0.88745569',
'Q-vector [z]': '0.4187462',
'recip semimajor axis orig': None,
'recip semimajor axis future': None,
'recip semimajor axis error': None,
'reference': 'MPEC 2018-S50',
'observations used': '334',
'residual rms': '0.60',
'perturbers coarse indicator': 'M-v',
'perturbers precise indicator': '0038h',
'first observation date used': '2003-08-01.0',
'last observation date used': '2018-09-19.0',
'computer name': 'MPCW',
'orbit quality code': None,
'obj_id': '243P/NEAT'}

elements = parse_mpcorbit(self.test_multiple_epochs_page, epoch)
self.assertEqual(expected_elements, elements)

def test_fetch_243P_pre2018Mar_epoch(self):

epoch = datetime(2018, 2, 14, 1, 2, 3)

expected_elements = {'epoch': '2018-03-23.0',
'epoch JD': '2458200.5',
'perihelion date': '2018-08-26.04162',
'perihelion JD': '2458356.54162',
'argument of perihelion': '283.56217',
'ascending node': '87.66076',
'inclination': '7.64150',
'eccentricity': '0.3591386',
'perihelion distance': '2.4544160',
'radial non-grav. param.': None,
'transverse non-grav. param.': None,
'semimajor axis': '3.8298701',
'mean anomaly': '339.48043',
'mean daily motion': '0.13150061',
'aphelion distance': '5.205',
'period': '7.5',
'P-vector [x]': '0.97225165',
'P-vector [y]': '0.23030922',
'P-vector [z]': '-0.04104137',
'Q-vector [x]': '-0.19254615',
'Q-vector [y]': '0.88745569',
'Q-vector [z]': '0.4187462',
'recip semimajor axis orig': None,
'recip semimajor axis future': None,
'recip semimajor axis error': None,
'reference': 'MPEC 2018-S50',
'observations used': '334',
'residual rms': '0.60',
'perturbers coarse indicator': 'M-v',
'perturbers precise indicator': '0038h',
'first observation date used': '2003-08-01.0',
'last observation date used': '2018-09-19.0',
'computer name': 'MPCW',
'orbit quality code': None,
'obj_id': '243P/NEAT'}

elements = parse_mpcorbit(self.test_multiple_epochs_page, epoch)
self.assertEqual(expected_elements, elements)

def test_badpage(self):

expected_elements = {}
Expand Down
67 changes: 67 additions & 0 deletions neoexchange/core/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -2153,6 +2153,12 @@ def setUp(self):

self.test_comet_elements = parse_mpcorbit(test_mpcdb_page)

test_fh = open(os.path.join('astrometrics', 'tests', 'test_mpcdb_Comet243P.html'), 'r')
self.test_multiple_epochs_page = BeautifulSoup(test_fh, "html.parser")
test_fh.close()
self.test_comet_elements_2018Aug_epoch = parse_mpcorbit(self.test_multiple_epochs_page, epoch_now=datetime(2018,9,25))
self.test_comet_elements_2018Mar_epoch = parse_mpcorbit(self.test_multiple_epochs_page, epoch_now=datetime(2018,2,14))

self.test_hyperbolic_elements = {
'argument of perihelion': '325.96205',
'ascending node': '276.22261',
Expand Down Expand Up @@ -2248,6 +2254,51 @@ def setUp(self):
'updated' : True
}

self.expected_mulepoch_params = {
'elements_type': 'MPC_COMET',
'argofperih': '283.55482',
'longascnode' : '87.65877',
'eccentricity' : '0.3593001',
'epochofel': datetime(2018, 8, 30, 0),
'meandist' : None,
'orbinc' : '7.64145',
'meananom': None,
'perihdist' : '2.4544438',
'epochofperih': datetime(2018, 8, 26, 0, 9, 55, int(0.296*1e6)),
'slope': '4.0',
'origin' : 'M',
'active' : True,
'source_type' : 'C',
'discovery_date': datetime(2003, 8, 1, 0),
'num_obs': '334',
'arc_length': '5528',
'not_seen' : 6.75,
'update_time' : datetime(2018, 9, 19, 0),
'updated' : True
}

self.expected_mulepoch_Mar18_params = {
'elements_type': 'MPC_COMET',
'argofperih': '283.56217',
'longascnode' : '87.66076',
'eccentricity' : '0.3591386',
'epochofel': datetime(2018, 3, 23, 0),
'meandist' : None,
'orbinc' : '7.64150',
'meananom': None,
'perihdist' : '2.4544160',
'epochofperih': datetime(2018, 8, 26, 0, 59, 55, int(0.968*1e6)),
'slope': '4.0',
'origin' : 'M',
'active' : True,
'source_type' : 'C',
'discovery_date': datetime(2003, 8, 1, 0),
'num_obs': '334',
'arc_length': '5528',
'not_seen' : -216.87383101851853,
'update_time' : datetime(2018, 9, 19, 0),
'updated' : True
}
self.maxDiff = None

@patch('core.views.datetime', MockDateTime)
Expand Down Expand Up @@ -2308,6 +2359,22 @@ def test_clean_A_2017U7(self):

self.assertEqual(self.expected_hyperbolic_params, params)

@patch('core.views.datetime', MockDateTime)
def test_clean_243P_postAug18_epoch(self):

MockDateTime.change_datetime(2018, 9, 25, 18, 0, 0)
params = clean_mpcorbit(self.test_comet_elements_2018Aug_epoch)

self.assertEqual(self.expected_mulepoch_params, params)

@patch('core.views.datetime', MockDateTime)
def test_clean_243P_preMar18_epoch(self):

MockDateTime.change_datetime(2018, 2, 14, 3, 1, 41)
params = clean_mpcorbit(self.test_comet_elements_2018Mar_epoch)

self.assertEqual(self.expected_mulepoch_Mar18_params, params)


class TestCreate_sourcemeasurement(TestCase):

Expand Down
4 changes: 3 additions & 1 deletion neoexchange/core/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -2060,6 +2060,8 @@ def clean_mpcorbit(elements, dbg=False, origin='M'):
params['perihdist'] = elements['perihelion distance']
perihelion_date = elements['perihelion date'].replace('-', ' ')
params['epochofperih'] = parse_neocp_decimal_date(perihelion_date)
params['meandist'] = None
params['meananom'] = None

not_seen = None
if last_obs is not None:
Expand Down Expand Up @@ -2089,7 +2091,7 @@ def update_MPC_orbit(obj_id_or_page, dbg=False, origin='M'):
else:
page = obj_id_or_page

elements = parse_mpcorbit(page, dbg)
elements = parse_mpcorbit(page, dbg=dbg)
if elements == {}:
logger.warning("Could not parse elements from page for %s" % obj_id)
return False
Expand Down
2 changes: 1 addition & 1 deletion neoexchange/neox/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import rollbar


VERSION = '2.7.7'
VERSION = '2.7.8'

CURRENT_PATH = os.path.dirname(os.path.realpath(__file__))
PRODUCTION = True if CURRENT_PATH.startswith('/var/www') else False
Expand Down

0 comments on commit 18b1f11

Please sign in to comment.