riser 1.1.0__py3-none-any.whl

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 (67) hide show
  1. riser/__init__.py +63 -0
  2. riser/cli/__init__.py +11 -0
  3. riser/cli/add_variables.py +111 -0
  4. riser/cli/calyr_to_age.py +187 -0
  5. riser/cli/compute_slip_rate.py +208 -0
  6. riser/cli/compute_slip_rates.py +211 -0
  7. riser/cli/compute_slip_rates_mc.py +272 -0
  8. riser/cli/divide_variables.py +110 -0
  9. riser/cli/interpolate_pdf.py +111 -0
  10. riser/cli/make_pdf.py +168 -0
  11. riser/cli/multiply_variables.py +110 -0
  12. riser/cli/subtract_variables.py +130 -0
  13. riser/cli/view_displacement_age_history.py +162 -0
  14. riser/cli/view_pdf.py +131 -0
  15. riser/cli/view_pdf_stack.py +140 -0
  16. riser/constants.py +23 -0
  17. riser/integration.py +61 -0
  18. riser/plotting/__init__.py +61 -0
  19. riser/plotting/cdf_plots.py +146 -0
  20. riser/plotting/filter_plots.py +39 -0
  21. riser/plotting/mc_plots.py +61 -0
  22. riser/plotting/pdf_plots.py +421 -0
  23. riser/plotting/variable_pair_plots.py +479 -0
  24. riser/precision.py +56 -0
  25. riser/probability_functions/__init__.py +50 -0
  26. riser/probability_functions/analytics.py +607 -0
  27. riser/probability_functions/interpolation.py +97 -0
  28. riser/probability_functions/metadata.py +190 -0
  29. riser/probability_functions/parametric_functions.py +785 -0
  30. riser/probability_functions/probability_density_function.py +324 -0
  31. riser/probability_functions/readers.py +487 -0
  32. riser/probability_functions/scaling.py +145 -0
  33. riser/probability_functions/value_arrays.py +240 -0
  34. riser/probability_functions/weight_functions.py +205 -0
  35. riser/sampling/__init__.py +29 -0
  36. riser/sampling/filtering.py +275 -0
  37. riser/sampling/mc_sampling.py +279 -0
  38. riser/sampling/pdf_formation.py +214 -0
  39. riser/sampling/sample_statistics.py +101 -0
  40. riser/slip_rates/__init__.py +22 -0
  41. riser/slip_rates/rate_computation.py +392 -0
  42. riser/slip_rates/reporting.py +255 -0
  43. riser/units.py +240 -0
  44. riser/variable_functions/__init__.py +28 -0
  45. riser/variable_functions/compare/__init__.py +20 -0
  46. riser/variable_functions/compare/comparison.py +234 -0
  47. riser/variable_functions/condition/__init__.py +36 -0
  48. riser/variable_functions/condition/bracketing.py +88 -0
  49. riser/variable_functions/condition/combination.py +79 -0
  50. riser/variable_functions/condition/core.py +103 -0
  51. riser/variable_functions/condition/self_constraint.py +118 -0
  52. riser/variable_functions/condition/trimming.py +107 -0
  53. riser/variable_functions/pool/__init__.py +20 -0
  54. riser/variable_functions/pool/pooling.py +93 -0
  55. riser/variable_functions/transform/__init__.py +23 -0
  56. riser/variable_functions/transform/arithmetic.py +585 -0
  57. riser/variable_pairs/__init__.py +25 -0
  58. riser/variable_pairs/dated_marker.py +142 -0
  59. riser/variable_pairs/readers.py +205 -0
  60. riser/variable_pairs/variable_pair.py +108 -0
  61. riser/variable_types.py +69 -0
  62. riser-1.1.0.dist-info/METADATA +41 -0
  63. riser-1.1.0.dist-info/RECORD +67 -0
  64. riser-1.1.0.dist-info/WHEEL +5 -0
  65. riser-1.1.0.dist-info/entry_points.txt +20 -0
  66. riser-1.1.0.dist-info/licenses/LICENSE +21 -0
  67. riser-1.1.0.dist-info/top_level.txt +1 -0
riser/__init__.py ADDED
@@ -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
riser/cli/__init__.py ADDED
@@ -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
@@ -0,0 +1,208 @@
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
+ constants,
14
+ plotting,
15
+ probability_functions as PDFs,
16
+ variable_pairs,
17
+ )
18
+ from riser.slip_rates import rate_computation, reporting
19
+
20
+
21
+ #################### ARGUMENT PARSER ####################
22
+ description = (
23
+ "Compute the slip rate for a single marker by dividing feature "
24
+ "displacement by age, using the analytical formulation."
25
+ )
26
+
27
+ examples = """Examples:
28
+ compute_slip_rate.py marker_config.toml -o v1
29
+ compute_slip_rate.py marker_config.toml --age-unit-out y --displacement-unit-out mm -o v2/v2
30
+ """
31
+
32
+ def create_parser():
33
+ parser = argparse.ArgumentParser(
34
+ description=description,
35
+ formatter_class=argparse.RawTextHelpFormatter,
36
+ epilog=examples,
37
+ )
38
+
39
+ return parser
40
+
41
+ def cmd_parser(iargs=None):
42
+ parser = create_parser()
43
+
44
+ # Inputs
45
+ input_args = parser.add_argument_group("Inputs")
46
+ input_args.add_argument(dest="marker_config",
47
+ type=str,
48
+ help="Dated displacement marker configuration file.")
49
+
50
+ # Units
51
+ unit_args = parser.add_argument_group("Units")
52
+ unit_args.add_argument("--age-unit-out", dest="age_unit_out",
53
+ type=str,
54
+ help="Output age units.")
55
+ unit_args.add_argument(
56
+ "--displacement-unit-out", dest="displacement_unit_out",
57
+ type=str,
58
+ help="Output displacement units.")
59
+
60
+ # Slip rate
61
+ rate_args = parser.add_argument_group("Slip rates")
62
+ rate_args.add_argument("--limit-positive", dest="limit_positive",
63
+ action="store_true",
64
+ help="Enforce the condition that values are >= to 0.")
65
+ rate_args.add_argument("--max-rate", dest="max_rate",
66
+ type=float,
67
+ help="Maximum slip rate to consider.")
68
+ rate_args.add_argument("--dr", dest="dr",
69
+ type=float, default=0.01,
70
+ help="Slip rate step. [0.01]")
71
+
72
+ # Reporting
73
+ reporting_args = parser.add_argument_group("Reporting")
74
+ reporting_args.add_argument(
75
+ "--confidence-metric", dest="confidence_metric",
76
+ type=str, choices=PDFs.analytics.PDF_CONFIDENCE_METRICS,
77
+ default=PDFs.analytics.DEFAULT_CONFIDENCE_METRIC,
78
+ help=f"Function for computing function confidence. "
79
+ f"[{PDFs.analytics.DEFAULT_CONFIDENCE_METRIC}]")
80
+ reporting_args.add_argument(
81
+ "--confidence-limits", dest="confidence_limits",
82
+ type=float, default=constants.Psigma["1"],
83
+ help=f"Confidence level. [{constants.Psigma['1']:.2f}]")
84
+
85
+ # Outputs
86
+ output_args = parser.add_argument_group("Outputs")
87
+ output_args.add_argument("-o", "--output-prefix", dest="output_prefix",
88
+ type=str, required=True,
89
+ help="Output prefix as <prefix> or <folder>/<prefix>.")
90
+ output_args.add_argument("-v", "--verbose", dest="verbose",
91
+ action="store_true",
92
+ help="Verbose mode.")
93
+ output_args.add_argument("-p", "--plot", dest="plot",
94
+ action="store_true",
95
+ help="Show results plots. Figures will be generated and saved "
96
+ "whether plot flag is raised.")
97
+
98
+ return parser.parse_args(args=iargs)
99
+
100
+
101
+ #################### MAIN ####################
102
+ def main() -> None:
103
+ # Parse arguments
104
+ inps = cmd_parser()
105
+
106
+ # Establish output directory
107
+ reporting.establish_output_dir(inps.output_prefix, verbose=inps.verbose)
108
+
109
+ # Read markers
110
+ markers = variable_pairs.readers.read_dated_markers_from_config(
111
+ inps.marker_config, verbose=inps.verbose
112
+ )
113
+
114
+ # Check that only one marker is specified
115
+ if len(markers) > 1:
116
+ raise ValueError("Only one marker can be specified")
117
+
118
+ # Use only first marker
119
+ marker = next(iter(markers.values()))
120
+
121
+ # Scale input units to output units
122
+ marker.age = PDFs.scaling.scale_pdf_by_units(
123
+ marker.age, inps.age_unit_out, verbose=inps.verbose
124
+ )
125
+
126
+ marker.displacement = PDFs.scaling.scale_pdf_by_units(
127
+ marker.displacement, inps.displacement_unit_out, verbose=inps.verbose
128
+ )
129
+
130
+ # Initialize figure and axis for input marker
131
+ marker_fig, marker_ax = plt.subplots()
132
+
133
+ # Plot marker
134
+ plotting.variable_pair_plots.plot_variable_pair_whisker(
135
+ marker_ax, marker, label=True
136
+ )
137
+
138
+ # Format marker fig
139
+ plotting.variable_pair_plots.set_origin_zero(marker_ax)
140
+ plotting.variable_pair_plots.format_marker_plot(marker_ax, marker)
141
+
142
+ # Save marker fig
143
+ reporting.save_marker_fig(
144
+ inps.output_prefix, marker_fig, verbose=inps.verbose
145
+ )
146
+
147
+ # Compute slip rate
148
+ slip_rate = rate_computation.compute_slip_rate(
149
+ marker=marker,
150
+ dr=inps.dr,
151
+ max_rate=inps.max_rate,
152
+ )
153
+
154
+ # Save PDF to file
155
+ rate_outname = f"{inps.output_prefix}_{slip_rate.name}_slip_rate.txt"
156
+ PDFs.readers.save_pdf(rate_outname, slip_rate, verbose=inps.verbose)
157
+
158
+ # Compute PDF statistics
159
+ pdf_stats = PDFs.analytics.compute_pdf_statistics(
160
+ slip_rate, verbose=inps.verbose
161
+ )
162
+
163
+ # Compute confidence range
164
+ conf_range = PDFs.analytics.compute_pdf_confidence_range(
165
+ pdf=slip_rate,
166
+ metric=inps.confidence_metric,
167
+ confidence=inps.confidence_limits,
168
+ verbose=inps.verbose,
169
+ )
170
+
171
+ # Initialize figure and axis for slip rate PDF
172
+ rate_fig, rate_ax = plt.subplots()
173
+
174
+ # Plot slip rate PDF
175
+ plotting.plot_pdf_labeled(rate_ax, slip_rate)
176
+
177
+ # Plot confidence range
178
+ plotting.plot_pdf_confidence_range(
179
+ rate_ax, slip_rate, conf_range
180
+ )
181
+
182
+ # Save slip rate figure
183
+ reporting.save_slip_rate_fig(
184
+ inps.output_prefix, rate_fig, verbose=inps.verbose
185
+ )
186
+
187
+ # Save slip rate report to file
188
+ if marker.name is None:
189
+ raise AssertionError("Marker name is guaranteed non-None.")
190
+
191
+ reporting.write_slip_rates_report(
192
+ output_prefix=inps.output_prefix,
193
+ formulation="analytical",
194
+ slip_rates={marker.name: slip_rate},
195
+ pdf_statistics={marker.name: pdf_stats},
196
+ verbose=inps.verbose
197
+ )
198
+
199
+ # Plot if requested
200
+ if inps.plot:
201
+ plt.show()
202
+
203
+
204
+ if __name__ == "__main__":
205
+ main()
206
+
207
+
208
+ # end of file