Skip to content

rlseaman/MPC_designations

Repository files navigation

MPC Designations

PyPI version Python versions License: CC0-1.0

Convert between packed and unpacked Minor Planet Center (MPC) designations for asteroids, comets, and natural satellites.

Based on the MPC specification: https://www.minorplanetcenter.net/iau/info/PackedDes.html

Python users: pip install mpc-designation. See docs/QUICKSTART.md for every other language.

Implementations

Language Directory Status
AWK awk/ Production
Bash bash/ Production
C c/ Production
C++ cpp/ Production
C# csharp/ Production
Forth forth/ Production
Fortran fortran/ Production
Go go/ Production
Haskell haskell/ Production
Java java/ Production
JavaScript js/ Production
Julia julia/ Production
Kotlin kotlin/ Production
Nim nim/ Production
Octave/MATLAB octave/ Production
Perl perl/ Production
PHP php/ Production
Python python/ Production
R r/ Production
Ruby ruby/ Production
Rust rust/ Production
SPP/IRAF spp/ Production
Swift swift/ Production
Tcl tcl/ Production
TypeScript typescript/ Production

All production implementations pass the same test suite and produce identical results.

Note: The Forth implementation passes 86 comprehensive tests covering all formats but has not been verified on the full 2M CSV test due to gforth memory constraints. The SPP/IRAF implementation requires the IRAF environment for compilation.

Test Results

All 25 implementations and their test status on the full test suite (2,022,404 conversions):

Implementation Pack (unpacked→packed) Status
AWK 2,022,404 / 2,022,404 ✅ 100%
Bash 2,022,404 / 2,022,404 ✅ 100%
C 2,022,404 / 2,022,404 ✅ 100%
C++ 2,022,404 / 2,022,404 ✅ 100%
C# 2,022,404 / 2,022,404 ✅ 100%
Forth 86 / 86 ✅ 100%*
Fortran 2,022,404 / 2,022,404 ✅ 100%
Go 2,022,404 / 2,022,404 ✅ 100%
Haskell 2,022,404 / 2,022,404 ✅ 100%
Java 2,022,404 / 2,022,404 ✅ 100%
JavaScript 2,022,404 / 2,022,404 ✅ 100%
Julia 2,022,404 / 2,022,404 ✅ 100%
Kotlin 2,022,404 / 2,022,404 ✅ 100%
Nim 2,022,404 / 2,022,404 ✅ 100%
Octave 2,022,404 / 2,022,404 ✅ 100%
Perl 2,022,404 / 2,022,404 ✅ 100%
PHP 2,022,404 / 2,022,404 ✅ 100%
Python 2,022,404 / 2,022,404 ✅ 100%
R 2,022,404 / 2,022,404 ✅ 100%
Ruby 2,022,404 / 2,022,404 ✅ 100%
Rust 2,022,404 / 2,022,404 ✅ 100%
SPP/IRAF 2,022,404 / 2,022,404 ✅ 100%
Swift 2,022,404 / 2,022,404 ✅ 100%
Tcl 2,022,404 / 2,022,404 ✅ 100%
TypeScript 2,022,404 / 2,022,404 ✅ 100%

*Forth passes 86 comprehensive tests covering all formats; full CSV test limited by gforth memory constraints.

Roundtrip note: 2,625 old-style designations (e.g., A873 OA) normalize to modern format (1873 OA) on unpack. This is correct behavior—the packed representation is identical either way.

Quick Start

AWK

cd awk
echo "1995 XA" | awk -f src/mpc_designation.awk -f src/mpc_designation_main.awk
# Output: J95X00A

Bash

cd bash
./src/mpc_designation.sh '1995 XA'    # Output: J95X00A
source src/mpc_designation.sh
result=$(convert_simple "1995 XA")    # Returns "J95X00A"

C

cd c && make
./mpc_designation '1995 XA'    # Output: J95X00A

C++

cd cpp && make
./mpc_designation '1995 XA'    # Output: J95X00A
#include "mpc_designation.hpp"
std::string result = mpc::MPCDesignation::convertSimple("1995 XA");  // Returns "J95X00A"

C#

cd csharp && dotnet build
dotnet run -- '1995 XA'    # Output: J95X00A
using MPC;
string result = MPCDesignation.ConvertSimple("1995 XA");  // Returns "J95X00A"

Forth

cd forth
gforth src/mpc_designation_cli.fs '1995 XA'    # Output: J95X00A
require src/mpc_designation.fs
s" 1995 XA" convert-simple type  \ Prints: J95X00A

Python

from mpc_designation import convert_simple
convert_simple('1995 XA')  # Returns 'J95X00A'

R

source("mpc_designation.R")
convert_simple("1995 XA")  # Returns "J95X00A"
cd r
Rscript src/mpc_designation_cli.R '1995 XA'    # Output: J95X00A

Tcl

source mpc_designation.tcl
MPCDesignation::convertSimple "1995 XA"  ;# Returns "J95X00A"

Swift

cd swift && make
./mpc_designation '1995 XA'    # Output: J95X00A

Perl

use MPC::Designation qw(convert_simple);
convert_simple('1995 XA');  # Returns 'J95X00A'

PHP

require_once 'src/MPCDesignation.php';
use MPC\MPCDesignation;
MPCDesignation::convertSimple('1995 XA');  // Returns 'J95X00A'
cd php
php src/mpc_designation_cli.php '1995 XA'    # Output: J95X00A

Fortran

cd fortran && make
./build/mpc_designation_cli '1995 XA'    # Output: J95X00A
use mpc_designation
character(len=80) :: result
result = convert_simple('1995 XA')  ! Returns 'J95X00A'

Go

cd go && make
./mpc_designation '1995 XA'    # Output: J95X00A
import "github.com/rlseaman/mpc_designations/go/mpc"
result, _ := mpc.ConvertSimple("1995 XA")  // Returns "J95X00A"

Haskell

cd haskell && make
./build/mpc_designation '1995 XA'    # Output: J95X00A
import MPCDesignation
case convertSimple "1995 XA" of
    Right result -> putStrLn result  -- "J95X00A"
    Left err -> print err

Rust

cd rust && cargo build --release
./target/release/mpc_designation '1995 XA'    # Output: J95X00A
use mpc_designation::convert_simple;
let result = convert_simple("1995 XA").unwrap();  // Returns "J95X00A"

Java

cd java && make
java -cp classes mpc.MPCDesignationCLI '1995 XA'    # Output: J95X00A
import mpc.MPCDesignation;
String result = MPCDesignation.convertSimple("1995 XA");  // Returns "J95X00A"

Julia

cd julia
julia src/mpc_designation_cli.jl '1995 XA'    # Output: J95X00A
push!(LOAD_PATH, "src")
using MPCDesignation
result = convert_simple("1995 XA")  # Returns "J95X00A"

Kotlin

cd kotlin && make
kotlin -cp build/mpc_designation.jar mpc.MainKt '1995 XA'    # Output: J95X00A
import mpc.MPCDesignation
val result = MPCDesignation.convertSimple("1995 XA")  // Returns "J95X00A"

Nim

cd nim && make
./mpc_designation '1995 XA'    # Output: J95X00A
import mpc_designation
let result = convertSimple("1995 XA")  # Returns "J95X00A"

Octave/MATLAB

source('src/mpc_designation.m');
mpc_convert_simple('1995 XA')  % Returns 'J95X00A'
cd octave
octave --no-gui src/mpc_designation_cli.m '1995 XA'    # Output: J95X00A

Ruby

require_relative 'src/mpc_designation'
MPCDesignation.convert_simple('1995 XA')  # Returns 'J95X00A'
cd ruby
ruby src/mpc_designation_cli.rb '1995 XA'    # Output: J95X00A

SPP/IRAF

include "mpc_designation.x"
char input[80], output[80]
call strcpy ("1995 XA", input, 80)
call mpc_convert (input, output, 80)  # output = "J95X00A"
cd spp/build
xc example_usage.x mpc_designation.x -o mpcdes.e
./mpcdes.e mpcdes    # Interactive converter

JavaScript (Node.js)

const { convertSimple } = require('./src/mpc_designation');
convertSimple('1995 XA');  // Returns 'J95X00A'
cd js
node src/mpc_designation_cli.js '1995 XA'    # Output: J95X00A

TypeScript

import { convertSimple } from 'mpc-designation-ts';
const result: string = convertSimple('1995 XA');  // Returns 'J95X00A'
cd typescript && npm install && npm run build
node dist/src/mpc_designation_cli.js '1995 XA'    # Output: J95X00A

Examples

# Asteroids - permanent (numbered)
1             -> 00001
100001        -> A0001
620000        -> ~0000

# Asteroids - provisional
1995 XA       -> J95X00A
2024 AB631    -> _OA004S

# Asteroids - survey
2040 P-L      -> PLS2040

# Comets
1P            -> 0001P
C/1995 O1     -> CJ95O010
D/1993 F2-B   -> DJ93F02b

# Natural satellites
S/2019 S 22   -> SK19S220

Project Structure

MPC_designations/
├── README.md           # This file
├── VERSION             # Version number (unified across languages)
├── LICENSE             # Public domain
├── CONTRIBUTING.md     # How to add new languages
├── docs/
│   ├── SPECIFICATION.md    # MPC format reference
│   ├── FORMATS.md          # Quick reference tables
│   └── ERROR_CHECKING.md   # Validation documentation
├── test-data/
│   ├── prov_unpack_to_pack.csv.gz  # 2M+ test cases
│   └── error_test_cases.csv         # Error handling tests
├── awk/
│   ├── README.md       # AWK documentation
│   ├── Makefile
│   ├── src/            # Source code
│   └── test/           # Test files
├── bash/
│   ├── README.md       # Bash documentation
│   ├── Makefile
│   ├── src/            # Source code
│   └── test/           # Test files
├── c/
│   ├── README.md       # C documentation
│   ├── Makefile
│   ├── src/            # Source code
│   ├── test/           # Test files
│   └── examples/       # Usage examples
├── cpp/
│   ├── README.md       # C++ documentation
│   ├── Makefile
│   └── src/            # Source code
├── csharp/
│   ├── README.md       # C# documentation
│   ├── Makefile
│   └── src/            # Source code
├── forth/
│   ├── README.md       # Forth documentation
│   ├── Makefile
│   ├── src/            # Source code (gforth)
│   └── test/           # Test files
├── fortran/
│   ├── README.md       # Fortran documentation
│   ├── Makefile
│   ├── src/            # Source code
│   └── test/           # Test files
├── python/
│   ├── README.md       # Python documentation
│   ├── pyproject.toml
│   ├── src/            # Source code
│   ├── test/           # Test files
│   └── examples/       # Usage examples
├── r/
│   ├── README.md       # R documentation
│   ├── Makefile
│   ├── src/            # Source code
│   ├── test/           # Test files
│   └── examples/       # Usage examples
├── tcl/
│   ├── README.md       # Tcl documentation
│   ├── src/            # Source code
│   ├── test/           # Test files
│   └── examples/       # Usage examples
├── swift/
│   ├── Makefile
│   ├── src/            # Source code
│   └── test/           # Test files
├── perl/
│   ├── src/            # Source code (MPC/Designation.pm)
│   └── test/           # Test files
├── php/
│   ├── Makefile
│   └── src/            # Source code
├── go/
│   ├── go.mod          # Go module definition
│   ├── Makefile
│   ├── mpc/            # Library package
│   ├── cmd/            # CLI
│   └── test/           # Test runners
├── haskell/
│   ├── README.md       # Haskell documentation
│   ├── Makefile
│   ├── src/            # Source code (MPCDesignation module)
│   └── test/           # Test files
├── java/
│   ├── Makefile
│   ├── src/            # Source code (mpc package)
│   └── test/           # Test files
├── julia/
│   ├── Makefile
│   ├── src/            # Source code (MPCDesignation module)
│   └── test/           # Test files
├── kotlin/
│   ├── Makefile
│   ├── src/            # Source code (mpc package)
│   └── test/           # Test files
├── nim/
│   ├── Makefile
│   ├── src/            # Source code
│   └── test/           # Test files
├── octave/
│   ├── README.md       # Octave/MATLAB documentation
│   ├── Makefile
│   ├── src/            # Source code
│   └── test/           # Test files
├── rust/
│   ├── Cargo.toml      # Rust package definition
│   ├── Makefile
│   └── src/            # Source code (lib.rs + binaries)
├── spp/
│   ├── README.md       # SPP/IRAF documentation
│   ├── ARCHITECTURE.txt # Code organization
│   ├── src/            # Source code (mpc_designation.x)
│   └── test/           # Test files
├── ruby/
│   ├── Makefile
│   └── src/            # Source code
├── js/
│   ├── package.json    # npm package definition
│   ├── Makefile
│   ├── src/            # Source code
│   └── test/           # Test files
└── typescript/
    ├── package.json    # npm package definition
    ├── tsconfig.json   # TypeScript configuration
    ├── Makefile
    ├── src/            # Source code
    └── test/           # Test files

Testing

Each implementation includes tests against 2+ million known-good conversions and 94 error handling tests.

# Run all tests for all languages
make test-all

# Run tests for a specific language
make test-awk
make test-bash
make test-c
make test-cpp
make test-csharp
make test-forth
make test-fortran
make test-go
make test-haskell
make test-java
make test-julia
make test-js
make test-kotlin
make test-nim
make test-octave
make test-perl
make test-php
make test-python
make test-r
make test-ruby
make test-rust
make test-spp
make test-swift
make test-tcl
make test-typescript

# Quick error tests only (faster)
make test-errors

# Benchmark all implementations
./scripts/benchmark.sh

Sparse Checkout

Download only the language you need:

git clone --filter=blob:none --sparse https://github.com/rlseaman/MPC_designations.git
cd MPC_designations
git sparse-checkout set python test-data docs

Supported Formats

Asteroids

Type Unpacked Packed
Permanent (< 100K) 1 - 99999 00001 - 99999
Permanent (100K-620K) 100001 - 619999 A0001 - z9999
Permanent (620K+) 620000+ ~0000+
Provisional 1995 XA J95X00A
Survey 2040 P-L PLS2040

Comets

Type Unpacked Packed
Numbered 1P 0001P
Numbered with fragment 73P-A 0073Pa
Numbered with 2-letter fragment 73P-AA 0073Paa
Provisional C/1995 O1 CJ95O010
Provisional with fragment D/1993 F2-B DJ93F02b
Ancient C/240 V1 C240V010
BCE C/-146 P1 C.53P010

Natural Satellites

Unpacked Packed
S/2019 S 22 SK19S220

Helper Functions

The following helper functions are available in C, Go, Java, JavaScript, Perl, PHP, Python, Ruby, Rust, Tcl, and TypeScript implementations:

Function Description
toReportFormat Convert minimal packed format to 12-character MPC observation report format
fromReportFormat Convert 12-character report format to minimal packed format
hasFragment Check if a comet designation has a fragment suffix
getFragment Extract fragment suffix (uppercase) from a comet designation
getParent Get parent comet designation without fragment
designationsEqual Compare two designations across different formats

Format Conversion Examples

# Python
to_report_format('0073Pa')   # '0073P      a' (numbered comet with fragment)
to_report_format('00001')    # '       00001' (numbered asteroid)

from_report_format('0073P      a')  # '0073Pa'

Fragment Handling Examples

# Python
has_fragment('73P-A')    # True
has_fragment('73P')      # False

get_fragment('73P-A')    # 'A'
get_fragment('73P-AA')   # 'AA'

get_parent('73P-A')      # '73P'
get_parent('0073Pa')     # '0073P'

Designation Comparison

# Python - same object, different formats
designations_equal('1995 XA', 'J95X00A')  # True
designations_equal('73P-A', '0073Pa')     # True
designations_equal('73P-A', '73P-B')      # False

Performance

Benchmark results on Apple M1 Max, processing 2,022,404 designation conversions.

Pack Direction (unpacked → packed)

Rank Language Time (ms) Rate (entries/sec) Relative
1 Go 566 3,569,824 1.00x
2 Nim 569 3,550,257 0.99x
3 JavaScript 834 2,423,369 0.68x
4 C 970 2,083,598 0.58x
5 SPP/IRAF 1,000 2,022,404 0.57x
6 TypeScript 1,163 1,737,825 0.49x
7 Rust 1,317 1,534,617 0.43x
8 Fortran 2,524 800,749 0.22x
9 Julia 3,051 662,503 0.19x
10 C# 3,265 619,017 0.17x
11 Forth* ~4,000 ~500,000 0.14x
12 Kotlin 5,822 347,147 0.10x
13 PHP 6,348 318,365 0.09x
14 Haskell 7,542 267,971 0.08x
15 Swift 8,871 227,831 0.06x
16 AWK 9,360 215,936 0.06x
17 Python 10,201 198,133 0.06x
18 Java 10,504 192,412 0.05x
19 Perl 15,965 126,595 0.04x
20 C++ 22,068 91,585 0.03x
21 Ruby 22,296 90,648 0.03x
22 Tcl 33,971 59,495 0.02x
23 R 603,586 3,348 <0.01x
24 Octave 768,240 2,631 <0.01x
25 Bash ~6,000,000 ~340 <0.01x

*Forth time estimated from 10k sample; Bash time extrapolated (full run would take ~100 minutes)

Unpack Direction (packed → unpacked)

Rank Language Time (ms) Rate (entries/sec) Relative
1 Nim 266 7,576,833 1.00x
2 C 284 7,116,514 0.94x
3 C# 297 6,805,017 0.90x
4 JavaScript 454 4,451,740 0.59x
5 C++ 456 4,432,215 0.59x
6 Go 469 4,308,162 0.57x
7 TypeScript 576 3,508,837 0.46x
8 Rust 796 2,539,058 0.34x
9 SPP/IRAF ~1,000 ~2,022,404 0.27x
10 Haskell 1,179 1,714,239 0.23x
11 Kotlin 1,333 1,516,196 0.20x
12 Fortran 1,939 1,042,336 0.14x
13 Java 2,293 881,417 0.12x
14 Julia 2,650 762,610 0.10x
15 Forth* ~4,000 ~500,000 0.07x
16 PHP 4,323 467,488 0.06x
17 Swift 4,363 463,234 0.06x
18 Python 4,929 410,014 0.05x
19 AWK 9,254 218,402 0.03x
20 Ruby 11,813 171,090 0.02x
21 Perl 12,426 162,650 0.02x
22 Tcl 18,567 108,854 0.01x
23 R* ~400,000 ~5,000 <0.01x
24 Octave* ~500,000 ~4,000 <0.01x
25 Bash ~7,200,000 ~280 <0.01x

*Forth time estimated from 10k sample; R and Octave times estimated (too slow to benchmark); Bash time extrapolated; SPP time estimated (requires IRAF environment)

Round-trip Verification

All production implementations pass the packed round-trip test: pack(unpack(y)) = y.

The 2,625 old-style provisional designations (e.g., A873 OA for year 1873) normalize to modern format (1873 OA) on unpack. This is expected behavior—both formats pack to the same representation (I73O00A).

Run benchmarks with: ./scripts/benchmark.sh --roundtrip

Documentation

Contributing

See CONTRIBUTING.md for guidelines on adding new language implementations.

License

CC0 1.0 Universal - Public Domain Dedication. See LICENSE.

About

Multi-language library for converting packed/unpacked Minor Planet Center designations (asteroids, comets, satellites)

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors