/rust/registry/src/index.crates.io-1949cf8c6b5b557f/sofars-0.6.1/src/astro/atoiq.rs
Line | Count | Source |
1 | | use crate::vm::{anp, c2s, s2c}; |
2 | | |
3 | | use super::IauAstrom; |
4 | | |
5 | | /// Quick observed −> CIRS |
6 | | /// |
7 | | /// Quick observed place to CIRS, given the star-independent astrometry |
8 | | /// parameters. |
9 | | /// |
10 | | /// Use of this function is appropriate when efficiency is important and |
11 | | /// where many star positions are all to be transformed for one date. |
12 | | /// The star-independent astrometry parameters can be obtained by |
13 | | /// calling iauApio[13] or iauApco[13]. |
14 | | /// |
15 | | /// This function is part of the International Astronomical Union's |
16 | | /// SOFA (Standards of Fundamental Astronomy) software collection. |
17 | | /// |
18 | | /// Status: support function. |
19 | | /// |
20 | | /// Given: |
21 | | /// ``` |
22 | | /// type char[] type of coordinates: "R", "H" or "A" (Note 1) |
23 | | /// ob1 double observed Az, HA or RA (radians; Az is N=0,E=90) |
24 | | /// ob2 double observed ZD or Dec (radians) |
25 | | /// astrom iauASTROM* star-independent astrometry parameters: |
26 | | /// pmt double PM time interval (SSB, Julian years) |
27 | | /// eb double[3] SSB to observer (vector, au) |
28 | | /// eh double[3] Sun to observer (unit vector) |
29 | | /// em double distance from Sun to observer (au) |
30 | | /// v double[3] barycentric observer velocity (vector, c) |
31 | | /// bm1 double sqrt(1-|v|^2): reciprocal of Lorenz factor |
32 | | /// bpn double[3][3] bias-precession-nutation matrix |
33 | | /// along double longitude + s' (radians) |
34 | | /// xpl double polar motion xp wrt local meridian (radians) |
35 | | /// ypl double polar motion yp wrt local meridian (radians) |
36 | | /// sphi double sine of geodetic latitude |
37 | | /// cphi double cosine of geodetic latitude |
38 | | /// diurab double magnitude of diurnal aberration vector |
39 | | /// eral double "local" Earth rotation angle (radians) |
40 | | /// refa double refraction constant A (radians) |
41 | | /// refb double refraction constant B (radians) |
42 | | /// ``` |
43 | | /// Returned: |
44 | | /// ``` |
45 | | /// ri double* CIRS right ascension (CIO-based, radians) |
46 | | /// di double* CIRS declination (radians) |
47 | | /// ``` |
48 | | /// Notes: |
49 | | /// |
50 | | /// 1) "Observed" Az,ZD means the position that would be seen by a |
51 | | /// perfect geodetically aligned theodolite. This is related to |
52 | | /// the observed HA,Dec via the standard rotation, using the geodetic |
53 | | /// latitude (corrected for polar motion), while the observed HA and |
54 | | /// (CIO-based) RA are related simply through the Earth rotation |
55 | | /// angle and the site longitude. "Observed" RA,Dec or HA,Dec thus |
56 | | /// means the position that would be seen by a perfect equatorial |
57 | | /// with its polar axis aligned to the Earth's axis of rotation. |
58 | | /// |
59 | | /// 2) Only the first character of the type argument is significant. |
60 | | /// "R" or "r" indicates that ob1 and ob2 are the observed right |
61 | | /// ascension (CIO-based) and declination; "H" or "h" indicates that |
62 | | /// they are hour angle (west +ve) and declination; anything else |
63 | | /// ("A" or "a" is recommended) indicates that ob1 and ob2 are |
64 | | /// azimuth (north zero, east 90 deg) and zenith distance. (Zenith |
65 | | /// distance is used rather than altitude in order to reflect the |
66 | | /// fact that no allowance is made for depression of the horizon.) |
67 | | /// |
68 | | /// 3) The accuracy of the result is limited by the corrections for |
69 | | /// refraction, which use a simple A*tan(z) + B*tan^3(z) model. |
70 | | /// Providing the meteorological parameters are known accurately and |
71 | | /// there are no gross local effects, the predicted intermediate |
72 | | /// coordinates should be within 0.05 arcsec (optical) or 1 arcsec |
73 | | /// (radio) for a zenith distance of less than 70 degrees, better |
74 | | /// than 30 arcsec (optical or radio) at 85 degrees and better than |
75 | | /// 20 arcmin (optical) or 25 arcmin (radio) at the horizon. |
76 | | /// |
77 | | /// Without refraction, the complementary functions iauAtioq and |
78 | | /// iauAtoiq are self-consistent to better than 1 microarcsecond all |
79 | | /// over the celestial sphere. With refraction included, consistency |
80 | | /// falls off at high zenith distances, but is still better than |
81 | | /// 0.05 arcsec at 85 degrees. |
82 | | /// |
83 | | /// 4) It is advisable to take great care with units, as even unlikely |
84 | | /// values of the input parameters are accepted and processed in |
85 | | /// accordance with the models used. |
86 | | /// |
87 | | /// Called: |
88 | | /// iauS2c spherical coordinates to unit vector |
89 | | /// iauC2s p-vector to spherical |
90 | | /// iauAnp normalize angle into range 0 to 2pi |
91 | | /// |
92 | 0 | pub fn atoiq(type_: &str, ob1: f64, ob2: f64, astrom: &IauAstrom) -> (f64, f64) { |
93 | | /* Minimum sin(alt) for refraction purposes */ |
94 | | const SELMIN: f64 = 0.05; |
95 | | |
96 | | let c1: f64; |
97 | | let c2: f64; |
98 | | let mut ce: f64; |
99 | | let xaeo: f64; |
100 | | let yaeo: f64; |
101 | | let zaeo: f64; |
102 | 0 | let mut v = [0.0; 3]; |
103 | | |
104 | | /* Coordinate type. */ |
105 | 0 | let c_char = type_.chars().next().unwrap_or('A'); |
106 | | |
107 | | /* Coordinates. */ |
108 | 0 | c1 = ob1; |
109 | 0 | c2 = ob2; |
110 | | |
111 | | /* Sin, cos of latitude. */ |
112 | 0 | let sphi = astrom.sphi; |
113 | 0 | let cphi = astrom.cphi; |
114 | | |
115 | | /* Standardize coordinate type. */ |
116 | 0 | let c = if c_char == 'r' || c_char == 'R' { |
117 | 0 | 'R' |
118 | 0 | } else if c_char == 'h' || c_char == 'H' { |
119 | 0 | 'H' |
120 | | } else { |
121 | 0 | 'A' |
122 | | }; |
123 | | |
124 | | /* If Az,ZD, convert to Cartesian (S=0,E=90). */ |
125 | 0 | if c == 'A' { |
126 | 0 | ce = c2.sin(); |
127 | 0 | xaeo = -c1.cos() * ce; |
128 | 0 | yaeo = c1.sin() * ce; |
129 | 0 | zaeo = c2.cos(); |
130 | 0 | } else { |
131 | 0 | let c1_mod = if c == 'R' { astrom.eral - c1 } else { c1 }; |
132 | | |
133 | | /* To Cartesian -HA,Dec. */ |
134 | 0 | v = s2c(-c1_mod, c2); |
135 | 0 | let xmhdo = v[0]; |
136 | 0 | let ymhdo = v[1]; |
137 | 0 | let zmhdo = v[2]; |
138 | | |
139 | | /* To Cartesian Az,El (S=0,E=90). */ |
140 | 0 | xaeo = sphi * xmhdo - cphi * zmhdo; |
141 | 0 | yaeo = ymhdo; |
142 | 0 | zaeo = cphi * xmhdo + sphi * zmhdo; |
143 | | } |
144 | | |
145 | | /* Azimuth (S=0,E=90). */ |
146 | 0 | let az = if xaeo != 0.0 || yaeo != 0.0 { |
147 | 0 | yaeo.atan2(xaeo) |
148 | | } else { |
149 | 0 | 0.0 |
150 | | }; |
151 | | |
152 | | /* Sine of observed ZD, and observed ZD. */ |
153 | 0 | let sz = (xaeo * xaeo + yaeo * yaeo).sqrt(); |
154 | 0 | let zdo = sz.atan2(zaeo); |
155 | | |
156 | | /* |
157 | | ** Refraction |
158 | | ** ---------- |
159 | | */ |
160 | | |
161 | | /* Fast algorithm using two constant model. */ |
162 | 0 | let refa = astrom.refa; |
163 | 0 | let refb = astrom.refb; |
164 | 0 | let tz = sz / if zaeo > SELMIN { zaeo } else { SELMIN }; |
165 | 0 | let dref = (refa + refb * tz * tz) * tz; |
166 | 0 | let zdt = zdo + dref; |
167 | | |
168 | | /* To Cartesian Az,ZD. */ |
169 | 0 | ce = zdt.sin(); |
170 | 0 | let xaet = az.cos() * ce; |
171 | 0 | let yaet = az.sin() * ce; |
172 | 0 | let zaet = zdt.cos(); |
173 | | |
174 | | /* Cartesian Az,ZD to Cartesian -HA,Dec. */ |
175 | 0 | let xmhda = sphi * xaet + cphi * zaet; |
176 | 0 | let ymhda = yaet; |
177 | 0 | let zmhda = -cphi * xaet + sphi * zaet; |
178 | | |
179 | | /* Diurnal aberration. */ |
180 | 0 | let f = 1.0 + astrom.diurab * ymhda; |
181 | 0 | let xhd = f * xmhda; |
182 | 0 | let yhd = f * (ymhda - astrom.diurab); |
183 | 0 | let zhd = f * zmhda; |
184 | | |
185 | | /* Polar motion. */ |
186 | 0 | let sx = astrom.xpl.sin(); |
187 | 0 | let cx = astrom.xpl.cos(); |
188 | 0 | let sy = astrom.ypl.sin(); |
189 | 0 | let cy = astrom.ypl.cos(); |
190 | 0 | v[0] = cx * xhd + sx * sy * yhd - sx * cy * zhd; |
191 | 0 | v[1] = cy * yhd + sy * zhd; |
192 | 0 | v[2] = sx * xhd - cx * sy * yhd + cx * cy * zhd; |
193 | | |
194 | | /* To spherical -HA,Dec. */ |
195 | 0 | let (hma, di) = c2s(&v); |
196 | | |
197 | | /* Right ascension. */ |
198 | 0 | let ri = anp(astrom.eral + hma); |
199 | | |
200 | 0 | (ri, di) |
201 | 0 | } |