#![cfg(feature = "chrono")]
use chrono::{DateTime, FixedOffset, TimeZone, Utc};
use solar_positioning::{spa, RefractionCorrection};
const EPSILON: f64 = 0.0001;
#[test]
fn validate_against_nrel_reference_data() {
let test_cases = [
(
"1910-03-15T00:30:00Z",
-36.840556,
174.740000,
0.188643,
34.269919,
),
(
"1910-03-15T03:30:00Z",
-36.840556,
174.740000,
298.894756,
53.637925,
),
(
"1910-03-15T06:30:00Z",
-36.840556,
174.740000,
268.082350,
88.143823,
),
(
"1910-03-15T09:30:00Z",
-36.840556,
174.740000,
237.156205,
122.642657,
),
(
"1910-03-15T12:30:00Z",
-36.840556,
174.740000,
180.112832,
140.797480,
),
];
for (datetime_str, latitude, longitude, expected_azimuth, expected_zenith) in test_cases {
let utc_datetime = datetime_str.parse::<DateTime<Utc>>().unwrap();
let datetime = FixedOffset::east_opt(0)
.unwrap()
.from_utc_datetime(&utc_datetime.naive_utc());
let result = spa::solar_position(
datetime,
latitude,
longitude,
0.0, 0.0, Some(RefractionCorrection::new(1000.0, 10.0).unwrap()), );
assert!(
result.is_ok(),
"SPA calculation failed for {}",
datetime_str
);
let position = result.unwrap();
let azimuth_error = (position.azimuth() - expected_azimuth).abs();
let zenith_error = (position.zenith_angle() - expected_zenith).abs();
println!(
"{}: Azimuth {:.6}° (expected {:.6}°, error {:.6}°), Zenith {:.6}° (expected {:.6}°, error {:.6}°)",
datetime_str,
position.azimuth(),
expected_azimuth,
azimuth_error,
position.zenith_angle(),
expected_zenith,
zenith_error
);
assert!(
azimuth_error < EPSILON,
"Azimuth error {:.6}° exceeds tolerance {:.6}° for {}",
azimuth_error,
EPSILON,
datetime_str
);
assert!(
zenith_error < EPSILON,
"Zenith error {:.6}° exceeds tolerance {:.6}° for {}",
zenith_error,
EPSILON,
datetime_str
);
}
}
#[test]
fn test_modern_date_calculation() {
let utc_datetime = "2023-06-21T20:00:00Z".parse::<DateTime<Utc>>().unwrap();
let datetime = FixedOffset::east_opt(0)
.unwrap()
.from_utc_datetime(&utc_datetime.naive_utc());
let result = spa::solar_position(
datetime,
37.7749, -122.4194, 0.0, 69.0, Some(RefractionCorrection::standard()), );
assert!(
result.is_ok(),
"SPA calculation should work for modern dates"
);
let position = result.unwrap();
println!(
"2023-06-21T20:00:00Z San Francisco: Azimuth {:.6}°, Zenith {:.6}°, Elevation {:.6}°",
position.azimuth(),
position.zenith_angle(),
position.elevation_angle()
);
assert!(
position.azimuth() > 150.0 && position.azimuth() < 210.0,
"Azimuth should be roughly south at solar noon"
);
assert!(
position.zenith_angle() > 0.0 && position.zenith_angle() < 45.0,
"Zenith angle should be small at summer solstice noon"
);
assert!(
position.elevation_angle() > 45.0 && position.elevation_angle() < 90.0,
"Elevation should be high at summer solstice noon"
);
}