@neilberkman/sidereon 0.32.0 → 0.33.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +30 -0
- package/README.md +52 -8
- package/THIRD-PARTY-NOTICES.md +99 -0
- package/licenses/Apache-2.0.txt +202 -0
- package/licenses/ERFA-BSD-3-Clause.txt +53 -0
- package/licenses/IERS-Conventions-Software-License.txt +78 -0
- package/licenses/SciPy-BSD-3-Clause.txt +30 -0
- package/licenses/libloading-ISC.txt +13 -0
- package/package.json +32 -5
- package/pkg/sidereon.d.ts +1899 -1806
- package/pkg/sidereon.js +341 -1
- package/pkg/sidereon_bg.wasm +0 -0
- package/pkg/sidereon_bg.wasm.d.ts +1759 -1738
- package/pkg-node/sidereon.d.ts +142 -70
- package/pkg-node/sidereon.js +348 -1
- package/pkg-node/sidereon_bg.wasm +0 -0
- package/pkg-node/sidereon_bg.wasm.d.ts +1759 -1738
- package/third_party_source/sidereon-core-0.33.1/tides/mod.rs +1082 -0
- package/third_party_source/sidereon-core-0.33.1/tides/ocean.rs +682 -0
- package/third_party_source/sidereon-core-0.33.1/tides/pole.rs +203 -0
- package/types/sidereon-extra.cjs +2 -0
- package/types/sidereon-extra.js +2 -0
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
//! Solid-Earth pole tide station displacement (IERS Conventions 2010, §7.1.4).
|
|
2
|
+
//!
|
|
3
|
+
//! [`solid_earth_pole_tide`] computes the displacement of an Earth-fixed (ITRF)
|
|
4
|
+
//! station caused by the centrifugal-potential change of polar motion (the
|
|
5
|
+
//! "rotational deformation due to polar motion"). It is the sibling of
|
|
6
|
+
//! [`super::solid_earth_tide`] and is wired into the PPP correction stack in the
|
|
7
|
+
//! identical way: a per-epoch station displacement vector projected onto the
|
|
8
|
+
//! line of sight.
|
|
9
|
+
//!
|
|
10
|
+
//! Physics (IERS Conventions 2010, Chapter 7, §7.1.4):
|
|
11
|
+
//!
|
|
12
|
+
//! * The wobble variables are formed from the polar motion `(xp, yp)` and the
|
|
13
|
+
//! IERS conventional mean pole `(x_bar, y_bar)`:
|
|
14
|
+
//!
|
|
15
|
+
//! ```text
|
|
16
|
+
//! m1 = xp - x_bar (arcsec)
|
|
17
|
+
//! m2 = -(yp - y_bar) (arcsec)
|
|
18
|
+
//! ```
|
|
19
|
+
//!
|
|
20
|
+
//! * The displacement, in the local radial / colatitude / longitude triad, is
|
|
21
|
+
//! IERS Conventions (2010) Eq. (7.24):
|
|
22
|
+
//!
|
|
23
|
+
//! ```text
|
|
24
|
+
//! S_r = -33 sin(2 theta) (m1 cos lambda + m2 sin lambda) mm
|
|
25
|
+
//! S_theta = -9 cos(2 theta) (m1 cos lambda + m2 sin lambda) mm
|
|
26
|
+
//! S_lambda = 9 cos(theta) (m1 sin lambda - m2 cos lambda) mm
|
|
27
|
+
//! ```
|
|
28
|
+
//!
|
|
29
|
+
//! where `theta` is the geocentric colatitude and `lambda` the longitude. The
|
|
30
|
+
//! integer mm coefficients embed the nominal degree-2 Love/Shida numbers
|
|
31
|
+
//! h2 = 0.6078 and l2 = 0.0847 (radial scales with h2; the horizontal terms
|
|
32
|
+
//! with l2). `S_theta` points to increasing colatitude (south), so the local
|
|
33
|
+
//! north component is `-S_theta`; `S_lambda` is east; `S_r` is up.
|
|
34
|
+
//!
|
|
35
|
+
//! Mean pole model. The IERS 2010 conventional mean pole (a cubic until 2010.0,
|
|
36
|
+
//! linear thereafter; IERS Conventions 2010 Table 7.7) was revised in 2018 to a
|
|
37
|
+
//! single **linear secular pole**, because the original post-2010 linear
|
|
38
|
+
//! extrapolation diverges from the observed secular drift at the multi-cm level
|
|
39
|
+
//! within a decade. This module uses the **revised IERS (2018) linear secular
|
|
40
|
+
//! pole** (updated Chapter 7), which is the conventional model for the modern
|
|
41
|
+
//! (post-2010) epochs Sidereon targets and the one adopted for ITRF2014/2020:
|
|
42
|
+
//!
|
|
43
|
+
//! ```text
|
|
44
|
+
//! x_bar(t) = 55.0 + 1.677 (t - 2000.0) mas
|
|
45
|
+
//! y_bar(t) = 320.5 + 3.460 (t - 2000.0) mas
|
|
46
|
+
//! ```
|
|
47
|
+
//!
|
|
48
|
+
//! with `t` the epoch in years. (The widely used RTKLIB still applies the
|
|
49
|
+
//! superseded 2010 cubic+linear model; at a 2026 epoch the two mean poles differ
|
|
50
|
+
//! by >0.1 arcsec in x, which is why the choice is documented here.)
|
|
51
|
+
//!
|
|
52
|
+
//! Polar motion `(xp, yp)` is **not** available from the engine's embedded EOP
|
|
53
|
+
//! table (it carries UT1-UTC only; see
|
|
54
|
+
//! `crate::astro::frames::transforms::PolarMotion`). The caller therefore
|
|
55
|
+
//! supplies `xp`/`yp` in arcseconds, sourced from IERS EOP exactly like the
|
|
56
|
+
//! other Earth-orientation inputs. They must not be fabricated.
|
|
57
|
+
|
|
58
|
+
#[cfg(test)]
|
|
59
|
+
mod tests;
|
|
60
|
+
|
|
61
|
+
use crate::astro::constants::time::{DAYS_PER_JULIAN_YEAR, J2000_JD};
|
|
62
|
+
use crate::astro::constants::units::MM_PER_M;
|
|
63
|
+
use crate::astro::math::vec3::norm3_ref as norm;
|
|
64
|
+
use crate::validate;
|
|
65
|
+
|
|
66
|
+
use super::{gregorian_to_two_part_julian_date, invalid_tide_input, TideError};
|
|
67
|
+
|
|
68
|
+
/// IERS (2018) linear secular pole coefficients, in milliarcseconds and
|
|
69
|
+
/// milliarcseconds per year (revised IERS Conventions 2010, updated Chapter 7).
|
|
70
|
+
const MEAN_POLE_X0_MAS: f64 = 55.0;
|
|
71
|
+
const MEAN_POLE_X_RATE_MAS_PER_YR: f64 = 1.677;
|
|
72
|
+
const MEAN_POLE_Y0_MAS: f64 = 320.5;
|
|
73
|
+
const MEAN_POLE_Y_RATE_MAS_PER_YR: f64 = 3.460;
|
|
74
|
+
|
|
75
|
+
/// Eq. (7.24) displacement coefficients in millimetres per arcsecond of wobble.
|
|
76
|
+
/// The radial coefficient carries Love number h2 = 0.6078; the horizontal
|
|
77
|
+
/// coefficients carry Shida number l2 = 0.0847.
|
|
78
|
+
const RADIAL_MM_PER_ARCSEC: f64 = -33.0;
|
|
79
|
+
const COLATITUDE_MM_PER_ARCSEC: f64 = -9.0;
|
|
80
|
+
const LONGITUDE_MM_PER_ARCSEC: f64 = 9.0;
|
|
81
|
+
|
|
82
|
+
/// Solid-Earth pole tide displacement of an ITRF station, in metres (ECEF).
|
|
83
|
+
///
|
|
84
|
+
/// Arguments:
|
|
85
|
+
/// * `xsta` - geocentric station position (m, ITRF).
|
|
86
|
+
/// * `year`, `month`, `day` - UTC calendar date (selects the mean pole epoch).
|
|
87
|
+
/// * `fhr` - UTC fractional hour of the day (`hour + min/60 + sec/3600`).
|
|
88
|
+
/// * `xp_arcsec`, `yp_arcsec` - IERS polar motion of the date (arcsec). These
|
|
89
|
+
/// are a data dependency the caller supplies from IERS EOP; the engine does
|
|
90
|
+
/// not embed them.
|
|
91
|
+
///
|
|
92
|
+
/// Returns the displacement vector (m, geocentric ITRF), to be projected onto
|
|
93
|
+
/// the line of sight identically to [`super::solid_earth_tide`].
|
|
94
|
+
///
|
|
95
|
+
/// Returns [`TideError`] when inputs are non-finite, the date/hour is invalid,
|
|
96
|
+
/// or the station vector is degenerate (zero radius or on the polar axis).
|
|
97
|
+
pub fn solid_earth_pole_tide(
|
|
98
|
+
xsta: &[f64; 3],
|
|
99
|
+
year: i32,
|
|
100
|
+
month: i32,
|
|
101
|
+
day: i32,
|
|
102
|
+
fhr: f64,
|
|
103
|
+
xp_arcsec: f64,
|
|
104
|
+
yp_arcsec: f64,
|
|
105
|
+
) -> Result<[f64; 3], TideError> {
|
|
106
|
+
validate_pole_tide_domain(xsta, year, month, day, fhr, xp_arcsec, yp_arcsec)?;
|
|
107
|
+
Ok(solid_earth_pole_tide_unchecked(
|
|
108
|
+
xsta, year, month, day, fhr, xp_arcsec, yp_arcsec,
|
|
109
|
+
))
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
fn validate_pole_tide_domain(
|
|
113
|
+
xsta: &[f64; 3],
|
|
114
|
+
year: i32,
|
|
115
|
+
month: i32,
|
|
116
|
+
day: i32,
|
|
117
|
+
fhr: f64,
|
|
118
|
+
xp_arcsec: f64,
|
|
119
|
+
yp_arcsec: f64,
|
|
120
|
+
) -> Result<(), TideError> {
|
|
121
|
+
validate::finite_vec3(*xsta, "station position").map_err(invalid_tide_input)?;
|
|
122
|
+
validate::civil_datetime_with_second_policy(
|
|
123
|
+
i64::from(year),
|
|
124
|
+
i64::from(month),
|
|
125
|
+
i64::from(day),
|
|
126
|
+
0,
|
|
127
|
+
0,
|
|
128
|
+
0.0,
|
|
129
|
+
validate::CivilSecondPolicy::Continuous,
|
|
130
|
+
)
|
|
131
|
+
.map_err(invalid_tide_input)?;
|
|
132
|
+
validate::finite_in_range_exclusive_upper(fhr, 0.0, 24.0, "fractional hour")
|
|
133
|
+
.map_err(invalid_tide_input)?;
|
|
134
|
+
validate::finite(xp_arcsec, "polar motion xp").map_err(invalid_tide_input)?;
|
|
135
|
+
validate::finite(yp_arcsec, "polar motion yp").map_err(invalid_tide_input)?;
|
|
136
|
+
|
|
137
|
+
validate::finite_positive(norm(xsta), "station radius").map_err(invalid_tide_input)?;
|
|
138
|
+
let station_horizontal_radius = (xsta[0] * xsta[0] + xsta[1] * xsta[1]).sqrt();
|
|
139
|
+
validate::finite_positive(station_horizontal_radius, "station horizontal radius")
|
|
140
|
+
.map_err(invalid_tide_input)?;
|
|
141
|
+
|
|
142
|
+
Ok(())
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
fn solid_earth_pole_tide_unchecked(
|
|
146
|
+
xsta: &[f64; 3],
|
|
147
|
+
year: i32,
|
|
148
|
+
month: i32,
|
|
149
|
+
day: i32,
|
|
150
|
+
fhr: f64,
|
|
151
|
+
xp_arcsec: f64,
|
|
152
|
+
yp_arcsec: f64,
|
|
153
|
+
) -> [f64; 3] {
|
|
154
|
+
let (x_bar_arcsec, y_bar_arcsec) = mean_pole_arcsec(year, month, day, fhr);
|
|
155
|
+
|
|
156
|
+
// Wobble variables (arcsec), IERS Conventions (2010) §7.1.4.
|
|
157
|
+
let m1 = xp_arcsec - x_bar_arcsec;
|
|
158
|
+
let m2 = -(yp_arcsec - y_bar_arcsec);
|
|
159
|
+
|
|
160
|
+
// Geocentric station triad: theta is colatitude, lambda longitude.
|
|
161
|
+
let rsta = norm(xsta);
|
|
162
|
+
let sinphi = xsta[2] / rsta; // cos(theta)
|
|
163
|
+
let cosphi = (xsta[0] * xsta[0] + xsta[1] * xsta[1]).sqrt() / rsta; // sin(theta)
|
|
164
|
+
let sinla = xsta[1] / cosphi / rsta;
|
|
165
|
+
let cosla = xsta[0] / cosphi / rsta;
|
|
166
|
+
|
|
167
|
+
let sin2theta = 2.0 * cosphi * sinphi;
|
|
168
|
+
let cos2theta = sinphi * sinphi - cosphi * cosphi;
|
|
169
|
+
let costheta = sinphi;
|
|
170
|
+
|
|
171
|
+
let radial_factor = m1 * cosla + m2 * sinla;
|
|
172
|
+
let longitude_factor = m1 * sinla - m2 * cosla;
|
|
173
|
+
|
|
174
|
+
// Eq. (7.24), in millimetres.
|
|
175
|
+
let s_r = RADIAL_MM_PER_ARCSEC * sin2theta * radial_factor;
|
|
176
|
+
let s_theta = COLATITUDE_MM_PER_ARCSEC * cos2theta * radial_factor;
|
|
177
|
+
let s_lambda = LONGITUDE_MM_PER_ARCSEC * costheta * longitude_factor;
|
|
178
|
+
|
|
179
|
+
// Local radial/north/east displacement in metres (north = -S_theta).
|
|
180
|
+
let up = s_r / MM_PER_M;
|
|
181
|
+
let north = -s_theta / MM_PER_M;
|
|
182
|
+
let east = s_lambda / MM_PER_M;
|
|
183
|
+
|
|
184
|
+
// Geocentric ENU -> ECEF, matching the solid-earth tide convention.
|
|
185
|
+
[
|
|
186
|
+
up * cosla * cosphi - east * sinla - north * sinphi * cosla,
|
|
187
|
+
up * sinla * cosphi + east * cosla - north * sinphi * sinla,
|
|
188
|
+
up * sinphi + north * cosphi,
|
|
189
|
+
]
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/// IERS (2018) linear secular mean pole at the given UTC epoch, in arcseconds.
|
|
193
|
+
fn mean_pole_arcsec(year: i32, month: i32, day: i32, fhr: f64) -> (f64, f64) {
|
|
194
|
+
// Epoch in years since J2000.0 (RTKLIB-compatible Julian-year measure).
|
|
195
|
+
let (jd0, jd1) = gregorian_to_two_part_julian_date(year, month, day);
|
|
196
|
+
let years = ((jd0 - J2000_JD) + jd1 + fhr / 24.0) / DAYS_PER_JULIAN_YEAR;
|
|
197
|
+
|
|
198
|
+
let x_bar_mas = MEAN_POLE_X0_MAS + MEAN_POLE_X_RATE_MAS_PER_YR * years;
|
|
199
|
+
let y_bar_mas = MEAN_POLE_Y0_MAS + MEAN_POLE_Y_RATE_MAS_PER_YR * years;
|
|
200
|
+
|
|
201
|
+
// Milliarcseconds -> arcseconds.
|
|
202
|
+
(x_bar_mas / 1000.0, y_bar_mas / 1000.0)
|
|
203
|
+
}
|