earthsciencekit 0.2.0__py3-none-any.whl
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.
- earthsciencekit/__init__.py +6 -0
- earthsciencekit/_validation.py +62 -0
- earthsciencekit/atmosphere/__init__.py +57 -0
- earthsciencekit/atmosphere/core/__init__.py +5 -0
- earthsciencekit/atmosphere/core/base.py +10 -0
- earthsciencekit/atmosphere/systems/__init__.py +1 -0
- earthsciencekit/atmosphere/systems/dynamics.py +208 -0
- earthsciencekit/atmosphere/systems/hydrostatics.py +214 -0
- earthsciencekit/atmosphere/systems/moisture.py +162 -0
- earthsciencekit/atmosphere/systems/thermodynamics.py +222 -0
- earthsciencekit/atmosphere/tests/__init__.py +0 -0
- earthsciencekit/atmosphere/tests/test_models.py +741 -0
- earthsciencekit/atmosphere/tests/test_physics.py +81 -0
- earthsciencekit/atmosphere/visualizers/__init__.py +9 -0
- earthsciencekit/climate/__init__.py +63 -0
- earthsciencekit/climate/core/__init__.py +5 -0
- earthsciencekit/climate/core/base.py +10 -0
- earthsciencekit/climate/systems/__init__.py +1 -0
- earthsciencekit/climate/systems/carbon.py +76 -0
- earthsciencekit/climate/systems/forcing.py +124 -0
- earthsciencekit/climate/systems/radiation.py +214 -0
- earthsciencekit/climate/systems/response.py +402 -0
- earthsciencekit/climate/systems/sea_level.py +77 -0
- earthsciencekit/climate/tests/__init__.py +0 -0
- earthsciencekit/climate/tests/test_models.py +1015 -0
- earthsciencekit/climate/tests/test_physics.py +16 -0
- earthsciencekit/climate/visualizers/__init__.py +9 -0
- earthsciencekit/constants/__init__.py +23 -0
- earthsciencekit/geophysics/__init__.py +77 -0
- earthsciencekit/geophysics/core/__init__.py +5 -0
- earthsciencekit/geophysics/core/base.py +10 -0
- earthsciencekit/geophysics/systems/__init__.py +1 -0
- earthsciencekit/geophysics/systems/deformation.py +161 -0
- earthsciencekit/geophysics/systems/dynamo.py +159 -0
- earthsciencekit/geophysics/systems/figure.py +292 -0
- earthsciencekit/geophysics/systems/gravity.py +235 -0
- earthsciencekit/geophysics/systems/magnetism.py +354 -0
- earthsciencekit/geophysics/tests/__init__.py +0 -0
- earthsciencekit/geophysics/tests/test_models.py +898 -0
- earthsciencekit/geophysics/tests/test_physics.py +171 -0
- earthsciencekit/geophysics/visualizers/__init__.py +9 -0
- earthsciencekit/integrators/__init__.py +62 -0
- earthsciencekit/oceanography/__init__.py +61 -0
- earthsciencekit/oceanography/core/__init__.py +5 -0
- earthsciencekit/oceanography/core/base.py +10 -0
- earthsciencekit/oceanography/systems/__init__.py +1 -0
- earthsciencekit/oceanography/systems/circulation.py +388 -0
- earthsciencekit/oceanography/systems/hydrography.py +212 -0
- earthsciencekit/oceanography/systems/inertial.py +86 -0
- earthsciencekit/oceanography/systems/waves.py +281 -0
- earthsciencekit/oceanography/tests/__init__.py +0 -0
- earthsciencekit/oceanography/tests/test_models.py +916 -0
- earthsciencekit/oceanography/tests/test_physics.py +102 -0
- earthsciencekit/oceanography/visualizers/__init__.py +9 -0
- earthsciencekit/plate_tectonics/__init__.py +59 -0
- earthsciencekit/plate_tectonics/core/__init__.py +5 -0
- earthsciencekit/plate_tectonics/core/base.py +10 -0
- earthsciencekit/plate_tectonics/systems/__init__.py +1 -0
- earthsciencekit/plate_tectonics/systems/boundaries.py +201 -0
- earthsciencekit/plate_tectonics/systems/cooling.py +238 -0
- earthsciencekit/plate_tectonics/systems/isostasy.py +157 -0
- earthsciencekit/plate_tectonics/systems/kinematics.py +290 -0
- earthsciencekit/plate_tectonics/tests/__init__.py +0 -0
- earthsciencekit/plate_tectonics/tests/test_models.py +920 -0
- earthsciencekit/plate_tectonics/tests/test_physics.py +94 -0
- earthsciencekit/plate_tectonics/visualizers/__init__.py +9 -0
- earthsciencekit/py.typed +0 -0
- earthsciencekit/results.py +73 -0
- earthsciencekit/seismology/__init__.py +59 -0
- earthsciencekit/seismology/core/__init__.py +5 -0
- earthsciencekit/seismology/core/base.py +10 -0
- earthsciencekit/seismology/systems/__init__.py +1 -0
- earthsciencekit/seismology/systems/interfaces.py +102 -0
- earthsciencekit/seismology/systems/rays.py +221 -0
- earthsciencekit/seismology/systems/sources.py +249 -0
- earthsciencekit/seismology/systems/waves.py +268 -0
- earthsciencekit/seismology/tests/__init__.py +0 -0
- earthsciencekit/seismology/tests/test_models.py +852 -0
- earthsciencekit/seismology/tests/test_physics.py +100 -0
- earthsciencekit/seismology/visualizers/__init__.py +9 -0
- earthsciencekit/tests/__init__.py +0 -0
- earthsciencekit/tests/test_core.py +181 -0
- earthsciencekit/tests/test_relations.py +36 -0
- earthsciencekit/units/__init__.py +66 -0
- earthsciencekit/visualizers/__init__.py +45 -0
- earthsciencekit/volcanology/__init__.py +61 -0
- earthsciencekit/volcanology/core/__init__.py +5 -0
- earthsciencekit/volcanology/core/base.py +10 -0
- earthsciencekit/volcanology/systems/__init__.py +1 -0
- earthsciencekit/volcanology/systems/eruptions.py +161 -0
- earthsciencekit/volcanology/systems/geochemistry.py +226 -0
- earthsciencekit/volcanology/systems/geochronology.py +304 -0
- earthsciencekit/volcanology/systems/magma.py +190 -0
- earthsciencekit/volcanology/tests/__init__.py +0 -0
- earthsciencekit/volcanology/tests/test_models.py +485 -0
- earthsciencekit/volcanology/tests/test_physics.py +176 -0
- earthsciencekit/volcanology/visualizers/__init__.py +9 -0
- earthsciencekit-0.2.0.dist-info/METADATA +127 -0
- earthsciencekit-0.2.0.dist-info/RECORD +102 -0
- earthsciencekit-0.2.0.dist-info/WHEEL +5 -0
- earthsciencekit-0.2.0.dist-info/licenses/LICENSE +15 -0
- earthsciencekit-0.2.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
"""Figure of the Earth: rotational flattening, normal gravity, J2 from satellite orbits and the geoid.
|
|
2
|
+
|
|
3
|
+
SI units unless stated otherwise; latitude, inclination and spherical distance in radians.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import numpy as np
|
|
7
|
+
|
|
8
|
+
from earthsciencekit._validation import model, quantity, require
|
|
9
|
+
|
|
10
|
+
__all__ = [
|
|
11
|
+
"centrifugal_ratio",
|
|
12
|
+
"homogeneous_flattening",
|
|
13
|
+
"clairaut_gravity",
|
|
14
|
+
"normal_gravity",
|
|
15
|
+
"flattening_from_j2",
|
|
16
|
+
"nodal_precession_rate",
|
|
17
|
+
"stokes_function",
|
|
18
|
+
"degree_geoid_height",
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
# GRS80 Somigliana constants: equatorial normal gravity, k = (b gamma_p) / (a gamma_e) - 1 and the first eccentricity squared.
|
|
22
|
+
_GAMMA_E = 9.7803267715
|
|
23
|
+
_SOMIGLIANA_K = 0.001931851353
|
|
24
|
+
_E2 = 0.00669438002290
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@model
|
|
28
|
+
def centrifugal_ratio(angular_speed, radius, gravity):
|
|
29
|
+
"""Ratio of centrifugal to gravitational acceleration at the equator.
|
|
30
|
+
|
|
31
|
+
Rotation flattens a planet in proportion to how strongly it competes with gravity.
|
|
32
|
+
|
|
33
|
+
Parameters
|
|
34
|
+
----------
|
|
35
|
+
angular_speed : float or array_like
|
|
36
|
+
rad/s; constraint: nonnegative.
|
|
37
|
+
radius : float or array_like
|
|
38
|
+
m; constraint: positive. Equatorial radius.
|
|
39
|
+
gravity : float or array_like
|
|
40
|
+
m/s^2; constraint: positive. Equatorial gravity.
|
|
41
|
+
|
|
42
|
+
Returns
|
|
43
|
+
-------
|
|
44
|
+
numpy scalar or ndarray
|
|
45
|
+
Model value [1]. Scalar input returns a NumPy scalar; arrays broadcast.
|
|
46
|
+
|
|
47
|
+
Notes
|
|
48
|
+
-----
|
|
49
|
+
The geodetic ``m`` uses ``GM / (a b)`` in place of gravity; the two differ at the 0.5% level.
|
|
50
|
+
Equation: ``angular_speed**2 * radius / gravity``.
|
|
51
|
+
Invalid, empty, nonreal or nonfinite inputs raise ValueError.
|
|
52
|
+
NumPy broadcasting applies; singular and overflowing outputs raise ValueError.
|
|
53
|
+
"""
|
|
54
|
+
angular_speed = quantity("angular_speed", angular_speed, lower=0)
|
|
55
|
+
radius = quantity("radius", radius, lower=0, strict_lower=True)
|
|
56
|
+
gravity = quantity("gravity", gravity, lower=0, strict_lower=True)
|
|
57
|
+
return angular_speed**2 * radius / gravity
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
@model
|
|
61
|
+
def homogeneous_flattening(centrifugal_ratio):
|
|
62
|
+
"""Flattening of a slowly rotating homogeneous fluid planet.
|
|
63
|
+
|
|
64
|
+
A uniform self-gravitating fluid in rotation settles into an oblate spheroid.
|
|
65
|
+
|
|
66
|
+
Parameters
|
|
67
|
+
----------
|
|
68
|
+
centrifugal_ratio : float or array_like
|
|
69
|
+
1; constraint: 0 <= value <= 0.1.
|
|
70
|
+
|
|
71
|
+
Returns
|
|
72
|
+
-------
|
|
73
|
+
numpy scalar or ndarray
|
|
74
|
+
Model value [1]: ``(a - c) / a``.
|
|
75
|
+
|
|
76
|
+
Notes
|
|
77
|
+
-----
|
|
78
|
+
First order in rotation (Maclaurin spheroid). A centrally condensed Earth is less flattened than this.
|
|
79
|
+
Equation: ``5 * centrifugal_ratio / 4``.
|
|
80
|
+
Invalid, empty, nonreal or nonfinite inputs raise ValueError.
|
|
81
|
+
NumPy broadcasting applies; singular and overflowing outputs raise ValueError.
|
|
82
|
+
"""
|
|
83
|
+
centrifugal_ratio = quantity("centrifugal_ratio", centrifugal_ratio, lower=0, upper=0.1)
|
|
84
|
+
return 5 * centrifugal_ratio / 4
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
@model
|
|
88
|
+
def clairaut_gravity(latitude, equatorial_gravity, flattening, centrifugal_ratio):
|
|
89
|
+
"""Gravity on a rotating spheroid from Clairaut's theorem.
|
|
90
|
+
|
|
91
|
+
The increase of gravity toward the poles measures the flattening without any surveying.
|
|
92
|
+
|
|
93
|
+
Parameters
|
|
94
|
+
----------
|
|
95
|
+
latitude : float or array_like
|
|
96
|
+
rad; constraint: -pi/2 <= latitude <= pi/2. Geodetic latitude.
|
|
97
|
+
equatorial_gravity : float or array_like
|
|
98
|
+
m/s^2; constraint: positive.
|
|
99
|
+
flattening : float or array_like
|
|
100
|
+
1; constraint: 0 <= value < 1.
|
|
101
|
+
centrifugal_ratio : float or array_like
|
|
102
|
+
1; constraint: nonnegative.
|
|
103
|
+
|
|
104
|
+
Returns
|
|
105
|
+
-------
|
|
106
|
+
numpy scalar or ndarray
|
|
107
|
+
Model value [m/s^2]. Scalar input returns a NumPy scalar; arrays broadcast.
|
|
108
|
+
|
|
109
|
+
Notes
|
|
110
|
+
-----
|
|
111
|
+
First order in flattening and rotation for a spheroid in hydrostatic equilibrium; the sin^4 term is omitted.
|
|
112
|
+
Equation: ``equatorial_gravity * (1 + (5 * centrifugal_ratio / 2 - flattening) * np.sin(latitude) ** 2)``.
|
|
113
|
+
Invalid, empty, nonreal or nonfinite inputs raise ValueError.
|
|
114
|
+
NumPy broadcasting applies; singular and overflowing outputs raise ValueError.
|
|
115
|
+
"""
|
|
116
|
+
latitude = quantity("latitude", latitude, lower=-np.pi / 2, upper=np.pi / 2)
|
|
117
|
+
equatorial_gravity = quantity("equatorial_gravity", equatorial_gravity, lower=0, strict_lower=True)
|
|
118
|
+
flattening = quantity("flattening", flattening, lower=0, upper=1, strict_upper=True)
|
|
119
|
+
centrifugal_ratio = quantity("centrifugal_ratio", centrifugal_ratio, lower=0)
|
|
120
|
+
return equatorial_gravity * (1 + (5 * centrifugal_ratio / 2 - flattening) * np.sin(latitude) ** 2)
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
@model
|
|
124
|
+
def normal_gravity(latitude):
|
|
125
|
+
"""Normal gravity on the GRS80 ellipsoid.
|
|
126
|
+
|
|
127
|
+
The reference field that gravity anomalies are measured against.
|
|
128
|
+
|
|
129
|
+
Parameters
|
|
130
|
+
----------
|
|
131
|
+
latitude : float or array_like
|
|
132
|
+
rad; constraint: -pi/2 <= latitude <= pi/2. Geodetic latitude.
|
|
133
|
+
|
|
134
|
+
Returns
|
|
135
|
+
-------
|
|
136
|
+
numpy scalar or ndarray
|
|
137
|
+
Model value [m/s^2]. Scalar input returns a NumPy scalar; arrays broadcast.
|
|
138
|
+
|
|
139
|
+
Notes
|
|
140
|
+
-----
|
|
141
|
+
Somigliana's closed form on the ellipsoid surface with the GRS80 constants
|
|
142
|
+
``gamma_e = 9.7803267715``, ``k = 0.001931851353`` and ``e2 = 0.00669438002290``; exact for the level ellipsoid.
|
|
143
|
+
Equation: ``gamma_e * (1 + k * np.sin(latitude) ** 2) / np.sqrt(1 - e2 * np.sin(latitude) ** 2)``.
|
|
144
|
+
Invalid, empty, nonreal or nonfinite inputs raise ValueError.
|
|
145
|
+
NumPy broadcasting applies; singular and overflowing outputs raise ValueError.
|
|
146
|
+
"""
|
|
147
|
+
latitude = quantity("latitude", latitude, lower=-np.pi / 2, upper=np.pi / 2)
|
|
148
|
+
sine_squared = np.sin(latitude) ** 2
|
|
149
|
+
return _GAMMA_E * (1 + _SOMIGLIANA_K * sine_squared) / np.sqrt(1 - _E2 * sine_squared)
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
@model
|
|
153
|
+
def flattening_from_j2(j2, centrifugal_ratio):
|
|
154
|
+
"""Flattening of a hydrostatic Earth from its J2.
|
|
155
|
+
|
|
156
|
+
The oblateness term of the gravity field and the rotation fix the shape of the level surface.
|
|
157
|
+
|
|
158
|
+
Parameters
|
|
159
|
+
----------
|
|
160
|
+
j2 : float or array_like
|
|
161
|
+
1; constraint: real. Unnormalized second zonal harmonic ``-C20``.
|
|
162
|
+
centrifugal_ratio : float or array_like
|
|
163
|
+
1; constraint: nonnegative.
|
|
164
|
+
|
|
165
|
+
Returns
|
|
166
|
+
-------
|
|
167
|
+
numpy scalar or ndarray
|
|
168
|
+
Model value [1]. Scalar input returns a NumPy scalar; arrays broadcast.
|
|
169
|
+
|
|
170
|
+
Notes
|
|
171
|
+
-----
|
|
172
|
+
First order in flattening (Clairaut's relation for the external field); second-order terms change ``1/f`` by
|
|
173
|
+
about 0.1%.
|
|
174
|
+
Equation: ``3 * j2 / 2 + centrifugal_ratio / 2``.
|
|
175
|
+
Invalid, empty, nonreal or nonfinite inputs raise ValueError.
|
|
176
|
+
NumPy broadcasting applies; singular and overflowing outputs raise ValueError.
|
|
177
|
+
"""
|
|
178
|
+
j2 = quantity("j2", j2)
|
|
179
|
+
centrifugal_ratio = quantity("centrifugal_ratio", centrifugal_ratio, lower=0)
|
|
180
|
+
return 3 * j2 / 2 + centrifugal_ratio / 2
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
@model
|
|
184
|
+
def nodal_precession_rate(semi_major_axis, eccentricity, inclination, j2, radius, gravitational_parameter):
|
|
185
|
+
"""Secular regression of a satellite orbit's node.
|
|
186
|
+
|
|
187
|
+
The equatorial bulge torques an inclined orbit, so the node drifts at a rate that measures J2.
|
|
188
|
+
|
|
189
|
+
Parameters
|
|
190
|
+
----------
|
|
191
|
+
semi_major_axis : float or array_like
|
|
192
|
+
m; constraint: positive.
|
|
193
|
+
eccentricity : float or array_like
|
|
194
|
+
1; constraint: 0 <= value < 1.
|
|
195
|
+
inclination : float or array_like
|
|
196
|
+
rad; constraint: 0 <= inclination <= pi.
|
|
197
|
+
j2 : float or array_like
|
|
198
|
+
1; constraint: real.
|
|
199
|
+
radius : float or array_like
|
|
200
|
+
m; constraint: positive. Equatorial reference radius of J2.
|
|
201
|
+
gravitational_parameter : float or array_like
|
|
202
|
+
m^3/s^2; constraint: positive. ``G M`` of the Earth.
|
|
203
|
+
|
|
204
|
+
Returns
|
|
205
|
+
-------
|
|
206
|
+
numpy scalar or ndarray
|
|
207
|
+
Model value [rad/s]: negative (westward) for prograde orbits and positive J2.
|
|
208
|
+
|
|
209
|
+
Notes
|
|
210
|
+
-----
|
|
211
|
+
First-order secular J2 perturbation, without drag or higher harmonics; perigee must clear the reference radius.
|
|
212
|
+
Equation: ``-1.5 * n * j2 * (radius / semi_major_axis) ** 2 * np.cos(inclination) / (1 - eccentricity**2) ** 2``
|
|
213
|
+
with mean motion ``n = np.sqrt(gravitational_parameter / semi_major_axis**3)``.
|
|
214
|
+
Invalid, empty, nonreal or nonfinite inputs raise ValueError.
|
|
215
|
+
NumPy broadcasting applies; singular and overflowing outputs raise ValueError.
|
|
216
|
+
"""
|
|
217
|
+
semi_major_axis = quantity("semi_major_axis", semi_major_axis, lower=0, strict_lower=True)
|
|
218
|
+
eccentricity = quantity("eccentricity", eccentricity, lower=0, upper=1, strict_upper=True)
|
|
219
|
+
inclination = quantity("inclination", inclination, lower=0, upper=np.pi)
|
|
220
|
+
j2 = quantity("j2", j2)
|
|
221
|
+
radius = quantity("radius", radius, lower=0, strict_lower=True)
|
|
222
|
+
gravitational_parameter = quantity("gravitational_parameter", gravitational_parameter, lower=0, strict_lower=True)
|
|
223
|
+
require(semi_major_axis * (1 - eccentricity) > radius, "perigee must lie above the reference radius")
|
|
224
|
+
mean_motion = np.sqrt(gravitational_parameter / semi_major_axis**3)
|
|
225
|
+
return -1.5 * mean_motion * j2 * (radius / semi_major_axis) ** 2 * np.cos(inclination) / (1 - eccentricity**2) ** 2
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
@model
|
|
229
|
+
def stokes_function(spherical_distance):
|
|
230
|
+
"""Stokes's kernel for the geoid.
|
|
231
|
+
|
|
232
|
+
Weighting gravity anomalies over the whole globe by spherical distance gives the geoid height.
|
|
233
|
+
|
|
234
|
+
Parameters
|
|
235
|
+
----------
|
|
236
|
+
spherical_distance : float or array_like
|
|
237
|
+
rad; constraint: 0 < value <= pi.
|
|
238
|
+
|
|
239
|
+
Returns
|
|
240
|
+
-------
|
|
241
|
+
numpy scalar or ndarray
|
|
242
|
+
Model value [1]. Scalar input returns a NumPy scalar; arrays broadcast.
|
|
243
|
+
|
|
244
|
+
Notes
|
|
245
|
+
-----
|
|
246
|
+
Spherical approximation with no masses outside the geoid; singular as ``2 / psi`` at zero distance. Its Legendre
|
|
247
|
+
expansion is ``sum((2 n + 1) / (n - 1) P_n(cos psi), n >= 2)``, so the geoid is
|
|
248
|
+
``radius / (4 pi gravity) * integral(anomaly * S dsigma)``.
|
|
249
|
+
Equation: ``1 / s - 6 * s + 1 - 5 * np.cos(psi) - 3 * np.cos(psi) * np.log(s + s**2)`` with ``s = np.sin(psi / 2)``.
|
|
250
|
+
Invalid, empty, nonreal or nonfinite inputs raise ValueError.
|
|
251
|
+
NumPy broadcasting applies; singular and overflowing outputs raise ValueError.
|
|
252
|
+
"""
|
|
253
|
+
psi = quantity("spherical_distance", spherical_distance, lower=0, upper=np.pi, strict_lower=True)
|
|
254
|
+
s = np.sin(psi / 2)
|
|
255
|
+
return 1 / s - 6 * s + 1 - 5 * np.cos(psi) - 3 * np.cos(psi) * np.log(s + s**2)
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
@model
|
|
259
|
+
def degree_geoid_height(anomaly_coefficient, degree, radius, gravity):
|
|
260
|
+
"""Geoid height of one spherical-harmonic degree of the gravity anomaly.
|
|
261
|
+
|
|
262
|
+
Stokes's integral divides each degree of the anomaly by ``n - 1``, so long wavelengths dominate the geoid.
|
|
263
|
+
|
|
264
|
+
Parameters
|
|
265
|
+
----------
|
|
266
|
+
anomaly_coefficient : float or array_like
|
|
267
|
+
m/s^2; constraint: real. Coefficient of the degree-``n`` surface harmonic of the gravity anomaly.
|
|
268
|
+
degree : float or array_like
|
|
269
|
+
1; constraint: integer >= 2.
|
|
270
|
+
radius : float or array_like
|
|
271
|
+
m; constraint: positive.
|
|
272
|
+
gravity : float or array_like
|
|
273
|
+
m/s^2; constraint: positive. Mean normal gravity.
|
|
274
|
+
|
|
275
|
+
Returns
|
|
276
|
+
-------
|
|
277
|
+
numpy scalar or ndarray
|
|
278
|
+
Model value [m]: coefficient of the same surface harmonic in the geoid height.
|
|
279
|
+
|
|
280
|
+
Notes
|
|
281
|
+
-----
|
|
282
|
+
Spherical approximation of Stokes's formula; degrees 0 and 1 are excluded by construction.
|
|
283
|
+
Equation: ``radius * anomaly_coefficient / ((degree - 1) * gravity)``.
|
|
284
|
+
Invalid, empty, nonreal or nonfinite inputs raise ValueError.
|
|
285
|
+
NumPy broadcasting applies; singular and overflowing outputs raise ValueError.
|
|
286
|
+
"""
|
|
287
|
+
anomaly_coefficient = quantity("anomaly_coefficient", anomaly_coefficient)
|
|
288
|
+
degree = quantity("degree", degree, lower=2)
|
|
289
|
+
require(degree == np.round(degree), "degree must be an integer")
|
|
290
|
+
radius = quantity("radius", radius, lower=0, strict_lower=True)
|
|
291
|
+
gravity = quantity("gravity", gravity, lower=0, strict_lower=True)
|
|
292
|
+
return radius * anomaly_coefficient / ((degree - 1) * gravity)
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
"""Gravity: buried masses, the Bouguer and free-air reductions and the weighing of the Earth.
|
|
2
|
+
|
|
3
|
+
SI units unless stated otherwise.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import numpy as np
|
|
7
|
+
|
|
8
|
+
from earthsciencekit._validation import model, quantity, require
|
|
9
|
+
from earthsciencekit.constants import G
|
|
10
|
+
|
|
11
|
+
__all__ = [
|
|
12
|
+
"sphere_gravity",
|
|
13
|
+
"bouguer_correction",
|
|
14
|
+
"free_air_correction",
|
|
15
|
+
"bouguer_anomaly",
|
|
16
|
+
"torsion_balance_gravitational_constant",
|
|
17
|
+
"earth_mean_density",
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@model
|
|
22
|
+
def sphere_gravity(x, depth, radius, density_contrast):
|
|
23
|
+
"""Gravitational attraction of a uniform sphere.
|
|
24
|
+
|
|
25
|
+
A compact body with excess density pulls a plumb line sideways and adds to gravity above it.
|
|
26
|
+
|
|
27
|
+
Parameters
|
|
28
|
+
----------
|
|
29
|
+
x : float or array_like
|
|
30
|
+
m; constraint: real. Horizontal distance of the observer from the point above the centre.
|
|
31
|
+
depth : float or array_like
|
|
32
|
+
m; constraint: real. Depth of the centre below the observer, positive downward.
|
|
33
|
+
radius : float or array_like
|
|
34
|
+
m; constraint: positive.
|
|
35
|
+
density_contrast : float or array_like
|
|
36
|
+
kg/m^3; constraint: real. Density minus that of the surroundings.
|
|
37
|
+
|
|
38
|
+
Returns
|
|
39
|
+
-------
|
|
40
|
+
ndarray, shape (..., 2)
|
|
41
|
+
Model value [m/s^2]: the horizontal component, positive toward increasing ``x``, and the downward component.
|
|
42
|
+
|
|
43
|
+
Notes
|
|
44
|
+
-----
|
|
45
|
+
The observer must lie outside the sphere, where it attracts as a point mass ``M = 4/3 pi radius**3 density_contrast``.
|
|
46
|
+
The horizontal component always points toward the centre for positive contrast.
|
|
47
|
+
Equation: ``G * M * [-x, depth] / (x**2 + depth**2) ** 1.5``.
|
|
48
|
+
Invalid, empty, nonreal or nonfinite inputs raise ValueError.
|
|
49
|
+
NumPy broadcasting applies; singular and overflowing outputs raise ValueError.
|
|
50
|
+
"""
|
|
51
|
+
x = quantity("x", x)
|
|
52
|
+
depth = quantity("depth", depth)
|
|
53
|
+
radius = quantity("radius", radius, lower=0, strict_lower=True)
|
|
54
|
+
density_contrast = quantity("density_contrast", density_contrast)
|
|
55
|
+
distance_squared = x**2 + depth**2
|
|
56
|
+
require(distance_squared >= radius**2, "the observer must lie outside the sphere")
|
|
57
|
+
mass = 4 / 3 * np.pi * radius**3 * density_contrast
|
|
58
|
+
scale = G * mass / distance_squared**1.5
|
|
59
|
+
return np.stack(np.broadcast_arrays(-scale * x, scale * depth), axis=-1)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
@model
|
|
63
|
+
def bouguer_correction(density, thickness):
|
|
64
|
+
"""Attraction of an infinite horizontal slab.
|
|
65
|
+
|
|
66
|
+
Rock between the station and the reference level adds gravity that does not depend on the slab's extent.
|
|
67
|
+
|
|
68
|
+
Parameters
|
|
69
|
+
----------
|
|
70
|
+
density : float or array_like
|
|
71
|
+
kg/m^3; constraint: positive.
|
|
72
|
+
thickness : float or array_like
|
|
73
|
+
m; constraint: real. Signed station height above the reference level.
|
|
74
|
+
|
|
75
|
+
Returns
|
|
76
|
+
-------
|
|
77
|
+
numpy scalar or ndarray
|
|
78
|
+
Model value [m/s^2]. Scalar input returns a NumPy scalar; arrays broadcast.
|
|
79
|
+
|
|
80
|
+
Notes
|
|
81
|
+
-----
|
|
82
|
+
Flat, uniform, laterally infinite slab; no terrain or curvature correction. About 0.112 mGal per metre at
|
|
83
|
+
2670 kg/m^3.
|
|
84
|
+
Equation: ``2 * np.pi * G * density * thickness``.
|
|
85
|
+
Invalid, empty, nonreal or nonfinite inputs raise ValueError.
|
|
86
|
+
NumPy broadcasting applies; singular and overflowing outputs raise ValueError.
|
|
87
|
+
"""
|
|
88
|
+
density = quantity("density", density, lower=0, strict_lower=True)
|
|
89
|
+
thickness = quantity("thickness", thickness)
|
|
90
|
+
return 2 * np.pi * G * density * thickness
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
@model
|
|
94
|
+
def free_air_correction(height, gravity, radius):
|
|
95
|
+
"""Free-air gravity correction.
|
|
96
|
+
|
|
97
|
+
Gravity falls off with distance from the Earth's centre, about 0.3086 mGal per metre at the surface.
|
|
98
|
+
|
|
99
|
+
Parameters
|
|
100
|
+
----------
|
|
101
|
+
height : float or array_like
|
|
102
|
+
m; constraint: real. Station height above the reference surface.
|
|
103
|
+
gravity : float or array_like
|
|
104
|
+
m/s^2; constraint: positive. Gravity on the reference surface.
|
|
105
|
+
radius : float or array_like
|
|
106
|
+
m; constraint: positive.
|
|
107
|
+
|
|
108
|
+
Returns
|
|
109
|
+
-------
|
|
110
|
+
numpy scalar or ndarray
|
|
111
|
+
Model value [m/s^2]: the amount to add to gravity observed at ``height``.
|
|
112
|
+
|
|
113
|
+
Notes
|
|
114
|
+
-----
|
|
115
|
+
First order in height / radius for a spherical point-mass Earth; no rock between station and reference.
|
|
116
|
+
Equation: ``2 * gravity * height / radius``.
|
|
117
|
+
Invalid, empty, nonreal or nonfinite inputs raise ValueError.
|
|
118
|
+
NumPy broadcasting applies; singular and overflowing outputs raise ValueError.
|
|
119
|
+
"""
|
|
120
|
+
height = quantity("height", height)
|
|
121
|
+
gravity = quantity("gravity", gravity, lower=0, strict_lower=True)
|
|
122
|
+
radius = quantity("radius", radius, lower=0, strict_lower=True)
|
|
123
|
+
return 2 * gravity * height / radius
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
@model
|
|
127
|
+
def bouguer_anomaly(observed_gravity, normal_gravity, height, density, radius):
|
|
128
|
+
"""Simple Bouguer gravity anomaly.
|
|
129
|
+
|
|
130
|
+
Removing latitude, height and the rock slab under a station leaves the attraction of buried density contrasts.
|
|
131
|
+
|
|
132
|
+
Parameters
|
|
133
|
+
----------
|
|
134
|
+
observed_gravity : float or array_like
|
|
135
|
+
m/s^2; constraint: positive.
|
|
136
|
+
normal_gravity : float or array_like
|
|
137
|
+
m/s^2; constraint: positive. Normal gravity on the reference surface at the station's latitude.
|
|
138
|
+
height : float or array_like
|
|
139
|
+
m; constraint: real. Station height above the reference surface.
|
|
140
|
+
density : float or array_like
|
|
141
|
+
kg/m^3; constraint: positive. Reduction density of the slab.
|
|
142
|
+
radius : float or array_like
|
|
143
|
+
m; constraint: positive.
|
|
144
|
+
|
|
145
|
+
Returns
|
|
146
|
+
-------
|
|
147
|
+
numpy scalar or ndarray
|
|
148
|
+
Model value [m/s^2]. Scalar input returns a NumPy scalar; arrays broadcast.
|
|
149
|
+
|
|
150
|
+
Notes
|
|
151
|
+
-----
|
|
152
|
+
Free-air and infinite-slab reductions only, without terrain correction. The free-air anomaly is the same
|
|
153
|
+
expression without the slab term.
|
|
154
|
+
Equation: ``observed_gravity - normal_gravity + 2 * normal_gravity * height / radius - 2 * np.pi * G * density * height``.
|
|
155
|
+
Invalid, empty, nonreal or nonfinite inputs raise ValueError.
|
|
156
|
+
NumPy broadcasting applies; singular and overflowing outputs raise ValueError.
|
|
157
|
+
"""
|
|
158
|
+
observed_gravity = quantity("observed_gravity", observed_gravity, lower=0, strict_lower=True)
|
|
159
|
+
normal_gravity = quantity("normal_gravity", normal_gravity, lower=0, strict_lower=True)
|
|
160
|
+
height = quantity("height", height)
|
|
161
|
+
density = quantity("density", density, lower=0, strict_lower=True)
|
|
162
|
+
radius = quantity("radius", radius, lower=0, strict_lower=True)
|
|
163
|
+
return observed_gravity - normal_gravity + 2 * normal_gravity * height / radius - 2 * np.pi * G * density * height
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
@model
|
|
167
|
+
def torsion_balance_gravitational_constant(arm_length, separation, deflection, attracting_mass, period):
|
|
168
|
+
"""Gravitational constant from a torsion balance.
|
|
169
|
+
|
|
170
|
+
The twist of a suspended rod between large masses, timed by its free swing, measures G.
|
|
171
|
+
|
|
172
|
+
Parameters
|
|
173
|
+
----------
|
|
174
|
+
arm_length : float or array_like
|
|
175
|
+
m; constraint: positive. Distance between the two small balls.
|
|
176
|
+
separation : float or array_like
|
|
177
|
+
m; constraint: positive. Centre distance between each small ball and its large ball.
|
|
178
|
+
deflection : float or array_like
|
|
179
|
+
rad; constraint: positive. Equilibrium twist of the rod.
|
|
180
|
+
attracting_mass : float or array_like
|
|
181
|
+
kg; constraint: positive. Mass of each large ball.
|
|
182
|
+
period : float or array_like
|
|
183
|
+
s; constraint: positive. Free oscillation period of the rod.
|
|
184
|
+
|
|
185
|
+
Returns
|
|
186
|
+
-------
|
|
187
|
+
numpy scalar or ndarray
|
|
188
|
+
Model value [m^3/(kg s^2)]. Scalar input returns a NumPy scalar; arrays broadcast.
|
|
189
|
+
|
|
190
|
+
Notes
|
|
191
|
+
-----
|
|
192
|
+
Point masses, a massless rod and attraction by the near large ball only; the small mass cancels.
|
|
193
|
+
Equation: ``2 * np.pi**2 * arm_length * separation**2 * deflection / (attracting_mass * period**2)``.
|
|
194
|
+
Invalid, empty, nonreal or nonfinite inputs raise ValueError.
|
|
195
|
+
NumPy broadcasting applies; singular and overflowing outputs raise ValueError.
|
|
196
|
+
"""
|
|
197
|
+
arm_length = quantity("arm_length", arm_length, lower=0, strict_lower=True)
|
|
198
|
+
separation = quantity("separation", separation, lower=0, strict_lower=True)
|
|
199
|
+
deflection = quantity("deflection", deflection, lower=0, strict_lower=True)
|
|
200
|
+
attracting_mass = quantity("attracting_mass", attracting_mass, lower=0, strict_lower=True)
|
|
201
|
+
period = quantity("period", period, lower=0, strict_lower=True)
|
|
202
|
+
return 2 * np.pi**2 * arm_length * separation**2 * deflection / (attracting_mass * period**2)
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
@model
|
|
206
|
+
def earth_mean_density(gravity, radius, gravitational_constant=G):
|
|
207
|
+
"""Mean density of the Earth.
|
|
208
|
+
|
|
209
|
+
Surface gravity and the gravitational constant together weigh the Earth.
|
|
210
|
+
|
|
211
|
+
Parameters
|
|
212
|
+
----------
|
|
213
|
+
gravity : float or array_like
|
|
214
|
+
m/s^2; constraint: positive.
|
|
215
|
+
radius : float or array_like
|
|
216
|
+
m; constraint: positive.
|
|
217
|
+
gravitational_constant : float or array_like
|
|
218
|
+
m^3/(kg s^2); constraint: positive. Defaults to :data:`earthsciencekit.constants.G`.
|
|
219
|
+
|
|
220
|
+
Returns
|
|
221
|
+
-------
|
|
222
|
+
numpy scalar or ndarray
|
|
223
|
+
Model value [kg/m^3]. Scalar input returns a NumPy scalar; arrays broadcast.
|
|
224
|
+
|
|
225
|
+
Notes
|
|
226
|
+
-----
|
|
227
|
+
Spherically symmetric, nonrotating Earth, so ``gravity = G M / radius**2``.
|
|
228
|
+
Equation: ``3 * gravity / (4 * np.pi * gravitational_constant * radius)``.
|
|
229
|
+
Invalid, empty, nonreal or nonfinite inputs raise ValueError.
|
|
230
|
+
NumPy broadcasting applies; singular and overflowing outputs raise ValueError.
|
|
231
|
+
"""
|
|
232
|
+
gravity = quantity("gravity", gravity, lower=0, strict_lower=True)
|
|
233
|
+
radius = quantity("radius", radius, lower=0, strict_lower=True)
|
|
234
|
+
gravitational_constant = quantity("gravitational_constant", gravitational_constant, lower=0, strict_lower=True)
|
|
235
|
+
return 3 * gravity / (4 * np.pi * gravitational_constant * radius)
|