Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions crates/geopotential/src/coefficients.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,21 @@ pub enum TideSystem {
TideFree,
/// Includes the permanent deformation (indirect) part, not the direct tidal potential.
ZeroTide,
/// Includes both the direct and the indirect permanent parts.
/// Includes both the direct and the indirect permanent parts. The direct part, the tide-generating
/// potential itself, then sits in the Earth's own field, falling as `r⁻³` where it grows as `r²`:
/// right on the sphere `r = R` only ("there is no mean-tide C̄20", Mäkinen 2021, J. Geod. 95,
/// 106). Its gravity is +45.7 µGal at the equator against the true −30.5; take mean-tide gravity
/// from `gravimetry::tides::permanent`.
MeanTide,
/// Not stated; cannot be converted.
Unknown,
}

impl TideSystem {
/// `C̄20` in this system minus `C̄20` tide-free. Uses the EGM96/EGM2008 convention
/// `ΔC̄20 = −3.11080e-8·k/√5` with `k = 0.3` (Rapp 1989), which gives the IERS 2010 value
/// −4.1736e-9 for zero-tide minus tide-free.
/// `ΔC̄20 = −3.11080e-8·k/√5` with `k = 0.3` (Rapp 1989), which gives −4.1736e-9 for zero-tide
/// minus tide-free, the value the IERS Conventions 2010 quote for EGM2008 (their own
/// `A₀H₀k₂₀`, Eq. 6.14 with `k₂₀ = 0.30190`, gives −4.2007e-9).
fn c20_offset(self) -> Option<f64> {
let direct = -3.11080e-8 / 5f64.sqrt();
let k = 0.3;
Expand Down
6 changes: 6 additions & 0 deletions crates/gravimetry/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ maximum likelihood over many series at once.
| `atom` | Phase, shot noise, and accelerometer and gradiometer noise of a cold-atom sensor, in orbit (double diffraction) or on the ground (single), its phase sensitivity and the gravitational Aharonov–Bohm rate ([Lévèque et al. 2021](https://arxiv.org/abs/2011.03382); [Stray et al. 2022](https://doi.org/10.1038/s41586-021-04315-3); [CARIOQA](https://arxiv.org/abs/2211.01215); [Trimeche et al. 2019](https://doi.org/10.1088/1361-6382/ab4548)) |
| `gradiometry` | The error of each coefficient a gradiometer mission like GOCE achieves |
| `local` | Gravity and gravity gradient of a buried sphere and horizontal cylinder, the shapes a ground survey fits, and the averaging time an instrument needs to see them |
| `tides` | The lunar and solar tide at a gravimeter, the gravimetric and diminishing factors of the Love numbers, and the permanent tide that separates mean-tide, zero-tide and tide-free gravity and geoids ([Longman 1959](https://doi.org/10.1029/JZ064i012p02351), as [LongmanTide](https://github.com/jrleeman/LongmanTide) codes it; [Mäkinen 2021](https://doi.org/10.1007/s00190-021-01541-5)) |
| `sim` | A closed-loop simulation of a GRACE-type pair: simulate, estimate the field back, and compare its errors with the predicted ones |
| `noise` | Noise with any spectrum, its whitening, and the FFT |
| `technotes` | NASA's TN-14 (C̄20 and C̄30 from laser ranging, [Loomis et al. 2020](https://doi.org/10.1029/2019GL085488)) and TN-13 (degree 1, [Sun et al. 2016](https://doi.org/10.1002/2016JB013073)), from [PO.DAAC](https://archive.podaac.earthdata.nasa.gov/podaac-ops-cumulus-docs/gracefo/open/docs/) |
Expand Down Expand Up @@ -161,6 +162,8 @@ errors of a real month.*
files; `prompt_lead` gives how far ahead of the P-wave a light-speed gravity signal arrives.
- **Site surveys and monitoring.** `local` gives the gravity and gradient of a buried void or
dense body, and the averaging time a quantum gravimeter needs to resolve it.
- **Absolute gravimetry.** `tides` corrects a reading for the lunar and solar tide and moves it
between the zero-tide convention of gravity and the mean-tide convention of the IHRS.
- **Mission design.** `missions`, `atom` and `sim` size the sensors and simulate what field a
satellite pair recovers, including cold-atom instruments.

Expand All @@ -179,6 +182,9 @@ errors of a real month.*
equivalent mass sums to zero); on the 2025 Kamchatka fault model, its uplift matches the
USGS's own surface displacement with r = 0.89.
- **Point masses:** their potential matches Newton's law.
- **Tides:** LongmanTide's test vector to 3×10⁻¹¹ mGal; averaged over the 18.61-year nodal cycle,
Longman's tide is δ₂ times the permanent tide to 0.2 µGal; the permanent tide matches Mäkinen's
(2021) Eqs. 19–21 to their printed digits.
- **Kalman smoother:** it matches the exact Gaussian-process solution to 1e-10, its fit
recovers the settings of simulated data, and on the real record withheld months are predicted
with calibrated errors.
Expand Down
33 changes: 27 additions & 6 deletions crates/gravimetry/examples/buried_tunnel.rs
Original file line number Diff line number Diff line change
@@ -1,30 +1,51 @@
//! Finding a void from the surface: the gravity and gradient of a buried tunnel, and how long a
//! quantum gravimeter must average to see it. The geometry is the Birmingham survey's
//! ([Stray et al. 2022](https://doi.org/10.1038/s41586-021-04315-3)), which found a tunnel at
//! about 1.9 m depth.
//! quantum gravimeter or gradiometer must average to see it. The geometry and the gradiometer are
//! the Birmingham survey's ([Stray et al. 2022](https://doi.org/10.1038/s41586-021-04315-3)),
//! which found a tunnel at about 1.9 m depth.
//!
//! ```text
//! cargo run -p gravimetry --example buried_tunnel
//! ```

use gravimetry::atom::AtomInterferometer;
use gravimetry::local::{EOTVOS, MICROGAL, averaging_time, cylinder};

fn main() {
let (radius, depth, contrast) = (1.0, 1.9, -2000.0); // an air-filled tunnel in soil
println!("{:>8} {:>12} {:>12}", "offset/m", "Δg/µGal", "Γuu/E");

// Stray et al.'s gradiometer: two single-diffraction interferometers 1 m apart vertically,
// T = 85 ms, 10⁵ atoms at 0.7 Hz. It reads the difference in gravity between its sensors.
let stray = AtomInterferometer { t: 0.085, contrast: 1.0, atoms: 1e5, cycle: 1.0 / 0.7, diffraction: 1 };
let baseline = 1.0;
let difference = |offset: f64| (cylinder(radius, depth, contrast, offset).0 - cylinder(radius, depth + baseline, contrast, offset).0) / baseline;

println!("{:>8} {:>10} {:>10} {:>12} {:>12}", "offset/m", "Δg/µGal", "Γuu/E", "Δg/1 m in E", "phase/mrad");
for offset in [0.0, 1.0, 2.0, 3.0, 5.0] {
let (gz, gradient) = cylinder(radius, depth, contrast, offset);
println!("{offset:>8.1} {:>12.1} {:>12.1}", gz / MICROGAL, gradient / EOTVOS);
let d = difference(offset);
println!("{offset:>8.1} {:>10.1} {:>10.1} {:>12.1} {:>12.2}", gz / MICROGAL, gradient / EOTVOS, d / EOTVOS, stray.phase(d * baseline) * 1e3);
}
let (peak, _) = cylinder(radius, depth, contrast, 0.0);
println!("peak anomaly {:.0} µGal", peak / MICROGAL);

// An Exail-class gravimeter at 500 nm/s²/√Hz needs this long per station for a 10:1 signal.
let target = peak.abs() / 10.0;
println!("to resolve it 10:1 ({:.0} nm/s²): {:.0} s per station", target * 1e9, averaging_time(500e-9, target));
println!("gravimeter, to resolve it 10:1 ({:.0} nm/s²): {:.0} s per station", target * 1e9, averaging_time(500e-9, target));

// The gradiometer at its projection limit, and at the 466 E/√Hz it reached outdoors.
let target = difference(0.0).abs() / 10.0;
for (what, asd) in [("projection limit", stray.gradient_asd(baseline)), ("outdoors", 466.0 * EOTVOS)] {
println!("gradiometer, {what} {:.0} E/√Hz: {:.0} s per station", asd / EOTVOS, averaging_time(asd, target));
}

assert!((peak / MICROGAL + 44.1).abs() < 0.1);
// The gradient changes sign away from the tunnel, which is what localises it.
assert!(cylinder(radius, depth, contrast, 0.0).1 < 0.0 && cylinder(radius, depth, contrast, 3.0).1 > 0.0);
// Over a line mass the difference across the baseline is the point gradient at the geometric
// mean of the two depths, 2Gλ/(z₁z₂): about Stray et al.'s 150 E and 17.5 mrad.
let mid = cylinder(radius, (depth * (depth + baseline)).sqrt(), contrast, 0.0).1;
assert!((difference(0.0) / mid - 1.0).abs() < 1e-12);
assert!((difference(0.0) / EOTVOS + 152.2).abs() < 0.1 && (stray.phase(difference(0.0)) * 1e3 + 17.7).abs() < 0.1);
}

#[test]
Expand Down
1 change: 1 addition & 0 deletions crates/gravimetry/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ pub mod missions;
pub mod noise;
pub mod sim;
pub mod technotes;
pub mod tides;

/// Area of the world ocean, m²: 3.618×10⁸ km², so 361.8 Gt of water raise sea level 1 mm.
pub const OCEAN_AREA: f64 = 3.618e14;
Expand Down
Loading