# JPL Ephemeris Library for Elixir
[](https://github.com/your-username/jpl_ephem/actions)
[](https://hex.pm/packages/jpl_ephem)
[](https://hexdocs.pm/jpl_ephem)
[](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**