Skip to main content

Crate spa_sra

Crate spa_sra 

Source
Expand description

§SPA_SRA

The SPA_SRA (Solar Position Algorithm for Solar Radiation Applications) calculates the solar zenith and azimuth angles in the period from the year -2000 to 6000, with uncertainties of +/- 0.0003 degrees based on the date, time, and location on Earth. (Reference: Reda, I.; Andreas, A., Solar Position Algorithm for Solar Radiation Applications, Solar Energy. Vol. 76(5), 2004; pp. 577-589).

It can also calculate the surface incidence angle for e.g. a solar panel. The surface incidence angle is the angle between an incoming ray (like light or radar) and a line perpendicular to the surface at the point where the ray hits.

Further information on this algorithm is available in the following NREL technical report (pdf): Reda, I.; Andreas, A. (2003). Solar Position Algorithm for Solar Radiation Applications. 55 pp.; NREL Report No. TP-560-34302, Revised January 2008.

§License and Acknowledgement

SPA_SRA is a port with rust specific adjustments from the original C-code prepared by employees of the Alliance for Sustainable Energy, LLC. Hence, the MIT license comes with an acknowledgement and disclaimer related to that original code. For personal use it should be fine though.

§Usage overview

The library has two main entry points:

  • Using the SpaBuilder for simple use-cases.
  • Using the SpaData struct and its sub-structs directly, which may be favourable for a more fine-grained integration.

It is possible to use a hybrid between the SpaBuilder and the SpaData struct.

However, if doing a hybrid when also using the chrono_0_4 feature it gets slightly more complicated. Changing date and time directly in the Input struct doesn’t automatically update the timezone offset numeric field (which is used by the SPA-SRA algorithm) and can change between two hours due to sunlight saving times

§Features

  • “chrono_0_4” - adds some chrono dependent constructors to both SpaBuilder and SpaData, as well as some methods. This makes date, time and timezone management easier, as well as providing easier access to e.g. sunset, sunrise and sun transit data. But it also brings in the chrono crate to the build.

§Examples using SpaBuilder

See examples in the SpaBuilder struct section

§Example using the SpaData struct directly

The code below uses the SpaData struct directly, instead of using the builder, to sweep over one day and report a vector of incidence together with sunrise and sunset. It assumes the “chrono_0_4” feature is included.

use std::ops::Add;
use chrono::{DateTime, Local, TimeDelta, TimeZone};
use spa_sra::errors::SpaError;
use spa_sra::spa::{Function, Input, SpaData};

fn main() {

    match get_day_incidence() {
        Err(e) => { println!("{}", e) },
        Ok(incidence) => {
            println!("Sunrise: {}", incidence.0);
            println!("Sunset:  {}", incidence.1);
            println!("Incidence: {:?}", incidence.2);
        }
    }
}

fn get_day_incidence() -> Result<(DateTime<Local>, DateTime<Local>, Vec<f64>), SpaError> {
    let mut result: Vec<f64> = Vec::new();

    // First decide on a date, time is not relevant at this point
    let date_time = Local::now()
        .timezone()
        .with_ymd_and_hms(2025, 8, 12, 0, 0, 0)
        .unwrap();

    // Create an Input instance with relevant parameters, and we are happy with the
    // defaults for atmospheric_refraction, delta_ut1 and delta_t.
    // We only need sunrise and sunset first, so we chose a specific function for that
    let mut input = Input::from_date_time(date_time);
    input.latitude = 56.198569;
    input.longitude = 15.637826;
    input.pressure = 1013.0;
    input.temperature = 10.0;
    input.elevation = 10.0;
    input.slope = 25.0;
    input.azm_rotation = 0.0;
    input.function = Function::SpaZaRts;

    // Create and calculate a SpaData struct
    let mut spa = SpaData::new(input);
    spa.spa_calculate()?;

    // Now we got sunrise and sunset for the chosen day
    let sunrise = spa.get_sunrise();
    let sunset = spa.get_sunset();
    let mut time_of_interest = sunrise;

    // We are only interested in the incidence from now on so we set that function
    spa.input.function = Function::SpaZaInc;

    // Loop through the day with a one minute incrementation and save the incidence to result
    while time_of_interest < sunset {
        spa.input.date_time(time_of_interest);
        spa.spa_calculate()?;
        result.push(spa.spa_za_inc.incidence);

        time_of_interest = time_of_interest.add(TimeDelta::minutes(1));
    }

    Ok((sunrise, sunset, result))
}

Modules§

errors
Defined error and its codes and messages
spa
This module hosts the main SPA algorithm and the SpaData struct together with its sub-structs.
utils
Utility functions for other applications (such as NREL’s SAMPA). They are all used internally by the main SPA algorithm, but was also made public in the original C-code header file, hence they are also here denoted as utility functions.

Structs§

SpaBuilder
Builder for creating and calculating an operational SpaData struct