README.md

# JPL Ephemeris Library for Elixir

[![Build Status](https://github.com/your-username/jpl_ephem/workflows/CI/badge.svg)](https://github.com/your-username/jpl_ephem/actions)
[![Hex.pm Version](https://img.shields.io/hexpm/v/jpl_ephem.svg)](https://hex.pm/packages/jpl_ephem)
[![Documentation](https://img.shields.io/badge/docs-hexdocs-blue.svg)](https://hexdocs.pm/jpl_ephem)
[![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)

A comprehensive Elixir library for astronomical calculations using NASA JPL ephemeris data. This library provides high-precision celestial mechanics calculations with built-in caching, coordinate transformations, and time scale conversions.

## Features

- **Time Scale Conversions**: UTC ↔ Julian Day, UTC → Terrestrial Time (TT), TT → Barycentric Dynamical Time (TDB)
- **Coordinate Transformations**: ICRF/J2000 ↔ Ecliptic, Cartesian ↔ Spherical, RA/Dec conversions
- **High-Performance Caching**: ETS-based caching with TTL, statistics tracking, and automatic garbage collection
- **Precise Calculations**: Leap second handling, obliquity corrections, unit conversions (AU ↔ km)
- **Vector Mathematics**: Comprehensive 3D vector operations for astronomical calculations
- **Production Ready**: Supervision tree, concurrent access, comprehensive error handling

## Quick Start

```elixir
# Convert current time to Julian Day
{:ok, jd} = JPLEphem.Time.utc_to_jd(DateTime.utc_now())

# Transform coordinates from ICRF to Ecliptic
{:ok, ecliptic_pos} = JPLEphem.Coord.icrf_to_ecliptic({1.0, 0.0, 0.0})

# Cache expensive calculations
key = {:mars, ~U[2025-08-24 12:00:00Z], []}
position = {{1.523, 0.321, -0.043}, {0.012, 0.009, -0.001}}
JPLEphem.Cache.put(key, position, 3600)  # Cache for 1 hour
{:ok, cached_position} = JPLEphem.Cache.get(key)
```

## Installation

Add `jpl_ephem` to your list of dependencies in `mix.exs`:

```elixir
def deps do
  [
    {:jpl_ephem, "~> 0.1.0"}
  ]
end
```

Then run:

```bash
mix deps.get
```

The library automatically starts its supervision tree with your application.

## Core Modules

### Time Module (`JPLEphem.Time`)

Handles time scale conversions and Julian Day calculations with leap second support.

```elixir
# UTC to Julian Day conversion
{:ok, jd} = JPLEphem.Time.utc_to_jd(~U[2025-01-01 12:00:00Z])
# => {:ok, 2460677.0}

# Julian Day to UTC conversion
{:ok, datetime} = JPLEphem.Time.jd_to_utc(2460677.0)
# => {:ok, ~U[2025-01-01 12:00:00.000Z]}

# UTC to Terrestrial Time (TT)
{:ok, tt_jd} = JPLEphem.Time.utc_to_tt(~U[2025-01-01 12:00:00Z])

# TT to Barycentric Dynamical Time (TDB)
{:ok, tdb_jd} = JPLEphem.Time.tt_to_tdb(2460677.0)

# Get leap seconds at a specific date
leap_secs = JPLEphem.Time.leap_seconds_at(~U[2025-01-01 12:00:00Z])
# => 37  # Current leap seconds as of 2017
```

### Coordinate Module (`JPLEphem.Coord`)

Provides coordinate system transformations and vector mathematics.

```elixir
# ICRF to Ecliptic coordinate transformation
{:ok, ecliptic} = JPLEphem.Coord.icrf_to_ecliptic({1.0, 0.0, 0.0})

# Ecliptic to ICRF (reverse transformation)
{:ok, icrf} = JPLEphem.Coord.ecliptic_to_icrf(ecliptic)

# Cartesian to Spherical conversion (physics convention)
{:ok, {r, theta, phi}} = JPLEphem.Coord.to_spherical({3.0, 4.0, 5.0})
# phi is polar angle from Z-axis, theta is azimuthal angle

# Spherical to Cartesian conversion
{:ok, cartesian} = JPLEphem.Coord.from_spherical(r, theta, phi)

# Right Ascension / Declination
{:ok, {ra, dec}} = JPLEphem.Coord.to_ra_dec({1.0, 0.0, 0.0})
{:ok, position} = JPLEphem.Coord.from_ra_dec({ra, dec}, 1.0)

# Unit conversions
position_km = JPLEphem.Coord.au_to_km({1.0, 0.5, 0.0})  # AU to kilometers
position_au = JPLEphem.Coord.km_to_au(position_km)      # km to AU

# Vector operations
magnitude = JPLEphem.Coord.vector_magnitude({3.0, 4.0, 0.0})  # => 5.0
unit_vector = JPLEphem.Coord.normalize_vector({3.0, 4.0, 0.0})
dot = JPLEphem.Coord.dot_product({1,0,0}, {0,1,0})      # => 0.0
cross = JPLEphem.Coord.cross_product({1,0,0}, {0,1,0})   # => {0,0,1}
```

### Cache Module (`JPLEphem.Cache`)

High-performance ETS-based caching with automatic TTL and garbage collection.

```elixir
# Store ephemeris data with 1-hour TTL
key = {:mars, ~U[2025-08-24 12:00:00Z], [observer: :earth]}
position = {{1.523679, 0.321456, -0.043211}, {0.012345, 0.008765, -0.001234}}
JPLEphem.Cache.put(key, position, 3600)

# Retrieve cached data
case JPLEphem.Cache.get(key) do
  {:ok, cached_position} -> IO.puts("Cache hit!")
  :not_found -> IO.puts("Cache miss or expired")
end

# Cache statistics
stats = JPLEphem.Cache.stats()
# => %{size: 42, hits: 156, misses: 23, hit_rate: 0.871}

# Manual garbage collection
JPLEphem.Cache.gc()

# Configure cache
JPLEphem.Cache.set_ttl(7200)        # Set default TTL to 2 hours
JPLEphem.Cache.set_max_size(50_000)  # Set maximum cache size

# Clear all entries
JPLEphem.Cache.clear()
```

## Time Scales and Coordinate Systems

### Time Scales

- **UTC (Coordinated Universal Time)**: Standard civil time with leap seconds
- **TT (Terrestrial Time)**: Uniform time scale for Earth-based observations
- **TDB (Barycentric Dynamical Time)**: Time scale for solar system dynamics
- **Julian Day (JD)**: Continuous count of days since noon UT on January 1, 4713 BCE

### Coordinate Systems

- **ICRF/J2000**: International Celestial Reference Frame, standard for stellar positions
- **Ecliptic**: Coordinate system based on Earth's orbital plane
- **Spherical**: Physics convention (r, θ, φ) where φ is polar angle from Z-axis
- **RA/Dec**: Right Ascension and Declination for celestial navigation

### Key Constants

- **J2000.0 Obliquity**: 23.43929111° (angle between equatorial and ecliptic planes)
- **AU**: 149,597,870.7 km (Astronomical Unit)
- **Leap Seconds**: Automatically handled for dates 1972-2017+

## Error Handling

The library uses comprehensive error handling with descriptive error atoms:

```elixir
case JPLEphem.Time.utc_to_jd(invalid_date) do
  {:ok, jd} -> # Success
  {:error, :time_out_of_range} -> # Date outside supported range
end

case JPLEphem.Coord.to_spherical({0.0, 0.0, 0.0}) do
  {:ok, spherical} -> # Success  
  {:error, :zero_vector} -> # Cannot convert zero vector
end

case JPLEphem.Coord.normalize_vector({0.0, 0.0, 0.0}) do
  {:ok, unit_vector} -> # Success
  {:error, :zero_vector} -> # Cannot normalize zero vector
end
```

## Performance and Caching

The library is designed for high-performance astronomical calculations:

- **ETS Tables**: Concurrent read/write access with minimal locking
- **Automatic TTL**: Configurable time-to-live with background garbage collection
- **Statistics Tracking**: Monitor cache hit rates and performance metrics
- **Memory Efficient**: Automatic cleanup of expired entries
- **Production Ready**: Supervised processes with graceful error handling

### Cache Performance Tips

```elixir
# Use structured keys for better organization
key = {body, datetime, options_list}

# Set appropriate TTL based on calculation precision needs
JPLEphem.Cache.put(key, result, 3600)  # 1 hour for ephemeris data
JPLEphem.Cache.put(key, result, 86400) # 24 hours for less precise data

# Monitor cache performance
stats = JPLEphem.Cache.stats()
if stats.hit_rate < 0.8 do
  IO.puts("Consider increasing TTL or cache size")
end
```

## Development

### Running Tests

```bash
# Run all tests
mix test

# Run tests with coverage
mix test --cover

# Run specific test modules
mix test test/jpl_ephem/time_test.exs
mix test test/jpl_ephem/coord_test.exs  
mix test test/jpl_ephem/cache_test.exs

# Run tests in watch mode during development
mix test.watch
```

### Code Quality

```bash
# Format code
mix format

# Run static analysis
mix credo

# Type checking (if using Dialyzer)
mix dialyzer

# Generate documentation
mix docs
```

### Project Structure

```
jpl_ephem/
├── lib/
│   └── jpl_ephem/
│       ├── application.ex      # Application supervisor
│       ├── time.ex            # Time scale conversions
│       ├── coord.ex           # Coordinate transformations
│       └── cache.ex           # ETS-based caching
├── test/
│   ├── support/
│   │   ├── test_helpers.ex    # Test utilities
│   │   └── test_data.ex       # Reference data
│   └── jpl_ephem/
│       ├── time_test.exs      # Time module tests
│       ├── coord_test.exs     # Coordinate tests
│       └── cache_test.exs     # Cache tests
├── docs/
│   ├── PRD.md                 # Product Requirements
│   ├── SPEC.md                # Technical Specifications
│   ├── API_SPEC.md            # API Documentation
│   └── TDD_PLAN.md            # Test-Driven Development Plan
└── mix.exs                    # Project configuration
```

## Testing Philosophy

This library was developed using strict Test-Driven Development (TDD):

1. **Red**: Write failing tests first
2. **Green**: Implement minimal code to pass tests
3. **Refactor**: Improve code while maintaining test coverage
4. **Commit**: Regular commits at each TDD cycle

All modules have comprehensive test coverage with:
- Happy path testing
- Edge case validation
- Error condition handling
- Precision validation for numerical calculations
- Concurrent access testing
- Performance validation

## Use Cases

### Astronomical Software
- Planetarium applications
- Telescope pointing systems
- Satellite tracking
- Astronomical observation planning

### Scientific Computing
- Orbital mechanics simulations
- Celestial navigation systems
- Space mission planning
- Educational astronomy tools

### Web Applications
- Astronomical event calculators
- Sky viewing applications
- Solar system visualizations
- Ephemeris data APIs

## API Reference

Complete API documentation is available at [HexDocs](https://hexdocs.pm/jpl_ephem).

For detailed technical specifications, see:
- [Technical Specifications](SPEC.md)
- [API Specification](API_SPEC.md)
- [Product Requirements](PRD.md)

## Contributing

We welcome contributions! Please see our contributing guidelines:

1. **Fork** the repository
2. **Create** a feature branch: `git checkout -b feature-name`
3. **Write tests** for your changes (TDD approach)
4. **Implement** the feature with tests passing
5. **Run** the full test suite: `mix test`
6. **Commit** your changes: `git commit -m 'Add feature'`
7. **Push** to your branch: `git push origin feature-name`
8. **Submit** a pull request

### Code Standards

- Follow Elixir formatting conventions (`mix format`)
- Maintain test coverage above 95%
- Add documentation for public functions
- Use descriptive commit messages
- Include tests for edge cases and error conditions

## License

This project is licensed under the Apache License 2.0 - see the [LICENSE](LICENSE) file for details.

## Acknowledgments

- NASA JPL for ephemeris data and algorithms
- International Astronomical Union (IAU) for coordinate system standards
- The Elixir community for excellent libraries and conventions
- Contributors and maintainers of this project

## Changelog

See [CHANGELOG.md](CHANGELOG.md) for version history and release notes.

---

**Made with ❤️ for the astronomical community**