use cty;
use crate::spaceweather;
use crate::AstroTime;
#[allow(non_camel_case_types)]
#[repr(C)]
struct ap_array {
a: [cty::c_double; 7],
}
#[repr(C)]
#[allow(non_camel_case_types)]
struct nrlmsise_flags {
switches: [cty::c_int; 24],
sw: [cty::c_double; 24],
swc: [cty::c_double; 24],
}
#[repr(C)]
#[allow(non_camel_case_types)]
struct nrlmsise_input {
year: cty::c_int,
day: cty::c_int,
sec: cty::c_double, alt: cty::c_double, g_lat: cty::c_double, g_lon: cty::c_double, lst: cty::c_double, f107a: cty::c_double, f107: cty::c_double, ap: cty::c_double, ap_a: *const ap_array,
}
#[repr(C)]
#[allow(non_camel_case_types)]
struct nrlmsise_output {
d: [cty::c_double; 9],
t: [cty::c_double; 2],
}
extern "C" {
fn gtd7d(input: *mut nrlmsise_input, flags: *mut nrlmsise_flags, output: *mut nrlmsise_output);
}
pub fn nrlmsise(
alt_km: f64,
lat_option: Option<f64>,
lon_option: Option<f64>,
time_option: Option<AstroTime>,
use_spaceweather: bool,
) -> (f64, f64) {
let lat: f64 = lat_option.unwrap_or(0.0);
let lon: f64 = lon_option.unwrap_or(0.0);
let mut day_of_year: i32 = 1;
let mut sec_of_day: f64 = 0.0;
let mut f107a: f64 = 150.0;
let mut f107: f64 = 150.0;
let mut ap: f64 = 4.0;
if time_option.is_some() {
let time = time_option.unwrap();
let (year, _mon, _day, dhour, dmin, dsec) = time.to_datetime();
let fday: f64 = (time - AstroTime::from_date(year as i32, 1, 1)).days() + 1.0;
day_of_year = fday.floor() as i32;
sec_of_day = dhour as f64 * 3600.0 + dmin as f64 * 60.0 + dsec;
if use_spaceweather {
match spaceweather::get(time - 1.0) {
Ok(r) => {
f107a = r.f10p7_adj_c81;
f107 = r.f10p7_adj;
ap = r.ap_avg as f64;
}
Err(_) => (),
}
}
}
let mut input: nrlmsise_input = nrlmsise_input {
year: 2022,
day: day_of_year,
sec: sec_of_day,
alt: alt_km,
g_lat: lat,
g_lon: lon,
lst: sec_of_day / 3600.0 + lon / 15.0,
f107a: f107a,
f107: f107,
ap: ap,
ap_a: std::ptr::null(),
};
let mut flags: nrlmsise_flags = nrlmsise_flags {
switches: [
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
],
sw: [
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
],
swc: [
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
],
};
let mut output: nrlmsise_output = nrlmsise_output {
d: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
t: [0.0, 0.0],
};
unsafe {
gtd7d(
std::ptr::addr_of_mut!(input),
std::ptr::addr_of_mut!(flags),
std::ptr::addr_of_mut!(output),
);
}
(output.d[5] * 1.0e3, output.t[1])
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_nrlmsise() {
let tm: AstroTime = AstroTime::from_date(2010, 1, 1) + 171.0 + 29000.0 / 86400.0;
let (_density, _temperature) = nrlmsise(400.0, Some(60.0), Some(-70.0), Some(tm), true);
}
}