erfa_rust/
G3_safe.rs

1// G3
2//   aper13.c  → eraAper13_safe
3//   apio.c    → eraApio_safe
4//   apio13.c  → eraApio13_safe
5//   atcc13.c  → eraAtcc13_safe
6//   atccq.c   → eraAtccq_safe
7
8
9use crate::G14_safe::eraEra00_safe;
10use crate::G19_safe::eraIr_safe;
11use crate::G1_safe::{eraAnp_safe, eraAnpm_safe, eraApci13_safe};
12use crate::G25_safe::eraPmpx_safe;
13use crate::G27_safe::eraPvtob_safe;
14use crate::G28_safe::{eraRefco_safe, eraRx_safe, eraRy_safe, eraRz_safe};
15use crate::G2_safe::eraAper_safe;
16use crate::G30_safe::eraSp00_safe;
17use crate::G32_safe::eraTaitt_safe;
18use crate::G33_safe::{eraUtctai_safe, eraUtcut1_safe};
19use crate::G7_safe::eraC2s_safe;
20use crate::H1_safe::{eraASTROM, ERFA_CMPS};
21
22pub type ErfaResult<T> = Result<T, ()>;
23
24// G3/aper13.c
25// Update only the ERA element inside an existing eraASTROM.
26pub fn eraAper13_safe(ut11: f64, ut12: f64, astrom: &mut eraASTROM) -> ErfaResult<()> {
27    let era = eraEra00_safe(ut11, ut12)?;
28    eraAper_safe(era, astrom)?;
29    Ok(())
30}
31
32// G3/apio.c
33// Prepare CIRS-observed astrometry parameters using supplied site/refraction.
34pub fn eraApio_safe(
35    sp: f64,
36    theta: f64,
37    elong: f64,
38    phi: f64,
39    hm: f64,
40    xp: f64,
41    yp: f64,
42    refa: f64,
43    refb: f64,
44    astrom: &mut eraASTROM,
45) -> ErfaResult<()> {
46    // Build rotation matrix CIRS → apparent [HA,Dec].
47    let mut r: [[f64; 3]; 3] = [[0.0; 3]; 3];
48    eraIr_safe(&mut r)?;
49    eraRz_safe(theta + sp, &mut r)?;
50    eraRy_safe(-xp, &mut r)?;
51    eraRx_safe(-yp, &mut r)?;
52    eraRz_safe(elong, &mut r)?;
53
54    // Local Earth rotation angle.
55    let a = r[0][0];
56    let b = r[0][1];
57    let eral = if a != 0.0 || b != 0.0 {
58        b.atan2(a)
59    } else {
60        0.0
61    };
62    astrom.eral = eral;
63
64    // Polar motion [X,Y] w.r.t local meridian.
65    let a0 = r[0][0];
66    let b0 = r[0][1];
67    let c0 = r[0][2];
68    astrom.xpl = c0.atan2((a0 * a0 + b0 * b0).sqrt());
69    let a1 = r[1][2];
70    let b1 = r[2][2];
71    astrom.ypl = if a1 != 0.0 || b1 != 0.0 {
72        -a1.atan2(b1)
73    } else {
74        0.0
75    };
76
77    // Adjusted longitude.
78    astrom.along = eraAnpm_safe(eral - theta)?;
79
80    // Functions of latitude.
81    astrom.sphi = phi.sin();
82    astrom.cphi = phi.cos();
83
84    // Observer geocentric position and velocity (m, m/s, CIRS).
85    let pv = eraPvtob_safe(elong, phi, hm, xp, yp, sp, theta)?;
86
87    // Magnitude of diurnal aberration vector.
88    astrom.diurab = (pv[1][0] * pv[1][0] + pv[1][1] * pv[1][1]).sqrt() / ERFA_CMPS;
89
90    // Refraction constants.
91    astrom.refa = refa;
92    astrom.refb = refb;
93
94    Ok(())
95}
96
97// G3/apio13.c
98// Derive CIRS-observed parameters from UTC/site/weather; returns status 0 or +1.
99pub fn eraApio13_safe(
100    utc1: f64,
101    utc2: f64,
102    dut1: f64,
103    elong: f64,
104    phi: f64,
105    hm: f64,
106    xp: f64,
107    yp: f64,
108    phpa: f64,
109    tc: f64,
110    rh: f64,
111    wl: f64,
112    astrom: &mut eraASTROM,
113) -> ErfaResult<i32> {
114    // UTC → TAI.
115    let ((tai1, tai2), j_utctai) = eraUtctai_safe(utc1, utc2)?;
116    if j_utctai < 0 {
117        return Err(());
118    }
119
120    // TAI → TT.
121    let ((tt1, tt2), _j_taitt) = eraTaitt_safe(tai1, tai2)?;
122
123    // UTC → UT1 (with DUT1).
124    let ((ut11, ut12), j_utcut1) = eraUtcut1_safe(utc1, utc2, dut1)?;
125    if j_utcut1 < 0 {
126        return Err(());
127    }
128
129    // TIO locator s'.
130    let sp = eraSp00_safe(tt1, tt2)?;
131
132    // Earth rotation angle.
133    let theta = eraEra00_safe(ut11, ut12)?;
134
135    // Refraction constants A and B.
136    let (refa, refb) = eraRefco_safe(phpa, tc, rh, wl)?;
137
138    // Populate astrometry parameters.
139    eraApio_safe(sp, theta, elong, phi, hm, xp, yp, refa, refb, astrom)?;
140
141    // Return the UT1 conversion warning status (0 or +1).
142    Ok(j_utcut1)
143}
144
145// G3/atcc13.c
146// Catalog ICRS (J2000) to ICRS astrometric using 2013 model; returns (ra, da).
147pub fn eraAtcc13_safe(
148    rc: f64,
149    dc: f64,
150    pr: f64,
151    pd: f64,
152    px: f64,
153    rv: f64,
154    date1: f64,
155    date2: f64,
156) -> ErfaResult<(f64, f64)> {
157    // Star-independent parameters.
158    let mut astrom = eraASTROM::default();
159
160    // Transformation parameters (ICRS catalog → astrometric).
161    let _eo = eraApci13_safe(date1, date2, &mut astrom)?;
162
163    // Quick transform using precomputed astrom.
164    let (ra, da) = eraAtccq_safe(rc, dc, pr, pd, px, rv, &astrom)?;
165    Ok((ra, da))
166}
167
168// G3/atccq.c
169// Quick catalog (ICRS) to astrometric given precomputed astrom; returns (ra, da).
170pub fn eraAtccq_safe(
171    rc: f64,
172    dc: f64,
173    pr: f64,
174    pd: f64,
175    px: f64,
176    rv: f64,
177    astrom: &eraASTROM,
178) -> ErfaResult<(f64, f64)> {
179    // Proper motion & parallax to BCRS coordinate direction.
180    let p = eraPmpx_safe(rc, dc, pr, pd, px, rv, astrom.pmt, &astrom.eb)?;
181
182    // ICRS astrometric RA,Dec.
183    let (w, da) = eraC2s_safe(&p)?;
184    let ra = eraAnp_safe(w)?;
185    Ok((ra, da))
186}