Date: 2026-02-08 (updated) Author: Rob Seaman (Catalina Sky Survey) / Claude (Anthropic) Repository: https://github.com/rlseaman/CSS_MPC_toolkit
The Catalina Sky Survey (CSS) at the University of Arizona's Lunar and Planetary Laboratory maintains a local PostgreSQL replica of the Minor Planet Center's (MPC) observation and orbit catalogs distributed through the PDS Small Bodies Node (SBN).
- Schema: https://www.minorplanetcenter.net/mpcops/documentation/replicated-tables-schema/
- General info: https://www.minorplanetcenter.net/mpcops/documentation/replicated-tables-info-general/
The database resides on a local replica (RHEL 8.6, 251 GB RAM, HDD), running
PostgreSQL 15.2 with logical replication from MPC. The database is 446 GB
with 18 tables in the public schema, dominated by obs_sbn (526M+ rows,
239 GB).
This project develops "value-added" data products: SQL scripts, Python libraries, and derived datasets useful to the NEO community.
The replicated database contains 18 tables. Full analysis in
sandbox/schema_review.md.
| Table | Rows | Used for |
|---|---|---|
obs_sbn |
526M | All published observations (239 GB) |
mpc_orbits |
1.51M | NEO selection by orbital elements |
numbered_identifications |
876K | Number-to-designation mapping |
obscodes |
2.4K | Observatory name enrichment |
neocp_obs_archive |
777K | NEOCP archived observations (ADES export) |
neocp_prev_des |
71K | NEOCP designation resolution |
neocp_events |
310K | NEOCP operational audit log |
-
No foreign keys exist anywhere in the schema. Referential integrity is unenforced -- all joins rely on matching text fields.
-
orbit_type_intis NULL for 35% ofmpc_orbits. These are objects with computed orbits but no MPC classification. -
primary_objects.object_type = 0is generic "minor planet" (1.5M objects). It cannot distinguish NEOs from the general population. -
NEOCP tables carry ADES-native uncertainty fields (
rmsra,rmsdec,rmscorr,rmstime) not present inobs_sbn. -
Logical replication means local DDL (schemas, functions, indexes) is safe. MPC enforces a 5% XMIN lag threshold and 14 days/year maximum downtime.
- Initial SQL --
sql/discovery_tracklets.sqlcomputing discovery tracklet statistics for all NEOs - Pipeline scripts --
run_pipeline.sh,validate_output.sh,upload_release.shfor automated execution - UNION-based refactor -- Replaced OR-based joins with 3x UNION branches targeting single indexes (permid, provid, num_provid)
- Refactored to use numbered_identifications -- Replaced
mpc_orbitsfor designation lookup (more reliable, fully populated) - NEO list from mpc_orbits -- Replaced NEA.txt download with orbital
criteria (
q < 1.32 OR orbit_type_int IN (0,1,2,3,20)) - Tracklet metrics -- Added nobs, span_hours, rate_deg_per_day, position_angle_deg, discovery_site_name (12 columns total)
- Output: 43,629 NEO discovery tracklets
lib/mpc_convert.py-- Python functions: date conversion (fractional day to ISO 8601), RA/Dec sexagesimal to decimal degrees, catalog/mode/band code mappings, packed designation encode/decode, full obs80 parsersql/css_utilities_functions.sql-- PostgreSQL equivalents as IMMUTABLE STRICT PARALLEL SAFE functions incss_utilitiesschema
lib/ades_export.py-- ADES XML and PSV generator conforming togeneral.xsd(version 2022). Produces standalone<optical>elements with all 7 required fields satisfied from NEOCP data.sql/ades_export.sql-- SQL query producing ADES-ready columns fromneocp_obs_archivewith designation resolution vianeocp_prev_des
- Health check toolkit --
scripts/db_health_check.shwith 9 diagnostic sections - Tuning applied --
shared_buffers128 MB -> 64 GB,work_mem4 MB -> 128 MB, autovacuum thresholds lowered. obs_sbn dead rows: 82M -> 2,308. - Index cleanup -- Identified and removed duplicate indexes created
by previous sessions. Retained only
idx_obs_sbn_disc(partial index ondisc = '*'). - Schema review -- Comprehensive analysis in
sandbox/schema_review.md - NEOCP analysis -- Table inventory, join paths, latency analysis,
ADES feasibility in
sandbox/neocp_ades_analysis.md
- Install
css_utilitiesschema on the replica (needs privileged user) - Install
postgresql15-contribon the replica forpg_buffercacheandpg_stat_statementsextensions - Enable huge pages at next maintenance reboot (instructions in
scripts/enable_huge_pages.md) - Contact MPC/SBN about unused indexes --
obs_sbn_submission_block_id_key(12 GB) andobs_sbn_trkmpc_idx(10 GB) are never used - Run production pipeline with finalized SQL and publish release
- Set up cron on a CSS server for daily/weekly pipeline execution
- Materialized views for discovery tracklets (refreshable, queryable)
- ADES validation against
general.xsdusing the IAU's Python tools - Extend ADES export to obs_sbn for non-NEOCP observations (limited to fields available in obs80)
- Observatory performance dashboard -- per-station discovery rates, follow-up contribution, astrometric quality trends
- Completeness analysis -- sky coverage gaps, magnitude-dependent completeness, temporal patterns
- JSONB materialization -- Extract key fields from
mpc_orb_jsonbinto flat columns (covariance, MOIDs, Tisserand parameter) - Cross-match with external catalogs -- JPL SBDB physical properties, NEOWISE diameters/albedos, NEODyS impact probabilities
- Publish CSV outputs as GitHub Release assets
- Daily/weekly updates via CSS cron using
gh release upload --clobber - Gate uploads on validation (row counts, format checks)
- SQL scripts written to be idempotent (
CREATE IF NOT EXISTS, etc.) - Local
css_utilitiesschema for functions and derived tables - Materialized views for refreshable computed datasets
- Provide SQL scripts for users with their own MPC replicas
- Provide
pg_dumpextracts of derived tables as release assets - Document schema dependencies clearly
object_type codes--primary_objects.object_type = 0is generic minor planet; cannot distinguish NEOs. NEO selection uses orbital criteria frommpc_orbitsinstead.mpc_orbits population-- 1.51M rows, 35% missingorbit_type_int. Orbital elements (q, e, i, etc.) are well-populated.earth_moidis available but not used for NEO selection.Update cadence-- Pipeline is self-contained; cadence is operationally determined by cron scheduling.
- Stakeholder communication -- How will downstream users know when new data products are available?
- Schema change handling -- MPC schema is "beta release". How do we handle upstream changes?
- ADES validation scope -- Should we validate against
submit.xsd(more restrictive) or onlygeneral.xsdfor distribution?