SolidTide#
- class SolidTide(tide_bodies: tuple = None, central_body: str = 'EARTH', love_h2: float = None, shida_l2: float = None, love_k: dict = None, remove_permanent_tide: bool = False, rate_step: float = 60.0, model: str = 'degree2')#
Bases:
objectSolid tide displacement of a surface point.
A station is not fixed in its body-fixed frame. Nearby masses deform the solid body it stands on, moving it by tens of centimetres on a diurnal and semidiurnal cycle. That is well above the noise of a modern ranging system, so a station geometry that omits it carries a signature no estimated parameter is supposed to absorb.
By default the degree-2 in-phase term of the IERS Conventions (2010), Chapter 7, Section 7.1.1, step 1;
model="IERS2010"evaluates the complete IERS routine instead. The degree-2 term is\[\delta\mathbf r = \sum_j \frac{GM_j}{GM_\oplus} \frac{R^4}{R_j^3} \left\{ h_2 \hat{\mathbf r} \left[\tfrac{3}{2}(\hat{\mathbf R}_j\cdot\hat{\mathbf r})^2 - \tfrac{1}{2}\right] + 3 l_2 (\hat{\mathbf R}_j\cdot\hat{\mathbf r}) \left[\hat{\mathbf R}_j - (\hat{\mathbf R}_j\cdot\hat{\mathbf r})\hat{\mathbf r} \right]\right\}\]summed over the tide-raising bodies.
One tide model serves two consumers. Attach it to
GroundStation.surface_displacementto move a station on the surface, and toSphericalHarmonicsGravity.solid_tideto perturb the gravity field.Nothing in the model is specific to Earth. Earth is the one body with a nominal response built in, because it is the one whose Love and Shida numbers are pinned by a convention; a station on any other body gets the same treatment once its numbers are supplied.
- Parameters:
- tide_bodiestuple of str, optional
Tide-raising bodies. Defaults to the Moon and the Sun for Earth, where everything else is below a millimetre. Required for any other central body.
- central_bodystr, optional
Deformed body, default EARTH. Its GM and equatorial radius set the scale, and the tide-raiser positions are taken relative to it. Nothing in the formulation is Earth-specific – a station on Mars gets its tide from this same class, given Mars values.
- love_h2, shida_l2float, optional
Degree-2 Love and Shida numbers. Default to the IERS nominal values of
Constants.EARTH_SOLID_TIDE, 0.6078 and 0.0847, for Earth only. For any other body they are required: the tidal response varies by a factor of several between bodies (Mars is near h2 = 0.17), so a default would be a large silent error rather than an approximation.- love_kdict, optional
Potential Love numbers \(k_{nm}\) keyed by
(degree, order), used only bygeopotential_coefficients(). Defaults to the IERS Table 6.3 values for Earth, degrees 2 and 3, fromConstants.EARTH_SOLID_TIDE. These are a table rather than one number for the same reason the field itself is: they vary with order (\(k_{20}\) and \(k_{22}\) differ by about 1%) and fall by a factor of three from degree 2 to degree 3. Supplying a subset restricts the perturbation to those terms.These are a different quantity from
love_h2: \(h\) says how far the surface moves, \(k\) how much the external gravity field changes. Confusing them is a factor-of-two error.- remove_permanent_tidebool, optional
Subtract the zero-frequency (permanent) deformation, IERS eq. 7.14. Default false, which is what conventional tide-free station coordinates need. See Notes – this is a real fork, not a preference.
- rate_stepfloat, optional
Half-interval in seconds for the central difference that supplies the body-fixed rate, default 60.
- model{“degree2”, “IERS2010”}, optional
"degree2"(default) is the degree-2 in-phase term above."IERS2010"is the complete IERS Conventions (2010) routine DEHANTTIDEINEL, Earth only, with its own constants (Constants.EARTH_SOLID_TIDE): step 1 in and out of phase for degrees 2 and 3 with latitude-dependent Love and Shida numbers, and the step-2 frequency corrections. It differs from the degree-2 term by up to about 13 mm, mostly the diurnal K1 correction.
- Attributes:
- love_h2
- love_k
- shida_l2
- tide_bodies
Methods
displacement(position_body_fixed, epoch[, frame])Tidal displacement of a body-fixed point.
displacement_partials(position_body_fixed, epoch)Sensitivity of the displacement to the Love and Shida numbers.
geopotential_coefficients(epoch[, frame])Tidal perturbation of the body's spherical-harmonic coefficients.
geopotential_partials(epoch[, frame])Sensitivity of the coefficient perturbation to each \(k_{nm}\).
iers2010_displacement(xsta, fhr, t, xsun, xmon)IERS Conventions (2010) solid-tide station displacement, DEHANTTIDEINEL.
state_displacement(position_body_fixed, epoch)Tidal displacement and its body-fixed rate.
state_displacement_partials(...[, frame])Love/Shida sensitivity of the displacement and of its body-fixed rate.
Notes
The degree-2 model retains the degree-2 in-phase term, which is the whole of the effect at the decimetre level – up to about 0.4 m radially at Earth.
The permanent-tide constants are Earth values from IERS eq. 7.14, kept in
Constants.EARTH_SOLID_TIDE, soremove_permanent_tideis only meaningful for Earth.The degree-2 model omits, with magnitudes: degree 3 (about 2 mm), the out-of-phase diurnal and semidiurnal contributions and the latitude dependence of \(h\) and \(l\) (a few mm), and the frequency-dependent step-2 corrections (up to about 13 mm, the diurnal K1 term above all).
model="IERS2010"includes all of these. Neither includes ocean and atmospheric loading (about 1 cm and a few mm) or the pole tide (about 1 cm).displacement_partials()is the degree-2 term’s sensitivity to the Love and Shida numbers under either model.The permanent tide is a genuine convention fork rather than a refinement. The formula above yields the total deformation including a zero-frequency part – roughly -12 cm radially at the poles and +6 cm at the equator. Conventional tide-free coordinates, which is what the ITRF and DSN tables publish, already exclude that permanent deformation, so it must be restored by this formula and
remove_permanent_tidestays false. Set it true only for coordinates that are already mean-tide or zero-tide, or the permanent part is applied twice.The choice is made on the coordinates’ stated convention, not on residuals: on the C2 and C3 deliveries the two settings differ by 0.010 m in the mean range residual and 0.0002 m in its scatter, so the data does not discriminate between them.
See orientation-station-estimation for how the model enters the station geometry and which higher-order terms are left out.
References
IERS Conventions (2010), IERS Technical Note 36, Chapter 7. https://iers-conventions.obspm.fr/content/chapter7/icc7.pdf
- classmethod iers2010_displacement(xsta, fhr, t, xsun, xmon) ndarray#
IERS Conventions (2010) solid-tide station displacement, DEHANTTIDEINEL.
What
displacement()evaluates formodel="IERS2010", with the routine’s own interface and units.- Parameters:
- xstaarray_like, shape (3,)
Station position, m, Earth-fixed (ITRF).
- fhrfloat
UTC hours of the day.
- tfloat
TT Julian centuries from J2000.
- xsun, xmonarray_like, shape (3,)
Geocentric Sun and Moon positions, m, in the same Earth-fixed axes.
- Returns:
- numpy.ndarray
Displacement in m, Earth-fixed axes: step 1 in and out of phase, degrees 2 and 3, with latitude-dependent Love and Shida numbers, and the step-2 diurnal and long-period frequency corrections. The permanent tide is included, as for conventional tide-free coordinates.
Notes
The numbers are
Constants.EARTH_SOLID_TIDE; the reference radius isConstants.EARTH.equatorial_radius.
- displacement(position_body_fixed, epoch: float, frame: str = None) ArrayWUnits#
Tidal displacement of a body-fixed point.
- Parameters:
- position_body_fixedArrayWUnits, ArrayWFrame or array_like, shape (3,)
Undisplaced position in
frame, relative to the body centre. Bare numbers are km.- epochfloat or EpochArray
TDB seconds past J2000.
- framestr or Frame, optional
Body-fixed axes the position is given in and the displacement is returned in. Defaults to
None,'IAU_'plus the central body’s name.
- Returns:
- ArrayWUnits
Displacement in km, shape (3,).
- Raises:
- ValueError
At the body centre, where the local vertical is undefined.
- displacement_partials(position_body_fixed, epoch: float, frame: str = None) ArrayWUnits#
Sensitivity of the displacement to the Love and Shida numbers.
- Parameters:
- position_body_fixedArrayWUnits, ArrayWFrame or array_like, shape (3,)
Undisplaced position in
frame. Bare numbers are km.- epochfloat or EpochArray
TDB seconds past J2000.
- framestr or Frame, optional
Body-fixed axes; see
displacement(). Defaults toNone.
- Returns:
- ArrayWUnits
(3, 2)Jacobian, columns \(\partial\delta r/\partial h_2\) and \(\partial\delta r/\partial l_2\), in km per unit.
- Raises:
- ValueError
At the body centre, where the local vertical is undefined.
Notes
The displacement is linear in \(h_2\) and \(l_2\), so these columns are the two terms evaluated with a unit coefficient and are exact rather than a linearization. The permanent-tide term does not depend on the Love numbers – it is a tabulated IERS correction – so it contributes nothing here whichever way that option is set.
- geopotential_coefficients(epoch: float, frame: str = None) dict#
Tidal perturbation of the body’s spherical-harmonic coefficients.
- Parameters:
- epochfloat
TDB seconds past J2000.
- framestr, optional
Body-fixed axes the tide-raiser positions are taken in. Defaults to
None,'IAU_'plus the central body’s name.
- Returns:
- dict
(degree, order)mapped to(dC, dS), normalized, for every(degree, order)present inlove_k. Add these to the nominal field.
Notes
IERS Conventions (2010), Chapter 6, eq. 6.6, step 1:
\[\Delta\bar C_{nm} - i\,\Delta\bar S_{nm} = \frac{k_{nm}}{2n+1} \sum_j \frac{GM_j}{GM} \left(\frac{R}{r_j}\right)^{n+1} \bar P_{nm}(\sin\Phi_j)\, e^{-im\lambda_j}\]This is the other half of the same tide that
displacement()moves the surface with: the deformed mass changes the external field. It is driven bylove_k, not by \(h_2\) and \(l_2\).Every
(degree, order)inlove_kis summed, so the resolution follows that table rather than being fixed at degree 2. At Earth this reaches about 5e-9 in \(\Delta\bar C_{20}\), which is 1e-5 of the nominal \(\bar C_{20}\); the degree-3 terms are three orders of magnitude smaller again.Each \(\Delta\bar C_{nm}\) depends on its own \(k_{nm}\) and no other, so the sensitivity is diagonal – see
geopotential_partials().Frequency-dependent step-2 corrections and the anelastic \(k^{+}\) term are not included; both are well below the step-1 terms retained here.
Beware the base field’s own tide convention. A geopotential published as zero-tide already contains the permanent deformation, so adding this on top counts it twice; a tide-free field does not. The difference is about 1e-8 in \(\bar C_{20}\), comparable to the whole tidal signal, and this method does not know which convention the loaded coefficients use.
- geopotential_partials(epoch: float, frame: str = None) dict#
Sensitivity of the coefficient perturbation to each \(k_{nm}\).
- Parameters:
- epochfloat
TDB seconds past J2000.
- framestr, optional
Body-fixed axes; see
geopotential_coefficients(). Defaults toNone.
- Returns:
- dict
(degree, order)mapped to(dC/dk, dS/dk)for that same(degree, order).
Notes
\(\Delta\bar C_{nm}\) depends on \(k_{nm}\) alone and linearly, so the Jacobian is diagonal and each entry is exact rather than a linearization – this is the same table evaluated at unit \(k_{nm}\).
- state_displacement(position_body_fixed, epoch: float, frame: str = None) ArrayWUnits#
Tidal displacement and its body-fixed rate.
- Parameters:
- position_body_fixedArrayWUnits, ArrayWFrame or array_like, shape (3,)
Undisplaced position in
frame. Bare numbers are km.- epochfloat or EpochArray
TDB seconds past J2000.
- framestr or Frame, optional
Body-fixed axes; see
displacement(). Defaults toNone.
- Returns:
- ArrayWUnits
Six components in km and km/s, shape (6,).
- Raises:
- ValueError
At the body centre, where the local vertical is undefined.
Notes
The rate is a central difference over
rate_step, which is ample for a signal whose shortest period is twelve hours. It reaches roughly 0.03 mm/s at Earth, comparable to the frame-rotation term the state transformation adds on top, and both matter against Doppler noise quoted near 1 mm/s.
- state_displacement_partials(position_body_fixed, epoch: float, frame: str = None) ArrayWUnits#
Love/Shida sensitivity of the displacement and of its body-fixed rate.
- Parameters:
- position_body_fixedArrayWUnits, ArrayWFrame or array_like, shape (3,)
Undisplaced position in
frame. Bare numbers are km.- epochfloat or EpochArray
TDB seconds past J2000.
- framestr or Frame, optional
Body-fixed axes; see
displacement(). Defaults toNone.
- Returns:
- ArrayWUnits
(6, 2)Jacobian in km and km/s per unit Love or Shida number, columns \(h_2\) and \(l_2\) as indisplacement_partials().
- Raises:
- ValueError
At the body centre, where the local vertical is undefined.
Notes
The rate rows use the same central difference as
state_displacement(), so the partial is the derivative of what the forward model actually applies.
- MODELS = ('degree2', 'IERS2010')#
Displacement models: the degree-2 in-phase term, or the complete IERS Conventions (2010) routine.
- NOMINAL_RESPONSE = {'EARTH': SolidTideInfo(love_h2=0.6078, shida_l2=0.0847, love_k={(2, 0): 0.29525, (2, 1): 0.2947, (2, 2): 0.29801, (3, 0): 0.093, (3, 1): 0.093, (3, 2): 0.093, (3, 3): 0.094}, tide_bodies=('MOON', 'SUN'), love_h3=0.292, shida_l3=0.015, love_h2_latitude=-0.0006, shida_l2_latitude=0.0002, out_of_phase_diurnal=(-0.0025, -0.0007), out_of_phase_semidiurnal=(-0.0022, -0.0007), shida_l1=(0.0012, 0.0024), mass_ratio_sun=332946.0482, mass_ratio_moon=0.0123000371, step2_diurnal=((-3, 0, 2, 0, 0, -0.01, 0, 0, 0), (-3, 2, 0, 0, 0, -0.01, 0, 0, 0), (-2, 0, 1, -1, 0, -0.02, 0, 0, 0), (-2, 0, 1, 0, 0, -0.08, 0, -0.01, 0.01), (-2, 2, -1, 0, 0, -0.02, 0, 0, 0), (-1, 0, 0, -1, 0, -0.1, 0, 0, 0), (-1, 0, 0, 0, 0, -0.51, 0, -0.02, 0.03), (-1, 2, 0, 0, 0, 0.01, 0, 0, 0), (0, -2, 1, 0, 0, 0.01, 0, 0, 0), (0, 0, -1, 0, 0, 0.02, 0, 0, 0), (0, 0, 1, 0, 0, 0.06, 0, 0, 0), (0, 0, 1, 1, 0, 0.01, 0, 0, 0), (0, 2, -1, 0, 0, 0.01, 0, 0, 0), (1, -3, 0, 0, 1, -0.06, 0, 0, 0), (1, -2, 0, -1, 0, 0.01, 0, 0, 0), (1, -2, 0, 0, 0, -1.23, -0.07, 0.06, 0.01), (1, -1, 0, 0, -1, 0.02, 0, 0, 0), (1, -1, 0, 0, 1, 0.04, 0, 0, 0), (1, 0, 0, -1, 0, -0.22, 0.01, 0.01, 0), (1, 0, 0, 0, 0, 12.0, -0.8, -0.67, -0.03), (1, 0, 0, 1, 0, 1.73, -0.12, -0.1, 0), (1, 0, 0, 2, 0, -0.04, 0, 0, 0), (1, 1, 0, 0, -1, -0.5, -0.01, 0.03, 0), (1, 1, 0, 0, 1, 0.01, 0, 0, 0), (0, 1, 0, 1, -1, -0.01, 0, 0, 0), (1, 2, -2, 0, 0, -0.01, 0, 0, 0), (1, 2, 0, 0, 0, -0.11, 0.01, 0.01, 0), (2, -2, 1, 0, 0, -0.01, 0, 0, 0), (2, 0, -1, 0, 0, -0.02, 0, 0, 0), (3, 0, 0, 0, 0, 0, 0, 0, 0), (3, 0, 0, 1, 0, 0, 0, 0, 0)), step2_long_period=((0, 0, 0, 1, 0, 0.47, 0.16, 0.23, 0.07), (0, 2, 0, 0, 0, -0.2, -0.11, -0.12, -0.05), (1, 0, -1, 0, 0, -0.11, -0.09, -0.08, -0.04), (2, 0, 0, 0, 0, -0.13, -0.15, -0.11, -0.07), (2, 0, 0, 1, 0, -0.05, -0.06, -0.05, -0.03)), step2_arguments={'s': (218.31664563, 481267.88194, -0.0014663889, 1.85139e-06), 'h': (280.46645, 36000.7697489, 0.00030322222, 2e-08, -6.54e-09), 'p': (83.35324312, 4069.01363525, -0.01032172222, -1.24991e-05, 5.263e-08), "N'": (234.95544499, 1934.13626197, -0.00207561111, -2.13944e-06, 1.65e-08), 'ps': (282.93734098, 1.71945766667, 0.00045688889, -1.778e-08, -3.34e-09), 'pr': (0.0, 1.396971278, 0.000308889, 2.1e-08, 7e-09), 'GMST': (280.4606184, 36000.7700536, 0.00038793, -2.58e-08)}, permanent_tide_radial=(-0.1206, 0.0001), permanent_tide_north=(-0.0252, -0.0001))}#
Central bodies with a nominal response, each a
SolidTideInfofrom Constants. Only bodies whose response is actually measured belong here: guessing one is a factor-of-several error, not a rounding one, so an unlisted body must be given explicit values.
- STATE_UNITS = (km, km, km, km/sec, km/sec, km/sec)#
Row units of
state_displacement()and of its Love/Shida partials.
- exception UnknownModelError#
Bases:
ValueErrorThe displacement model is not one of
MODELS, or the IERS 2010 routine was asked for with a body or Love numbers it does not define: it is Earth’s, with its own fixed numbers.
- exception UnknownTidalResponseError#
Bases:
ValueErrorNo tidal response is known for this body and none was supplied.
Raised by the constructor. The degree-2 Love and Shida numbers differ by a factor of several between bodies, so falling back on Earth’s would be a large silent error. Supply
love_h2,shida_l2andtide_bodiesexplicitly, or, once its response is actually known, give it aSolidTideInfoin Constants and list it inNOMINAL_RESPONSE.