FAILURE MAP
← Case archive

FA-55206 / Astronomical coordinate conventions / Open access

Sidereal hour angle adapter: Equation of equinoxes is removed instead of added to sidereal angle · case 01

The adapter reports an incorrect local apparent while other fields remain valid.

Verified by executionVariant 1 · 6 checks per implementationDownload source bundle ↓JSON ↗

ROOT CAUSE

Equation of equinoxes is removed instead of added to sidereal angle. Faulty expression: (d['gmst']+d['lon'])%360

VERIFIED REPAIR

Preserve the declared model convention at this site: (d['gmst']+d['lon']+d['eqeq'])%360

Unsuccessful approach: A partial convention repair still uses (d['gmst']+d['lon']-d['eqeq'])%360

Case contract

All angular values are exact model degrees. East longitude is positive. Local mean sidereal angle is gmst+lon, apparent sidereal includes eqeq, apparent RA is ra+dra. Hour angle is sidereal minus RA, normalized into [0,360). No Earth rotation is calculated. Output fields are defined by: local_mean = (d['gmst']+d['lon'])%360; local_apparent = (d['gmst']+d['lon']+d['eqeq'])%360; apparent_ra = (d['ra']+d['dra'])%360; mean_hour_angle = (d['gmst']+d['lon']-d['ra'])%360; apparent_hour_angle = (d['gmst']+d['lon']+d['eqeq']-d['ra']-d['dra'])%360; meridian_ra = (d['gmst']+d['lon']+d['eqeq']-d['dra'])%360

Why this case matters

Catalog, detector, sky-coordinate, and spectroscopy adapters must preserve the association between numeric coordinates and their declared reference conventions.

1 / The failure

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(d):
    return {'local_mean': (d['gmst']+d['lon'])%360, 'local_apparent': (d['gmst']+d['lon'])%360, 'apparent_ra': (d['ra']+d['dra'])%360, 'mean_hour_angle': (d['gmst']+d['lon']-d['ra'])%360, 'apparent_hour_angle': (d['gmst']+d['lon']+d['eqeq']-d['ra']-d['dra'])%360, 'meridian_ra': (d['gmst']+d['lon']+d['eqeq']-d['dra'])%360}
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = {1: [({'gmst': 100, 'lon': 30, 'eqeq': 2, 'ra': 50, 'dra': 3}, {'local_mean': 130, 'local_apparent': 132, 'apparent_ra': 53, 'mean_hour_angle': 80, 'apparent_hour_angle': 79, 'meridian_ra': 129}), ({'gmst': 100, 'lon': -40, 'eqeq': 2, 'ra': 50, 'dra': 3}, {'local_mean': 60, 'local_apparent': 62, 'apparent_ra': 53, 'mean_hour_angle': 10, 'apparent_hour_angle': 9, 'meridian_ra': 59}), ({'gmst': 100, 'lon': 30, 'eqeq': 0, 'ra': 50, 'dra': 0}, {'local_mean': 130, 'local_apparent': 130, 'apparent_ra': 50, 'mean_hour_angle': 80, 'apparent_hour_angle': 80, 'meridian_ra': 130}), ({'gmst': 350, 'lon': 30, 'eqeq': 2, 'ra': 5, 'dra': 3}, {'local_mean': 20, 'local_apparent': 22, 'apparent_ra': 8, 'mean_hour_angle': 15, 'apparent_hour_angle': 14, 'meridian_ra': 19}), ({'gmst': 100, 'lon': 30, 'eqeq': 2, 'ra': 300, 'dra': 3}, {'local_mean': 130, 'local_apparent': 132, 'apparent_ra': 303, 'mean_hour_angle': 190, 'apparent_hour_angle': 189, 'meridian_ra': 129}), ({'gmst': 100, 'lon': 0, 'eqeq': -3, 'ra': 50, 'dra': -2}, {'local_mean': 100, 'local_apparent': 97, 'apparent_ra': 48, 'mean_hour_angle': 50, 'apparent_hour_angle': 49, 'meridian_ra': 99})], 2: [({'gmst': 101, 'lon': 30, 'eqeq': 2, 'ra': 50, 'dra': 3}, {'local_mean': 131, 'local_apparent': 133, 'apparent_ra': 53, 'mean_hour_angle': 81, 'apparent_hour_angle': 80, 'meridian_ra': 130}), ({'gmst': 101, 'lon': -40, 'eqeq': 2, 'ra': 50, 'dra': 3}, {'local_mean': 61, 'local_apparent': 63, 'apparent_ra': 53, 'mean_hour_angle': 11, 'apparent_hour_angle': 10, 'meridian_ra': 60}), ({'gmst': 101, 'lon': 30, 'eqeq': 0, 'ra': 50, 'dra': 0}, {'local_mean': 131, 'local_apparent': 131, 'apparent_ra': 50, 'mean_hour_angle': 81, 'apparent_hour_angle': 81, 'meridian_ra': 131}), ({'gmst': 351, 'lon': 30, 'eqeq': 2, 'ra': 5, 'dra': 3}, {'local_mean': 21, 'local_apparent': 23, 'apparent_ra': 8, 'mean_hour_angle': 16, 'apparent_hour_angle': 15, 'meridian_ra': 20}), ({'gmst': 101, 'lon': 30, 'eqeq': 2, 'ra': 300, 'dra': 3}, {'local_mean': 131, 'local_apparent': 133, 'apparent_ra': 303, 'mean_hour_angle': 191, 'apparent_hour_angle': 190, 'meridian_ra': 130}), ({'gmst': 101, 'lon': 0, 'eqeq': -3, 'ra': 50, 'dra': -2}, {'local_mean': 101, 'local_apparent': 98, 'apparent_ra': 48, 'mean_hour_angle': 51, 'apparent_hour_angle': 50, 'meridian_ra': 100})], 3: [({'gmst': 102, 'lon': 30, 'eqeq': 2, 'ra': 50, 'dra': 3}, {'local_mean': 132, 'local_apparent': 134, 'apparent_ra': 53, 'mean_hour_angle': 82, 'apparent_hour_angle': 81, 'meridian_ra': 131}), ({'gmst': 102, 'lon': -40, 'eqeq': 2, 'ra': 50, 'dra': 3}, {'local_mean': 62, 'local_apparent': 64, 'apparent_ra': 53, 'mean_hour_angle': 12, 'apparent_hour_angle': 11, 'meridian_ra': 61}), ({'gmst': 102, 'lon': 30, 'eqeq': 0, 'ra': 50, 'dra': 0}, {'local_mean': 132, 'local_apparent': 132, 'apparent_ra': 50, 'mean_hour_angle': 82, 'apparent_hour_angle': 82, 'meridian_ra': 132}), ({'gmst': 352, 'lon': 30, 'eqeq': 2, 'ra': 5, 'dra': 3}, {'local_mean': 22, 'local_apparent': 24, 'apparent_ra': 8, 'mean_hour_angle': 17, 'apparent_hour_angle': 16, 'meridian_ra': 21}), ({'gmst': 102, 'lon': 30, 'eqeq': 2, 'ra': 300, 'dra': 3}, {'local_mean': 132, 'local_apparent': 134, 'apparent_ra': 303, 'mean_hour_angle': 192, 'apparent_hour_angle': 191, 'meridian_ra': 131}), ({'gmst': 102, 'lon': 0, 'eqeq': -3, 'ra': 50, 'dra': -2}, {'local_mean': 102, 'local_apparent': 99, 'apparent_ra': 48, 'mean_hour_angle': 52, 'apparent_hour_angle': 51, 'meridian_ra': 101})], 4: [({'gmst': 103, 'lon': 30, 'eqeq': 2, 'ra': 50, 'dra': 3}, {'local_mean': 133, 'local_apparent': 135, 'apparent_ra': 53, 'mean_hour_angle': 83, 'apparent_hour_angle': 82, 'meridian_ra': 132}), ({'gmst': 103, 'lon': -40, 'eqeq': 2, 'ra': 50, 'dra': 3}, {'local_mean': 63, 'local_apparent': 65, 'apparent_ra': 53, 'mean_hour_angle': 13, 'apparent_hour_angle': 12, 'meridian_ra': 62}), ({'gmst': 103, 'lon': 30, 'eqeq': 0, 'ra': 50, 'dra': 0}, {'local_mean': 133, 'local_apparent': 133, 'apparent_ra': 50, 'mean_hour_angle': 83, 'apparent_hour_angle': 83, 'meridian_ra': 133}), ({'gmst': 353, 'lon': 30, 'eqeq': 2, 'ra': 5, 'dra': 3}, {'local_mean': 23, 'local_apparent': 25, 'apparent_ra': 8, 'mean_hour_angle': 18, 'apparent_hour_angle': 17, 'meridian_ra': 22}), ({'gmst': 103, 'lon': 30, 'eqeq': 2, 'ra': 300, 'dra': 3}, {'local_mean': 133, 'local_apparent': 135, 'apparent_ra': 303, 'mean_hour_angle': 193, 'apparent_hour_angle': 192, 'meridian_ra': 132}), ({'gmst': 103, 'lon': 0, 'eqeq': -3, 'ra': 50, 'dra': -2}, {'local_mean': 103, 'local_apparent': 100, 'apparent_ra': 48, 'mean_hour_angle': 53, 'apparent_hour_angle': 52, 'meridian_ra': 102})], 5: [({'gmst': 104, 'lon': 30, 'eqeq': 2, 'ra': 50, 'dra': 3}, {'local_mean': 134, 'local_apparent': 136, 'apparent_ra': 53, 'mean_hour_angle': 84, 'apparent_hour_angle': 83, 'meridian_ra': 133}), ({'gmst': 104, 'lon': -40, 'eqeq': 2, 'ra': 50, 'dra': 3}, {'local_mean': 64, 'local_apparent': 66, 'apparent_ra': 53, 'mean_hour_angle': 14, 'apparent_hour_angle': 13, 'meridian_ra': 63}), ({'gmst': 104, 'lon': 30, 'eqeq': 0, 'ra': 50, 'dra': 0}, {'local_mean': 134, 'local_apparent': 134, 'apparent_ra': 50, 'mean_hour_angle': 84, 'apparent_hour_angle': 84, 'meridian_ra': 134}), ({'gmst': 354, 'lon': 30, 'eqeq': 2, 'ra': 5, 'dra': 3}, {'local_mean': 24, 'local_apparent': 26, 'apparent_ra': 8, 'mean_hour_angle': 19, 'apparent_hour_angle': 18, 'meridian_ra': 23}), ({'gmst': 104, 'lon': 30, 'eqeq': 2, 'ra': 300, 'dra': 3}, {'local_mean': 134, 'local_apparent': 136, 'apparent_ra': 303, 'mean_hour_angle': 194, 'apparent_hour_angle': 193, 'meridian_ra': 133}), ({'gmst': 104, 'lon': 0, 'eqeq': -3, 'ra': 50, 'dra': -2}, {'local_mean': 104, 'local_apparent': 101, 'apparent_ra': 48, 'mean_hour_angle': 54, 'apparent_hour_angle': 53, 'meridian_ra': 103})]}
for i, (record, expected) in enumerate(fixtures[N]):
    check('astronomical fixture %s' % i, solve(record), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
astronomical fixture 0{'apparent_hour_angle': 79, 'apparent_ra': 53, 'local_apparent': 130, 'local_mean': 130, 'mean_hour_angle': 80, 'meridian_ra': 129}{'apparent_hour_angle': 79, 'apparent_ra': 53, 'local_apparent': 132, 'local_mean': 130, 'mean_hour_angle': 80, 'meridian_ra': 129}Failed
astronomical fixture 1{'apparent_hour_angle': 9, 'apparent_ra': 53, 'local_apparent': 60, 'local_mean': 60, 'mean_hour_angle': 10, 'meridian_ra': 59}{'apparent_hour_angle': 9, 'apparent_ra': 53, 'local_apparent': 62, 'local_mean': 60, 'mean_hour_angle': 10, 'meridian_ra': 59}Failed
astronomical fixture 2{'apparent_hour_angle': 80, 'apparent_ra': 50, 'local_apparent': 130, 'local_mean': 130, 'mean_hour_angle': 80, 'meridian_ra': 130}{'apparent_hour_angle': 80, 'apparent_ra': 50, 'local_apparent': 130, 'local_mean': 130, 'mean_hour_angle': 80, 'meridian_ra': 130}Passed
astronomical fixture 3{'apparent_hour_angle': 14, 'apparent_ra': 8, 'local_apparent': 20, 'local_mean': 20, 'mean_hour_angle': 15, 'meridian_ra': 19}{'apparent_hour_angle': 14, 'apparent_ra': 8, 'local_apparent': 22, 'local_mean': 20, 'mean_hour_angle': 15, 'meridian_ra': 19}Failed
astronomical fixture 4{'apparent_hour_angle': 189, 'apparent_ra': 303, 'local_apparent': 130, 'local_mean': 130, 'mean_hour_angle': 190, 'meridian_ra': 129}{'apparent_hour_angle': 189, 'apparent_ra': 303, 'local_apparent': 132, 'local_mean': 130, 'mean_hour_angle': 190, 'meridian_ra': 129}Failed
astronomical fixture 5{'apparent_hour_angle': 49, 'apparent_ra': 48, 'local_apparent': 100, 'local_mean': 100, 'mean_hour_angle': 50, 'meridian_ra': 99}{'apparent_hour_angle': 49, 'apparent_ra': 48, 'local_apparent': 97, 'local_mean': 100, 'mean_hour_angle': 50, 'meridian_ra': 99}Failed

SHA-256 / 31acb9bd7f85e4bce898d7652a999c138048d01487df4b3da95836d5969f3b23

2 / The unsuccessful fix

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(d):
    return {'local_mean': (d['gmst']+d['lon'])%360, 'local_apparent': (d['gmst']+d['lon']-d['eqeq'])%360, 'apparent_ra': (d['ra']+d['dra'])%360, 'mean_hour_angle': (d['gmst']+d['lon']-d['ra'])%360, 'apparent_hour_angle': (d['gmst']+d['lon']+d['eqeq']-d['ra']-d['dra'])%360, 'meridian_ra': (d['gmst']+d['lon']+d['eqeq']-d['dra'])%360}
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = {1: [({'gmst': 100, 'lon': 30, 'eqeq': 2, 'ra': 50, 'dra': 3}, {'local_mean': 130, 'local_apparent': 132, 'apparent_ra': 53, 'mean_hour_angle': 80, 'apparent_hour_angle': 79, 'meridian_ra': 129}), ({'gmst': 100, 'lon': -40, 'eqeq': 2, 'ra': 50, 'dra': 3}, {'local_mean': 60, 'local_apparent': 62, 'apparent_ra': 53, 'mean_hour_angle': 10, 'apparent_hour_angle': 9, 'meridian_ra': 59}), ({'gmst': 100, 'lon': 30, 'eqeq': 0, 'ra': 50, 'dra': 0}, {'local_mean': 130, 'local_apparent': 130, 'apparent_ra': 50, 'mean_hour_angle': 80, 'apparent_hour_angle': 80, 'meridian_ra': 130}), ({'gmst': 350, 'lon': 30, 'eqeq': 2, 'ra': 5, 'dra': 3}, {'local_mean': 20, 'local_apparent': 22, 'apparent_ra': 8, 'mean_hour_angle': 15, 'apparent_hour_angle': 14, 'meridian_ra': 19}), ({'gmst': 100, 'lon': 30, 'eqeq': 2, 'ra': 300, 'dra': 3}, {'local_mean': 130, 'local_apparent': 132, 'apparent_ra': 303, 'mean_hour_angle': 190, 'apparent_hour_angle': 189, 'meridian_ra': 129}), ({'gmst': 100, 'lon': 0, 'eqeq': -3, 'ra': 50, 'dra': -2}, {'local_mean': 100, 'local_apparent': 97, 'apparent_ra': 48, 'mean_hour_angle': 50, 'apparent_hour_angle': 49, 'meridian_ra': 99})], 2: [({'gmst': 101, 'lon': 30, 'eqeq': 2, 'ra': 50, 'dra': 3}, {'local_mean': 131, 'local_apparent': 133, 'apparent_ra': 53, 'mean_hour_angle': 81, 'apparent_hour_angle': 80, 'meridian_ra': 130}), ({'gmst': 101, 'lon': -40, 'eqeq': 2, 'ra': 50, 'dra': 3}, {'local_mean': 61, 'local_apparent': 63, 'apparent_ra': 53, 'mean_hour_angle': 11, 'apparent_hour_angle': 10, 'meridian_ra': 60}), ({'gmst': 101, 'lon': 30, 'eqeq': 0, 'ra': 50, 'dra': 0}, {'local_mean': 131, 'local_apparent': 131, 'apparent_ra': 50, 'mean_hour_angle': 81, 'apparent_hour_angle': 81, 'meridian_ra': 131}), ({'gmst': 351, 'lon': 30, 'eqeq': 2, 'ra': 5, 'dra': 3}, {'local_mean': 21, 'local_apparent': 23, 'apparent_ra': 8, 'mean_hour_angle': 16, 'apparent_hour_angle': 15, 'meridian_ra': 20}), ({'gmst': 101, 'lon': 30, 'eqeq': 2, 'ra': 300, 'dra': 3}, {'local_mean': 131, 'local_apparent': 133, 'apparent_ra': 303, 'mean_hour_angle': 191, 'apparent_hour_angle': 190, 'meridian_ra': 130}), ({'gmst': 101, 'lon': 0, 'eqeq': -3, 'ra': 50, 'dra': -2}, {'local_mean': 101, 'local_apparent': 98, 'apparent_ra': 48, 'mean_hour_angle': 51, 'apparent_hour_angle': 50, 'meridian_ra': 100})], 3: [({'gmst': 102, 'lon': 30, 'eqeq': 2, 'ra': 50, 'dra': 3}, {'local_mean': 132, 'local_apparent': 134, 'apparent_ra': 53, 'mean_hour_angle': 82, 'apparent_hour_angle': 81, 'meridian_ra': 131}), ({'gmst': 102, 'lon': -40, 'eqeq': 2, 'ra': 50, 'dra': 3}, {'local_mean': 62, 'local_apparent': 64, 'apparent_ra': 53, 'mean_hour_angle': 12, 'apparent_hour_angle': 11, 'meridian_ra': 61}), ({'gmst': 102, 'lon': 30, 'eqeq': 0, 'ra': 50, 'dra': 0}, {'local_mean': 132, 'local_apparent': 132, 'apparent_ra': 50, 'mean_hour_angle': 82, 'apparent_hour_angle': 82, 'meridian_ra': 132}), ({'gmst': 352, 'lon': 30, 'eqeq': 2, 'ra': 5, 'dra': 3}, {'local_mean': 22, 'local_apparent': 24, 'apparent_ra': 8, 'mean_hour_angle': 17, 'apparent_hour_angle': 16, 'meridian_ra': 21}), ({'gmst': 102, 'lon': 30, 'eqeq': 2, 'ra': 300, 'dra': 3}, {'local_mean': 132, 'local_apparent': 134, 'apparent_ra': 303, 'mean_hour_angle': 192, 'apparent_hour_angle': 191, 'meridian_ra': 131}), ({'gmst': 102, 'lon': 0, 'eqeq': -3, 'ra': 50, 'dra': -2}, {'local_mean': 102, 'local_apparent': 99, 'apparent_ra': 48, 'mean_hour_angle': 52, 'apparent_hour_angle': 51, 'meridian_ra': 101})], 4: [({'gmst': 103, 'lon': 30, 'eqeq': 2, 'ra': 50, 'dra': 3}, {'local_mean': 133, 'local_apparent': 135, 'apparent_ra': 53, 'mean_hour_angle': 83, 'apparent_hour_angle': 82, 'meridian_ra': 132}), ({'gmst': 103, 'lon': -40, 'eqeq': 2, 'ra': 50, 'dra': 3}, {'local_mean': 63, 'local_apparent': 65, 'apparent_ra': 53, 'mean_hour_angle': 13, 'apparent_hour_angle': 12, 'meridian_ra': 62}), ({'gmst': 103, 'lon': 30, 'eqeq': 0, 'ra': 50, 'dra': 0}, {'local_mean': 133, 'local_apparent': 133, 'apparent_ra': 50, 'mean_hour_angle': 83, 'apparent_hour_angle': 83, 'meridian_ra': 133}), ({'gmst': 353, 'lon': 30, 'eqeq': 2, 'ra': 5, 'dra': 3}, {'local_mean': 23, 'local_apparent': 25, 'apparent_ra': 8, 'mean_hour_angle': 18, 'apparent_hour_angle': 17, 'meridian_ra': 22}), ({'gmst': 103, 'lon': 30, 'eqeq': 2, 'ra': 300, 'dra': 3}, {'local_mean': 133, 'local_apparent': 135, 'apparent_ra': 303, 'mean_hour_angle': 193, 'apparent_hour_angle': 192, 'meridian_ra': 132}), ({'gmst': 103, 'lon': 0, 'eqeq': -3, 'ra': 50, 'dra': -2}, {'local_mean': 103, 'local_apparent': 100, 'apparent_ra': 48, 'mean_hour_angle': 53, 'apparent_hour_angle': 52, 'meridian_ra': 102})], 5: [({'gmst': 104, 'lon': 30, 'eqeq': 2, 'ra': 50, 'dra': 3}, {'local_mean': 134, 'local_apparent': 136, 'apparent_ra': 53, 'mean_hour_angle': 84, 'apparent_hour_angle': 83, 'meridian_ra': 133}), ({'gmst': 104, 'lon': -40, 'eqeq': 2, 'ra': 50, 'dra': 3}, {'local_mean': 64, 'local_apparent': 66, 'apparent_ra': 53, 'mean_hour_angle': 14, 'apparent_hour_angle': 13, 'meridian_ra': 63}), ({'gmst': 104, 'lon': 30, 'eqeq': 0, 'ra': 50, 'dra': 0}, {'local_mean': 134, 'local_apparent': 134, 'apparent_ra': 50, 'mean_hour_angle': 84, 'apparent_hour_angle': 84, 'meridian_ra': 134}), ({'gmst': 354, 'lon': 30, 'eqeq': 2, 'ra': 5, 'dra': 3}, {'local_mean': 24, 'local_apparent': 26, 'apparent_ra': 8, 'mean_hour_angle': 19, 'apparent_hour_angle': 18, 'meridian_ra': 23}), ({'gmst': 104, 'lon': 30, 'eqeq': 2, 'ra': 300, 'dra': 3}, {'local_mean': 134, 'local_apparent': 136, 'apparent_ra': 303, 'mean_hour_angle': 194, 'apparent_hour_angle': 193, 'meridian_ra': 133}), ({'gmst': 104, 'lon': 0, 'eqeq': -3, 'ra': 50, 'dra': -2}, {'local_mean': 104, 'local_apparent': 101, 'apparent_ra': 48, 'mean_hour_angle': 54, 'apparent_hour_angle': 53, 'meridian_ra': 103})]}
for i, (record, expected) in enumerate(fixtures[N]):
    check('astronomical fixture %s' % i, solve(record), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
astronomical fixture 0{'apparent_hour_angle': 79, 'apparent_ra': 53, 'local_apparent': 128, 'local_mean': 130, 'mean_hour_angle': 80, 'meridian_ra': 129}{'apparent_hour_angle': 79, 'apparent_ra': 53, 'local_apparent': 132, 'local_mean': 130, 'mean_hour_angle': 80, 'meridian_ra': 129}Failed
astronomical fixture 1{'apparent_hour_angle': 9, 'apparent_ra': 53, 'local_apparent': 58, 'local_mean': 60, 'mean_hour_angle': 10, 'meridian_ra': 59}{'apparent_hour_angle': 9, 'apparent_ra': 53, 'local_apparent': 62, 'local_mean': 60, 'mean_hour_angle': 10, 'meridian_ra': 59}Failed
astronomical fixture 2{'apparent_hour_angle': 80, 'apparent_ra': 50, 'local_apparent': 130, 'local_mean': 130, 'mean_hour_angle': 80, 'meridian_ra': 130}{'apparent_hour_angle': 80, 'apparent_ra': 50, 'local_apparent': 130, 'local_mean': 130, 'mean_hour_angle': 80, 'meridian_ra': 130}Passed
astronomical fixture 3{'apparent_hour_angle': 14, 'apparent_ra': 8, 'local_apparent': 18, 'local_mean': 20, 'mean_hour_angle': 15, 'meridian_ra': 19}{'apparent_hour_angle': 14, 'apparent_ra': 8, 'local_apparent': 22, 'local_mean': 20, 'mean_hour_angle': 15, 'meridian_ra': 19}Failed
astronomical fixture 4{'apparent_hour_angle': 189, 'apparent_ra': 303, 'local_apparent': 128, 'local_mean': 130, 'mean_hour_angle': 190, 'meridian_ra': 129}{'apparent_hour_angle': 189, 'apparent_ra': 303, 'local_apparent': 132, 'local_mean': 130, 'mean_hour_angle': 190, 'meridian_ra': 129}Failed
astronomical fixture 5{'apparent_hour_angle': 49, 'apparent_ra': 48, 'local_apparent': 103, 'local_mean': 100, 'mean_hour_angle': 50, 'meridian_ra': 99}{'apparent_hour_angle': 49, 'apparent_ra': 48, 'local_apparent': 97, 'local_mean': 100, 'mean_hour_angle': 50, 'meridian_ra': 99}Failed

SHA-256 / 9b852991581bb2543d7a32d55c8e90c86fd7d958c6c79a119f102b0ae172773e

3 / The verified repair

Exit 0
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(d):
    return {'local_mean': (d['gmst']+d['lon'])%360, 'local_apparent': (d['gmst']+d['lon']+d['eqeq'])%360, 'apparent_ra': (d['ra']+d['dra'])%360, 'mean_hour_angle': (d['gmst']+d['lon']-d['ra'])%360, 'apparent_hour_angle': (d['gmst']+d['lon']+d['eqeq']-d['ra']-d['dra'])%360, 'meridian_ra': (d['gmst']+d['lon']+d['eqeq']-d['dra'])%360}
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = {1: [({'gmst': 100, 'lon': 30, 'eqeq': 2, 'ra': 50, 'dra': 3}, {'local_mean': 130, 'local_apparent': 132, 'apparent_ra': 53, 'mean_hour_angle': 80, 'apparent_hour_angle': 79, 'meridian_ra': 129}), ({'gmst': 100, 'lon': -40, 'eqeq': 2, 'ra': 50, 'dra': 3}, {'local_mean': 60, 'local_apparent': 62, 'apparent_ra': 53, 'mean_hour_angle': 10, 'apparent_hour_angle': 9, 'meridian_ra': 59}), ({'gmst': 100, 'lon': 30, 'eqeq': 0, 'ra': 50, 'dra': 0}, {'local_mean': 130, 'local_apparent': 130, 'apparent_ra': 50, 'mean_hour_angle': 80, 'apparent_hour_angle': 80, 'meridian_ra': 130}), ({'gmst': 350, 'lon': 30, 'eqeq': 2, 'ra': 5, 'dra': 3}, {'local_mean': 20, 'local_apparent': 22, 'apparent_ra': 8, 'mean_hour_angle': 15, 'apparent_hour_angle': 14, 'meridian_ra': 19}), ({'gmst': 100, 'lon': 30, 'eqeq': 2, 'ra': 300, 'dra': 3}, {'local_mean': 130, 'local_apparent': 132, 'apparent_ra': 303, 'mean_hour_angle': 190, 'apparent_hour_angle': 189, 'meridian_ra': 129}), ({'gmst': 100, 'lon': 0, 'eqeq': -3, 'ra': 50, 'dra': -2}, {'local_mean': 100, 'local_apparent': 97, 'apparent_ra': 48, 'mean_hour_angle': 50, 'apparent_hour_angle': 49, 'meridian_ra': 99})], 2: [({'gmst': 101, 'lon': 30, 'eqeq': 2, 'ra': 50, 'dra': 3}, {'local_mean': 131, 'local_apparent': 133, 'apparent_ra': 53, 'mean_hour_angle': 81, 'apparent_hour_angle': 80, 'meridian_ra': 130}), ({'gmst': 101, 'lon': -40, 'eqeq': 2, 'ra': 50, 'dra': 3}, {'local_mean': 61, 'local_apparent': 63, 'apparent_ra': 53, 'mean_hour_angle': 11, 'apparent_hour_angle': 10, 'meridian_ra': 60}), ({'gmst': 101, 'lon': 30, 'eqeq': 0, 'ra': 50, 'dra': 0}, {'local_mean': 131, 'local_apparent': 131, 'apparent_ra': 50, 'mean_hour_angle': 81, 'apparent_hour_angle': 81, 'meridian_ra': 131}), ({'gmst': 351, 'lon': 30, 'eqeq': 2, 'ra': 5, 'dra': 3}, {'local_mean': 21, 'local_apparent': 23, 'apparent_ra': 8, 'mean_hour_angle': 16, 'apparent_hour_angle': 15, 'meridian_ra': 20}), ({'gmst': 101, 'lon': 30, 'eqeq': 2, 'ra': 300, 'dra': 3}, {'local_mean': 131, 'local_apparent': 133, 'apparent_ra': 303, 'mean_hour_angle': 191, 'apparent_hour_angle': 190, 'meridian_ra': 130}), ({'gmst': 101, 'lon': 0, 'eqeq': -3, 'ra': 50, 'dra': -2}, {'local_mean': 101, 'local_apparent': 98, 'apparent_ra': 48, 'mean_hour_angle': 51, 'apparent_hour_angle': 50, 'meridian_ra': 100})], 3: [({'gmst': 102, 'lon': 30, 'eqeq': 2, 'ra': 50, 'dra': 3}, {'local_mean': 132, 'local_apparent': 134, 'apparent_ra': 53, 'mean_hour_angle': 82, 'apparent_hour_angle': 81, 'meridian_ra': 131}), ({'gmst': 102, 'lon': -40, 'eqeq': 2, 'ra': 50, 'dra': 3}, {'local_mean': 62, 'local_apparent': 64, 'apparent_ra': 53, 'mean_hour_angle': 12, 'apparent_hour_angle': 11, 'meridian_ra': 61}), ({'gmst': 102, 'lon': 30, 'eqeq': 0, 'ra': 50, 'dra': 0}, {'local_mean': 132, 'local_apparent': 132, 'apparent_ra': 50, 'mean_hour_angle': 82, 'apparent_hour_angle': 82, 'meridian_ra': 132}), ({'gmst': 352, 'lon': 30, 'eqeq': 2, 'ra': 5, 'dra': 3}, {'local_mean': 22, 'local_apparent': 24, 'apparent_ra': 8, 'mean_hour_angle': 17, 'apparent_hour_angle': 16, 'meridian_ra': 21}), ({'gmst': 102, 'lon': 30, 'eqeq': 2, 'ra': 300, 'dra': 3}, {'local_mean': 132, 'local_apparent': 134, 'apparent_ra': 303, 'mean_hour_angle': 192, 'apparent_hour_angle': 191, 'meridian_ra': 131}), ({'gmst': 102, 'lon': 0, 'eqeq': -3, 'ra': 50, 'dra': -2}, {'local_mean': 102, 'local_apparent': 99, 'apparent_ra': 48, 'mean_hour_angle': 52, 'apparent_hour_angle': 51, 'meridian_ra': 101})], 4: [({'gmst': 103, 'lon': 30, 'eqeq': 2, 'ra': 50, 'dra': 3}, {'local_mean': 133, 'local_apparent': 135, 'apparent_ra': 53, 'mean_hour_angle': 83, 'apparent_hour_angle': 82, 'meridian_ra': 132}), ({'gmst': 103, 'lon': -40, 'eqeq': 2, 'ra': 50, 'dra': 3}, {'local_mean': 63, 'local_apparent': 65, 'apparent_ra': 53, 'mean_hour_angle': 13, 'apparent_hour_angle': 12, 'meridian_ra': 62}), ({'gmst': 103, 'lon': 30, 'eqeq': 0, 'ra': 50, 'dra': 0}, {'local_mean': 133, 'local_apparent': 133, 'apparent_ra': 50, 'mean_hour_angle': 83, 'apparent_hour_angle': 83, 'meridian_ra': 133}), ({'gmst': 353, 'lon': 30, 'eqeq': 2, 'ra': 5, 'dra': 3}, {'local_mean': 23, 'local_apparent': 25, 'apparent_ra': 8, 'mean_hour_angle': 18, 'apparent_hour_angle': 17, 'meridian_ra': 22}), ({'gmst': 103, 'lon': 30, 'eqeq': 2, 'ra': 300, 'dra': 3}, {'local_mean': 133, 'local_apparent': 135, 'apparent_ra': 303, 'mean_hour_angle': 193, 'apparent_hour_angle': 192, 'meridian_ra': 132}), ({'gmst': 103, 'lon': 0, 'eqeq': -3, 'ra': 50, 'dra': -2}, {'local_mean': 103, 'local_apparent': 100, 'apparent_ra': 48, 'mean_hour_angle': 53, 'apparent_hour_angle': 52, 'meridian_ra': 102})], 5: [({'gmst': 104, 'lon': 30, 'eqeq': 2, 'ra': 50, 'dra': 3}, {'local_mean': 134, 'local_apparent': 136, 'apparent_ra': 53, 'mean_hour_angle': 84, 'apparent_hour_angle': 83, 'meridian_ra': 133}), ({'gmst': 104, 'lon': -40, 'eqeq': 2, 'ra': 50, 'dra': 3}, {'local_mean': 64, 'local_apparent': 66, 'apparent_ra': 53, 'mean_hour_angle': 14, 'apparent_hour_angle': 13, 'meridian_ra': 63}), ({'gmst': 104, 'lon': 30, 'eqeq': 0, 'ra': 50, 'dra': 0}, {'local_mean': 134, 'local_apparent': 134, 'apparent_ra': 50, 'mean_hour_angle': 84, 'apparent_hour_angle': 84, 'meridian_ra': 134}), ({'gmst': 354, 'lon': 30, 'eqeq': 2, 'ra': 5, 'dra': 3}, {'local_mean': 24, 'local_apparent': 26, 'apparent_ra': 8, 'mean_hour_angle': 19, 'apparent_hour_angle': 18, 'meridian_ra': 23}), ({'gmst': 104, 'lon': 30, 'eqeq': 2, 'ra': 300, 'dra': 3}, {'local_mean': 134, 'local_apparent': 136, 'apparent_ra': 303, 'mean_hour_angle': 194, 'apparent_hour_angle': 193, 'meridian_ra': 133}), ({'gmst': 104, 'lon': 0, 'eqeq': -3, 'ra': 50, 'dra': -2}, {'local_mean': 104, 'local_apparent': 101, 'apparent_ra': 48, 'mean_hour_angle': 54, 'apparent_hour_angle': 53, 'meridian_ra': 103})]}
for i, (record, expected) in enumerate(fixtures[N]):
    check('astronomical fixture %s' % i, solve(record), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
astronomical fixture 0{'apparent_hour_angle': 79, 'apparent_ra': 53, 'local_apparent': 132, 'local_mean': 130, 'mean_hour_angle': 80, 'meridian_ra': 129}{'apparent_hour_angle': 79, 'apparent_ra': 53, 'local_apparent': 132, 'local_mean': 130, 'mean_hour_angle': 80, 'meridian_ra': 129}Passed
astronomical fixture 1{'apparent_hour_angle': 9, 'apparent_ra': 53, 'local_apparent': 62, 'local_mean': 60, 'mean_hour_angle': 10, 'meridian_ra': 59}{'apparent_hour_angle': 9, 'apparent_ra': 53, 'local_apparent': 62, 'local_mean': 60, 'mean_hour_angle': 10, 'meridian_ra': 59}Passed
astronomical fixture 2{'apparent_hour_angle': 80, 'apparent_ra': 50, 'local_apparent': 130, 'local_mean': 130, 'mean_hour_angle': 80, 'meridian_ra': 130}{'apparent_hour_angle': 80, 'apparent_ra': 50, 'local_apparent': 130, 'local_mean': 130, 'mean_hour_angle': 80, 'meridian_ra': 130}Passed
astronomical fixture 3{'apparent_hour_angle': 14, 'apparent_ra': 8, 'local_apparent': 22, 'local_mean': 20, 'mean_hour_angle': 15, 'meridian_ra': 19}{'apparent_hour_angle': 14, 'apparent_ra': 8, 'local_apparent': 22, 'local_mean': 20, 'mean_hour_angle': 15, 'meridian_ra': 19}Passed
astronomical fixture 4{'apparent_hour_angle': 189, 'apparent_ra': 303, 'local_apparent': 132, 'local_mean': 130, 'mean_hour_angle': 190, 'meridian_ra': 129}{'apparent_hour_angle': 189, 'apparent_ra': 303, 'local_apparent': 132, 'local_mean': 130, 'mean_hour_angle': 190, 'meridian_ra': 129}Passed
astronomical fixture 5{'apparent_hour_angle': 49, 'apparent_ra': 48, 'local_apparent': 97, 'local_mean': 100, 'mean_hour_angle': 50, 'meridian_ra': 99}{'apparent_hour_angle': 49, 'apparent_ra': 48, 'local_apparent': 97, 'local_mean': 100, 'mean_hour_angle': 50, 'meridian_ra': 99}Passed

SHA-256 / b07be2936bb304c385d2d3d7615fe06ae3fd00d379a9a98700c506bc0e000365

Verification & scope

Explicitly stipulated finite algebraic adapter; no standards conformance, physical accuracy, or production-library claim. Inputs are the documented finite valid model domain. This reproducer isolates one failure mechanism. Results cover the supplied fixtures. Variants within a family share a test contract and should remain grouped when constructing evaluation splits. Related mechanisms with a shared evaluation_group must also remain together; these controlled models are not independent production incidents.

Observations recorded using Python 3.12.14 at 2026-09-29T14:45:55.616940+00:00.

Case digest / 667a8742a77d20230fcfb979342c14de720c5c9a8d72152b5d9025bc45e53394