201.08. SSSource table#
201.8. SSSource 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 SSSource table and how to access it.
LSST data products: SSSource
Packages: lsst.rsp, lsst.daf.butler, lsst.utils.plotting
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 SSSource table contains single-epoch solar system source information corresponding to a specific difference image detection.
- TAP table name:
dp2.SSSource - butler table name:
ss_source - columns: 39
- rows: 8,136,150
Related tutorials: The TAP and butler data access services are demonstrated in the 100-level "How to" tutorials.
1.1. Import packages¶
Import standard python packages numpy, matplotlib and astropy.
From the lsst package, import modules for the TAP service, the butler, and plotting.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
from lsst.rsp import RSPDiscovery
from lsst.daf.butler import Butler
from lsst.utils.plotting import (get_multiband_plot_colors,
get_multiband_plot_symbols)
1.2. Define parameters and functions¶
Create an instance of the TAP service.
discovery = RSPDiscovery("dp2")
service = discovery.get_tap_client()
Create an instance of the Rubin data butler.
butler = Butler('dp2', collections="dp2")
Define the colors and symbols to represent the LSST filters in plots.
filter_colors = get_multiband_plot_colors()
filter_names = filter_colors.keys()
filter_symbols = get_multiband_plot_symbols()
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 SSSource table and run the query job.
query = "SELECT column_name, datatype, description, unit " \
"FROM tap_schema.columns " \
"WHERE table_name = 'dp2.SSSource'"
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 |
| diaSourceId | long | Unique identifier of the observation (matching DiaSource.diaSourceId). | |
| ssObjectId | long | Unique LSST identifier of the Solar System object. | |
| designation | char | The unpacked primary provisional designation for this object. | |
| eclLambda | double | Ecliptic longitude, converted from the observed coordinates. | deg |
| eclBeta | double | Ecliptic latitude, converted from the observed coordinates. | deg |
| galLon | double | Galactic longitude, converted from the observed coordinates. | deg |
| galLat | double | Galactic latitude, converted from the observed coordinates. | deg |
| elongation | float | Solar elongation of the object at the time of observation. | deg |
| phaseAngle | float | Phase angle between the Sun, object, and observer. | deg |
| topoRange | float | Topocentric distance (delta) at light-emission time. | AU |
| topoRangeRate | float | Topocentric radial (line-of-sight) velocity (deldot); positive values indicate motion away from the observer. | km/s |
| helioRange | float | Heliocentric distance (r) at light-emission time. | AU |
| helioRangeRate | float | Heliocentric radial velocity (rdot); positive values indicate motion away from the Sun. | km/s |
| ephRa | double | Predicted ICRS right ascension from the orbit in mpc_orbits. | deg |
| ephDec | double | Predicted ICRS declination from the orbit in mpc_orbits. | deg |
| ephVmag | float | Predicted magnitude in V band, computed from mpc_orbits data including the mpc_orbits-provided (H, G) estimates | mag |
| ephRate | float | Total predicted on-sky angular rate of motion. | deg/d |
| ephRateRa | float | Predicted on-sky angular rate in the R.A. direction (includes the cos(dec) factor). | deg/d |
| ephRateDec | float | Predicted on-sky angular rate in the declination direction. | deg/d |
| ephOffset | float | Total observed versus predicted angular separation on the sky. | arcsec |
| ephOffsetRa | double | Offset between observed and predicted position in the R.A. direction (includes cos(dec) term). | arcsec |
| ephOffsetDec | double | Offset between observed and predicted position in declination. | arcsec |
| ephOffsetAlongTrack | float | Offset between observed and predicted position in the along-track direction on the sky. | arcsec |
| ephOffsetCrossTrack | float | Offset between observed and predicted position in the cross-track direction on the sky. | arcsec |
| helio_x | float | Cartesian heliocentric X coordinate at light-emission time (ICRS). | AU |
| helio_y | float | Cartesian heliocentric Y coordinate at light-emission time (ICRS). | AU |
| helio_z | float | Cartesian heliocentric Z coordinate at light-emission time (ICRS). | AU |
| helio_vx | float | Cartesian heliocentric X velocity at light-emission time (ICRS). | km/s |
| helio_vy | float | Cartesian heliocentric Y velocity at light-emission time (ICRS). | km/s |
| helio_vz | float | Cartesian heliocentric Z velocity at light-emission time (ICRS). | km/s |
| helio_vtot | float | The magnitude of the heliocentric velocity vector, sqrt(vx*vx + vy*vy + vz*vz). | km/s |
| topo_x | float | Cartesian topocentric X coordinate at light-emission time (ICRS). | AU |
| topo_y | float | Cartesian topocentric Y coordinate at light-emission time (ICRS). | AU |
| topo_z | float | Cartesian topocentric Z coordinate at light-emission time (ICRS). | AU |
| topo_vx | float | Cartesian topocentric X velocity at light-emission time (ICRS). | km/s |
| topo_vy | float | Cartesian topocentric Y velocity at light-emission time (ICRS). | km/s |
| topo_vz | float | Cartesian topocentric Z velocity at light-emission time (ICRS). | km/s |
| topo_vtot | float | The magnitude of the topocentric velocity vector, sqrt(vx*vx + vy*vy + vz*vz). | km/s |
| diaDistanceRank | short | The rank of the diaSourceId-identified source in terms of its closeness to the predicted SSO position. If diaSourceId is the nearest DiaSource to this SSO prediction, diaSourceDistanceRank=1 would be set. If it is the second nearest, it would be 2, etc. |
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.2. Unpacked primary provisional designation¶
The unpacked primary provisional designation for this object:
designation
2.2.3. Heliocentric distance and velocity¶
The cartesian heliocentric position and velocity coordinates:
helio_x,helio_y,helio_z,helio_vx,helio_vy,helio_vz
The heliocentric distance at light-emission time and heliocentric radial velocity (positive values indicate motion away from the Sun):
helioRangehelioRate
The magnitude of the heliocentric velocity vector:
helio_vtot
2.2.4. Topocentric distance and velocity¶
The topocentric position and velocity coordinates:
topo_x,topo_y,topo_z,topo_vx,topo_vy,topo_vz
The topocentric distance at light-emission time and topocentric radial velocity (positive values indicate motion away from the Sun):
topoRangetopoRate
The magnitude of the topocentric velocity vector:
topo_vtot
2.2.5. Phase angle and solar elongation¶
The phase angle is the angle between the light incident onto an observed object and the light reflected from the object:
phaseAngle
The solar elongation at the time of observation:
elongation
2.2.6. Ecliptic coordinates¶
The ecliptic latitude and longitude, converted from the observed coordinates:
eclLambdaeclBeta
2.2.7. Predicted magnitude, ra, dec, and on-sky angular rates¶
The predicted V-band magnitude, computed from mpc_orbits data including the mpc_orbits-provided (H, G) estimates:
ephVmag
The predicted ICRS right ascension (ra) and declincation (dec) from the orbit in mpc_orbits:
ephRaephDec
The total predicted on-sky angular rate of motion and the predicted on-sky angular rates in the ra (includes the cos(dec) factor) and dec direction:
ephRateephRateRaephRateDec
2.2.8. Offsets from predicted magnitude, ra, dec, and on-sky angular rates¶
The total observed versus predicted angular separation on the sky and the offsets between the observed and predicted positions in the ra (includes cos(dec) term)and dec directions:
ephOffsetephOffsetRaephOffsetDec
The offsets between observed and predicted positions in the along-track and cross-track directions on the sky:
ephOffsetAlongTrackephOffsetCrossTrack
2.2.9. Rank of source in its closeness to a predicted SSO position¶
For diaSources with known Solar System objects (SSOs) predicted to be within a 1 arcsecond association radius, the rank of the diaSourceId -identified source in terms of its closeness to the predicted SSO position:
diaDistanceRank
I.e., if diaSourceId is the nearest DiaSource to the SSO prediction, diaSourceDistanceRank = 1 would be set. If it is the second nearest, it would be 2, etc. Source association in DP2 provides more information.
2.3. Descriptions and units¶
For a subset of the key columns in Section 2.2, show the table of their descriptions and units.
col_list = set(['ssObjectId', 'helioRange', 'topoRange', 'ephOffset'])
tx = [i for i, item in enumerate(results['column_name']) if item in col_list]
results[tx]
| column_name | datatype | description | unit |
|---|---|---|---|
| str64 | str64 | str512 | str64 |
| ssObjectId | long | Unique LSST identifier of the Solar System object. | |
| topoRange | float | Topocentric distance (delta) at light-emission time. | AU |
| helioRange | float | Heliocentric distance (r) at light-emission time. | AU |
| ephOffset | float | Total observed versus predicted angular separation on the sky. | arcsec |
Clean up.
del col_list, tx, results
3. Data access¶
The SSSource table is available via the TAP service and the butler.
Recommended access method: TAP.
3.1. TAP (Table Access Protocol)¶
The SSSource table is stored in Qserv and accessible via the TAP services using ADQL queries.
3.1.1. Catalog size¶
Retrieve the size of the SSSource catalog.
results = service.search("SELECT COUNT(*) FROM dp2.SSSource")
results.to_table()
| COUNT1 |
|---|
| int64 |
| 8136150 |
The SSSource table contains 8,136,150 Solar System sources. Querying the entire table results in long query times. To reduce query times, retrieve a subset of the data by ssObjectId.
3.1.2. Retrieve a subset¶
To retrieve a subset of rows, use the where option in queries to select ssObjectId values within a range. By using ssObjectId, the query returns a subset of SSSource rows that are associated with a row in the SSObject table.
First, figure out the full range of ssObjectId values by using the ADQL MIN and MAX functions.
results = service.search("SELECT min(ssObjectId), max(ssObjectId)"
"FROM dp2.SSSource")
results.to_table()
| min1 | max2 |
|---|---|
| int64 | int64 |
| 20606185051795521 | 6001945050679883312 |
Each SSObject has a different number of source measurements. Define a search range for ssObjectId that would return roughly 5% of the source measurements in the SSSource table. This is done by estimating a new maximum ssObjectId that is 0.005% above the minimum ssObjectId for the full range of ssObjectId values.
min_val = int(results[0].get('min1'))
max_val = int(results[0].get('max2'))
print('Full range: ', min_val, max_val)
max_val = int(min_val + 0.00005*(max_val-min_val))
print('Search range: ', min_val, max_val)
Full range: 20606185051795521 6001945050679883312 Search range: 20606185051795521 20905251995076924
3.1.3. Demo query¶
Define a query to return three of the "key columns" from Section 2.2 for objects with ssObjectId values in the "search range" returned above.
Although it can take several minutes to retrieve the SSSource data for the full set of SSObject values, to retrieve all SSSources, use the following query:
SELECT ssObjectId, helioRange, topoRange
FROM dp2.SSSource
ORDER BY ssObjectId AS
For more details on the observations of the DP2 Solar System objects, see tutorial 308.02 Observations.
query = "SELECT ssObjectId, "\
"helioRange, topoRange "\
"FROM dp2.SSSource " \
"WHERE ssObjectId BETWEEN "\
"20606185051795521 "\
"AND 20905251995076924 "\
"ORDER BY ssObjectId 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. The random subset returns 511,980 Solar System sources. This is ~ 6% of the DP2 Solar System source measurements.
assert job.phase == 'COMPLETED'
results = job.fetch_result().to_table()
print(len(results))
511980
Option to print the results.
# results
Plot histograms of the heliocentric and topocentric distances for the subset (~6%) of DP2 Solar System sources out to 5 au.
fig, ax = plt.subplots(figsize=(6, 4))
ax.hist(results['helioRange'].clip(0, 5), bins=100,
edgecolor='none', alpha=0.85, label='Heliocentric')
ax.hist(results['topoRange'].clip(0, 5), bins=100,
edgecolor='none', alpha=0.6, label='Topocentric')
ax.set_xlabel('Distance (au)')
ax.set_ylabel('Count')
ax.set_title('Distance distributions (< 5 au)')
ax.legend()
plt.tight_layout()
plt.show()
Figure 1: Histograms of the heliocentric and topocentric distances for a subset (~6%) of DP2 Solar System sources out to 5 au.
Clean up.
job.delete()
del query, results
3.1.4. Joinable tables¶
The SSSource table can be joined to the DiaSource table on the column containing the unique visit identifier, ssObjectId.
The DiaSource table contains information about the astrometric and photometric measurements for solar system objects detected in difference images.
With 8,136,150 source measurements of Solar System objects in DP2, the best way to demonstrate the difference image detections in the SSSource table is to look at just one SSObject. ssObjectId = 21163615737558602 has the largest number of detections in DP2.
Query the SSSource table for the topocentric distance (topoRange) adding a table join to the DiaSource table and retrieving the midpointMjdTai column for the observation midpoint of the source measurements for ssObjectId = 21163615737558602.
query = "SELECT sss.ssObjectId, "\
"sss.topoRange, dia.midpointMjdTai, "\
"dia.band "\
"FROM dp2.SSSource as sss " \
"JOIN dp2.DiaSource as dia "\
"ON sss.diaSourceId = dia.diaSourceId " \
"WHERE sss.ssObjectId = 21163615737558602 "
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. ssObjectId = 21163615737558602 has 732 source measurements.
assert job.phase == 'COMPLETED'
results = job.fetch_result().to_table()
print(len(results))
732
Option to print the results.
# results
Plot topocentric distance as a function of the observation midpoint for ssObjectId = 21163615737558602.
fig, ax = plt.subplots(1, 2, figsize=(10, 4))
for filt in filter_names:
fx = np.where(results['band'] == filt)[0]
if len(fx) > 0:
ax[0].plot(results['midpointMjdTai'][fx],
results['topoRange'][fx],
filter_symbols[filt], ms=5, mew=0, alpha=0.7,
color=filter_colors[filt], label=filt)
ax[0].set_xlabel('midpointMjdTai')
ax[0].set_ylabel('topocentric distance (au)')
ax[0].set_title('Full range of source measurements')
ax[0].legend(loc='upper left')
ax[1].plot(results['midpointMjdTai'][fx],
results['topoRange'][fx],
filter_symbols[filt], ms=5, mew=0, alpha=0.7,
color=filter_colors[filt], label=filt)
ax[1].set_xlim(60793.04, 60793.22)
ax[1].set_ylim(1.5709, 1.5717)
ax[1].set_xlabel('midpointMjdTai')
ax[1].set_ylabel('topocentric distance (au)')
ax[1].set_title('Zoom-in of source measurements')
ax[1].legend(loc='upper left')
plt.subplots_adjust(wspace=0.3)
plt.suptitle(f"ssObjectId = {results['ssObjectId'][0]}",
y=1.01)
plt.show()
Figure 2: Left: topocentric distance as a function of the observation midpoint for
ssObjectId=21163615737558602, with colors and symbols to represent the four filters (ugri) obtained on the nights of MJD = 60790 - 60799. Right: similar to left panel but zoomed-in on the night of MJD = 60793. The topocentric distance ofssObjectId=21163615737558602increases with observation date.
Clean up.
job.delete()
del query, results
3.2. Butler¶
TAP is the recommended way to access the solar system source table, but the butler can be used to retrieve the same table information.
The butler query can be much faster than the TAP query. This allows the selected columns (ssObjectId, heliocentric distance, and solar elongation) for the full SSSource table to be easily retrieved.
3.2.1. Demo query¶
Define the columns to retrieve.
col_list = ['ssObjectId', 'topoRange', 'phaseAngle']
Get the data from the butler.
results = butler.get('ss_source', parameters={'columns': col_list})
print(len(results))
8136150
Option to display the results.
# results
Plot the phase angle as a function of topocentric distance for every DP2 Solar System source.
fig, ax = plt.subplots(figsize=(6, 4))
ax.scatter(results['topoRange'], results['phaseAngle'], s=0.5)
plt.xlabel('Topocentric Distance (au)')
plt.ylabel('Phase angle (deg)')
plt.tight_layout()
ax.xaxis.set_minor_locator(ticker.MultipleLocator(5))
plt.show()
Figure 3: Phase angle as a function of topocentric distance for every DP2 Solar System source. Only relatively nearby objects are observed at high phase angles.
Clean up.
del col_list, results