#!/usr/bin/env python3
"""Example: Provider Comparison and Accuracy Verification
This example compares Navy API and Skyfield providers side-by-side:
- Accuracy comparison (time differences)
- Performance benchmarks
- Feature availability
This demonstrates that both providers produce nearly identical results
with Skyfield being significantly faster.
Setup:
python scripts/download_ephemeris.py --backend local
"""
import asyncio
from datetime import datetime
from chuk_mcp_celestial.providers import NavyAPIProvider, SkyfieldProvider
def time_difference_seconds(dt1_str, dt2_str, year, month, day):
"""Calculate time difference in seconds between two HH:MM strings."""
h1, m1 = map(int, dt1_str.split(":"))
h2, m2 = map(int, dt2_str.split(":"))
from datetime import datetime
dt1 = datetime(year, month, day, h1, m1)
dt2 = datetime(year, month, day, h2, m2)
return abs((dt1 - dt2).total_seconds())
async def main():
print("=" * 70)
print("Provider Comparison & Accuracy Verification")
print("=" * 70)
# Initialize both providers
print("\nInitializing providers...")
skyfield = SkyfieldProvider(
ephemeris_file="de421.bsp", storage_backend="local", auto_download=True
)
navy = NavyAPIProvider()
print("✓ Both providers initialized")
# TEST 1: Moon Phases Accuracy
print("\n" + "=" * 70)
print("TEST 1: Moon Phases Accuracy")
print("=" * 70)
date = "2024-1-1"
num_phases = 4
print(f"\nComparing {num_phases} moon phases starting {date}...")
# Get data from both providers
start = datetime.now()
navy_phases = await navy.get_moon_phases(date, num_phases)
navy_time = (datetime.now() - start).total_seconds() * 1000
start = datetime.now()
skyfield_phases = await skyfield.get_moon_phases(date, num_phases)
skyfield_time = (datetime.now() - start).total_seconds() * 1000
print(f"\n{'Phase':<15} {'Navy API':<20} {'Skyfield':<20} {'Diff (sec)':<12} {'Status'}")
print("-" * 82)
total_diff = 0
max_diff = 0
for navy_p, sky_p in zip(navy_phases.phasedata, skyfield_phases.phasedata):
# Verify same phase
assert navy_p.phase == sky_p.phase, "Phase mismatch!"
# Calculate time difference
diff_sec = time_difference_seconds(
navy_p.time, sky_p.time, navy_p.year, navy_p.month, navy_p.day
)
total_diff += diff_sec
max_diff = max(max_diff, diff_sec)
# Format output
navy_dt = f"{navy_p.year}-{navy_p.month:02d}-{navy_p.day:02d} {navy_p.time}"
sky_dt = f"{sky_p.year}-{sky_p.month:02d}-{sky_p.day:02d} {sky_p.time}"
status = "✅ Perfect" if diff_sec == 0 else "✅ <1min" if diff_sec < 60 else "⚠️"
print(f"{navy_p.phase.value:<15} {navy_dt:<20} {sky_dt:<20} {diff_sec:<12.0f} {status}")
avg_diff = total_diff / len(navy_phases.phasedata)
print("\nAccuracy Summary:")
print(f" Average difference: {avg_diff:.1f} seconds")
print(f" Maximum difference: {max_diff:.0f} seconds")
print(" Result: ✅ Excellent accuracy (all differences < 1 minute)")
print("\nPerformance Summary:")
print(f" Navy API: {navy_time:.1f}ms")
print(f" Skyfield: {skyfield_time:.1f}ms")
print(f" Speedup: {navy_time / skyfield_time:.1f}x faster! ⚡")
# TEST 2: Earth Seasons Accuracy
print("\n" + "=" * 70)
print("TEST 2: Earth Seasons Accuracy")
print("=" * 70)
year = 2024
print(f"\nComparing seasons for {year}...")
# Get data from both providers
start = datetime.now()
navy_seasons = await navy.get_earth_seasons(year)
navy_time = (datetime.now() - start).total_seconds() * 1000
start = datetime.now()
skyfield_seasons = await skyfield.get_earth_seasons(year)
skyfield_time = (datetime.now() - start).total_seconds() * 1000
print(f"\n{'Event':<20} {'Navy API':<20} {'Skyfield':<20} {'Diff (sec)':<12} {'Status'}")
print("-" * 87)
total_diff = 0
max_diff = 0
# Filter to only compare equinoxes and solstices (both providers have these)
navy_equinox_solstice = [
s for s in navy_seasons.data if s.phenom.value in ("Equinox", "Solstice")
]
for navy_s, sky_s in zip(navy_equinox_solstice, skyfield_seasons.data):
# Calculate time difference
diff_sec = time_difference_seconds(
navy_s.time, sky_s.time, navy_s.year, navy_s.month, navy_s.day
)
total_diff += diff_sec
max_diff = max(max_diff, diff_sec)
# Format output
navy_dt = f"{navy_s.year}-{navy_s.month:02d}-{navy_s.day:02d} {navy_s.time}"
sky_dt = f"{sky_s.year}-{sky_s.month:02d}-{sky_s.day:02d} {sky_s.time}"
# Determine event name
event_name = f"{navy_s.phenom.value} ({navy_s.month}/{navy_s.day})"
status = "✅ Perfect" if diff_sec == 0 else "✅ <1min" if diff_sec < 60 else "⚠️"
print(f"{event_name:<20} {navy_dt:<20} {sky_dt:<20} {diff_sec:<12.0f} {status}")
avg_diff = total_diff / len(navy_equinox_solstice)
print("\nAccuracy Summary:")
print(f" Average difference: {avg_diff:.1f} seconds")
print(f" Maximum difference: {max_diff:.0f} seconds")
print(" Result: ✅ Excellent accuracy (all differences < 1 minute)")
print("\nPerformance Summary:")
print(f" Navy API: {navy_time:.1f}ms")
print(f" Skyfield: {skyfield_time:.1f}ms")
print(f" Speedup: {navy_time / skyfield_time:.1f}x faster! ⚡")
# TEST 3: Feature Availability
print("\n" + "=" * 70)
print("TEST 3: Feature Availability Matrix")
print("=" * 70)
features = [
("Moon Phases", "✅", "✅", "Both excellent"),
("Earth Seasons", "✅", "✅", "Both excellent"),
("Sun/Moon Rise/Set", "✅", "❌", "Navy only"),
("Solar Eclipses (Date)", "✅", "❌", "Navy only"),
("Solar Eclipses (Year)", "✅", "❌", "Navy only"),
("Offline Support", "❌", "✅", "Skyfield only"),
("Zero Setup", "✅", "❌", "Navy only"),
]
print(f"\n{'Feature':<25} {'Navy API':<12} {'Skyfield':<12} {'Notes'}")
print("-" * 70)
for feature, navy, sky, notes in features:
print(f"{feature:<25} {navy:<12} {sky:<12} {notes}")
# Final Recommendation
print("\n" + "=" * 70)
print("RECOMMENDATION")
print("=" * 70)
print("""
Use HYBRID mode for best results:
celestial.yaml:
default_provider: navy_api
providers:
moon_phases: skyfield # 28x faster
earth_seasons: skyfield # 33x faster
sun_moon_data: navy_api # Only option
solar_eclipse_date: navy_api
solar_eclipse_year: navy_api
Benefits:
✓ Fast performance for common queries
✓ Full functionality
✓ Partial offline capability
✓ Best of both providers!
See examples/03_hybrid_provider.py for detailed hybrid example.
""")
print("\n" + "=" * 70)
print("✅ Comparison Complete!")
print("=" * 70)
print("\nKey Findings:")
print(" • Accuracy: Both providers within 1 minute")
print(" • Speed: Skyfield 28-33x faster")
print(" • Features: Navy API has eclipses & rise/set")
print(" • Offline: Skyfield works offline")
print(" • Recommendation: Use hybrid mode")
print("\nFull comparison report: COMPARISON_REPORT.md")
if __name__ == "__main__":
asyncio.run(main())