SeisAug 0.2.0__tar.gz

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.
@@ -0,0 +1,2 @@
1
+ include README.md
2
+ include pyproject.toml
seisaug-0.2.0/PKG-INFO ADDED
@@ -0,0 +1,206 @@
1
+ Metadata-Version: 2.4
2
+ Name: SeisAug
3
+ Version: 0.2.0
4
+ Summary: Seismic waveform augmentation, STEAD-format I/O, plotting, and batch processing utilities
5
+ Author: Pragnath
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/Pragnath/SeisAug
8
+ Project-URL: Repository, https://github.com/Pragnath/SeisAug
9
+ Project-URL: Issues, https://github.com/Pragnath/SeisAug/issues
10
+ Keywords: seismology,augmentation,obspy,earthquake,STEAD,machine-learning
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Science/Research
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3 :: Only
16
+ Classifier: Programming Language :: Python :: 3.9
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Topic :: Scientific/Engineering :: Physics
20
+ Requires-Python: >=3.9
21
+ Description-Content-Type: text/markdown
22
+ Requires-Dist: numpy>=1.23
23
+ Requires-Dist: scipy>=1.10
24
+ Requires-Dist: matplotlib>=3.6
25
+ Requires-Dist: obspy>=1.4
26
+ Requires-Dist: pandas>=1.5
27
+ Requires-Dist: h5py>=3.8
28
+ Requires-Dist: ipywidgets>=8.0
29
+ Requires-Dist: tqdm>=4.65
30
+ Requires-Dist: pyyaml>=6.0
31
+ Provides-Extra: dev
32
+ Requires-Dist: pytest>=7.0; extra == "dev"
33
+ Requires-Dist: build>=1.2.1; extra == "dev"
34
+ Requires-Dist: twine>=5.1.1; extra == "dev"
35
+
36
+ # SeisAug
37
+
38
+ SeisAug is a Python package for **seismic waveform augmentation**, **STEAD-format data handling**, **validation**, and **basic visualization** for earthquake machine-learning workflows.
39
+
40
+ It is designed for researchers working with waveform datasets such as STEAD and for users building training pipelines for phase picking, event detection, and waveform classification.
41
+
42
+ ## Features
43
+
44
+ - Add seismic waveform augmentations such as noise injection, spikes, and time shifts
45
+ - Validate STEAD-format HDF5 and CSV datasets
46
+ - Read and process three-component waveform traces
47
+ - Plot SNR distributions from STEAD metadata
48
+ - Build batch augmentation pipelines from YAML configuration files
49
+ - Use a command-line interface for augmentation, validation, and plotting
50
+
51
+ ## Installation
52
+
53
+ Install from PyPI:
54
+
55
+ ```bash
56
+ pip install SeisAug
57
+ ```
58
+
59
+ For development:
60
+
61
+ ```bash
62
+ git clone https://github.com/Pragnath/SeisAug.git
63
+ cd SeisAug
64
+ pip install -e .[dev]
65
+ ```
66
+
67
+ ## Command-Line Usage
68
+
69
+ After installation, the `seisaug` command is available.
70
+
71
+ ### Show help
72
+
73
+ ```bash
74
+ seisaug --help
75
+ ```
76
+
77
+ ### Batch augment a dataset
78
+
79
+ ```bash
80
+ seisaug batch \
81
+ --input_hdf5 data/input.hdf5 \
82
+ --input_csv data/input.csv \
83
+ --output_hdf5 data/output_aug.hdf5 \
84
+ --output_csv data/output_aug.csv \
85
+ --config examples/augment_config.yaml
86
+ ```
87
+
88
+ ### Validate a STEAD-format dataset
89
+
90
+ ```bash
91
+ seisaug validate \
92
+ --input_hdf5 data/output_aug.hdf5 \
93
+ --input_csv data/output_aug.csv
94
+ ```
95
+
96
+ ### Plot SNR distribution
97
+
98
+ ```bash
99
+ seisaug snr \
100
+ --input_csv data/output_aug.csv \
101
+ --output_png snr_distribution.png
102
+ ```
103
+
104
+ ### Plot an augmentation grid
105
+
106
+ ```bash
107
+ seisaug grid \
108
+ --input_hdf5 data/output_aug.hdf5 \
109
+ --trace_name trace_001 \
110
+ --augmented_names trace_001_aug1 trace_001_aug2 \
111
+ --output_png augmentation_grid.png
112
+ ```
113
+
114
+ ## Python Usage
115
+
116
+ ### Validate a dataset
117
+
118
+ ```python
119
+ from seisaug.validate import validate_stead_file
120
+
121
+ issues = validate_stead_file("data/input.hdf5", "data/input.csv")
122
+
123
+ if issues:
124
+ for issue in issues:
125
+ print(issue)
126
+ else:
127
+ print("Validation passed.")
128
+ ```
129
+
130
+ ### Apply a simple augmentation
131
+
132
+ ```python
133
+ import numpy as np
134
+ from seisaug.noise import add_spikes
135
+
136
+ x = np.ones(1000, dtype=np.float32)
137
+ y = add_spikes(x, num_spikes=5, spike_amp_ratio=0.5, seed=42)
138
+ ```
139
+
140
+ ## Project Structure
141
+
142
+ ```text
143
+ SeisAug/
144
+ ├── src/seisaug/
145
+ │ ├── __main__.py
146
+ │ ├── cli.py
147
+ │ ├── noise.py
148
+ │ ├── signal.py
149
+ │ ├── validate.py
150
+ │ └── ...
151
+ ├── tests/
152
+ ├── examples/
153
+ ├── pyproject.toml
154
+ └── README.md
155
+ ```
156
+
157
+ ## Development
158
+
159
+ Run tests with:
160
+
161
+ ```bash
162
+ pytest -q
163
+ ```
164
+
165
+ Build the package with:
166
+
167
+ ```bash
168
+ python -m build
169
+ ```
170
+
171
+ Check package metadata and README rendering with:
172
+
173
+ ```bash
174
+ python -m twine check dist/*
175
+ ```
176
+
177
+ ## Use Cases
178
+
179
+ SeisAug is useful for:
180
+
181
+ - Earthquake phase-picking model training
182
+ - Data augmentation for seismic ML experiments
183
+ - STEAD-format dataset validation and preprocessing
184
+ - Quick CLI-based augmentation and visualization workflows
185
+
186
+ ## Requirements
187
+
188
+ - Python 3.9+
189
+ - NumPy
190
+ - SciPy
191
+ - Matplotlib
192
+ - ObsPy
193
+ - pandas
194
+ - h5py
195
+ - PyYAML
196
+
197
+ ## License
198
+
199
+ MIT License
200
+
201
+ ## Repository
202
+
203
+ Source code, issues, and updates:
204
+
205
+ - Repository: https://github.com/Pragnath/SeisAug
206
+ - Issues: https://github.com/Pragnath/SeisAug/issues
@@ -0,0 +1,171 @@
1
+ # SeisAug
2
+
3
+ SeisAug is a Python package for **seismic waveform augmentation**, **STEAD-format data handling**, **validation**, and **basic visualization** for earthquake machine-learning workflows.
4
+
5
+ It is designed for researchers working with waveform datasets such as STEAD and for users building training pipelines for phase picking, event detection, and waveform classification.
6
+
7
+ ## Features
8
+
9
+ - Add seismic waveform augmentations such as noise injection, spikes, and time shifts
10
+ - Validate STEAD-format HDF5 and CSV datasets
11
+ - Read and process three-component waveform traces
12
+ - Plot SNR distributions from STEAD metadata
13
+ - Build batch augmentation pipelines from YAML configuration files
14
+ - Use a command-line interface for augmentation, validation, and plotting
15
+
16
+ ## Installation
17
+
18
+ Install from PyPI:
19
+
20
+ ```bash
21
+ pip install SeisAug
22
+ ```
23
+
24
+ For development:
25
+
26
+ ```bash
27
+ git clone https://github.com/Pragnath/SeisAug.git
28
+ cd SeisAug
29
+ pip install -e .[dev]
30
+ ```
31
+
32
+ ## Command-Line Usage
33
+
34
+ After installation, the `seisaug` command is available.
35
+
36
+ ### Show help
37
+
38
+ ```bash
39
+ seisaug --help
40
+ ```
41
+
42
+ ### Batch augment a dataset
43
+
44
+ ```bash
45
+ seisaug batch \
46
+ --input_hdf5 data/input.hdf5 \
47
+ --input_csv data/input.csv \
48
+ --output_hdf5 data/output_aug.hdf5 \
49
+ --output_csv data/output_aug.csv \
50
+ --config examples/augment_config.yaml
51
+ ```
52
+
53
+ ### Validate a STEAD-format dataset
54
+
55
+ ```bash
56
+ seisaug validate \
57
+ --input_hdf5 data/output_aug.hdf5 \
58
+ --input_csv data/output_aug.csv
59
+ ```
60
+
61
+ ### Plot SNR distribution
62
+
63
+ ```bash
64
+ seisaug snr \
65
+ --input_csv data/output_aug.csv \
66
+ --output_png snr_distribution.png
67
+ ```
68
+
69
+ ### Plot an augmentation grid
70
+
71
+ ```bash
72
+ seisaug grid \
73
+ --input_hdf5 data/output_aug.hdf5 \
74
+ --trace_name trace_001 \
75
+ --augmented_names trace_001_aug1 trace_001_aug2 \
76
+ --output_png augmentation_grid.png
77
+ ```
78
+
79
+ ## Python Usage
80
+
81
+ ### Validate a dataset
82
+
83
+ ```python
84
+ from seisaug.validate import validate_stead_file
85
+
86
+ issues = validate_stead_file("data/input.hdf5", "data/input.csv")
87
+
88
+ if issues:
89
+ for issue in issues:
90
+ print(issue)
91
+ else:
92
+ print("Validation passed.")
93
+ ```
94
+
95
+ ### Apply a simple augmentation
96
+
97
+ ```python
98
+ import numpy as np
99
+ from seisaug.noise import add_spikes
100
+
101
+ x = np.ones(1000, dtype=np.float32)
102
+ y = add_spikes(x, num_spikes=5, spike_amp_ratio=0.5, seed=42)
103
+ ```
104
+
105
+ ## Project Structure
106
+
107
+ ```text
108
+ SeisAug/
109
+ ├── src/seisaug/
110
+ │ ├── __main__.py
111
+ │ ├── cli.py
112
+ │ ├── noise.py
113
+ │ ├── signal.py
114
+ │ ├── validate.py
115
+ │ └── ...
116
+ ├── tests/
117
+ ├── examples/
118
+ ├── pyproject.toml
119
+ └── README.md
120
+ ```
121
+
122
+ ## Development
123
+
124
+ Run tests with:
125
+
126
+ ```bash
127
+ pytest -q
128
+ ```
129
+
130
+ Build the package with:
131
+
132
+ ```bash
133
+ python -m build
134
+ ```
135
+
136
+ Check package metadata and README rendering with:
137
+
138
+ ```bash
139
+ python -m twine check dist/*
140
+ ```
141
+
142
+ ## Use Cases
143
+
144
+ SeisAug is useful for:
145
+
146
+ - Earthquake phase-picking model training
147
+ - Data augmentation for seismic ML experiments
148
+ - STEAD-format dataset validation and preprocessing
149
+ - Quick CLI-based augmentation and visualization workflows
150
+
151
+ ## Requirements
152
+
153
+ - Python 3.9+
154
+ - NumPy
155
+ - SciPy
156
+ - Matplotlib
157
+ - ObsPy
158
+ - pandas
159
+ - h5py
160
+ - PyYAML
161
+
162
+ ## License
163
+
164
+ MIT License
165
+
166
+ ## Repository
167
+
168
+ Source code, issues, and updates:
169
+
170
+ - Repository: https://github.com/Pragnath/SeisAug
171
+ - Issues: https://github.com/Pragnath/SeisAug/issues
@@ -0,0 +1,62 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "SeisAug"
7
+ version = "0.2.0"
8
+ description = "Seismic waveform augmentation, STEAD-format I/O, plotting, and batch processing utilities"
9
+ dynamic = ["readme"]
10
+ requires-python = ">=3.9"
11
+ license = {text = "MIT"}
12
+ authors = [
13
+ {name = "Pragnath"}
14
+ ]
15
+ keywords = ["seismology", "augmentation", "obspy", "earthquake", "STEAD", "machine-learning"]
16
+ classifiers = [
17
+ "Development Status :: 4 - Beta",
18
+ "Intended Audience :: Science/Research",
19
+ "License :: OSI Approved :: MIT License",
20
+ "Programming Language :: Python :: 3",
21
+ "Programming Language :: Python :: 3 :: Only",
22
+ "Programming Language :: Python :: 3.9",
23
+ "Programming Language :: Python :: 3.10",
24
+ "Programming Language :: Python :: 3.11",
25
+ "Topic :: Scientific/Engineering :: Physics"
26
+ ]
27
+ dependencies = [
28
+ "numpy>=1.23",
29
+ "scipy>=1.10",
30
+ "matplotlib>=3.6",
31
+ "obspy>=1.4",
32
+ "pandas>=1.5",
33
+ "h5py>=3.8",
34
+ "ipywidgets>=8.0",
35
+ "tqdm>=4.65",
36
+ "pyyaml>=6.0"
37
+ ]
38
+
39
+ [project.optional-dependencies]
40
+ dev = [
41
+ "pytest>=7.0",
42
+ "build>=1.2.1",
43
+ "twine>=5.1.1"
44
+ ]
45
+
46
+ [project.urls]
47
+ Homepage = "https://github.com/Pragnath/SeisAug"
48
+ Repository = "https://github.com/Pragnath/SeisAug"
49
+ Issues = "https://github.com/Pragnath/SeisAug/issues"
50
+
51
+ [project.scripts]
52
+ seisaug = "seisaug.cli:main"
53
+
54
+ [tool.setuptools]
55
+ package-dir = {"" = "src"}
56
+ include-package-data = true
57
+
58
+ [tool.setuptools.packages.find]
59
+ where = ["src"]
60
+
61
+ [tool.setuptools.dynamic]
62
+ readme = {file = ["README.md"], content-type = "text/markdown"}
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,206 @@
1
+ Metadata-Version: 2.4
2
+ Name: SeisAug
3
+ Version: 0.2.0
4
+ Summary: Seismic waveform augmentation, STEAD-format I/O, plotting, and batch processing utilities
5
+ Author: Pragnath
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/Pragnath/SeisAug
8
+ Project-URL: Repository, https://github.com/Pragnath/SeisAug
9
+ Project-URL: Issues, https://github.com/Pragnath/SeisAug/issues
10
+ Keywords: seismology,augmentation,obspy,earthquake,STEAD,machine-learning
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Science/Research
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3 :: Only
16
+ Classifier: Programming Language :: Python :: 3.9
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Topic :: Scientific/Engineering :: Physics
20
+ Requires-Python: >=3.9
21
+ Description-Content-Type: text/markdown
22
+ Requires-Dist: numpy>=1.23
23
+ Requires-Dist: scipy>=1.10
24
+ Requires-Dist: matplotlib>=3.6
25
+ Requires-Dist: obspy>=1.4
26
+ Requires-Dist: pandas>=1.5
27
+ Requires-Dist: h5py>=3.8
28
+ Requires-Dist: ipywidgets>=8.0
29
+ Requires-Dist: tqdm>=4.65
30
+ Requires-Dist: pyyaml>=6.0
31
+ Provides-Extra: dev
32
+ Requires-Dist: pytest>=7.0; extra == "dev"
33
+ Requires-Dist: build>=1.2.1; extra == "dev"
34
+ Requires-Dist: twine>=5.1.1; extra == "dev"
35
+
36
+ # SeisAug
37
+
38
+ SeisAug is a Python package for **seismic waveform augmentation**, **STEAD-format data handling**, **validation**, and **basic visualization** for earthquake machine-learning workflows.
39
+
40
+ It is designed for researchers working with waveform datasets such as STEAD and for users building training pipelines for phase picking, event detection, and waveform classification.
41
+
42
+ ## Features
43
+
44
+ - Add seismic waveform augmentations such as noise injection, spikes, and time shifts
45
+ - Validate STEAD-format HDF5 and CSV datasets
46
+ - Read and process three-component waveform traces
47
+ - Plot SNR distributions from STEAD metadata
48
+ - Build batch augmentation pipelines from YAML configuration files
49
+ - Use a command-line interface for augmentation, validation, and plotting
50
+
51
+ ## Installation
52
+
53
+ Install from PyPI:
54
+
55
+ ```bash
56
+ pip install SeisAug
57
+ ```
58
+
59
+ For development:
60
+
61
+ ```bash
62
+ git clone https://github.com/Pragnath/SeisAug.git
63
+ cd SeisAug
64
+ pip install -e .[dev]
65
+ ```
66
+
67
+ ## Command-Line Usage
68
+
69
+ After installation, the `seisaug` command is available.
70
+
71
+ ### Show help
72
+
73
+ ```bash
74
+ seisaug --help
75
+ ```
76
+
77
+ ### Batch augment a dataset
78
+
79
+ ```bash
80
+ seisaug batch \
81
+ --input_hdf5 data/input.hdf5 \
82
+ --input_csv data/input.csv \
83
+ --output_hdf5 data/output_aug.hdf5 \
84
+ --output_csv data/output_aug.csv \
85
+ --config examples/augment_config.yaml
86
+ ```
87
+
88
+ ### Validate a STEAD-format dataset
89
+
90
+ ```bash
91
+ seisaug validate \
92
+ --input_hdf5 data/output_aug.hdf5 \
93
+ --input_csv data/output_aug.csv
94
+ ```
95
+
96
+ ### Plot SNR distribution
97
+
98
+ ```bash
99
+ seisaug snr \
100
+ --input_csv data/output_aug.csv \
101
+ --output_png snr_distribution.png
102
+ ```
103
+
104
+ ### Plot an augmentation grid
105
+
106
+ ```bash
107
+ seisaug grid \
108
+ --input_hdf5 data/output_aug.hdf5 \
109
+ --trace_name trace_001 \
110
+ --augmented_names trace_001_aug1 trace_001_aug2 \
111
+ --output_png augmentation_grid.png
112
+ ```
113
+
114
+ ## Python Usage
115
+
116
+ ### Validate a dataset
117
+
118
+ ```python
119
+ from seisaug.validate import validate_stead_file
120
+
121
+ issues = validate_stead_file("data/input.hdf5", "data/input.csv")
122
+
123
+ if issues:
124
+ for issue in issues:
125
+ print(issue)
126
+ else:
127
+ print("Validation passed.")
128
+ ```
129
+
130
+ ### Apply a simple augmentation
131
+
132
+ ```python
133
+ import numpy as np
134
+ from seisaug.noise import add_spikes
135
+
136
+ x = np.ones(1000, dtype=np.float32)
137
+ y = add_spikes(x, num_spikes=5, spike_amp_ratio=0.5, seed=42)
138
+ ```
139
+
140
+ ## Project Structure
141
+
142
+ ```text
143
+ SeisAug/
144
+ ├── src/seisaug/
145
+ │ ├── __main__.py
146
+ │ ├── cli.py
147
+ │ ├── noise.py
148
+ │ ├── signal.py
149
+ │ ├── validate.py
150
+ │ └── ...
151
+ ├── tests/
152
+ ├── examples/
153
+ ├── pyproject.toml
154
+ └── README.md
155
+ ```
156
+
157
+ ## Development
158
+
159
+ Run tests with:
160
+
161
+ ```bash
162
+ pytest -q
163
+ ```
164
+
165
+ Build the package with:
166
+
167
+ ```bash
168
+ python -m build
169
+ ```
170
+
171
+ Check package metadata and README rendering with:
172
+
173
+ ```bash
174
+ python -m twine check dist/*
175
+ ```
176
+
177
+ ## Use Cases
178
+
179
+ SeisAug is useful for:
180
+
181
+ - Earthquake phase-picking model training
182
+ - Data augmentation for seismic ML experiments
183
+ - STEAD-format dataset validation and preprocessing
184
+ - Quick CLI-based augmentation and visualization workflows
185
+
186
+ ## Requirements
187
+
188
+ - Python 3.9+
189
+ - NumPy
190
+ - SciPy
191
+ - Matplotlib
192
+ - ObsPy
193
+ - pandas
194
+ - h5py
195
+ - PyYAML
196
+
197
+ ## License
198
+
199
+ MIT License
200
+
201
+ ## Repository
202
+
203
+ Source code, issues, and updates:
204
+
205
+ - Repository: https://github.com/Pragnath/SeisAug
206
+ - Issues: https://github.com/Pragnath/SeisAug/issues
@@ -0,0 +1,20 @@
1
+ MANIFEST.in
2
+ README.md
3
+ pyproject.toml
4
+ src/SeisAug.egg-info/PKG-INFO
5
+ src/SeisAug.egg-info/SOURCES.txt
6
+ src/SeisAug.egg-info/dependency_links.txt
7
+ src/SeisAug.egg-info/entry_points.txt
8
+ src/SeisAug.egg-info/requires.txt
9
+ src/SeisAug.egg-info/top_level.txt
10
+ src/seisaug/__init__.py
11
+ src/seisaug/__main__.py
12
+ src/seisaug/cli.py
13
+ src/seisaug/io.py
14
+ src/seisaug/noise.py
15
+ src/seisaug/plotting.py
16
+ src/seisaug/signal.py
17
+ src/seisaug/validate.py
18
+ tests/test_noise.py
19
+ tests/test_signal.py
20
+ tests/test_validate.py
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ seisaug = seisaug.cli:main
@@ -0,0 +1,14 @@
1
+ numpy>=1.23
2
+ scipy>=1.10
3
+ matplotlib>=3.6
4
+ obspy>=1.4
5
+ pandas>=1.5
6
+ h5py>=3.8
7
+ ipywidgets>=8.0
8
+ tqdm>=4.65
9
+ pyyaml>=6.0
10
+
11
+ [dev]
12
+ pytest>=7.0
13
+ build>=1.2.1
14
+ twine>=5.1.1
@@ -0,0 +1 @@
1
+ seisaug
@@ -0,0 +1,25 @@
1
+ from .noise import (
2
+ add_white_noise,
3
+ add_pink_noise,
4
+ add_monofrequency_noise,
5
+ add_bandpass_noise,
6
+ add_spikes,
7
+ )
8
+ from .signal import time_shift_zero_pad, convolve_with_sine, convolve_with_step
9
+ from .io import read_waveform, read_stead_trace, write_stead_trace
10
+
11
+ __all__ = [
12
+ "add_white_noise",
13
+ "add_pink_noise",
14
+ "add_monofrequency_noise",
15
+ "add_bandpass_noise",
16
+ "add_spikes",
17
+ "time_shift_zero_pad",
18
+ "convolve_with_sine",
19
+ "convolve_with_step",
20
+ "read_waveform",
21
+ "read_stead_trace",
22
+ "write_stead_trace",
23
+ ]
24
+
25
+ __version__ = "1.2.0"
@@ -0,0 +1,4 @@
1
+ from .cli import batch_main
2
+
3
+ if __name__ == "__main__":
4
+ batch_main()
@@ -0,0 +1,115 @@
1
+ import argparse
2
+
3
+
4
+ def batch_main(args):
5
+ from .pipeline import batch_augment
6
+
7
+ batch_augment(
8
+ input_hdf5=args.input_hdf5,
9
+ input_csv=args.input_csv,
10
+ output_hdf5=args.output_hdf5,
11
+ output_csv=args.output_csv,
12
+ config_path=args.config,
13
+ )
14
+ print(f"Augmented dataset written to: {args.output_hdf5}")
15
+ print(f"Metadata written to: {args.output_csv}")
16
+
17
+
18
+ def validate_main(args):
19
+ from .validate import validate_stead_file
20
+
21
+ issues = validate_stead_file(args.input_hdf5, args.input_csv)
22
+
23
+ if issues:
24
+ print("Validation issues found:")
25
+ for item in issues:
26
+ print(f"- {item}")
27
+ raise SystemExit(1)
28
+
29
+ print("Validation passed.")
30
+
31
+
32
+ def snr_main(args):
33
+ from .plotting import plot_snr_distribution
34
+
35
+ plot_snr_distribution(args.input_csv, outfile=args.output_png)
36
+ print(f"SNR distribution saved to: {args.output_png}")
37
+
38
+
39
+ def grid_main(args):
40
+ from .io import read_stead_trace
41
+ from .plotting import plot_augmentation_grid
42
+
43
+ original, _ = read_stead_trace(args.input_hdf5, args.trace_name)
44
+
45
+ augmented = {}
46
+ for name in args.augmented_names:
47
+ augmented_data, _ = read_stead_trace(args.input_hdf5, name)
48
+ augmented[name] = augmented_data
49
+
50
+ plot_augmentation_grid(original, augmented, outfile=args.output_png)
51
+ print(f"Augmentation grid saved to: {args.output_png}")
52
+
53
+
54
+ def build_parser():
55
+ parser = argparse.ArgumentParser(
56
+ prog="seisaug",
57
+ description="SeisAug command-line tools for seismic augmentation, validation, and plotting.",
58
+ )
59
+
60
+ subparsers = parser.add_subparsers(dest="command")
61
+
62
+ batch_parser = subparsers.add_parser(
63
+ "batch",
64
+ help="Batch augment a STEAD-format HDF5+CSV dataset",
65
+ )
66
+ batch_parser.add_argument("--input_hdf5", required=True, help="Input STEAD HDF5 file")
67
+ batch_parser.add_argument("--input_csv", required=True, help="Input STEAD metadata CSV")
68
+ batch_parser.add_argument("--output_hdf5", required=True, help="Output augmented HDF5 file")
69
+ batch_parser.add_argument("--output_csv", required=True, help="Output augmented CSV file")
70
+ batch_parser.add_argument("--config", required=True, help="YAML augmentation config file")
71
+ batch_parser.set_defaults(func=batch_main)
72
+
73
+ validate_parser = subparsers.add_parser(
74
+ "validate",
75
+ help="Validate a STEAD-format HDF5/CSV dataset",
76
+ )
77
+ validate_parser.add_argument("--input_hdf5", required=True, help="Input STEAD HDF5 file")
78
+ validate_parser.add_argument("--input_csv", default=None, help="Optional STEAD metadata CSV")
79
+ validate_parser.set_defaults(func=validate_main)
80
+
81
+ snr_parser = subparsers.add_parser(
82
+ "snr",
83
+ help="Plot SNR distribution from STEAD CSV metadata",
84
+ )
85
+ snr_parser.add_argument("--input_csv", required=True, help="Input STEAD metadata CSV")
86
+ snr_parser.add_argument("--output_png", required=True, help="Output PNG path")
87
+ snr_parser.set_defaults(func=snr_main)
88
+
89
+ grid_parser = subparsers.add_parser(
90
+ "grid",
91
+ help="Plot augmentation grid from original and augmented traces",
92
+ )
93
+ grid_parser.add_argument("--input_hdf5", required=True, help="Input STEAD HDF5 file")
94
+ grid_parser.add_argument("--trace_name", required=True, help="Original trace name")
95
+ grid_parser.add_argument(
96
+ "--augmented_names",
97
+ nargs="+",
98
+ required=True,
99
+ help="One or more augmented trace names",
100
+ )
101
+ grid_parser.add_argument("--output_png", required=True, help="Output PNG path")
102
+ grid_parser.set_defaults(func=grid_main)
103
+
104
+ return parser
105
+
106
+
107
+ def main(argv=None):
108
+ parser = build_parser()
109
+ args = parser.parse_args(argv)
110
+
111
+ if not hasattr(args, "func"):
112
+ parser.print_help()
113
+ raise SystemExit(0)
114
+
115
+ args.func(args)
@@ -0,0 +1,35 @@
1
+ import h5py
2
+ import numpy as np
3
+ import pandas as pd
4
+ from obspy import read
5
+
6
+
7
+ def read_waveform(path):
8
+ return read(str(path))
9
+
10
+
11
+ def read_stead_trace(hdf5_path, trace_name):
12
+ with h5py.File(hdf5_path, "r") as f:
13
+ ds = f[f"data/{trace_name}"]
14
+ data = np.array(ds)
15
+ attrs = {k: ds.attrs[k] for k in ds.attrs.keys()}
16
+ return data, attrs
17
+
18
+
19
+ def read_stead_metadata(csv_path):
20
+ return pd.read_csv(csv_path)
21
+
22
+
23
+ def write_stead_trace(hdf5_path, trace_name, data, attrs=None, compression="gzip"):
24
+ attrs = attrs or {}
25
+ with h5py.File(hdf5_path, "a") as f:
26
+ grp = f.require_group("data")
27
+ if trace_name in grp:
28
+ del grp[trace_name]
29
+ ds = grp.create_dataset(trace_name, data=np.asarray(data, dtype=np.float32), compression=compression)
30
+ for k, v in attrs.items():
31
+ ds.attrs[k] = v
32
+
33
+
34
+ def write_stead_metadata(csv_path, rows):
35
+ pd.DataFrame(rows).to_csv(csv_path, index=False)
@@ -0,0 +1,60 @@
1
+ import numpy as np
2
+ from scipy import signal
3
+
4
+
5
+ def _db_to_amplitude_ratio(noise_level_db: float) -> float:
6
+ return 10 ** (noise_level_db / 20.0)
7
+
8
+
9
+ def add_white_noise(data, noise_level_db):
10
+ data = np.asarray(data, dtype=np.float32)
11
+ ratio = _db_to_amplitude_ratio(noise_level_db)
12
+ noise = np.random.normal(size=data.shape).astype(np.float32)
13
+ noise_std = np.std(noise) or 1.0
14
+ return data + ratio * (noise / noise_std)
15
+
16
+
17
+ def add_pink_noise(data, noise_level_db):
18
+ data = np.asarray(data, dtype=np.float32)
19
+ ratio = _db_to_amplitude_ratio(noise_level_db)
20
+ n = len(data)
21
+ freqs = np.fft.rfftfreq(n)
22
+ freqs[0] = 1.0
23
+ white = np.fft.rfft(np.random.normal(size=n))
24
+ pink = white / np.sqrt(freqs)
25
+ noise = np.fft.irfft(pink, n=n).astype(np.float32)
26
+ noise_std = np.std(noise) or 1.0
27
+ return data + ratio * (noise / noise_std)
28
+
29
+
30
+ def add_monofrequency_noise(data, noise_level_db, fs, freq):
31
+ data = np.asarray(data, dtype=np.float32)
32
+ ratio = _db_to_amplitude_ratio(noise_level_db)
33
+ t = np.arange(data.shape[0], dtype=np.float32) / float(fs)
34
+ noise = np.sin(2 * np.pi * float(freq) * t).astype(np.float32)
35
+ noise_std = np.std(noise) or 1.0
36
+ return data + ratio * (noise / noise_std)
37
+
38
+
39
+ def add_bandpass_noise(data, noise_level_db, fs, low_freq, high_freq, order=6):
40
+ data = np.asarray(data, dtype=np.float32)
41
+ ratio = _db_to_amplitude_ratio(noise_level_db)
42
+ white = np.random.normal(size=data.shape).astype(np.float32)
43
+ white_std = np.std(white) or 1.0
44
+ white = white / white_std
45
+ sos = signal.butter(order, [low_freq, high_freq], btype="band", fs=fs, output="sos")
46
+ filtered = signal.sosfilt(sos, white).astype(np.float32)
47
+ filt_std = np.std(filtered) or 1.0
48
+ return data + ratio * (filtered / filt_std)
49
+
50
+
51
+ def add_spikes(data, num_spikes=10, spike_amp_ratio=0.3, seed=None):
52
+ data = np.asarray(data, dtype=np.float32).copy()
53
+ rng = np.random.default_rng(seed)
54
+ if len(data) == 0:
55
+ return data
56
+ max_amp = np.max(np.abs(data)) or 1.0
57
+ idx = rng.integers(0, len(data), size=int(num_spikes))
58
+ signs = rng.choice([-1.0, 1.0], size=int(num_spikes))
59
+ data[idx] += signs * float(spike_amp_ratio) * max_amp
60
+ return data
@@ -0,0 +1,63 @@
1
+ import ast
2
+ import numpy as np
3
+ import pandas as pd
4
+ import matplotlib.pyplot as plt
5
+
6
+
7
+ def plot_trace(data, title="Waveform", outfile=None):
8
+ data = np.asarray(data)
9
+ fig, axes = plt.subplots(3, 1, figsize=(10, 6), sharex=True)
10
+ labels = ["E", "N", "Z"]
11
+ for i, ax in enumerate(axes):
12
+ ax.plot(data[:, i], lw=0.8, color="k")
13
+ ax.set_ylabel(labels[i])
14
+ axes[-1].set_xlabel("Sample")
15
+ fig.suptitle(title)
16
+ fig.tight_layout()
17
+ if outfile:
18
+ fig.savefig(outfile, dpi=200, bbox_inches="tight")
19
+ return fig
20
+
21
+
22
+ def plot_augmentation_grid(original, augmented_dict, outfile=None):
23
+ n = 1 + len(augmented_dict)
24
+ fig, axes = plt.subplots(n, 3, figsize=(14, 3 * n), sharex=True)
25
+ labels = ["E", "N", "Z"]
26
+ rows = [("original", original)] + list(augmented_dict.items())
27
+ for r, (name, arr) in enumerate(rows):
28
+ arr = np.asarray(arr)
29
+ for c in range(3):
30
+ ax = axes[r, c] if n > 1 else axes[c]
31
+ ax.plot(arr[:, c], lw=0.7, color="k")
32
+ ax.set_title(f"{name} - {labels[c]}")
33
+ if r == n - 1:
34
+ ax.set_xlabel("Sample")
35
+ fig.tight_layout()
36
+ if outfile:
37
+ fig.savefig(outfile, dpi=200, bbox_inches="tight")
38
+ return fig
39
+
40
+
41
+ def plot_snr_distribution(csv_path, outfile=None):
42
+ df = pd.read_csv(csv_path)
43
+
44
+ def parse_snr(x):
45
+ try:
46
+ vals = ast.literal_eval(str(x))
47
+ vals = np.asarray(vals, dtype=float)
48
+ vals = vals[np.isfinite(vals)]
49
+ vals = vals[vals > -900]
50
+ return float(np.mean(vals)) if len(vals) else np.nan
51
+ except Exception:
52
+ return np.nan
53
+
54
+ df["snr_mean_db"] = df["snr_db"].apply(parse_snr)
55
+ fig, ax = plt.subplots(figsize=(8, 5))
56
+ ax.hist(df["snr_mean_db"].dropna(), bins=40, color="steelblue", alpha=0.8)
57
+ ax.set_xlabel("Mean SNR (dB)")
58
+ ax.set_ylabel("Count")
59
+ ax.set_title("SNR Distribution")
60
+ fig.tight_layout()
61
+ if outfile:
62
+ fig.savefig(outfile, dpi=200, bbox_inches="tight")
63
+ return fig
@@ -0,0 +1,36 @@
1
+ import numpy as np
2
+
3
+
4
+ def time_shift_zero_pad(data, shift_samples):
5
+ data = np.asarray(data, dtype=np.float32)
6
+ shift_samples = int(shift_samples)
7
+ out = np.zeros_like(data)
8
+ if shift_samples == 0:
9
+ return data.copy()
10
+ if abs(shift_samples) >= len(data):
11
+ return out
12
+ if shift_samples > 0:
13
+ out[shift_samples:] = data[:-shift_samples]
14
+ else:
15
+ out[:shift_samples] = data[-shift_samples:]
16
+ return out
17
+
18
+
19
+ def convolve_with_sine(data, fs, freq=1.0):
20
+ data = np.asarray(data, dtype=np.float32)
21
+ t = np.arange(len(data), dtype=np.float32) / float(fs)
22
+ sig = np.sin(2 * np.pi * float(freq) * t).astype(np.float32)
23
+ out = np.convolve(sig, data, mode="same").astype(np.float32)
24
+ norm = np.max(np.abs(out)) or 1.0
25
+ return out / norm
26
+
27
+
28
+ def convolve_with_step(data, fs, num_steps=10):
29
+ data = np.asarray(data, dtype=np.float32)
30
+ sig = np.zeros(len(data), dtype=np.float32)
31
+ edges = np.linspace(0, len(data), int(num_steps) + 1).astype(int)
32
+ for i in range(len(edges) - 1):
33
+ sig[edges[i]:edges[i + 1]] = i % 2
34
+ out = np.convolve(sig, data, mode="same").astype(np.float32)
35
+ norm = np.max(np.abs(out)) or 1.0
36
+ return out / norm
@@ -0,0 +1,41 @@
1
+ import h5py
2
+ import numpy as np
3
+ import pandas as pd
4
+
5
+
6
+ REQUIRED_ATTRS = [
7
+ "network_code",
8
+ "receiver_code",
9
+ "receiver_type",
10
+ "trace_name",
11
+ "trace_category",
12
+ ]
13
+
14
+
15
+ def validate_stead_file(hdf5_path, csv_path=None):
16
+ issues = []
17
+
18
+ with h5py.File(hdf5_path, "r") as f:
19
+ if "data" not in f:
20
+ issues.append("Missing /data group")
21
+ return issues
22
+
23
+ for trace_name, ds in f["data"].items():
24
+ arr = np.array(ds)
25
+
26
+ if arr.ndim != 2 or arr.shape[1] != 3:
27
+ issues.append(f"{trace_name}: expected shape (N, 3), got {arr.shape}")
28
+
29
+ if not np.all(np.isfinite(arr)):
30
+ issues.append(f"{trace_name}: contains NaN/Inf")
31
+
32
+ for attr in REQUIRED_ATTRS:
33
+ if attr not in ds.attrs:
34
+ issues.append(f"{trace_name}: missing attr {attr}")
35
+
36
+ if csv_path:
37
+ df = pd.read_csv(csv_path)
38
+ if "trace_name" not in df.columns:
39
+ issues.append("CSV missing trace_name column")
40
+
41
+ return issues
@@ -0,0 +1,23 @@
1
+ import numpy as np
2
+
3
+ from seisaug.noise import add_white_noise, add_pink_noise, add_spikes
4
+
5
+
6
+ def test_add_white_noise_preserves_shape():
7
+ x = np.zeros(1000, dtype=np.float32)
8
+ y = add_white_noise(x, noise_level_db=10)
9
+ assert y.shape == x.shape
10
+
11
+
12
+ def test_add_pink_noise_returns_finite_values():
13
+ x = np.zeros(2000, dtype=np.float32)
14
+ y = add_pink_noise(x, noise_level_db=8)
15
+ assert y.shape == x.shape
16
+ assert np.isfinite(y).all()
17
+
18
+
19
+ def test_add_spikes_preserves_shape_and_changes_samples():
20
+ x = np.ones(1000, dtype=np.float32)
21
+ y = add_spikes(x, num_spikes=5, spike_amp_ratio=0.5, seed=42)
22
+ assert y.shape == x.shape
23
+ assert not np.allclose(x, y)
@@ -0,0 +1,29 @@
1
+ import numpy as np
2
+
3
+ from seisaug.signal import time_shift_zero_pad, convolve_with_sine, convolve_with_step
4
+
5
+
6
+ def test_time_shift_zero_pad_positive_shift():
7
+ x = np.array([1, 2, 3, 4], dtype=np.float32)
8
+ y = time_shift_zero_pad(x, 2)
9
+ assert np.allclose(y, [0, 0, 1, 2])
10
+
11
+
12
+ def test_time_shift_zero_pad_negative_shift():
13
+ x = np.array([1, 2, 3, 4], dtype=np.float32)
14
+ y = time_shift_zero_pad(x, -2)
15
+ assert np.allclose(y, [3, 4, 0, 0])
16
+
17
+
18
+ def test_convolve_with_sine_shape():
19
+ x = np.random.randn(1000).astype(np.float32)
20
+ y = convolve_with_sine(x, fs=100.0, freq=2.0)
21
+ assert y.shape == x.shape
22
+ assert np.isfinite(y).all()
23
+
24
+
25
+ def test_convolve_with_step_shape():
26
+ x = np.random.randn(1000).astype(np.float32)
27
+ y = convolve_with_step(x, fs=100.0, num_steps=8)
28
+ assert y.shape == x.shape
29
+ assert np.isfinite(y).all()
@@ -0,0 +1,37 @@
1
+ import tempfile
2
+ from pathlib import Path
3
+
4
+ import h5py
5
+ import numpy as np
6
+ import pandas as pd
7
+
8
+ from seisaug.validate import validate_stead_file
9
+
10
+
11
+ def test_validate_stead_file_passes_for_minimal_valid_input():
12
+ with tempfile.TemporaryDirectory() as tmpdir:
13
+ h5_path = Path(tmpdir) / "test.hdf5"
14
+ csv_path = Path(tmpdir) / "test.csv"
15
+
16
+ with h5py.File(h5_path, "w") as f:
17
+ grp = f.create_group("data")
18
+ ds = grp.create_dataset("trace_1", data=np.zeros((100, 3), dtype=np.float32))
19
+ ds.attrs["network_code"] = "XX"
20
+ ds.attrs["receiver_code"] = "STAT"
21
+ ds.attrs["receiver_type"] = "HH"
22
+ ds.attrs["trace_name"] = "trace_1"
23
+ ds.attrs["trace_category"] = "earthquake_local"
24
+
25
+ pd.DataFrame([{"trace_name": "trace_1"}]).to_csv(csv_path, index=False)
26
+
27
+ issues = validate_stead_file(h5_path, csv_path)
28
+ assert issues == []
29
+
30
+
31
+ def test_validate_stead_file_flags_missing_data_group():
32
+ with tempfile.TemporaryDirectory() as tmpdir:
33
+ h5_path = Path(tmpdir) / "bad.hdf5"
34
+ with h5py.File(h5_path, "w"):
35
+ pass
36
+ issues = validate_stead_file(h5_path)
37
+ assert any("Missing /data group" in item for item in issues)