/rust/registry/src/index.crates.io-1949cf8c6b5b557f/sofars-0.6.1/src/astro/starpv.rs
Line | Count | Source |
1 | | use crate::{ |
2 | | consts::{DAU, DAYSEC, DC, DJY, DR2AS}, |
3 | | vm::{pdp, pm, pmp, pn, ppp, s2pv, sxp, zp}, |
4 | | }; |
5 | | |
6 | | /// Convert star catalog coordinates to position+velocity vector. |
7 | | /// |
8 | | /// This function is part of the International Astronomical Union's |
9 | | /// SOFA (Standards of Fundamental Astronomy) software collection. |
10 | | /// |
11 | | /// Status: support function. |
12 | | /// |
13 | | /// Given (Note 1): |
14 | | /// ra double right ascension (radians) |
15 | | /// dec double declination (radians) |
16 | | /// pmr double RA proper motion (radians/year) |
17 | | /// pmd double Dec proper motion (radians/year) |
18 | | /// px double parallax (arcseconds) |
19 | | /// rv double radial velocity (km/s, positive = receding) |
20 | | /// |
21 | | /// Returned (Note 2): |
22 | | /// pv double[2][3] pv-vector (au, au/day) |
23 | | /// |
24 | | /// Returned (function value): |
25 | | /// int status: |
26 | | /// 0 = no warnings |
27 | | /// 1 = distance overridden (Note 6) |
28 | | /// 2 = excessive speed (Note 7) |
29 | | /// 4 = solution didn't converge (Note 8) |
30 | | /// else = binary logical OR of the above |
31 | | /// |
32 | | /// Notes: |
33 | | /// |
34 | | /// 1) The star data accepted by this function are "observables" for an |
35 | | /// imaginary observer at the solar-system barycenter. Proper motion |
36 | | /// and radial velocity are, strictly, in terms of barycentric |
37 | | /// coordinate time, TCB. For most practical applications, it is |
38 | | /// permissible to neglect the distinction between TCB and ordinary |
39 | | /// "proper" time on Earth (TT/TAI). The result will, as a rule, be |
40 | | /// limited by the intrinsic accuracy of the proper-motion and |
41 | | /// radial-velocity data; moreover, the pv-vector is likely to be |
42 | | /// merely an intermediate result, so that a change of time unit |
43 | | /// would cancel out overall. |
44 | | /// |
45 | | /// In accordance with normal star-catalog conventions, the object's |
46 | | /// right ascension and declination are freed from the effects of |
47 | | /// secular aberration. The frame, which is aligned to the catalog |
48 | | /// equator and equinox, is Lorentzian and centered on the SSB. |
49 | | /// |
50 | | /// 2) The resulting position and velocity pv-vector is with respect to |
51 | | /// the same frame and, like the catalog coordinates, is freed from |
52 | | /// the effects of secular aberration. Should the "coordinate |
53 | | /// direction", where the object was located at the catalog epoch, be |
54 | | /// required, it may be obtained by calculating the magnitude of the |
55 | | /// position vector pv[0][0-2] dividing by the speed of light in |
56 | | /// au/day to give the light-time, and then multiplying the space |
57 | | /// velocity pv[1][0-2] by this light-time and adding the result to |
58 | | /// pv[0][0-2]. |
59 | | /// |
60 | | /// Summarizing, the pv-vector returned is for most stars almost |
61 | | /// identical to the result of applying the standard geometrical |
62 | | /// "space motion" transformation. The differences, which are the |
63 | | /// subject of the Stumpff paper referenced below, are: |
64 | | /// |
65 | | /// (i) In stars with significant radial velocity and proper motion, |
66 | | /// the constantly changing light-time distorts the apparent proper |
67 | | /// motion. Note that this is a classical, not a relativistic, |
68 | | /// effect. |
69 | | /// |
70 | | /// (ii) The transformation complies with special relativity. |
71 | | /// |
72 | | /// 3) Care is needed with units. The star coordinates are in radians |
73 | | /// and the proper motions in radians per Julian year, but the |
74 | | /// parallax is in arcseconds; the radial velocity is in km/s, but |
75 | | /// the pv-vector result is in au and au/day. |
76 | | /// |
77 | | /// 4) The RA proper motion is in terms of coordinate angle, not true |
78 | | /// angle. If the catalog uses arcseconds for both RA and Dec proper |
79 | | /// motions, the RA proper motion will need to be divided by cos(Dec) |
80 | | /// before use. |
81 | | /// |
82 | | /// 5) Straight-line motion at constant speed, in the inertial frame, |
83 | | /// is assumed. |
84 | | /// |
85 | | /// 6) An extremely small (or zero or negative) parallax is interpreted |
86 | | /// to mean that the object is on the "celestial sphere", the radius |
87 | | /// of which is an arbitrary (large) value (see the constant PXMIN). |
88 | | /// When the distance is overridden in this way, the status, |
89 | | /// initially zero, has 1 added to it. |
90 | | /// |
91 | | /// 7) If the space velocity is a significant fraction of c (see the |
92 | | /// constant VMAX), it is arbitrarily set to zero. When this action |
93 | | /// occurs, 2 is added to the status. |
94 | | /// |
95 | | /// 8) The relativistic adjustment involves an iterative calculation. |
96 | | /// If the process fails to converge within a set number (IMAX) of |
97 | | /// iterations, 4 is added to the status. |
98 | | /// |
99 | | /// 9) The inverse transformation is performed by the function |
100 | | /// iauPvstar. |
101 | | /// |
102 | | /// Called: |
103 | | /// iauS2pv spherical coordinates to pv-vector |
104 | | /// iauPm modulus of p-vector |
105 | | /// iauZp zero p-vector |
106 | | /// iauPn decompose p-vector into modulus and direction |
107 | | /// iauPdp scalar product of two p-vectors |
108 | | /// iauSxp multiply p-vector by scalar |
109 | | /// iauPmp p-vector minus p-vector |
110 | | /// iauPpp p-vector plus p-vector |
111 | | /// |
112 | | /// Reference: |
113 | | /// |
114 | | /// Stumpff, P., 1985, Astron.Astrophys. 144, 232-240. |
115 | | /// |
116 | | /// This revision: 2023 May 4 |
117 | | /// |
118 | | /// SOFA release 2023-10-11 |
119 | | /// |
120 | | /// Copyright (C) 2023 IAU SOFA Board. See notes at end. |
121 | | /// |
122 | 0 | pub fn starpv( |
123 | 0 | ra: f64, |
124 | 0 | dec: f64, |
125 | 0 | pmr: f64, |
126 | 0 | pmd: f64, |
127 | 0 | px: f64, |
128 | 0 | rv: f64, |
129 | 0 | ) -> ([[f64; 3]; 2], i32) { |
130 | | /* Smallest allowed parallax */ |
131 | | const PXMIN: f64 = 1e-7; |
132 | | |
133 | | /* Largest allowed speed (fraction of c) */ |
134 | | const VMAX: f64 = 0.5; |
135 | | |
136 | | /* Maximum number of iterations for relativistic solution */ |
137 | | const IMAX: i32 = 100; |
138 | | |
139 | 0 | let mut i: i32 = 0; |
140 | | let mut iwarn: i32; |
141 | | let mut w: f64; |
142 | | let (r, rd, rad, decd, v, vsr, vst): (f64, f64, f64, f64, f64, f64, f64); |
143 | | let (betst, betsr, mut bett, mut betr, mut dd, mut ddel): (f64, f64, f64, f64, f64, f64); |
144 | | |
145 | 0 | let (mut d, mut del, mut odd, mut oddel, mut od, mut odel) = (0.0, 0.0, 0.0, 0.0, 0.0, 0.0); |
146 | | |
147 | | // Distance (au). |
148 | 0 | if px >= PXMIN { |
149 | 0 | w = px; |
150 | 0 | iwarn = 0; |
151 | 0 | } else { |
152 | 0 | w = PXMIN; |
153 | 0 | iwarn = 1; |
154 | 0 | } |
155 | 0 | r = DR2AS / w; |
156 | | |
157 | | // Radial speed (au/day). |
158 | 0 | rd = DAYSEC * rv * 1e3 / DAU; |
159 | | |
160 | | // Proper motion (radian/day). |
161 | 0 | rad = pmr / DJY; |
162 | 0 | decd = pmd / DJY; |
163 | | |
164 | | // To pv-vector (au, au/day). |
165 | 0 | let mut pv = s2pv(ra, dec, r, rad, decd, rd); |
166 | | |
167 | | // If excessive velocity, arbitrarily set it to zero. |
168 | 0 | v = pm(pv[1]); |
169 | 0 | if v / DC > VMAX { |
170 | 0 | zp(&mut pv[1]); |
171 | 0 | iwarn += 2; |
172 | 0 | } |
173 | | |
174 | | // Isolate the radial component of the velocity (au/day). |
175 | 0 | let (_, pu) = pn(&pv[0]); |
176 | 0 | vsr = pdp(&pu, &pv[1]); |
177 | 0 | let usr = sxp(vsr, &pu); |
178 | | |
179 | | // Isolate the transverse component of the velocity (au/day). |
180 | 0 | let ust = pmp(&pv[1], &usr); |
181 | 0 | vst = pm(ust); |
182 | | |
183 | | // Special-relativity dimensionless parameters. |
184 | 0 | betsr = vsr / DC; |
185 | 0 | betst = vst / DC; |
186 | | |
187 | | // Determine the observed-to-inertial correction terms. |
188 | 0 | bett = betst; |
189 | 0 | betr = betsr; |
190 | 0 | while i < IMAX { |
191 | 0 | d = 1.0 + betr; |
192 | 0 | w = betr * betr + bett * bett; |
193 | 0 | del = -w / ((1.0 - w).sqrt() + 1.0); |
194 | 0 | betr = d * betsr + del; |
195 | 0 | bett = d * betst; |
196 | 0 | if i > 0 { |
197 | 0 | dd = (d - od).abs(); |
198 | 0 | ddel = (del - odel).abs(); |
199 | 0 | if i > 1 && dd >= odd && ddel >= oddel { |
200 | 0 | break; |
201 | 0 | } |
202 | 0 | odd = dd; |
203 | 0 | oddel = ddel; |
204 | 0 | } |
205 | 0 | od = d; |
206 | 0 | odel = del; |
207 | 0 | i += 1; |
208 | | } |
209 | 0 | if i >= IMAX { |
210 | 0 | iwarn += 4; |
211 | 0 | } |
212 | | |
213 | | // Scale observed tangential velocity vector into inertial (au/d). |
214 | 0 | let ut = sxp(d, &ust); |
215 | | |
216 | | // Compute inertial radial velocity vector (au/d). |
217 | 0 | let ur = sxp(DC * (d * betsr + del), &pu); |
218 | | |
219 | | // Combine the two to obtain the inertial space velocity vector. |
220 | 0 | pv[1] = ppp(&ur, &ut); |
221 | | |
222 | 0 | (pv, iwarn) |
223 | 0 | } |