Skip to content
MohammadAmin-AminianPublic

About

This repository houses the ComPy software suite, designed specifically for advanced processing and analysis of ocean bottom seismological data. ComPy facilitates robust calculations and inversions of compliance functions, a critical tool for mapping subsurface shear velocity structures with precision. The software is equipped to handle complex data

Topics

Resources

Contributing

Stars

5 stars

Watchers

1 watching

Forks

Latest commit

 

History

256 Commits

Folders and files

Repository files navigation

ComPy logo

ComPy

Seafloor compliance, pressure-gauge calibration and Bayesian shear-velocity inversion for broadband ocean-bottom seismometers.

Tests DOI GJI 2025 Python 3.10–3.13 License GPL-3.0 ORCID

ComPy turns raw ocean-bottom seismometer (OBS) and differential pressure gauge (DPG) records into crustal shear-velocity models. It covers the full chain: data cleaning, tilt and coherent-noise removal, Rayleigh-wave pressure calibration, stacked compliance estimation and Bayesian inversion for Vs and serpentinization. It was developed for the RHUM-RUM experiment in the Indian Ocean (Aminian et al. 2025, GJI) and runs unattended on any broadband OBS network stored as an SDS archive.

Contents

Highlights

  • End-to-end pipeline. One command takes an SDS archive and StationXML to compliance, Vs models, figures and a report (pipeline/run_pipeline.py).
  • Stacked compliance with full error budget. Cross-spectra stacked over non-overlapping windows, gravity and wave-attraction corrections, Bendat & Piersol errors and monthly stacks for the covariance.
  • Rayleigh-wave DPG calibration. Per-event gains from teleseismic Rayleigh waves, cross-checked against microseism and local-P estimates (compy_pressure).
  • Vs inversion that says what it resolves. One command (compy-invert) from a compliance curve to Vs with credible intervals: errors measured from the station's own windows, a prior about a reference model, Vp, density, Moho depth and pressure gain uncertain, sampling repeated until it converges, and each depth marked as resolved by the data or not (docs/INVERSION.md).
  • Two networks processed. RHUM-RUM (YV, 8 stations, Indian Ocean) and Pacific Array Young ORCA (XE, 30 stations, Pacific).
  • Tested. CI on Python 3.10–3.13 with lint, format, wheel build and an offline multi-chain benchmark.

Method

Long-period seafloor pressure from infragravity waves deforms the crust. The normalized compliance is the vertical displacement per unit pressure, scaled by the water-wave wavenumber:

$$ \eta(\omega) = k(\omega),\frac{\left|S_{pz}(\omega)\right|}{S_{pp}(\omega)}, \qquad \omega^2 = g,k,\tanh(kH), $$

where $S_{pz}$ and $S_{pp}$ are the pressure–displacement cross-spectrum and the pressure auto-spectrum stacked over the selected windows, and $H$ is the water depth. Low frequencies sense deeper structure, down to about one sixth of the longest water wavelength. ComPy inverts η(ω) for a layered Vs model with a propagator-matrix forward solver.

Installation

Python 3.10 or later. With conda (recommended, for Numba):

git clone https://github.com/MohammadAmin-Aminian/ComPy.git
cd ComPy
conda env create -f environment.yml
conda activate compy

or with pip:

python -m venv .venv && source .venv/bin/activate
python -m pip install -e '.[dev,pressure,fast]'
python -m pytest -q

The distribution is seafloor-compy; it installs the compy package and the compy_pressure package. The ComPy 2.x module names (inv_compy, ffplot, compy_processing, ...) still import, with a deprecation warning that names the new location. Dependencies: NumPy, SciPy, Matplotlib, ObsPy, TiSKitPy 2.3 and disba; Numba is optional and speeds up the inversion about 140×.

Quick start

Offline synthetic inversion (seconds):

MPLBACKEND=Agg python examples/synthetic_inversion.py

A full network run from an SDS archive:

export COMPY_RUN_DIR=~/runs/xe          # metadata/, work/, results/, logs/
python pipeline/run_pipeline.py CC11 CC05 --workers 8 --processes 8 --fetch

The pipeline runs stages A → G (preprocessing, cleaning, calibration, compliance, inversion, figures, report) with checkpoints and a JSON run manifest. All network-specific values live in pipeline/config.py; see the pipeline guide.

Workflow, step by step

The figures follow one station through the whole pipeline: XE.CC11 (Pacific Array Young ORCA, 7.54°S 133.42°W, 4636 m water depth, April 2018 – May 2019). Steps 1 and 8 place it within the XE network.

Step Stage What it does
1. Network and data A Read waveforms and StationXML responses
2. Response removal and cleaning A, B Decimate, remove responses, drop clipped data, mask earthquakes
3. Tilt and coherent noise B Remove tilt and horizontal-coherent noise from Z
4. Pressure-gauge calibration D Rayleigh-wave gain of the DPG
5. Coherence and window selection C Select windows with high Z–P coherence
6. Compliance C Stacked compliance with errors and monthly stacks
7. Bayesian Vs inversion E Multi-chain inversion for Vs, Vp/Vs and gain
8. Vs profiles and serpentinization F Station values and network profiles

1. Network and data

Waveforms are read from an SDS archive with their full StationXML responses; response epochs, units, timing and gaps are checked per station. XE has 30 Scripps broadband OBS (Trillium 240 + DPG, 50 Hz) at 4386–4824 m water depth on ~40 Ma Pacific seafloor. CC11 is in the central (CC) line.

python pipeline/fetch_inventory.py && python pipeline/fetch_catalog.py
python pipeline/a_preprocess.py CC11 --workers 8

XE broadband OBS network map with compliance status

XE network. Red: inverted (20 stations, including CC11); orange: compliance only; grey: not processed.

2. Response removal and cleaning

Each channel is decimated with an anti-alias filter and the instrument response is removed with an explicit pre-filter: acceleration or displacement for the seismometer, pascals for the DPG. Ten-minute blocks containing a clipped or flat sample are removed from all channels. Earthquakes are masked from the global catalogue with TiSKitPy, and STA/LTA picks local events. No hourly glitches were found on XE (fold strength below 2.0), so glitch removal is off for this network.

import tiskitpy

spans = tiskitpy.TimeSpans.from_eqs(
    (z.stats.starttime, z.stats.endtime),
    minmag=5.5,
    days_per_magnitude=0.5,
    save_eq_file=False,
)

CC11 vertical and pressure PSDs before and after cleaning

XE.CC11 spectra. (a) Vertical acceleration after response removal (blue) and after cleaning (orange), median and 10–90 %, with the Peterson noise models. (b) Calibrated pressure. Green: compliance band.

3. Tilt and coherent noise

Hourly tilt angles from TiSKitPy's CleanRotator are median-smoothed and interpolated per sample. Horizontal-coherent noise is then removed from the vertical only, in 24-h windows that avoid the earthquake spans.

import compy
from compy import cleaning

rotated = cleaning.rotate_smoothly(st, hour_centres, angles, azimuths)
local = cleaning.sta_lta_spans(rotated.select(component="Z")[0])
cleaned = compy.remove_coherent_noise(rotated, 24, avoid_spans=spans, cover_all=True)

CC11 hourly tilt azimuth and incidence angle

XE.CC11 tilt. Hourly azimuth and incidence angle that minimize vertical variance, coloured by variance reduction.

4. Pressure-gauge calibration

The DPG gain is fitted per teleseism by comparing the measured pressure-to-acceleration ratio of the Rayleigh wave with the water-layer prediction, in bins of high coherence. The station gain is the median of the accepted events. For CC11 it is 0.698 ± 0.012 from 12 events, against 0.702 from the independent BRUIT-FM microseism method.

python examples/3_DPG_Calibration.py SDS/ stationxml/ XE CC11 events.geojson

CC11 Rayleigh-wave DPG calibration

XE.CC11 calibration. (a) P–Z coherence of 12 teleseisms (M ≥ 7). (b) Measured, theoretical and corrected spectral ratios; gain g = 0.698 ± 0.012.

5. Coherence and window selection

The cleaned record is cut into non-overlapping 35-min windows. A window is kept when its median Z–P coherence in the compliance band exceeds 0.9 and its pressure and acceleration levels lie inside the selection gates. CC11 keeps 7314 windows over 14 months.

CC11 pressure and vertical spectrograms and Z–P coherogram

XE.CC11, February 2019. Pressure and vertical spectrograms and the Z–P coherogram; dashed lines bound the compliance band.

6. Compliance

Compliance comes from cross-spectra stacked over all selected windows, with the gravity and wave-attraction corrections and the Bendat & Piersol error. Monthly stacks give the data covariance and track changes in time. For CC11 the band is 4.9–14.6 mHz, the mean coherence 0.97, and the monthly stacks stay within −0.9 % and +1.2 % of the full stack.

from compy.compliance import GJI2025, stacked_compliance

pair = cleaned.select(channel="BHZ") + cleaned.select(channel="BDH")
windows = compy.split_stream(pair, 2100)  # 35-min windows
result = stacked_compliance(
    windows, 4636, 0.698, band=(0.0049, 0.0146), criteria=GJI2025, nseg=1024
)
result.compliance, result.uncertainty, result.n_windows

CC11 selected windows: spectra, coherence and compliance

XE.CC11 selected windows (150 of 7314 shown): corrected vertical acceleration, calibrated pressure, coherence and per-window compliance with the stacked estimate (red).

7. Vs inversion

Since ComPy 3 the default is compy.inversion.auto (docs/INVERSION.md; tests in docs/inversion_overhaul_2026-11/REPORT.md). Compliance measures stiffness, so Vs follows only with Vp and density: both are tied to Vs by rock relations with sampled factors. A soft-sediment unit, crustal layers that double in thickness, a free Moho depth and a mantle half-space are sampled with a prior about the CRUST1.0 model of the station (or a model you give). Errors come from the bootstrap of the station's own windows plus terms for the slope and level of the curve. Eight chains with parallel tempering run until they converge.

compy-invert CC11_compliance_compy.npz --lat -7.5368 --lon -133.4166 --crust1 ~/crust1 --fetch-crust1
from compy.inversion import auto, dram

model = auto.model_from_crust1(dram.crust1_column(-7.5368, -133.4166, "crust1"))
result = auto.invert(data, model, gain_sigma=0.05)  # data: auto.compliance_data(...)
result.quality(), result.profile()  # label with reasons; Vs, prior, resolved depths

CC11: data and fit, residuals, Vs with prior and reference, and what the data constrain

XE.CC11 with ComPy 3. Data and fit, residuals in units of the error, Vs with its prior and the reference, and how much the data narrowed each parameter. The black bar marks the depths the data resolve.

8. Vs profiles and serpentinization

The numbers and figures of this section and of the Results below were made with ComPy 2.4 to 2.8. ComPy 3 changes Vs (by about +6 % at 2 km and +11 % at 5 km in the median over 155 stations, more at the YV stations) and the sediment thickness; see docs/inversion_overhaul_2026-11/REPORT.md. They are kept as the record of those runs.

Posterior draws are converted to serpentinization with the Miller & Christensen (1997) relation used in Aminian et al. (2025, Fig. 10c): 0 % at 4.2 km/s and 100 % at 2.2 km/s. The conversion attributes all of the Vs reduction to serpentinization, so it gives an upper bound.

beta_q = post.serpentinization_quantiles(z)  # (5 quantiles, len(z)) in %

XE.CC11, median (5–95 %):

Depth Vs [m/s] Serpentinization upper bound [%]
0.5 km 2530 (1942–3428) 84 (39–100)
1 km 2848 (2387–3369) 68 (42–91)
2 km 3168 (2890–3482) 52 (36–66)
4 km 3496 (3261–3976) 35 (11–47)

Sediment thickness 121 m (20–182), crustal Vp/Vs 2.17 (1.88–2.37).

XE Vs profiles by sub-array and pooled posterior

XE network. (a) Median Vs by sub-array (CC11 in Central). (b) Pooled posterior with free Vp/Vs and with Vp/Vs = 1.85. (c) Serpentinization upper bound.

Results

Pacific Array Young ORCA (XE), Pacific Ocean

30 stations on ~40 Ma seafloor, 20 inverted, 18 with a Rayleigh-wave gain.

  • Compliance at 4.9–14.6 mHz with Z–P coherence 0.93–0.97 and thousands of windows per station; month-to-month variation of 1–3 % (CC07: ±10–25 %).
  • 80–170 m of sediment, then Vs of about 2.4 km/s at 0.3 km, 2.9 km/s at 1 km and 3.2 km/s at 2 km.
  • Rayleigh-wave gains agree with the independent BRUIT-FM microseism gains (median ratio ≈ 0.99).

Normalized compliance of the XE stations by sub-array

XE compliance by sub-array, ±1σ of the full covariance.

Full report (PDF, LaTeX source and tables): docs/results/xe_young_orca_2026-10-29.

RHUM-RUM (YV), Indian Ocean

Eight broadband stations, 2012–2013, the network of Aminian et al. (2025). Final inversion: free Vp/Vs, gain sampled, stable and post-jump epochs inverted together. Vs in m/s, median (5–95 %).

Station Setting χ²/N R-hat Sediment [m] Vs 0.5 km Vs 1 km Vs 2 km
RR28 Somali plate 2.9/6 1.012 311 (138–398) 2157 (1450–3760) 2789 (2150–3725) 3421 (2910–3931)
RR29 Somali plate 2.9/5 1.005 91 (15–139) 3186 (2333–4252) 3426 (2709–4217) 3678 (3106–4218)
RR34 Somali plate 2.4/6 1.008 219 (50–309) 2258 (1723–3727) 2811 (2203–3560) 3185 (2757–3686)
RR36 SWIR 6.8/16 1.017 72 (10–143) 2236 (1756–3320) 2578 (2082–3094) 3090 (2740–3594)
RR38 SWIR 33.0/12 1.015 224 (138–251) 3062 (2307–4369) 3722 (3025–4402) 4058 (3697–4471)
RR40 SWIR 4.2/10 1.009 164 (40–219) 2964 (2092–4165) 3269 (2581–3978) 3556 (3078–3994)
RR50 Rodrigues TJ 5.7/12 1.005 80 (14–112) 3389 (2502–4346) 3672 (2980–4363) 3964 (3495–4429)
RR52 CIR 3.3/9 1.007 46 (6–81) 2823 (2332–3632) 3193 (2779–3672) 3590 (3283–4013)

RR38's pressure channel changes behaviour after its sensitivity jump, so RR38 is excluded from the interpretation. Figures, variants and full tables: docs/results/yv_inversion_2026-10-29 and docs/results/yv_compliance_2026-10-28.

Repository structure

ComPy/
├── compy/                   # the package
│   ├── streams.py           #   window splitting and stream checks
│   ├── cleaning.py          #   smooth tilt rotation, periodic transients, STA/LTA spans
│   ├── preprocessing.py     #   tilt correction, coherent-noise removal
│   ├── compliance.py        #   spectra, window selection, stacked compliance, errors
│   ├── inversion/           #   Vs inversion
│   │   ├── auto.py          #     default inversion (ComPy 3): invert, SeafloorModel, compy-invert
│   │   ├── errors.py        #     covariance of a stacked compliance curve from its windows
│   │   ├── dram.py          #     DRAM sampler, forward model, CRUST1.0, the 2.x model, serpentinization
│   │   ├── metropolis.py    #     Metropolis sampler of the GJI paper, tempering
│   │   ├── occam.py         #     Occam smooth-model inversion
│   │   ├── minimum_structure.py  # minimum-structure inversion after Crawford (2004)
│   │   ├── literature_mcmc.py    # Monte Carlo with Zha & Webb (2016), Zheng et al. (2024)
│   │   ├── impedance.py     #     independent forward model (surface impedance)
│   │   ├── propagator.py    #     forward model (Crawford's raydep) and kernels
│   │   └── models.py        #     starting and reference models
│   ├── diagnostics.py       #   R-hat, ESS, reproducible run records
│   ├── plotting/            #   style, spectra, inversion and QC figures
│   └── numerics.py          #   constants, gravity-wave dispersion, shared maths
├── inv_compy.py, ffplot.py, compy_*.py   # ComPy 2.x names (deprecated aliases)
├── compy_pressure/          # DPG QC, Rayleigh/microseism/local-P calibration, noise models
├── pipeline/                # end-to-end network pipeline (stages A–G)
├── examples/                # offline synthetic examples and per-step scripts
├── tests/                   # pytest suite
├── docs/
│   ├── USER_GUIDE.md        # API reference
│   ├── INVERSION.md, PRESSURE.md, VALIDATION.md, ...
│   ├── images/              # logos and figures used by the documentation
│   ├── benchmark/           # CI inversion benchmark record
│   └── results/             # processed networks: scripts, figures, tables
│       ├── xe_young_orca_2026-10-29/
│       ├── yv_compliance_2026-10-28/
│       └── yv_inversion_2026-10-29/
└── pressure/                # pressure-gauge campaign scripts, method notes and tests

Documentation

Document Content
Documentation index All guides, method notes and results
User guide Input conventions, estimators, inversion API, pressure QC, plotting
Pipeline guide Running a whole network, stages and configuration
Examples Offline synthetic examples and per-step scripts
Inversion notes Parameterization, sampler and validation
Alternative inversions The Moho rule, published Monte Carlo setups, Crawford's minimum-structure inversion
Pressure tools compy_pressure commands and outputs
Validation Test coverage and scientific references
Changelog Release history

Citation

If you use ComPy, please cite the article and the software version you used (CITATION.cff, Zenodo).

@article{aminian2025shallow,
  author  = {Aminian, Mohammad Amin and Crawford, Wayne and Stutzmann, Éléonore
             and Montagner, Jean-Paul and Cannat, Mathilde and Hadziioannou, Céline},
  title   = {Shallow crustal structures of the Indian ocean derived from compliance function analysis},
  journal = {Geophysical Journal International},
  year    = {2025},
  volume  = {242},
  number  = {3},
  pages   = {ggaf253},
  doi     = {10.1093/gji/ggaf253}
}

License and acknowledgments

ComPy is released under the GPL-3.0. Contributions are welcome; see CONTRIBUTING.md.

Author: Mohammad-Amin Aminian · LinkedIn · Research software portfolio

Developed at the Institut de Physique du Globe de Paris with support from the SPIN Innovative Training Network, funded by the European Commission under Horizon 2020 Marie Skłodowska-Curie Actions.

Horizon 2020 acknowledgment IPGP and Université Paris Cité

Related software

About

This repository houses the ComPy software suite, designed specifically for advanced processing and analysis of ocean bottom seismological data. ComPy facilitates robust calculations and inversions of compliance functions, a critical tool for mapping subsurface shear velocity structures with precision. The software is equipped to handle complex data

Topics

Resources

Contributing

Stars

5 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages