riser 1.1.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.
Files changed (98) hide show
  1. riser-1.1.0/LICENSE +21 -0
  2. riser-1.1.0/PKG-INFO +41 -0
  3. riser-1.1.0/README.md +117 -0
  4. riser-1.1.0/pyproject.toml +58 -0
  5. riser-1.1.0/setup.cfg +4 -0
  6. riser-1.1.0/src/riser/__init__.py +63 -0
  7. riser-1.1.0/src/riser/cli/__init__.py +11 -0
  8. riser-1.1.0/src/riser/cli/add_variables.py +111 -0
  9. riser-1.1.0/src/riser/cli/calyr_to_age.py +187 -0
  10. riser-1.1.0/src/riser/cli/compute_slip_rate.py +208 -0
  11. riser-1.1.0/src/riser/cli/compute_slip_rates.py +211 -0
  12. riser-1.1.0/src/riser/cli/compute_slip_rates_mc.py +272 -0
  13. riser-1.1.0/src/riser/cli/divide_variables.py +110 -0
  14. riser-1.1.0/src/riser/cli/interpolate_pdf.py +111 -0
  15. riser-1.1.0/src/riser/cli/make_pdf.py +168 -0
  16. riser-1.1.0/src/riser/cli/multiply_variables.py +110 -0
  17. riser-1.1.0/src/riser/cli/subtract_variables.py +130 -0
  18. riser-1.1.0/src/riser/cli/view_displacement_age_history.py +162 -0
  19. riser-1.1.0/src/riser/cli/view_pdf.py +131 -0
  20. riser-1.1.0/src/riser/cli/view_pdf_stack.py +140 -0
  21. riser-1.1.0/src/riser/constants.py +23 -0
  22. riser-1.1.0/src/riser/integration.py +61 -0
  23. riser-1.1.0/src/riser/plotting/__init__.py +61 -0
  24. riser-1.1.0/src/riser/plotting/cdf_plots.py +146 -0
  25. riser-1.1.0/src/riser/plotting/filter_plots.py +39 -0
  26. riser-1.1.0/src/riser/plotting/mc_plots.py +61 -0
  27. riser-1.1.0/src/riser/plotting/pdf_plots.py +421 -0
  28. riser-1.1.0/src/riser/plotting/variable_pair_plots.py +479 -0
  29. riser-1.1.0/src/riser/precision.py +56 -0
  30. riser-1.1.0/src/riser/probability_functions/__init__.py +50 -0
  31. riser-1.1.0/src/riser/probability_functions/analytics.py +607 -0
  32. riser-1.1.0/src/riser/probability_functions/interpolation.py +97 -0
  33. riser-1.1.0/src/riser/probability_functions/metadata.py +190 -0
  34. riser-1.1.0/src/riser/probability_functions/parametric_functions.py +785 -0
  35. riser-1.1.0/src/riser/probability_functions/probability_density_function.py +324 -0
  36. riser-1.1.0/src/riser/probability_functions/readers.py +487 -0
  37. riser-1.1.0/src/riser/probability_functions/scaling.py +145 -0
  38. riser-1.1.0/src/riser/probability_functions/value_arrays.py +240 -0
  39. riser-1.1.0/src/riser/probability_functions/weight_functions.py +205 -0
  40. riser-1.1.0/src/riser/sampling/__init__.py +29 -0
  41. riser-1.1.0/src/riser/sampling/filtering.py +275 -0
  42. riser-1.1.0/src/riser/sampling/mc_sampling.py +279 -0
  43. riser-1.1.0/src/riser/sampling/pdf_formation.py +214 -0
  44. riser-1.1.0/src/riser/sampling/sample_statistics.py +101 -0
  45. riser-1.1.0/src/riser/slip_rates/__init__.py +22 -0
  46. riser-1.1.0/src/riser/slip_rates/rate_computation.py +392 -0
  47. riser-1.1.0/src/riser/slip_rates/reporting.py +255 -0
  48. riser-1.1.0/src/riser/units.py +240 -0
  49. riser-1.1.0/src/riser/variable_functions/__init__.py +28 -0
  50. riser-1.1.0/src/riser/variable_functions/compare/__init__.py +20 -0
  51. riser-1.1.0/src/riser/variable_functions/compare/comparison.py +234 -0
  52. riser-1.1.0/src/riser/variable_functions/condition/__init__.py +36 -0
  53. riser-1.1.0/src/riser/variable_functions/condition/bracketing.py +88 -0
  54. riser-1.1.0/src/riser/variable_functions/condition/combination.py +79 -0
  55. riser-1.1.0/src/riser/variable_functions/condition/core.py +103 -0
  56. riser-1.1.0/src/riser/variable_functions/condition/self_constraint.py +118 -0
  57. riser-1.1.0/src/riser/variable_functions/condition/trimming.py +107 -0
  58. riser-1.1.0/src/riser/variable_functions/pool/__init__.py +20 -0
  59. riser-1.1.0/src/riser/variable_functions/pool/pooling.py +93 -0
  60. riser-1.1.0/src/riser/variable_functions/transform/__init__.py +23 -0
  61. riser-1.1.0/src/riser/variable_functions/transform/arithmetic.py +585 -0
  62. riser-1.1.0/src/riser/variable_pairs/__init__.py +25 -0
  63. riser-1.1.0/src/riser/variable_pairs/dated_marker.py +142 -0
  64. riser-1.1.0/src/riser/variable_pairs/readers.py +205 -0
  65. riser-1.1.0/src/riser/variable_pairs/variable_pair.py +108 -0
  66. riser-1.1.0/src/riser/variable_types.py +69 -0
  67. riser-1.1.0/src/riser.egg-info/PKG-INFO +41 -0
  68. riser-1.1.0/src/riser.egg-info/SOURCES.txt +96 -0
  69. riser-1.1.0/src/riser.egg-info/dependency_links.txt +1 -0
  70. riser-1.1.0/src/riser.egg-info/entry_points.txt +20 -0
  71. riser-1.1.0/src/riser.egg-info/requires.txt +14 -0
  72. riser-1.1.0/src/riser.egg-info/top_level.txt +1 -0
  73. riser-1.1.0/tests/test_integration.py +48 -0
  74. riser-1.1.0/tests/test_pdf.py +157 -0
  75. riser-1.1.0/tests/test_pdf_analytics.py +424 -0
  76. riser-1.1.0/tests/test_pdf_interpolation.py +121 -0
  77. riser-1.1.0/tests/test_pdf_metadata.py +280 -0
  78. riser-1.1.0/tests/test_pdf_parametric_functions.py +363 -0
  79. riser-1.1.0/tests/test_pdf_readers.py +211 -0
  80. riser-1.1.0/tests/test_pdf_scaling.py +72 -0
  81. riser-1.1.0/tests/test_pdf_value_arrays.py +114 -0
  82. riser-1.1.0/tests/test_precision.py +48 -0
  83. riser-1.1.0/tests/test_sample_filtering.py +65 -0
  84. riser-1.1.0/tests/test_sample_statistics.py +59 -0
  85. riser-1.1.0/tests/test_sampling_mc.py +185 -0
  86. riser-1.1.0/tests/test_sampling_pdf_formation.py +65 -0
  87. riser-1.1.0/tests/test_units.py +107 -0
  88. riser-1.1.0/tests/test_variable_arithmetic.py +359 -0
  89. riser-1.1.0/tests/test_variable_bracketing.py +110 -0
  90. riser-1.1.0/tests/test_variable_combination.py +133 -0
  91. riser-1.1.0/tests/test_variable_comparison.py +163 -0
  92. riser-1.1.0/tests/test_variable_conditioning.py +72 -0
  93. riser-1.1.0/tests/test_variable_constraint.py +110 -0
  94. riser-1.1.0/tests/test_variable_pairs.py +158 -0
  95. riser-1.1.0/tests/test_variable_pooling.py +113 -0
  96. riser-1.1.0/tests/test_variable_trimming.py +100 -0
  97. riser-1.1.0/tests/test_variable_types.py +31 -0
  98. riser-1.1.0/tests/test_weight_functions.py +202 -0
riser-1.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 rzinke
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
riser-1.1.0/PKG-INFO ADDED
@@ -0,0 +1,41 @@
1
+ Metadata-Version: 2.4
2
+ Name: riser
3
+ Version: 1.1.0
4
+ License: MIT License
5
+
6
+ Copyright (c) 2025 rzinke
7
+
8
+ Permission is hereby granted, free of charge, to any person obtaining a copy
9
+ of this software and associated documentation files (the "Software"), to deal
10
+ in the Software without restriction, including without limitation the rights
11
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
+ copies of the Software, and to permit persons to whom the Software is
13
+ furnished to do so, subject to the following conditions:
14
+
15
+ The above copyright notice and this permission notice shall be included in all
16
+ copies or substantial portions of the Software.
17
+
18
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24
+ SOFTWARE.
25
+
26
+ Requires-Python: >=3.12
27
+ License-File: LICENSE
28
+ Requires-Dist: matplotlib>=3.9.0
29
+ Requires-Dist: numpy>=2.0.0
30
+ Requires-Dist: scipy>=1.13.0
31
+ Requires-Dist: toml>=0.10.2
32
+ Requires-Dist: tqdm>=4.67.1
33
+ Provides-Extra: dev
34
+ Requires-Dist: mypy; extra == "dev"
35
+ Requires-Dist: types-toml; extra == "dev"
36
+ Requires-Dist: scipy-stubs; extra == "dev"
37
+ Requires-Dist: types-tqdm; extra == "dev"
38
+ Requires-Dist: pytest; extra == "dev"
39
+ Requires-Dist: ruff; extra == "dev"
40
+ Requires-Dist: sphinx; extra == "dev"
41
+ Dynamic: license-file
riser-1.1.0/README.md ADDED
@@ -0,0 +1,117 @@
1
+ # ***R***ejection sampling for ***I***ncremental ***S***lip ***R***ate calculation v.**2** – RISeR2
2
+
3
+ ![alt text](https://github.com/rzinke/RISeR2/blob/main/assets/RISeR_logo-name.png "RISeR")
4
+
5
+ ## Purpose
6
+ Earthquake fault slip rates describe the displacement accumulation rate across a fault, averaged over some time interval. Slip rates are determined from geologic, geomorphic, or sedimentary markers recording measureable fault slip, and which can be dated using absolute geochronologic methods. Where multiple dateable displacement markers share a common slip history and record different epochs in that history, one can determine *incremental* slip rates. These average over shorter intervals relative to the oldest displacement, and can show the constancy or variability of fault slip over time.
7
+
8
+ **RISeR2** is designed to measure incremental fault slip rates based on the dated displacement history of a fault while fully accounting for uncertainties in the ages, displacements, and derived slip rates. It allows enforcement of Bayesian conditions, including the assumption that the fault did not slip backward at any point in its history. The RISeR2 library hosts a set of analytical functions and sampling tools for computing slip rates; formatting, conditioning, and displaying data; and analyzing the results.
9
+
10
+ ![alt text](https://github.com/rzinke/RISeR2/blob/main/assets/incremental_slip_rates.png "incremental slip rates example")
11
+
12
+ *Example incremental slip rates. Three incremental rates are computed between pairs of among four dated displacement markers (Marker 01–Marker 04). The exact value of each incremental slip rate is uncertain, therefore possible slip rate values are expressed as probability densities. Blue fields show the most probability 68.2% of values.*
13
+
14
+ ## Setup
15
+ RISeR2 can be used as a set of command line tools or as an API. The command line tools form an adaptable pipeline for handling and computing probability density functions, and the API modules form a generalized PDF laboratory.
16
+
17
+ ### Installation
18
+ To install RISeR2, simply run the following command in a UNIX shell:
19
+
20
+ ```
21
+ pip install git+https://github.com/rzinke/RISeR2.git
22
+ ```
23
+
24
+ ### Development Setup
25
+ To use these scripts, clone the GitHub repository to a location of your choice and navigate to that folder.
26
+
27
+ Note: It is recommended to use a Python package manager such conda or mamba. Create a new environment with the necessary packages installed and activate it:
28
+
29
+ ```
30
+ conda env create -n riser -f requirements.yaml
31
+ conda activate riser
32
+ ```
33
+
34
+ Then install RISeR2 into that environment:
35
+
36
+ ```
37
+ pip install -e .
38
+ ```
39
+
40
+ OR
41
+
42
+ ```
43
+ pip install -e ".[dev]"
44
+ ```
45
+
46
+ if you are developing.
47
+
48
+
49
+ ## Top-level Functions and Examples
50
+ RISeR2 provides three command line functions for determining slip rates:
51
+
52
+ - `riser-compute-slip-rate`
53
+ - `riser-compute-slip-rates`
54
+ - `riser-compute-slip-rates-mc`
55
+
56
+ Each tool is designed for different scenarios, and to incorporate different assumptions. See [Slip rate determination](#slip-rate-determination).
57
+
58
+ Example data sets and launch scripts can be found in the `RISeR2/examples` folder.
59
+
60
+
61
+ ## Under the Hood
62
+ For a single dated measurement of fault displacement, a fault **slip rate** measured since the present day is defined as:
63
+
64
+ $\bar{v} = \frac{u}{t}$
65
+
66
+ where $\bar{v}$ is the slip rate averaged over time, $u$ is the displacement across the fault, and $t$ is the time interval over which the displacement accumulated. If multiple dated displacement markers are available along a fault (and all share a common slip history), a displacement-time history or slip history can be determined. For $n$ dated markers, $m = n - 1$ closed intervals in the fault slip history are defined. Slip rates averaged over closed intervals are ***incremental*** **slip rates**, defined as:
67
+
68
+ $\bar{v}_i = \frac{\Delta u_i}{\Delta t_i}$
69
+
70
+ where $i$ is one of the $m$ closed intervals, and $\Delta$ is the change in displacement or time within each interval. RISeR2 is specifically designed to compute incremental slip rates.
71
+
72
+ Often, both the displacement measurement and age of the feature have non-negligible uncertainties. These uncertainties can be expressed as *probability density functions (PDFs)*, which express the *relative likelihood* of any *value* (e.g., time or age, displacement, slip rate, *etc.*) as a function of values. A PDF can take on any shape that adheres to the following criteria:
73
+ - Probability density is never negative. It can be zero or positive over the range of all possible values.
74
+ - The area under the curve is 1.0. I.e., the event is guaranteed to have occurred at some point in the defined values.
75
+
76
+ Strictly defined, a PDF is absolutely continuous (defined over infinitely many values). RISeR2 uses *discrete PDFs*, represented by a discrete and finite vector of possible values, each with a corresponding probability density. The probability density of any value within the vector of PDF values can be determined by linear interpolation between defined probability densities, and values outside the defined vector are assigned zero probability density. Use of discrete PDFs is essential because RISeR2 is designed to work with non-parametric functions (such as calibrated radiocarbon dates) that cannot be described by closed-form equations.
77
+
78
+ **`PDFs`** are the fundamental object in the RISeR2 library. All ages, displacements, and slip rates are expressed as PDFs with the above properties. The PDF can be given a descriptive *name*, and a description of the *variable-type*, e.g., "age", "displacement", "slip rate". The PDF can also be assigned a *unit*—RISeR2 recognizes units consisting of multiples of years (**y**) and meters (**m**).
79
+
80
+ ![alt text](https://github.com/rzinke/RISeR2/blob/main/assets/S1cal_age.png "example multi-modal PDF")
81
+
82
+ *Example of a multi-modal (multi-peaked) PDF. Blue field indicates the most probable 95.4% of values.*
83
+
84
+ Data points defining displacement-time history of a fault are encoded as a **`DatedMarker`**, comprising a PDF representing *age*, and a PDF representing *displacement*. Like a PDF, a DatedMarker can carry a descriptive name. The unit (e.g., "m/y") is determined from the units of the constituent age and displacement PDFs.
85
+
86
+ ![alt text](https://github.com/rzinke/RISeR2/blob/main/assets/dated_markers.png "example dated markers")
87
+
88
+ *Example of a series of dated displacement markers, defining the slip history of a hypothetical fault.*
89
+
90
+
91
+ ### Slip rate determination
92
+
93
+ `riser-compute-slip-rate` is used to determine the slip rate of a fault since present day, based on a single DatedMarker. It uses the analytical formulation (a weighted convolution) of Bird (2007).
94
+
95
+ `riser-compute-slip-rates` is used to compute incremental slip rates between multiple DateMarkers using convolution-based analytical formulas. It assumes that neither the change in age between markers $\Delta t$, nor the change in displacement $\Delta u$ are negative.
96
+
97
+ `riser-compute-slip-rates-mc` invokes Monte Carlo-style sampling of the ages and displacements of multiple DateMarkers in a slip history. The age and displacement PDFs are sampled according to their non-parametric forms using the **Probability Inverse Transform (PIT)** method. Multiple conditions can be enforced on whether the random samples are valid and accepted, or invalid and rejected in the process of **rejection sampling** (discussed in this context in Zinke et al., 2019). Like Gold & Cowgill (2011), `riser-compute-slip-rates-mc` enforces the assumption that the fault did not slip backwards (inversely to its overall kinematics) at any point in its history. This can be especially important in cases where ages and/or displacements uncertainties overlap. A maximum-allowable slip rate may also be provided, to avoid possibilities in which the fault slipped unrealistically fast over multiple earthquake cycles.
98
+
99
+
100
+ ## References
101
+ - Bird, P. (2007), Uncertainties in long-term geologic offset rates of faults: General principles illustrated with data from California and other western states, *Geosphere, 3*, 577–595, https://doi:10.1130/GES00127.1.
102
+ - Gold, R. D., & Cowgill, E. (2011). Deriving fault-slip histories to test for secular variation in slip, with examples from the Kunlun and Awatere faults. *Earth and Planetary Science Letters, 301*, 52–64. https://doi.org/10.1016/j.epsl.2010.10.011
103
+ - Zinke, R., Dolan, J. F., Rhodes, E. J., Van Dissen, R., McGuire, C. P., Hatem, A. E., et al. (2019). Multimillennial incremental slip rate variability of the Clarnce fault at the Tophouse Road site, Marlborough Fault System, New Zealand. *Geophysical Research Letters, 46*, 717–725. https://doi.org/10.1029/2018GL080688
104
+ - Zinke, R., Dolan, J. F., Rhodes, E. J., Van Dissen, R. J., Hatem, A. E., McGuire, C. P., et al. (2021). Latest Pleistocene–Holocene incremental slip rates of the Wairau fault: Implications for long-distance and long-term coordination of faulting between North and South Island, New Zealand. *Geochemistry, Geophysics, Geosystems, 22*, e2021GC009656. https://doi.org/10.1029/2021GC009656
105
+
106
+
107
+ ## Citation
108
+ - Zinke, R., Dolan, J. F., Rhodes, E. J., Van Dissen, R. J., Hatem, A. E., McGuire, C. P., et al. (2021). Latest Pleistocene–Holocene incremental slip rates of the Wairau fault: Implications for long-distance and long-term coordination of faulting between North and South Island, New Zealand. *Geochemistry, Geophysics, Geosystems, 22*, e2021GC009656. https://doi.org/10.1029/2021GC009656
109
+ - Zenodo: https://zenodo.org/records/4733235. https://doi.org/10.5281/zenodo.4733235
110
+
111
+
112
+ ## ⚠️ Disclaimer
113
+ This codebase is provided for research and experimental purposes only.
114
+ It may contain bugs, incomplete features, or incorrect implementations.
115
+
116
+ No warranty is provided, express or implied, regarding the correctness or reliability of the code.
117
+ By using this code, you agree that the authors and contributors are not liable for any damages or issues that may arise.
@@ -0,0 +1,58 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "riser"
7
+ version = "1.1.0"
8
+ license = {file = "LICENSE"}
9
+ requires-python = ">=3.12"
10
+ dependencies = [
11
+ "matplotlib>=3.9.0",
12
+ "numpy>=2.0.0",
13
+ "scipy>=1.13.0",
14
+ "toml>=0.10.2",
15
+ "tqdm>=4.67.1",
16
+ ]
17
+
18
+ [project.optional-dependencies]
19
+ dev = [
20
+ "mypy",
21
+ "types-toml",
22
+ "scipy-stubs",
23
+ "types-tqdm",
24
+ "pytest",
25
+ "ruff",
26
+ "sphinx",
27
+ ]
28
+
29
+ [project.scripts]
30
+ riser-add-variables = "riser.cli.add_variables:main"
31
+ riser-calyr-to-age = "riser.cli.calyr_to_age:main"
32
+ riser-combine-variables = "riser.cli.combine_variables:main"
33
+ riser-compute-gap-probabilities = "riser.cli.compute_gap_probabilities:main"
34
+ riser-compute-ks-statistic = "riser.cli.compute_ks_statistic:main"
35
+ riser-compute-overlap-index = "riser.cli.compute_overlap_index:main"
36
+ riser-compute-slip-rate = "riser.cli.compute_slip_rate:main"
37
+ riser-compute-slip-rates = "riser.cli.compute_slip_rates:main"
38
+ riser-compute-slip-rates-mc = "riser.cli.compute_slip_rates_mc:main"
39
+ riser-cross-correlate-variables = "riser.cli.cross_correlate_variables:main"
40
+ riser-divide-variables = "riser.cli.divide_variables:main"
41
+ riser-interpolate-pdf = "riser.cli.interpolate_pdf:main"
42
+ riser-make-pdf = "riser.cli.make_pdf:main"
43
+ riser-merge-variables = "riser.cli.merge_variables:main"
44
+ riser-multiply-variables = "riser.cli.multiply_variables:main"
45
+ riser-subtract-variables = "riser.cli.subtract_variables:main"
46
+ riser-view-displacement-age-history = "riser.cli.view_displacement_age_history:main"
47
+ riser-view-pdf = "riser.cli.view_pdf:main"
48
+ riser-view-pdf-stack = "riser.cli.view_pdf_stack:main"
49
+
50
+ [tool.ruff]
51
+ line-length = 80
52
+
53
+ [tool.ruff.lint]
54
+ ignore = ["UP009", "RUF022"]
55
+
56
+ [tool.ruff.lint.isort]
57
+ combine-as-imports = true
58
+ lines-after-imports = 2
riser-1.1.0/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,63 @@
1
+ # src/riser/__init__.py
2
+ # -*- coding: utf-8 -*-
3
+ #
4
+ # Copyright (c) 2025 Rob Zinke. Licensed under the MIT License.
5
+
6
+ """
7
+ RISeR2: Rejection sampling for Incremental Slip Rate calculation.
8
+ """
9
+
10
+ from importlib.metadata import version as _version
11
+
12
+
13
+ __version__ = _version("riser")
14
+
15
+
16
+ # Core modules (no internal dependency)
17
+ from . import ( # noqa: I001
18
+ constants,
19
+ integration,
20
+ precision,
21
+ units,
22
+ variable_types,
23
+ )
24
+
25
+
26
+ # Subpackages (imported in dependency order)
27
+ from . import (
28
+ probability_functions,
29
+ variable_functions,
30
+ variable_pairs,
31
+ sampling,
32
+ slip_rates,
33
+ plotting,
34
+ )
35
+
36
+
37
+ # Commonly used classes
38
+ from .probability_functions import PDF
39
+ from .variable_pairs import DatedMarker, VariablePair
40
+
41
+
42
+ # Public API
43
+ __all__ = [
44
+ # Core modules and subpackages
45
+ "constants",
46
+ "integration",
47
+ "precision",
48
+ "units",
49
+ "variable_types",
50
+ "probability_functions",
51
+ "variable_functions",
52
+ "sampling",
53
+ "variable_pairs",
54
+ "slip_rates",
55
+ "plotting",
56
+ # Commonly used classes
57
+ "PDF",
58
+ "VariablePair",
59
+ "DatedMarker",
60
+ ]
61
+
62
+
63
+ # end of file
@@ -0,0 +1,11 @@
1
+ # src/riser/cli/__init__.py
2
+ # -*- coding: utf-8 -*-
3
+ #
4
+ # Copyright (c) 2025 Rob Zinke. Licensed under the MIT License.
5
+
6
+ """
7
+ Command Line Interface tools live here.
8
+ """
9
+
10
+
11
+ # end of file
@@ -0,0 +1,111 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ #
4
+ # Copyright (c) 2025 Rob Zinke. Licensed under the MIT License.
5
+
6
+
7
+ # Import modules
8
+ import argparse
9
+
10
+ import matplotlib.pyplot as plt
11
+
12
+ from riser import (
13
+ plotting,
14
+ probability_functions as PDFs,
15
+ variable_functions as var_fcns,
16
+ )
17
+
18
+
19
+ #################### ARGUMENT PARSER ####################
20
+ description = "Add two random variables expressed as PDFs."
21
+
22
+ examples = """Examples:
23
+ add_variables.py pdf1.txt pdf2.txt -o pdf12.txt
24
+ """
25
+
26
+ def create_parser():
27
+ parser = argparse.ArgumentParser(
28
+ description=description,
29
+ formatter_class=argparse.RawTextHelpFormatter,
30
+ epilog=examples,
31
+ )
32
+
33
+ return parser
34
+
35
+ def cmd_parser(iargs=None):
36
+ parser = create_parser()
37
+
38
+ input_args = parser.add_argument_group("Inputs")
39
+ input_args.add_argument(dest="fname1",
40
+ type=str,
41
+ help="File name of first PDF.")
42
+ input_args.add_argument(dest="fname2",
43
+ type=str,
44
+ help="File name of second PDF.")
45
+
46
+ input_args.add_argument("--name", dest="name",
47
+ type=str,
48
+ help="Name of summed PDF. [None]")
49
+
50
+ output_args = parser.add_argument_group("Outputs")
51
+ output_args.add_argument("-o", "--outname", dest="outname",
52
+ type=str, required=True,
53
+ help="Output file.")
54
+ output_args.add_argument("-v", "--verbose", dest="verbose",
55
+ action="store_true",
56
+ help="Verbose mode.")
57
+ output_args.add_argument("-p", "--plot", dest="plot",
58
+ action="store_true",
59
+ help="Plot distribution.")
60
+
61
+ return parser.parse_args(args=iargs)
62
+
63
+
64
+ #################### MAIN ####################
65
+ def main() -> None:
66
+ # Parse arguments
67
+ inps = cmd_parser()
68
+
69
+ # Read PDFs from files
70
+ pdf1 = PDFs.readers.read_pdf(inps.fname1, verbose=inps.verbose)
71
+ pdf2 = PDFs.readers.read_pdf(inps.fname2, verbose=inps.verbose)
72
+
73
+ # Sample PDFs on same axis
74
+ pdf1, pdf2 = PDFs.interpolation.interpolate_pdfs(
75
+ [pdf1, pdf2], verbose=inps.verbose
76
+ )
77
+
78
+ # Compute summed PDF
79
+ sum_pdf = var_fcns.transform.arithmetic.add_variables(
80
+ pdf1, pdf2, name=inps.name, verbose=inps.verbose
81
+ )
82
+
83
+ # Save to file
84
+ PDFs.readers.save_pdf(inps.outname, sum_pdf, verbose=inps.verbose)
85
+
86
+ # Plot function if requested
87
+ if inps.plot:
88
+ # Initialize figure and axis
89
+ fig, (inpt_ax, sum_ax) = plt.subplots(nrows=2)
90
+
91
+ # Plot input PDFs
92
+ plotting.plot_pdf_filled(inpt_ax, pdf1)
93
+ plotting.plot_pdf_filled(inpt_ax, pdf2)
94
+
95
+ # Plot PDF
96
+ plotting.plot_pdf_labeled(sum_ax, sum_pdf)
97
+
98
+ # Format figure
99
+ inpt_ax.legend()
100
+ inpt_ax.set_title("Inputs")
101
+ sum_ax.set_title("Summed PDF")
102
+ fig.tight_layout()
103
+
104
+ plt.show()
105
+
106
+
107
+ if __name__ == "__main__":
108
+ main()
109
+
110
+
111
+ # end of file
@@ -0,0 +1,187 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ #
4
+ # Copyright (c) 2025 Rob Zinke. Licensed under the MIT License.
5
+
6
+
7
+ # Import modules
8
+ import argparse
9
+
10
+ import matplotlib.pyplot as plt
11
+
12
+ from riser import (
13
+ plotting,
14
+ probability_functions as PDFs,
15
+ sampling,
16
+ units,
17
+ )
18
+
19
+
20
+ #################### ARGUMENT PARSER ####################
21
+ description = (
22
+ "Convert an age PDF from calendar years to (kilo)years before present."
23
+ )
24
+
25
+ examples = """Examples:
26
+ riser-calyr-to-age C_date.txt -o C_age.txt
27
+ riser-calyr-to-age C_date.txt --name C14 --smoothing-type mean --smoothing-width 3 -v -p -o C_age.txt
28
+ """
29
+
30
+ def create_parser():
31
+ parser = argparse.ArgumentParser(
32
+ description=description,
33
+ formatter_class=argparse.RawTextHelpFormatter,
34
+ epilog=examples,
35
+ )
36
+
37
+ return parser
38
+
39
+ def cmd_parser(iargs=None):
40
+ parser = create_parser()
41
+
42
+ input_args = parser.add_argument_group("Inputs")
43
+ input_args.add_argument(dest="date_fname",
44
+ type=str,
45
+ help="Calendar years file name.")
46
+
47
+ # Metadata
48
+ metadata_args = parser.add_argument_group("Metadata")
49
+ metadata_args.add_argument("--name", dest="name",
50
+ type=str,
51
+ help="Name.")
52
+ metadata_args.add_argument("--variable-type", dest="variable_type",
53
+ type=str, default="age",
54
+ help="Variable type. [age]")
55
+
56
+ # Referencing
57
+ referencing_args = parser.add_argument_group("Referencing")
58
+ referencing_args.add_argument("--reference-date", dest="reference_date",
59
+ type=float, default=1950,
60
+ help="Reference date, e.g., 1950 for radiocarbon, 2000 for OSL, etc. "
61
+ "[1950]")
62
+ referencing_args.add_argument("--limit-zero", dest="limit_zero",
63
+ action="store_true",
64
+ help="Limit youngest value to zero.")
65
+
66
+ # Units
67
+ unit_args = parser.add_argument_group("Units")
68
+ unit_args.add_argument("--input-unit", dest="input_unit",
69
+ type=str, default="y",
70
+ help="Unit of input data. [y]")
71
+ unit_args.add_argument("--output-unit", dest="output_unit",
72
+ type=str, default="ky",
73
+ help="Unit of output data. [ky]")
74
+
75
+ # Smoothing
76
+ smoothing_args = parser.add_argument_group("Smoothing")
77
+ smoothing_args.add_argument("--smoothing-type", dest="smoothing_type",
78
+ type=str, choices=sampling.filtering.FILTER_TYPES,
79
+ help="Smoothing filter type. [None]")
80
+ smoothing_args.add_argument("--smoothing-width", dest="smoothing_width",
81
+ type=int, default=0,
82
+ help="Smoothing kernel width. [0]")
83
+
84
+ # Outputs
85
+ output_args = parser.add_argument_group("Outputs")
86
+ output_args.add_argument("-o", "--outname", dest="outname",
87
+ type=str, required=True,
88
+ help="Output file.")
89
+ output_args.add_argument("-v", "--verbose", dest="verbose",
90
+ action="store_true",
91
+ help="Verbose mode.")
92
+ output_args.add_argument("-p", "--plot", dest="plot",
93
+ action="store_true",
94
+ help="Plot.")
95
+
96
+ return parser.parse_args(args=iargs)
97
+
98
+
99
+ #################### MAIN ####################
100
+ def main() -> None:
101
+ # Parse arguments
102
+ inps = cmd_parser()
103
+
104
+ # Read calendar years file
105
+ calyr, calpx, metadata = PDFs.readers.read_calendar_file(
106
+ fname=inps.date_fname,
107
+ name=inps.name,
108
+ variable_type=inps.variable_type,
109
+ unit=inps.input_unit,
110
+ verbose=inps.verbose,
111
+ )
112
+
113
+ # Convert calendar year to years before present (ypb)
114
+ if inps.verbose:
115
+ print(f"Shifting dates relative to reference: {inps.reference_date}")
116
+ ybp = inps.reference_date - calyr
117
+
118
+ # Scale from input units to output units
119
+ x = units.scale_values_by_units(
120
+ ybp, metadata["unit"], inps.output_unit, verbose=inps.verbose
121
+ )
122
+
123
+ # Flip left for right, so age is increasing
124
+ x = x[::-1]
125
+ px = calpx[::-1]
126
+
127
+ # Limit minimum age to zero
128
+ if inps.limit_zero:
129
+ # Non-negative indices
130
+ non_neg_ndx = (x >= 0)
131
+
132
+ # Crop arrays
133
+ x = x[non_neg_ndx]
134
+ px = px[non_neg_ndx]
135
+
136
+ # Form data into PDF
137
+ pdf = PDFs.PDF(
138
+ x=x,
139
+ px=px,
140
+ name=inps.name,
141
+ variable_type=inps.variable_type,
142
+ unit=inps.output_unit,
143
+ )
144
+
145
+ # Smooth data
146
+ if inps.smoothing_width > 0:
147
+ pdf = sampling.filtering.filter_pdf(
148
+ pdf=pdf,
149
+ filter_type=inps.smoothing_type,
150
+ filter_width=inps.smoothing_width,
151
+ edge_padding="zeros",
152
+ verbose=inps.verbose,
153
+ )
154
+
155
+ # Report final stats if requested
156
+ if inps.verbose:
157
+ PDFs.analytics.compute_pdf_statistics(pdf, verbose=True)
158
+
159
+ # Save to file
160
+ PDFs.readers.save_pdf(inps.outname, pdf, verbose=inps.verbose)
161
+
162
+ # Plot function if requested
163
+ if inps.plot:
164
+ # Initialize figure and axis
165
+ fig, (cal_ax, age_ax) = plt.subplots(nrows=2)
166
+
167
+ # Plot calendar years
168
+ cal_ax.plot(calyr, calpx, color="k")
169
+
170
+ # Plot PDF
171
+ plotting.plot_pdf_labeled(age_ax, pdf)
172
+
173
+ # Format plot
174
+ cal_ax.invert_xaxis()
175
+ cal_ax.set_xlabel("Calendar year (CE / BCE)")
176
+ cal_ax.set_ylabel("Probability density")
177
+
178
+ fig.tight_layout()
179
+
180
+ plt.show()
181
+
182
+
183
+ if __name__ == "__main__":
184
+ main()
185
+
186
+
187
+ # end of file