| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106 |
- """
- Step 1: Ground truth — compute houses/angles locally using swisseph directly.
- No server, no container, no network. Pure Python + Swiss Ephemeris.
- This gives us the reference values to compare all servers against.
- """
- from __future__ import annotations
- import sys
- import os
- # Add ephemeris-mcp to path so we can import swisseph from its venv
- sys.path.insert(0, os.path.expanduser("~/.openclaw/workspace/ephemeris-mcp/src"))
- import swisseph as swe
- # ── Reference birth data ──────────────────────────────────────────────
- PEOPLE = {
- "trump": {
- "label": "Donald Trump",
- "datetime_utc": "1946-06-14T14:54:00", # 10:54 AM EDT = 14:54 UTC
- "lat": 40.6413,
- "lon": -73.7781,
- },
- "einstein": {
- "label": "Albert Einstein",
- "datetime_utc": "1879-03-14T10:37:00", # 11:30 AM LMT (UTC+0:53) = 10:37 UTC
- "lat": 48.39841,
- "lon": 9.99155,
- },
- "chaka": {
- "label": "Chaka Khan",
- "datetime_utc": "1953-03-24T03:05:00", # 9:05 PM CST (UTC-6) = 03:05 UTC next day
- "lat": 41.87811,
- "lon": -87.62980,
- },
- }
- TOLERANCE = 0.01 # degrees — very tight
- def _parse_utc_dt(dt_str):
- from datetime import datetime
- return datetime.fromisoformat(dt_str)
- def _compute_houses(dt_utc, lat, lon, house_system=b"P"):
- jd = swe.julday(dt_utc.year, dt_utc.month, dt_utc.day,
- dt_utc.hour + dt_utc.minute / 60 + dt_utc.second / 3600)
- cusps, ascmc = swe.houses(jd, lat, lon, house_system)
- return {
- "jd": jd,
- "cusps": list(cusps),
- "asc": ascmc[0],
- "mc": ascmc[1],
- "dsc": ascmc[0] + 180.0 if ascmc[0] < 180.0 else ascmc[0] - 180.0,
- "ic": ascmc[1] + 180.0 if ascmc[1] < 180.0 else ascmc[1] - 180.0,
- }
- def _fmt(lon):
- signs = ["Ari", "Tau", "Gem", "Can", "Leo", "Vir",
- "Lib", "Sco", "Sag", "Cap", "Aqu", "Pis"]
- idx = int(lon // 30) % 12
- deg = lon % 30.0
- return f"{signs[idx]} {deg:05.2f}° (abs {lon:.6f}°)"
- def main():
- print("=" * 70)
- print("STEP 1: Ground truth — swisseph direct computation")
- print("=" * 70)
- results = {}
- for key, p in PEOPLE.items():
- dt = _parse_utc_dt(p["datetime_utc"])
- h = _compute_houses(dt, p["lat"], p["lon"])
- results[key] = h
- print(f"\n{p['label']}:")
- print(f" UTC: {p['datetime_utc']} lat={p['lat']} lon={p['lon']}")
- print(f" JD: {h['jd']:.6f}")
- print(f" ASC: {_fmt(h['asc'])}")
- print(f" MC: {_fmt(h['mc'])}")
- print(f" DSC: {_fmt(h['dsc'])}")
- print(f" IC: {_fmt(h['ic'])}")
- print(f" Cusps: ", end="")
- cusp_strs = [f"H{i+1}={_fmt(c)}" for i, c in enumerate(h["cusps"])]
- print(" | ".join(cusp_strs))
- # Print machine-readable summary for easy comparison
- print("\n" + "=" * 70)
- print("MACHINE-READABLE REFERENCE VALUES:")
- print("=" * 70)
- for key, p in PEOPLE.items():
- h = results[key]
- print(f"{key}: ASC={h['asc']:.6f} MC={h['mc']:.6f} "
- f"DSC={h['dsc']:.6f} IC={h['ic']:.6f} "
- f"JD={h['jd']:.6f}")
- return results
- if __name__ == "__main__":
- main()
|