201.09. MPC orbits table#
201.9. MPC_orbits table¶
For the Rubin Science Platform at data.lsst.cloud.
Data Release: Data Preview 2
Container Size: Large
LSST Science Pipelines version: r30.0.9
Last verified to run: 2026-07-20
Repository: github.com/lsst/tutorial-notebooks
DOI: 10.11578/rubin/dc.20250909.20
Learning objective: To understand the contents of the mpc_orbits table and how to access it.
LSST data products: mpc_orbits
Packages: lsst.rsp
Credit: Originally developed by the Rubin Community Science team. Please consider acknowledging them if this notebook is used for the preparation of journal articles, software releases, or other notebooks.
Get Support: Everyone is encouraged to ask questions or raise issues in the Support Category of the Rubin Community Forum. Rubin staff will respond to all questions posted there.
1. Introduction¶
The mpc_orbits table contains orbit information from the Minor Planet Center (MPC) for all known Solar System objects (SSOs) as of a given date, including but not limited to detections and discoveries made by Rubin. For DP2, this includes known SSOs up to 11 March 2026 (minus those with an arc length over the total number of observations selected for use in orbit fitting by the MPC (arc_length_sel) $\leq$ 2 days), a total of 1,505,545 objects.
This table is ingested from the MPC, where Rubin acts as a downstream distributor with many fields in the mpc_orbits table originating upstream at the MPC; inconsistencies or missing information in the MPC's mpc_orbits table may therefore be present in the DP2 table.
Known issues: Some fields in the
mpc_orbitstable are known to contain inconsistent information. For further information on thempc_orbitstable, including known issues, see the MPC documentation.
- TAP table name:
dp2.mpc_orbits - columns: 53
- rows: 1,505,545
Related tutorials: The TAP data access services are demonstrated in the 100-level "How to" tutorials.
1.1. Import packages¶
Import standard python package numpy.
From the lsst package, import the module for the TAP service.
import pandas as pd
import matplotlib.pyplot as plt
from lsst.rsp import RSPDiscovery
1.2. Define parameters and functions¶
Create an instance of the TAP service.
discovery = RSPDiscovery("dp2")
service = discovery.get_tap_client()
2. Schema (columns)¶
To browse the table schema visit the Rubin schema browser, or use the TAP service via the Portal Aspect or as demonstrated in Section 2.1.
2.1. Retrieve table schema¶
To retrieve the table schema, define a query for the schema columns of the mpc_orbits table and run the query job.
query = "SELECT column_name, datatype, description, unit " \
"FROM tap_schema.columns " \
"WHERE table_name = 'dp2.mpc_orbits'"
job = service.submit_job(query)
job.run()
job.wait(phases=['COMPLETED', 'ERROR'])
print('Job phase is', job.phase)
if job.phase == 'ERROR':
job.raise_if_error()
Job phase is COMPLETED
Retrieve the query results and display them as an astropy table with the to_table() attribute.
assert job.phase == 'COMPLETED'
results = job.fetch_result().to_table()
results
| column_name | datatype | description | unit |
|---|---|---|---|
| str64 | str64 | str512 | str64 |
| id | int | Internal ID (generally not seen/used by the user) | |
| designation | char | The primary provisional designation in unpacked form (e.g. 2008 AB). | |
| packed_primary_provisional_designation | char | The primary provisional designation in packed form (e.g. K08A00B) | |
| unpacked_primary_provisional_designation | char | The primary provisional designation in unpacked form (e.g. 2008 AB) | |
| mpc_orb_jsonb | char | Details of the orbit solution in JSON form | |
| created_at | char | When this row was created | |
| updated_at | char | When this row was updated | |
| orbit_type_int | int | Orbit Type (Integer) | |
| u_param | int | U parameter | |
| nopp | int | number of oppositions | |
| arc_length_total | double | Arc length over total observations [days] | d |
| arc_length_sel | double | Arc length over total observations *selected* [days] | d |
| nobs_total | int | Total number of all observations (optical + radar) available | |
| nobs_total_sel | int | Total number of all observations (optical + radar) selected for use in orbit fitting | |
| a | double | Semi Major Axis [au] | AU |
| q | double | Pericenter Distance [au] | AU |
| e | double | Eccentricity | |
| i | double | Inclination [degrees] | deg |
| node | double | Longitude of Ascending Node [degrees] | deg |
| argperi | double | Argument of Pericenter [degrees] | deg |
| peri_time | double | Time from Pericenter Passage [days] | d |
| yarkovsky | double | Yarkovsky Component [10^(-10)*au/day^2] | 1e-10.au.d-2 |
| ... | ... | ... | ... |
| q_unc | double | Uncertainty on Pericenter Distance [au] | AU |
| e_unc | double | Uncertainty on Eccentricity | |
| i_unc | double | Uncertainty on Inclination [degrees] | deg |
| node_unc | double | Uncertainty on Longitude of Ascending Node [degrees] | deg |
| argperi_unc | double | Uncertainty on Argument of Pericenter [degrees] | deg |
| peri_time_unc | double | Uncertainty on Time from Pericenter Passage [days] | d |
| yarkovsky_unc | double | Uncertainty on Yarkovsky Component [10^(-10)*au/day^2] | 1e-10.au.d-2 |
| srp_unc | double | Uncertainty on Solar-Radiation Pressure Component [m^2/ton] | m2.t-1 |
| a1_unc | double | Uncertainty on A1 non-grav components [m^2/ton] | m2.t-1 |
| a2_unc | double | Uncertainty on A2 non-grav components [m^2/ton] | m2.t-1 |
| a3_unc | double | Uncertainty on A3 non-grav components [m^2/ton] | m2.t-1 |
| dt_unc | double | Uncertainty on DT non-grav component | |
| mean_anomaly_unc | double | Uncertainty on Mean Anomaly [degrees] | deg |
| period_unc | double | Uncertainty on Orbital Period [days] | d |
| mean_motion_unc | double | Uncertainty on Orbital Mean Motion [degrees per day] | deg.d-1 |
| epoch_mjd | double | Epoch of the Orbfit-Solution in MJD | d |
| h | double | H-Magnitude | mag |
| g | double | G-Slope Parameter | |
| not_normalized_rms | double | unnormalized rms of the fit [arcsec] | arcsec |
| normalized_rms | double | rms of the fit [unitless] | |
| earth_moid | double | Minimum Orbit Intersection Distance [au] with respect to the Earths Orbit | AU |
| fitting_datetime | char | Date of the last orbit fit |
The table displayed above has been truncated.
Option to print every column name as a list.
# for col in results['column_name']:
# print(col)
Delete the job, but not the results.
del query
job.delete()
2.2. Key Columns¶
Of the 53 columns in the mpc_orbits table, several are the most commonly used.
2.2.1. Designation¶
The primary provisional designation in unpacked form:
designation
The designation field can be used to join the mpc_orbits table with other DP2 Solar System tables.
2.2.2. Primary provisional designation¶
The primary provisional designation (unpacked format):
unpacked_primary_provisional_designation
The primary provisional designation (packed format):
packed_primary_provisional_designation
2.2.3. Orbital elements¶
The osculating orbital elements (distances measured in units of au, angles measured in units of deg):
a,q,e,i,argperi,node,mean_anomaly,peri_time
The osculating orbital element uncertainties:
a_unc,q_unc,e_unc,i_unc,argperi_unc,node_unc,mean_anomaly_unc,peri_time_unc
2.2.4. Period and mean motion¶
Orbital period and uncertainty (days):
period,period_unc
Mean motion and uncertainty (deg/day):
mean_motion,mean_motion_unc
2.2.6. Orbit type¶
Orbit type (integer):
orbit_type_int
For the orbit type definitions, see the Minor Planet Center website. Tutorial 308.1 Orbits in the Solar System science series also discusses the orbit type definitions.
2.2.7. Number of observations¶
Total number of all observations (optical + radar) available:
nobs_total
Total number of all observations (optical + radar) selected for use in orbit fitting:
nobs_total_sel
2.2.9. Non-gravitational acceleration components¶
A1 component of the non-gravitational acceleration for comets and uncertainty (10^(-10) au/d^2):
a1,a1_unc
A2 component of the non-gravitational acceleration for comets and uncertainty (10^(-10) au/d^2):
a2,a2_unc
A3 component of the non-gravitational acceleration for comets and uncertainty (10^(-10) au/d^2):
a3,a3_unc
2.2.11. Yarkovsky acceleration¶
Yarkovsky acceleration component and uncertainty:
yarkovsky,yarkovsky_unc
3. Data access¶
The mpc_orbits table is only available via the TAP service. It is not available with the butler.
3.1. TAP (Table Access Protocol)¶
The mpc_orbits table is stored in Qserv and accessible via the TAP services using ADQL queries.
3.1.1. Catalog size¶
Retrieve the size of the mpc_orbits catalog.
query = "SELECT COUNT(*) "\
"FROM dp2.mpc_orbits "
job = service.submit_job(query)
job.run()
job.wait(phases=['COMPLETED', 'ERROR'])
print('Job phase is', job.phase)
if job.phase == 'ERROR':
job.raise_if_error()
Job phase is COMPLETED
Fetch the results as an astropy table.
assert job.phase == 'COMPLETED'
results = job.fetch_result().to_table()
print(results)
COUNT1 ------- 1505545
The DP2 mpc_orbits table contains orbit information from the MPC for all known SSOs as of 11 March 2026, consisting of 1,505,545 objects in total and includes but is not limited to detections and discoveries made by Rubin.
3.1.2. Demo query¶
Define a query to return three of the key columns from Section 2.2.
query = "SELECT designation, q, e, i "\
"FROM dp2.mpc_orbits " \
"ORDER BY designation ASC "
job = service.submit_job(query)
job.run()
job.wait(phases=['COMPLETED', 'ERROR'])
print('Job phase is', job.phase)
if job.phase == 'ERROR':
job.raise_if_error()
Job phase is COMPLETED
Fetch the results as an astropy table.
assert job.phase == 'COMPLETED'
results = job.fetch_result()
print(len(results))
1505545
Convert the results astropy table to a pandas dataframe.
result_df = pd.DataFrame(results)
Option to display the results.
# result_df
The semimajor axis is included in the mpc_orbits table, but many entries are missing, as described in Section 1. For further information on the known issues with the mpc_orbits table, see the MPC documentation. The semimajor axis ($a$) can be computed from the perihelion distance ($q$) and eccentricity ($e$) using the relationship $a$ = $q$ / (1.0-$e$).
Add a column to results with the calculated semimajor axis.
result_df['a_calc'] = result_df['q'] / (1.0-result_df['e'])
Plot semimajor axis versus eccentricity and semimajor axis versus inclination for each Solar System object in the DP2 mpc_orbits table.
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(9, 4))
ax1.scatter(result_df['a_calc'], result_df['e'], s=0.3)
ax1.set_xlim(0., 1000.)
ax1.set_ylim(0., 1.)
ax1.set_xlabel('Semimajor axis (au)')
ax1.set_ylabel('Eccentricity')
ax2.scatter(result_df['a_calc'], result_df['i'], s=0.3)
ax2.set_xlim(0., 1000.)
ax2.set_ylim(0., 180.)
ax2.set_xlabel('Semimajor axis (au)')
ax2.set_ylabel('Inclination (deg)')
plt.tight_layout()
plt.show()
Figure 1: Semimajor axis versus eccentricity (left) and semimajor axis versus inclination (right) for each Solar System object in the DP2
mpc_orbitstable.
For more details on the orbital classifications of the DP2 Solar System objects, see tutorial 308.01 Orbits.
job.delete()
del query
3.1.3. Joinable tables¶
The mpc_orbits table can be joined to the SSObject table on the designation column.
The SSObject table contains linked Solar System objects (groupings of difference image detections) from Rubin.
The DP2 release SSObject table contains 299,343 unique Solar System objects detected by Rubin.
The mpc_orbits table has many more rows than the SSObject table with each designation field in the SSObject table having a 1:1 corresponding entry in the mpc_orbits tables.
While these two tables can be joined, the DP2 mpc_orbits and SSObject tables are too large (1,505,545, and 299,343 rows, respectively) to query both for the orbital parameters of all Rubin-detected DP2 Solar System objects without long query times.
To avoid long query times on joined tables, query the SSObject table separately and merge the results as a dataframe with result_df from the query above on the mpc_orbits table.
query = "SELECT designation, nObs "\
"FROM dp2.SSObject "\
"ORDER BY designation ASC"
job = service.submit_job(query)
job.run()
job.wait(phases=['COMPLETED', 'ERROR'])
print('Job phase is', job.phase)
if job.phase == 'ERROR':
job.raise_if_error()
Job phase is COMPLETED
Fetch the job results and assign to an astropy result table.
assert job.phase == 'COMPLETED'
result = job.fetch_result()
len(result)
299343
Convert the result astropy table to a pandas dataframe.
result_df_rubin = pd.DataFrame(result)
Option to print the results
# result_df_rubin
Merge the result_df dataframe from the mpc_orbits query above with the result_df_rubin dataframe containing only Rubin-detected objects on the designation field. Use an inner merge to only keep matching rows present in both dataframes.
merged_df = pd.merge(result_df, result_df_rubin, on='designation', how='inner')
len(merged_df)
299343
Option to print the merged dataframe.
# merged_df
Plot semimajor axis versus number of observations for each Rubin-detected DP2 Solar System object.
fig, ax = plt.subplots(figsize=(8, 4))
ax.scatter(merged_df['a_calc'], merged_df['nObs'], s=0.3)
ax.set_xlabel('Semimajor axis (au)')
ax.set_ylabel('Number of observations')
plt.xscale('log')
plt.tight_layout()
plt.show()
Figure 2: Semimajor axis versus number of observations for each Rubin-detected DP2 Solar System object. Note the log scale in semimajor axis.
Clean up.
job.delete()
del query, results, result_df, result_df_rubin, merged_df