klausbrunner / solarpositioning

Java sun position code (topocentric coordinates, sunrise/sunset/twilight) based on the NREL SPA and ENEA/Grena algorithms.
MIT License
88 stars 24 forks source link
astronomy java library science solar solartracker sun sun-position sunposition sunrise sunrise-sunset twilight

solarpositioning

CI Maven javadoc

A Java library for finding topocentric solar coordinates, i.e. the sun’s position on the sky for a given date, latitude, and longitude (and other parameters), as well as times of sunrise and sunset. Calculations strictly follow well-known, peer-reviewed algorithms: SPA by Reda and Andreas and, alternatively, Grena/ENEA by Grena. More than 1000 test points are included to validate against the reference code and other sources.

A command-line application using this library is available as solarpos.

Usage

Maven coordinates

<dependency>
    <groupId>net.e175.klaus</groupId>
    <artifactId>solarpositioning</artifactId>
    <version>2.0.3</version>
</dependency>

Requirements

Java 17 or newer. No additional runtime dependencies.

(Still stuck on old Java? Use version 0.1.10 of this library, which requires Java 8 only.)

Code

The API is intentionally "flat", comprising a handful of static methods and simple records as results. To get refraction-corrected topocentric coordinates:

var dateTime = new ZonedDateTime.now();

// replace SPA with Grena3 as needed
var position = SPA.calculateSolarPosition(
    dateTime,
    48.21, // latitude (degrees)
    16.37, // longitude (degrees)
    190, // elevation (m)
    DeltaT.estimate(dateTime.toLocalDate()), // delta T (s)
    1010, // avg. air pressure (hPa)
    11); // avg. air temperature (°C)

System.out.println(position);

The SPA class includes methods to calculate the times of sunrise, sun transit, and sunset in one fell swoop. The actual return type depends on the type of day (regular day, polar day, polar night).

var result=SPA.calculateSunriseTransitSet(
        dateTime,
        70.978, // latitude  
        25.974, // longitude
        69); // delta T

if(result instanceof SunriseResult.RegularDay regular) {
    System.out.println(regular);
} else {
    System.out.println("no sunrise or sunset today!");    
}

Twilight start and end times can be obtained like sunrise and sunset, but assuming a different horizon:

var result=SPA.calculateSunriseTransitSet(
        dateTime,
        70.978, // latitude  
        25.974, // longitude
        69, // delta T
        SPA.Horizon.CIVIL_TWILIGHT); 

See the Javadoc for more methods.

Which position algorithm should I use?

Notes on sunrise, sunset, and twilight

What's this "delta T" thing?

See Wikipedia for an explanation. For many simple applications, this value could be negligible as it's just over a minute (about 70 seconds) as of this writing. However, if you're looking for maximum accuracy, you should either use a current observed value (available from e.g. the US Naval Observatory) or at least a solid estimate.

The DeltaT class provides an estimator based on polynomials fitting a number of observed (or extrapolated) historical values, published by Espenak and Meeus in 2007 and slightly updated by Espenak in 2014. Here's a plot of its output compared with some published ΔT data:

deltat

Is the code thread-safe?

Yes. None of the classes hold any mutable shared state.