ertkit 0.1.0__tar.gz → 0.1.1__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.
- {ertkit-0.1.0 → ertkit-0.1.1}/.pre-commit-config.yaml +4 -4
- {ertkit-0.1.0 → ertkit-0.1.1}/CHANGELOG.md +24 -1
- {ertkit-0.1.0 → ertkit-0.1.1}/CITATION.cff +10 -2
- {ertkit-0.1.0 → ertkit-0.1.1}/PKG-INFO +11 -5
- {ertkit-0.1.0 → ertkit-0.1.1}/README.md +9 -4
- ertkit-0.1.1/docs/citing.md +17 -0
- {ertkit-0.1.0 → ertkit-0.1.1}/docs/user_guide/ves.md +14 -2
- {ertkit-0.1.0 → ertkit-0.1.1}/pyproject.toml +1 -0
- {ertkit-0.1.0 → ertkit-0.1.1}/src/ertkit/_version.py +2 -2
- {ertkit-0.1.0 → ertkit-0.1.1}/src/ertkit/ves/data.py +17 -5
- {ertkit-0.1.0 → ertkit-0.1.1}/src/ertkit/ves/smooth.py +19 -8
- {ertkit-0.1.0 → ertkit-0.1.1}/tests/ves/test_data.py +26 -0
- {ertkit-0.1.0 → ertkit-0.1.1}/tests/ves/test_invert_smooth.py +21 -1
- ertkit-0.1.0/docs/citing.md +0 -9
- {ertkit-0.1.0 → ertkit-0.1.1}/.git_archival.txt +0 -0
- {ertkit-0.1.0 → ertkit-0.1.1}/.gitattributes +0 -0
- {ertkit-0.1.0 → ertkit-0.1.1}/.gitignore +0 -0
- {ertkit-0.1.0 → ertkit-0.1.1}/.mailmap +0 -0
- {ertkit-0.1.0 → ertkit-0.1.1}/.zenodo.json +0 -0
- {ertkit-0.1.0 → ertkit-0.1.1}/CODE_OF_CONDUCT.md +0 -0
- {ertkit-0.1.0 → ertkit-0.1.1}/CONTRIBUTING.md +0 -0
- {ertkit-0.1.0 → ertkit-0.1.1}/LICENSE +0 -0
- {ertkit-0.1.0 → ertkit-0.1.1}/ci/crosscheck.txt +0 -0
- {ertkit-0.1.0 → ertkit-0.1.1}/docs/_ext/verification_report.py +0 -0
- {ertkit-0.1.0 → ertkit-0.1.1}/docs/_templates/autosummary/class.rst +0 -0
- {ertkit-0.1.0 → ertkit-0.1.1}/docs/api.md +0 -0
- {ertkit-0.1.0 → ertkit-0.1.1}/docs/changelog.md +0 -0
- {ertkit-0.1.0 → ertkit-0.1.1}/docs/conf.py +0 -0
- {ertkit-0.1.0 → ertkit-0.1.1}/docs/contributing.md +0 -0
- {ertkit-0.1.0 → ertkit-0.1.1}/docs/dev/design.md +0 -0
- {ertkit-0.1.0 → ertkit-0.1.1}/docs/dev/index.md +0 -0
- {ertkit-0.1.0 → ertkit-0.1.1}/docs/index.md +0 -0
- {ertkit-0.1.0 → ertkit-0.1.1}/docs/install.md +0 -0
- {ertkit-0.1.0 → ertkit-0.1.1}/docs/roadmap.md +0 -0
- {ertkit-0.1.0 → ertkit-0.1.1}/docs/verification.md +0 -0
- {ertkit-0.1.0 → ertkit-0.1.1}/examples/README.rst +0 -0
- {ertkit-0.1.0 → ertkit-0.1.1}/examples/plot_01_few_layer_inversion.py +0 -0
- {ertkit-0.1.0 → ertkit-0.1.1}/examples/plot_02_smooth_inversion.py +0 -0
- {ertkit-0.1.0 → ertkit-0.1.1}/examples/plot_03_equivalence.py +0 -0
- {ertkit-0.1.0 → ertkit-0.1.1}/examples/plot_04_static_shift.py +0 -0
- {ertkit-0.1.0 → ertkit-0.1.1}/examples/plot_05_read_csv.py +0 -0
- {ertkit-0.1.0 → ertkit-0.1.1}/examples/plot_06_check_installation.py +0 -0
- {ertkit-0.1.0 → ertkit-0.1.1}/src/ertkit/__init__.py +0 -0
- {ertkit-0.1.0 → ertkit-0.1.1}/src/ertkit/_linalg.py +0 -0
- {ertkit-0.1.0 → ertkit-0.1.1}/src/ertkit/_show_versions.py +0 -0
- {ertkit-0.1.0 → ertkit-0.1.1}/src/ertkit/_warnings.py +0 -0
- {ertkit-0.1.0 → ertkit-0.1.1}/src/ertkit/arrays.py +0 -0
- {ertkit-0.1.0 → ertkit-0.1.1}/src/ertkit/noise.py +0 -0
- {ertkit-0.1.0 → ertkit-0.1.1}/src/ertkit/plot/__init__.py +0 -0
- {ertkit-0.1.0 → ertkit-0.1.1}/src/ertkit/plot/_ves.py +0 -0
- {ertkit-0.1.0 → ertkit-0.1.1}/src/ertkit/py.typed +0 -0
- {ertkit-0.1.0 → ertkit-0.1.1}/src/ertkit/results.py +0 -0
- {ertkit-0.1.0 → ertkit-0.1.1}/src/ertkit/ves/__init__.py +0 -0
- {ertkit-0.1.0 → ertkit-0.1.1}/src/ertkit/ves/forward.py +0 -0
- {ertkit-0.1.0 → ertkit-0.1.1}/src/ertkit/ves/invert.py +0 -0
- {ertkit-0.1.0 → ertkit-0.1.1}/src/ertkit/ves/io.py +0 -0
- {ertkit-0.1.0 → ertkit-0.1.1}/src/ertkit/ves/model.py +0 -0
- {ertkit-0.1.0 → ertkit-0.1.1}/src/ertkit/ves/survey.py +0 -0
- {ertkit-0.1.0 → ertkit-0.1.1}/tests/analytic_solutions.py +0 -0
- {ertkit-0.1.0 → ertkit-0.1.1}/tests/conftest.py +0 -0
- {ertkit-0.1.0 → ertkit-0.1.1}/tests/crosscheck/test_crosscheck_ves.py +0 -0
- {ertkit-0.1.0 → ertkit-0.1.1}/tests/test_arrays.py +0 -0
- {ertkit-0.1.0 → ertkit-0.1.1}/tests/test_linalg.py +0 -0
- {ertkit-0.1.0 → ertkit-0.1.1}/tests/test_noise.py +0 -0
- {ertkit-0.1.0 → ertkit-0.1.1}/tests/test_package.py +0 -0
- {ertkit-0.1.0 → ertkit-0.1.1}/tests/test_plot.py +0 -0
- {ertkit-0.1.0 → ertkit-0.1.1}/tests/verification_report.py +0 -0
- {ertkit-0.1.0 → ertkit-0.1.1}/tests/ves/test_forward.py +0 -0
- {ertkit-0.1.0 → ertkit-0.1.1}/tests/ves/test_invert_few_layer.py +0 -0
- {ertkit-0.1.0 → ertkit-0.1.1}/tests/ves/test_model_survey.py +0 -0
- {ertkit-0.1.0 → ertkit-0.1.1}/tests/ves/test_review_regressions.py +0 -0
- {ertkit-0.1.0 → ertkit-0.1.1}/uv.lock +0 -0
|
@@ -21,19 +21,19 @@ repos:
|
|
|
21
21
|
- id: trailing-whitespace
|
|
22
22
|
|
|
23
23
|
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
24
|
-
rev: v0.17.
|
|
24
|
+
rev: v0.17.4
|
|
25
25
|
hooks:
|
|
26
26
|
- id: ruff-check
|
|
27
27
|
args: [--fix, --show-fixes, --exit-non-zero-on-fix]
|
|
28
28
|
- id: ruff-format
|
|
29
29
|
|
|
30
30
|
- repo: https://github.com/abravalheri/validate-pyproject
|
|
31
|
-
rev: v0.
|
|
31
|
+
rev: v0.27
|
|
32
32
|
hooks:
|
|
33
33
|
- id: validate-pyproject
|
|
34
34
|
|
|
35
35
|
- repo: https://github.com/python-jsonschema/check-jsonschema
|
|
36
|
-
rev: 0.
|
|
36
|
+
rev: 0.39.0
|
|
37
37
|
hooks:
|
|
38
38
|
- id: check-github-workflows
|
|
39
39
|
- id: check-dependabot
|
|
@@ -52,6 +52,6 @@ repos:
|
|
|
52
52
|
- id: rst-inline-touching-normal
|
|
53
53
|
|
|
54
54
|
- repo: https://github.com/zizmorcore/zizmor-pre-commit
|
|
55
|
-
rev: v1.
|
|
55
|
+
rev: v1.32.0
|
|
56
56
|
hooks:
|
|
57
57
|
- id: zizmor
|
|
@@ -6,6 +6,28 @@ project uses [semantic versioning](https://semver.org/).
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.1.1] - 2026-11-09
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- The Zenodo DOI in `CITATION.cff`, the README and the documentation, and a
|
|
14
|
+
`Citation` link in the package metadata.
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
|
|
18
|
+
- Synthetic soundings screen noise-free readings before adding log-space
|
|
19
|
+
noise, preventing signals below the noise floor from becoming enormous
|
|
20
|
+
accepted readings or overflowing. Noisy readings are screened again.
|
|
21
|
+
- Smooth inversion preserves the stopping reason after relaxing the misfit
|
|
22
|
+
target, rather than claiming the target was matched when the smoothest
|
|
23
|
+
model already fits better or the relaxed target remains unreachable.
|
|
24
|
+
- Smooth inversion requires at least three layers to span both endpoints of
|
|
25
|
+
`depth_range`. Two-layer fitting remains available with `invert_few_layer`.
|
|
26
|
+
|
|
27
|
+
### Changed
|
|
28
|
+
|
|
29
|
+
- Updated pre-commit hook versions as part of the release checklist.
|
|
30
|
+
|
|
9
31
|
## [0.1.0] - 2026-10-15
|
|
10
32
|
|
|
11
33
|
### Added
|
|
@@ -80,5 +102,6 @@ project uses [semantic versioning](https://semver.org/).
|
|
|
80
102
|
recorded in a verification report (`pytest -m verification
|
|
81
103
|
--verification-report=PATH`).
|
|
82
104
|
|
|
83
|
-
[Unreleased]: https://github.com/abdgafartunde/ertkit/compare/v0.1.
|
|
105
|
+
[Unreleased]: https://github.com/abdgafartunde/ertkit/compare/v0.1.1...HEAD
|
|
106
|
+
[0.1.1]: https://github.com/abdgafartunde/ertkit/compare/v0.1.0...v0.1.1
|
|
84
107
|
[0.1.0]: https://github.com/abdgafartunde/ertkit/releases/tag/v0.1.0
|
|
@@ -7,8 +7,16 @@ authors:
|
|
|
7
7
|
given-names: "Abd'gafar Tunde"
|
|
8
8
|
orcid: "https://orcid.org/0000-0003-1641-7196"
|
|
9
9
|
affiliation: "School of Mathematics, Jilin University"
|
|
10
|
-
version: "0.1.
|
|
11
|
-
date-released: "2026-
|
|
10
|
+
version: "0.1.1"
|
|
11
|
+
date-released: "2026-11-09"
|
|
12
|
+
doi: 10.5281/zenodo.23385097
|
|
13
|
+
identifiers:
|
|
14
|
+
- type: doi
|
|
15
|
+
value: 10.5281/zenodo.23385097
|
|
16
|
+
description: "Concept DOI: all versions, resolving to the latest"
|
|
17
|
+
- type: doi
|
|
18
|
+
value: 10.5281/zenodo.23385098
|
|
19
|
+
description: "Version 0.1.0"
|
|
12
20
|
license: MIT
|
|
13
21
|
repository-code: "https://github.com/abdgafartunde/ertkit"
|
|
14
22
|
url: "https://abdgafartunde.github.io/ertkit/"
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: ertkit
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.1
|
|
4
4
|
Summary: Resistivity inversion for groundwater exploration (VES now, 2.5-D ERT planned), with uncertainty and depth of investigation.
|
|
5
5
|
Project-URL: Documentation, https://abdgafartunde.github.io/ertkit/
|
|
6
6
|
Project-URL: Source, https://github.com/abdgafartunde/ertkit
|
|
7
7
|
Project-URL: Issues, https://github.com/abdgafartunde/ertkit/issues
|
|
8
8
|
Project-URL: Changelog, https://github.com/abdgafartunde/ertkit/blob/main/CHANGELOG.md
|
|
9
|
+
Project-URL: Citation, https://doi.org/10.5281/zenodo.23385097
|
|
9
10
|
Author: Abd'gafar Tunde Tiamiyu
|
|
10
11
|
License-Expression: MIT
|
|
11
12
|
License-File: LICENSE
|
|
@@ -37,6 +38,7 @@ Description-Content-Type: text/markdown
|
|
|
37
38
|
[](https://github.com/abdgafartunde/ertkit/actions/workflows/ci.yml)
|
|
38
39
|
[](https://abdgafartunde.github.io/ertkit/)
|
|
39
40
|
[](https://github.com/abdgafartunde/ertkit/blob/main/LICENSE)
|
|
41
|
+
[](https://doi.org/10.5281/zenodo.23385097)
|
|
40
42
|
|
|
41
43
|
**Resistivity imaging for groundwater exploration, with an honest account of
|
|
42
44
|
what the data can resolve.**
|
|
@@ -107,10 +109,12 @@ deviation).
|
|
|
107
109
|
|
|
108
110
|
## Status
|
|
109
111
|
|
|
110
|
-
Release 0.1 covers vertical electrical sounding: a layered-earth forward
|
|
112
|
+
Release 0.1.1 covers vertical electrical sounding: a layered-earth forward
|
|
111
113
|
model, few-layer inversion with linearized uncertainty, smooth inversion with
|
|
112
|
-
sensitivity and a depth of investigation, CSV input and plotting.
|
|
113
|
-
|
|
114
|
+
sensitivity and a depth of investigation, CSV input and plotting. This patch
|
|
115
|
+
screens weak synthetic signals before adding noise, corrects smooth-inversion
|
|
116
|
+
stopping summaries, and requires at least three layers for a smooth grid.
|
|
117
|
+
Two-layer fitting remains available through `invert_few_layer`. Planned releases:
|
|
114
118
|
|
|
115
119
|
| Release | Content |
|
|
116
120
|
|---|---|
|
|
@@ -147,7 +151,9 @@ and the [Code of Conduct](https://github.com/abdgafartunde/ertkit/blob/main/CODE
|
|
|
147
151
|
|
|
148
152
|
## Citing
|
|
149
153
|
|
|
150
|
-
Each release is archived on Zenodo with a DOI
|
|
154
|
+
Each release is archived on Zenodo with a DOI; to cite ertkit in general, use
|
|
155
|
+
the concept DOI [10.5281/zenodo.23385097](https://doi.org/10.5281/zenodo.23385097),
|
|
156
|
+
which always resolves to the latest version. Citation metadata are in
|
|
151
157
|
[CITATION.cff](https://github.com/abdgafartunde/ertkit/blob/main/CITATION.cff);
|
|
152
158
|
please also cite the methods ertkit implements.
|
|
153
159
|
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
[](https://github.com/abdgafartunde/ertkit/actions/workflows/ci.yml)
|
|
5
5
|
[](https://abdgafartunde.github.io/ertkit/)
|
|
6
6
|
[](https://github.com/abdgafartunde/ertkit/blob/main/LICENSE)
|
|
7
|
+
[](https://doi.org/10.5281/zenodo.23385097)
|
|
7
8
|
|
|
8
9
|
**Resistivity imaging for groundwater exploration, with an honest account of
|
|
9
10
|
what the data can resolve.**
|
|
@@ -74,10 +75,12 @@ deviation).
|
|
|
74
75
|
|
|
75
76
|
## Status
|
|
76
77
|
|
|
77
|
-
Release 0.1 covers vertical electrical sounding: a layered-earth forward
|
|
78
|
+
Release 0.1.1 covers vertical electrical sounding: a layered-earth forward
|
|
78
79
|
model, few-layer inversion with linearized uncertainty, smooth inversion with
|
|
79
|
-
sensitivity and a depth of investigation, CSV input and plotting.
|
|
80
|
-
|
|
80
|
+
sensitivity and a depth of investigation, CSV input and plotting. This patch
|
|
81
|
+
screens weak synthetic signals before adding noise, corrects smooth-inversion
|
|
82
|
+
stopping summaries, and requires at least three layers for a smooth grid.
|
|
83
|
+
Two-layer fitting remains available through `invert_few_layer`. Planned releases:
|
|
81
84
|
|
|
82
85
|
| Release | Content |
|
|
83
86
|
|---|---|
|
|
@@ -114,7 +117,9 @@ and the [Code of Conduct](https://github.com/abdgafartunde/ertkit/blob/main/CODE
|
|
|
114
117
|
|
|
115
118
|
## Citing
|
|
116
119
|
|
|
117
|
-
Each release is archived on Zenodo with a DOI
|
|
120
|
+
Each release is archived on Zenodo with a DOI; to cite ertkit in general, use
|
|
121
|
+
the concept DOI [10.5281/zenodo.23385097](https://doi.org/10.5281/zenodo.23385097),
|
|
122
|
+
which always resolves to the latest version. Citation metadata are in
|
|
118
123
|
[CITATION.cff](https://github.com/abdgafartunde/ertkit/blob/main/CITATION.cff);
|
|
119
124
|
please also cite the methods ertkit implements.
|
|
120
125
|
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Citing ertkit
|
|
2
|
+
|
|
3
|
+
Each release of ertkit is archived on Zenodo, which issues a DOI for every
|
|
4
|
+
version and a concept DOI that always resolves to the latest version:
|
|
5
|
+
|
|
6
|
+
- all versions (concept DOI):
|
|
7
|
+
[10.5281/zenodo.23385097](https://doi.org/10.5281/zenodo.23385097)
|
|
8
|
+
- version 0.1.0:
|
|
9
|
+
[10.5281/zenodo.23385098](https://doi.org/10.5281/zenodo.23385098)
|
|
10
|
+
|
|
11
|
+
To make results reproducible, cite the version you used. The citation
|
|
12
|
+
metadata are in
|
|
13
|
+
[CITATION.cff](https://github.com/abdgafartunde/ertkit/blob/main/CITATION.cff),
|
|
14
|
+
from which GitHub offers APA and BibTeX entries ("Cite this repository").
|
|
15
|
+
|
|
16
|
+
Please also cite the methods ertkit implements; the references are listed in
|
|
17
|
+
the [user guide](user_guide/ves.md#references).
|
|
@@ -87,6 +87,10 @@ $$
|
|
|
87
87
|
|
|
88
88
|
A {class}`~ertkit.ves.Sounding` removes readings that cannot be inverted in
|
|
89
89
|
log space ($R \le 0$, or $|R|$ below three times $a$) and warns about them.
|
|
90
|
+
{meth}`~ertkit.ves.Sounding.synthetic` screens the noise-free readings before
|
|
91
|
+
drawing noise, then screens the noisy readings again. A weak signal cannot
|
|
92
|
+
become an accepted reading just because a large log-space noise draw amplified
|
|
93
|
+
it. If no reading is usable, it raises `ValueError`.
|
|
90
94
|
|
|
91
95
|
## Few-layer inversion
|
|
92
96
|
|
|
@@ -162,8 +166,16 @@ Constable et al. 1987): the regularization weight $\mu$ is the largest with
|
|
|
162
166
|
$\chi^2 = N_d$. If even the smoothest model fits better than that, ertkit
|
|
163
167
|
reports it and warns that the errors may be overestimated. If no model reaches
|
|
164
168
|
$\chi^2 = N_d$, which happens for a few percent of soundings even with correct
|
|
165
|
-
errors, the inversion
|
|
166
|
-
`chi2_target`), and warns only when
|
|
169
|
+
errors, the inversion targets 1.1 times the smallest misfit instead (recorded
|
|
170
|
+
in `chi2_target`), and warns about a poor fit only when the smallest misfit is
|
|
171
|
+
improbably large. The `stop_reason` distinguishes reaching the relaxed target
|
|
172
|
+
from finding that the smoothest model already fits better, or that the target
|
|
173
|
+
remains unreachable.
|
|
174
|
+
|
|
175
|
+
The smooth grid requires at least three layers, including the bottom
|
|
176
|
+
half-space, so that its first and last interfaces span `depth_range`. For a
|
|
177
|
+
two-layer fit with an estimated interface depth, use
|
|
178
|
+
{func}`~ertkit.ves.invert_few_layer` with `n_layers=2`.
|
|
167
179
|
|
|
168
180
|
The result, a {class}`~ertkit.ves.SmoothFit`, includes:
|
|
169
181
|
|
|
@@ -51,6 +51,7 @@ Documentation = "https://abdgafartunde.github.io/ertkit/"
|
|
|
51
51
|
Source = "https://github.com/abdgafartunde/ertkit"
|
|
52
52
|
Issues = "https://github.com/abdgafartunde/ertkit/issues"
|
|
53
53
|
Changelog = "https://github.com/abdgafartunde/ertkit/blob/main/CHANGELOG.md"
|
|
54
|
+
Citation = "https://doi.org/10.5281/zenodo.23385097"
|
|
54
55
|
|
|
55
56
|
[dependency-groups]
|
|
56
57
|
test = [
|
|
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
|
|
|
18
18
|
commit_id: str | None
|
|
19
19
|
__commit_id__: str | None
|
|
20
20
|
|
|
21
|
-
__version__ = version = '0.1.
|
|
22
|
-
__version_tuple__ = version_tuple = (0, 1,
|
|
21
|
+
__version__ = version = '0.1.1'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 1, 1)
|
|
23
23
|
|
|
24
24
|
__commit_id__ = commit_id = None
|
|
@@ -121,7 +121,9 @@ class Sounding:
|
|
|
121
121
|
Noise is drawn from the error model in log space:
|
|
122
122
|
:math:`\ln \rho_a^{\mathrm{obs}} = \ln \rho_a + s \, \varepsilon`, with
|
|
123
123
|
:math:`\varepsilon \sim N(0, 1)` and :math:`s` evaluated at the
|
|
124
|
-
noise-free data.
|
|
124
|
+
noise-free data. Unusable noise-free readings are removed before
|
|
125
|
+
drawing noise, so a signal below the noise floor cannot be amplified
|
|
126
|
+
into a usable reading. Noisy readings are screened again afterwards.
|
|
125
127
|
|
|
126
128
|
Parameters
|
|
127
129
|
----------
|
|
@@ -138,13 +140,23 @@ class Sounding:
|
|
|
138
140
|
Returns
|
|
139
141
|
-------
|
|
140
142
|
Sounding
|
|
143
|
+
|
|
144
|
+
Raises
|
|
145
|
+
------
|
|
146
|
+
ValueError
|
|
147
|
+
If no noise-free or noisy reading is usable.
|
|
148
|
+
|
|
149
|
+
Warns
|
|
150
|
+
-----
|
|
151
|
+
DataWarning
|
|
152
|
+
If noise-free or noisy readings are removed.
|
|
141
153
|
"""
|
|
142
154
|
error = ErrorModel() if error is None else error
|
|
143
155
|
generator = np.random.default_rng(rng)
|
|
144
|
-
clean = forward(model, survey)
|
|
145
|
-
s = error.log_std(clean
|
|
146
|
-
noisy = clean * np.exp(s * generator.standard_normal(clean.
|
|
147
|
-
return cls(survey=survey, rhoa=noisy, error=error)
|
|
156
|
+
clean = cls(survey=survey, rhoa=forward(model, survey), error=error)
|
|
157
|
+
s = error.log_std(clean.resistance)
|
|
158
|
+
noisy = clean.rhoa * np.exp(s * generator.standard_normal(clean.n_data))
|
|
159
|
+
return cls(survey=clean.survey, rhoa=noisy, error=error)
|
|
148
160
|
|
|
149
161
|
@property
|
|
150
162
|
def n_data(self) -> int:
|
|
@@ -385,7 +385,9 @@ def invert_smooth(
|
|
|
385
385
|
data : Sounding
|
|
386
386
|
The data and their error model.
|
|
387
387
|
n_layers : int, optional
|
|
388
|
-
Number of layers, including the bottom half-space.
|
|
388
|
+
Number of layers, including the bottom half-space. At least 3, so
|
|
389
|
+
that distinct first and last interfaces span ``depth_range``.
|
|
390
|
+
Default 30. Use :func:`~ertkit.ves.invert_few_layer` for a two-layer fit.
|
|
389
391
|
depth_range : (float, float), optional
|
|
390
392
|
Depths in meters of the first and last layer interfaces, which are
|
|
391
393
|
spaced logarithmically. Default: 0.3 times the smallest and 3 times
|
|
@@ -405,7 +407,7 @@ def invert_smooth(
|
|
|
405
407
|
TypeError
|
|
406
408
|
If ``data`` is not a :class:`Sounding`.
|
|
407
409
|
ValueError
|
|
408
|
-
If ``n_layers`` is less than
|
|
410
|
+
If ``n_layers`` is less than 3, ``max_iter`` is less than 1, or
|
|
409
411
|
``depth_range`` is invalid.
|
|
410
412
|
|
|
411
413
|
Warns
|
|
@@ -424,9 +426,11 @@ def invert_smooth(
|
|
|
424
426
|
-----
|
|
425
427
|
The method is Occam's inversion (Constable et al. 1987). If no model
|
|
426
428
|
reaches :math:`\chi^2 = N_d` (which happens for a few percent of soundings
|
|
427
|
-
even with correct errors), the inversion
|
|
428
|
-
misfit instead, recorded in ``chi2_target
|
|
429
|
-
|
|
429
|
+
even with correct errors), the inversion targets 1.1 times the smallest
|
|
430
|
+
misfit instead, recorded in ``chi2_target``. The ``stop_reason`` says
|
|
431
|
+
whether this relaxed target was reached, the smoothest model already fits
|
|
432
|
+
better, or the target remains unreachable. A poor-fit warning is issued
|
|
433
|
+
only if the smallest misfit is improbably large.
|
|
430
434
|
|
|
431
435
|
The depth of investigation follows Oldenburg and Li (1999), with reference
|
|
432
436
|
models of 0.1 and 10 times the geometric mean apparent resistivity (a
|
|
@@ -448,8 +452,11 @@ def invert_smooth(
|
|
|
448
452
|
raise TypeError(f"data must be a Sounding, got {type(data_obj).__name__}")
|
|
449
453
|
n_layers = operator.index(n_layers)
|
|
450
454
|
max_iter = operator.index(max_iter)
|
|
451
|
-
if n_layers <
|
|
452
|
-
raise ValueError(
|
|
455
|
+
if n_layers < 3:
|
|
456
|
+
raise ValueError(
|
|
457
|
+
"a smooth model needs at least 3 layers to span depth_range; "
|
|
458
|
+
"use invert_few_layer for a two-layer fit"
|
|
459
|
+
)
|
|
453
460
|
if max_iter < 1:
|
|
454
461
|
raise ValueError("max_iter must be at least 1")
|
|
455
462
|
thickness = _layer_thicknesses(data, n_layers, depth_range)
|
|
@@ -466,7 +473,11 @@ def invert_smooth(
|
|
|
466
473
|
start, max_iter, target=target
|
|
467
474
|
)
|
|
468
475
|
n_iter += refit_iter
|
|
469
|
-
reason =
|
|
476
|
+
reason = (
|
|
477
|
+
_TARGET_RELAXED
|
|
478
|
+
if converged and refit_reason == _TARGET_REACHED
|
|
479
|
+
else f"chi2 = N_d cannot be reached; relaxed target: {refit_reason}"
|
|
480
|
+
)
|
|
470
481
|
if stats.chi2.sf(chi2_min, data.n_data) < _POOR_FIT_P_VALUE:
|
|
471
482
|
n_segments = int(_segments(data.survey.mn2).max()) + 1
|
|
472
483
|
warnings.warn(
|
|
@@ -26,6 +26,32 @@ class TestSounding:
|
|
|
26
26
|
b = Sounding.synthetic(MODEL, SURVEY, rng=np.random.default_rng(7))
|
|
27
27
|
np.testing.assert_array_equal(a.rhoa, b.rhoa)
|
|
28
28
|
|
|
29
|
+
def test_synthetic_screens_weak_signals_before_drawing_noise(self) -> None:
|
|
30
|
+
# Long spacings have negligible transfer resistance. Log-space noise
|
|
31
|
+
# must not amplify them into apparently usable, enormous readings.
|
|
32
|
+
model = LayeredModel(resistivity=[100.0], thickness=[])
|
|
33
|
+
survey = Survey.schlumberger(ab2=np.geomspace(2.5, 1e6, 30), mn2=0.5)
|
|
34
|
+
error = ErrorModel(relative=0.03, absolute=1e-4)
|
|
35
|
+
clean = forward(model, survey)
|
|
36
|
+
usable = error.usable(clean / survey.geometric_factor)
|
|
37
|
+
assert usable.any()
|
|
38
|
+
assert not usable.all()
|
|
39
|
+
with pytest.warns(DataWarning, match="removed"):
|
|
40
|
+
data = Sounding.synthetic(model, survey, error, rng=0)
|
|
41
|
+
assert np.isin(data.survey.ab2, survey.ab2[usable]).all()
|
|
42
|
+
assert np.all(np.isfinite(data.rhoa))
|
|
43
|
+
# A loose bound for this fixed noise draw around 100 ohm m; the
|
|
44
|
+
# regression produced enormous outliers (and eventually overflow).
|
|
45
|
+
assert data.rhoa.max() < 1000.0
|
|
46
|
+
|
|
47
|
+
def test_synthetic_rejects_a_survey_entirely_below_the_noise_floor(self) -> None:
|
|
48
|
+
model = LayeredModel(resistivity=[100.0], thickness=[])
|
|
49
|
+
survey = Survey.schlumberger(ab2=[1e4, 1e5], mn2=0.5)
|
|
50
|
+
with pytest.raises(ValueError, match="no reading is usable"):
|
|
51
|
+
Sounding.synthetic(
|
|
52
|
+
model, survey, ErrorModel(relative=0.03, absolute=1e-4), rng=0
|
|
53
|
+
)
|
|
54
|
+
|
|
29
55
|
def test_synthetic_noise_has_the_stated_distribution(self) -> None:
|
|
30
56
|
# 2000 soundings of 22 readings: the standardized log residuals should
|
|
31
57
|
# have mean 0 and standard deviation 1. With 44,000 draws the standard
|
|
@@ -267,6 +267,23 @@ def test_unreachable_target_with_correct_errors_is_not_a_poor_fit() -> None:
|
|
|
267
267
|
assert np.isfinite(result.doi)
|
|
268
268
|
|
|
269
269
|
|
|
270
|
+
def test_relaxed_target_preserves_the_smoothest_model_stop_reason() -> None:
|
|
271
|
+
# This coarse grid cannot fit the three-layer earth. After relaxation,
|
|
272
|
+
# even the smoothest model lies below the new target; it has converged,
|
|
273
|
+
# but must not claim to have matched that target.
|
|
274
|
+
survey = Survey.schlumberger(ab2=np.geomspace(2.5, 200.0, 22), mn2=0.5)
|
|
275
|
+
data = Sounding.synthetic(README_MODEL, survey, NOISE, rng=0)
|
|
276
|
+
with pytest.warns(DataWarning, match="poor fit"):
|
|
277
|
+
result = invert_smooth(data, n_layers=3, depth_of_investigation=False)
|
|
278
|
+
assert result.converged
|
|
279
|
+
assert result.chi2 < 0.99 * result.chi2_target
|
|
280
|
+
assert "relaxed target" in result.stop_reason
|
|
281
|
+
assert (
|
|
282
|
+
"the smoothest model fits better than the target misfit" in result.stop_reason
|
|
283
|
+
)
|
|
284
|
+
assert result.stop_reason != _TARGET_RELAXED
|
|
285
|
+
|
|
286
|
+
|
|
270
287
|
@pytest.mark.filterwarnings("ignore:poor fit:ertkit.DataWarning")
|
|
271
288
|
def test_extreme_data_do_not_overflow() -> None:
|
|
272
289
|
# A contrast of 1e4 with 20% noise reported as 0.5%, on 80 layers: before
|
|
@@ -305,7 +322,10 @@ def test_too_few_iterations_warns() -> None:
|
|
|
305
322
|
@pytest.mark.parametrize(
|
|
306
323
|
("kwargs", "match"),
|
|
307
324
|
[
|
|
308
|
-
({"n_layers": 1}, "at least
|
|
325
|
+
({"n_layers": 1}, "at least 3 layers"),
|
|
326
|
+
({"n_layers": 2}, "at least 3 layers"),
|
|
327
|
+
({"n_layers": 2, "depth_range": (1.0, 100.0)}, "at least 3 layers"),
|
|
328
|
+
({"n_layers": 2, "depth_range": (1.0, 1000.0)}, "at least 3 layers"),
|
|
309
329
|
({"max_iter": 0}, "max_iter must be at least 1"),
|
|
310
330
|
({"depth_range": (5.0, 1.0)}, "0 < top < bottom"),
|
|
311
331
|
({"depth_range": (0.0, 10.0)}, "0 < top < bottom"),
|
ertkit-0.1.0/docs/citing.md
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
# Citing ertkit
|
|
2
|
-
|
|
3
|
-
Each release of ertkit is archived on Zenodo, which issues a DOI for every
|
|
4
|
-
version and a concept DOI that always resolves to the latest version. The
|
|
5
|
-
citation metadata are in
|
|
6
|
-
[CITATION.cff](https://github.com/abdgafartunde/ertkit/blob/main/CITATION.cff).
|
|
7
|
-
|
|
8
|
-
Please also cite the methods ertkit implements; the references are listed in
|
|
9
|
-
the [user guide](user_guide/ves.md#references).
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|