wmbe 0.1.1__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.
wmbe/__init__.py ADDED
@@ -0,0 +1,23 @@
1
+ """
2
+ Initialize WMBE package.
3
+ """
4
+
5
+ from wmbe import data
6
+ from wmbe import initialize
7
+ from wmbe import plot
8
+ from wmbe import save
9
+ from wmbe import solve1p1d
10
+ from wmbe import theory
11
+
12
+ __version__ = "2026.6.07"
13
+
14
+ __all__ = [
15
+ "data",
16
+ "initialize",
17
+ "plot",
18
+ "save",
19
+ "solve",
20
+ "solve1p1d",
21
+ "symbols",
22
+ "theory",
23
+ ]
wmbe/data.py ADDED
@@ -0,0 +1,220 @@
1
+ """
2
+ ---------------------------------------------------------------------
3
+
4
+ Module to import and model Inoue & Li experimental data.
5
+
6
+ ---------------------------------------------------------------------
7
+
8
+ Requires Python packages/modules:
9
+ - :mod:`numpy`
10
+ - :mod:`os`
11
+ - :mod:`pandas`
12
+ - :mod:`scipy.optimize`
13
+
14
+ ---------------------------------------------------------------------
15
+
16
+ .. _`Inoue et al (2017)`: https://doi.org/10.1016/j.geomorph.2017.02.018
17
+ .. _`Li et al (2016)`: https://doi.org/10.25103/jestr.093.10
18
+
19
+ """
20
+
21
+ import os, pandas as pd, numpy as np
22
+ from scipy.optimize import curve_fit
23
+
24
+ def linear_model(x,m,c):
25
+ """
26
+ Simple linear model of form: :math:`y = m x + c`
27
+
28
+ Args:
29
+ x (float or numpy.ndarray) : coordinate
30
+ m (float) : gradient
31
+ c (float) : intercept
32
+
33
+ Returns:
34
+ float or numpy.ndarray: y
35
+ """
36
+ return m*x+c
37
+
38
+ def exponential_decay_model(x,m,c):
39
+ r"""
40
+ Shifted exponential decay model of form: :math:`y = 1 + c \exp(-x/m)`
41
+
42
+ Args:
43
+ x (float or numpy.ndarray) : coordinate
44
+ m (float) : e-folding scale
45
+ c (float) : magnitude
46
+
47
+ Returns:
48
+ float or numpy.ndarray: y
49
+ """
50
+ return 1 + c*np.exp(-x/m)
51
+
52
+ def weathering_model(wetdryN_P,k,w0,tau0):
53
+ r"""
54
+ Shifted exponential decay weathering model:
55
+ :math:`w = 1 + w_0(\\tau+\\tau_0)\exp(-k\chi)`
56
+
57
+ Args:
58
+ wetdryN_P (numpy.ndarray) : pair :math:`(\\tau,\chi)`
59
+ k (float) : reciprocal e-folding scale :math:`k`
60
+ w0 (float) : magnitude :math:`w_0`
61
+ tau0 (float) : time offset :math:`\\tau_0`
62
+
63
+ Returns:
64
+ float: y
65
+ """
66
+ tau = wetdryN_P[0]
67
+ chi = wetdryN_P[1]
68
+ return 1 + w0*(tau+tau0)*np.exp(-k*chi)
69
+
70
+ class ExptData:
71
+ """
72
+ Rock weathering experimental data import and modeling
73
+
74
+ """
75
+ def __init__(self):
76
+ """
77
+ Initialize class instance.
78
+
79
+ Attributes:
80
+ ddict (:obj:`dict`) : data dictionary, to contain experimental results of
81
+ `Inoue et al (2017)`_ and `Li et al (2016)`_ variously on
82
+ rock tensile strength, rock compressive strength,
83
+ erodibility, number of wetting/drying cycles, and confining pressure
84
+ fdict (:obj:`dict`) : 1d model dictionary, to contain regression fits of
85
+ weathering model(s) to experimental data
86
+ sdict (:obj:`dict`) : 2d model dictionary, to contain regression fits of
87
+ 2d weathering model to experimental data
88
+ """
89
+ self.ddict = dict()
90
+ self.fdict = dict()
91
+ self.sdict = dict()
92
+
93
+ def read_excel(self, data_set,
94
+ dir_name=("..","data"), file_name="Inoue_wetdryN_sigmaT",
95
+ header=0, skiprows=[1]):
96
+ """
97
+ Read data from an Excel file into a :mod:`pandas` dataframe
98
+
99
+ Attributes:
100
+ data_set (:obj:`str`) : name of dataset in data dictionary
101
+ dir_name (:obj:`list`) : data source directory as platform-indepedent list
102
+ file_name (:obj:`str`) : data source filename
103
+ header (:obj:`int`) : number of header (column title etc) rows
104
+ skiprows (:obj:`int`) : number of rows to skip when creating dataframe
105
+
106
+ """
107
+ dir_name = os.path.join(*dir_name)
108
+ if not os.path.exists(dir_name):
109
+ print("Cannot find data directory")
110
+ raise
111
+ try:
112
+ df = pd.read_excel(os.path.join(dir_name,file_name+".xlsx"),
113
+ header=header, skiprows=skiprows)
114
+ except OSError:
115
+ print("Cannot find data directory")
116
+ raise
117
+ except:
118
+ raise
119
+ self.ddict.update({data_set:df})
120
+
121
+ def fit_linear_model(self, data_set, x_name, y_name, select=None):
122
+ """
123
+ Regress a 1d model against experimental data.
124
+
125
+ Perform a linear regression fit of a linear model to the given
126
+ experimental data, such as modeling the degree of rock weakness
127
+ as a linear function of the number of wetting and drying cycles.
128
+
129
+ Args:
130
+ data_set (str) : which experimental dataset,
131
+ as key to ddict element :class:`pandas.DataFrame`
132
+ x_name (numpy.ndarray) : abscissa :math:`x`
133
+ y_name (numpy.ndarray) : ordinate :math:`y`
134
+ select (str) : which computation of weakness from rock strength
135
+
136
+ Attributes:
137
+ fdict[data_set] or fdict[selection_name] (:obj:`dict` element) :
138
+ model fit
139
+ w_s2_means (:class:`numpy.ndarray`) :
140
+ mean values of weakness :math:`w`
141
+ w_s2_stds (:class:`numpy.ndarray`) :
142
+ standard deviations of weakness :math:`w`
143
+ """
144
+ df = self.ddict[data_set]
145
+ if select is not None:
146
+ for selection in np.unique(self.ddict[data_set][select]):
147
+ selection_name = "{0}_{1}_{2}".format(data_set,select,selection)
148
+ x = df.loc[df[select]==selection][x_name]
149
+ y = df.loc[df[select]==selection][y_name]
150
+ self.fdict[selection_name] = curve_fit(linear_model, x, y)
151
+ else:
152
+ x = df[x_name]
153
+ y = df[y_name]
154
+ self.fdict[data_set] = curve_fit(linear_model, x, y)
155
+
156
+ self.w_s2_means = self.ddict[data_set].groupby("wetdryN").mean()["w_sigma2"]
157
+ self.w_s2_stds = self.ddict[data_set].groupby("wetdryN").std()[ "w_sigma2"]
158
+
159
+ def fit_weathering_model(self, data_set, select):
160
+ """
161
+ Regress a 2d model against experimental data.
162
+
163
+ Args:
164
+ data_set (:obj:`str`) : which experimental dataset,
165
+ as key to ddict element :class:`pandas.DataFrame`
166
+ select (:obj:`str`) : which computation of weakness from rock strength
167
+
168
+ Attributes:
169
+ fdict[data_set] (:obj:`list`) : model surface fit as
170
+ meshgrid X=wet/dry :math:`N`, Y=confining pressure :math:`P`
171
+ and corresponding surface Z[X,Y] as list (X,Y,Z)
172
+ sdict[data_set] (:obj:`list`) : model surface estimates at experimental values as
173
+ meshgrid X=wet/dry :math:`N`, Y=confining pressure :math:`P`
174
+ and corresponding surface Z[X,Y] as list (X,Y,Z)
175
+ w_s2normed_means (:class:`numpy.ndarray`) :
176
+ mean values of model-normed weakness :math:`w`
177
+ w_s2normed_stds (:class:`numpy.ndarray`) :
178
+ standard deviations of :math:`w`
179
+
180
+ """
181
+ df = self.ddict[data_set]
182
+ wdN_vec = df.wetdryN
183
+ P_vec = df.P
184
+ sig_vec = df.sigmaC/180
185
+ w_vec = sig_vec**(-2)
186
+ wdN_P_array = np.vstack((wdN_vec,P_vec))
187
+ model_fit = curve_fit(weathering_model, wdN_P_array, w_vec)
188
+ self.fdict[data_set] = model_fit
189
+
190
+ n_pts = 30
191
+ X = np.linspace(0, wdN_vec.max()*1.1, n_pts)
192
+ Y = np.linspace(0, P_vec.max()*1.1, n_pts)
193
+ X,Y = np.meshgrid(X, Y)
194
+ X_Y_array = np.vstack((X.reshape(n_pts**2), Y.reshape(n_pts**2)))
195
+ Z = weathering_model(X_Y_array,*model_fit[0]).reshape(n_pts,n_pts)
196
+ self.fdict[data_set+"_"+select+"_surface"] = (X,Y,Z)
197
+
198
+ P_vec = np.linspace(0,P_vec.max()*1.3)
199
+ X,Y = np.meshgrid(np.unique(wdN_vec), P_vec)
200
+ X_Y_array = np.vstack((X.reshape(X.shape[0]*Y.shape[1]),
201
+ Y.reshape(X.shape[0]*Y.shape[1])))
202
+ self.sdict[data_set] \
203
+ = X[0], Y[:,0], \
204
+ weathering_model(X_Y_array,*model_fit[0]).reshape(X.shape[0],Y.shape[1])
205
+
206
+ pd.options.mode.chained_assignment = None
207
+ w_ref_vec = (self.sdict[data_set][2].T.copy())[:,0]-1
208
+ df["w_s2normed"] = 0.0
209
+ for idx,wetdryN in enumerate(np.unique(df.wetdryN)):
210
+ w__ = df.w_sigma2[df.wetdryN==wetdryN].copy()
211
+ w_normed = (w__-1)/w_ref_vec[idx]+1
212
+ # df["w_s2normed"][(idx*3):(idx*3+3)] = w_normed
213
+ # Updated 2024/05/29
214
+ df.loc[(idx*3):(idx*3+3),"w_s2normed"] = w_normed #.astype("float")
215
+
216
+ self.w_s2normed_means = self.ddict["li"].groupby("P").mean()["w_s2normed"]
217
+ self.w_s2normed_stds = self.ddict["li"].groupby("P").std()["w_s2normed"]
218
+
219
+
220
+
wmbe/initialize.py ADDED
@@ -0,0 +1,65 @@
1
+ """
2
+ Configure to run in `IPython`_.
3
+
4
+ ---------------------------------------------------------------------
5
+
6
+ Sets up `IPython`_ environment if e.g. we're running
7
+ in a `Jupyter notebook`_ or `Jupyter QtConsole`_.
8
+
9
+ - prepares Matplotlib to display inline and (for Macs)
10
+ at a 'retina' resolution -- if this
11
+ is not available, a benign error report (currently disabled)
12
+ is made and progress continues
13
+ - enables automatic reloading (in case the code has been modded) when
14
+ a notebook is re-run in-situ
15
+ """
16
+
17
+ __all__ = [
18
+ "initialize",
19
+ ]
20
+
21
+ def initialize() -> None:
22
+ try:
23
+ from IPython import get_ipython #type: ignore
24
+
25
+ def check_is_ipython() -> bool:
26
+ """Check if we are running an IPython kernel from Jupyter etc."""
27
+ try:
28
+ if "IPKernelApp" not in get_ipython().config: # pragma: no cover
29
+ return False
30
+ except ImportError:
31
+ return False
32
+ except AttributeError:
33
+ return False
34
+ return True
35
+
36
+
37
+ is_python: bool = check_is_ipython()
38
+
39
+ if is_python:
40
+ try:
41
+ get_ipython().run_line_magic(
42
+ "config",
43
+ "InlineBackend.figure_format = 'retina'",
44
+ )
45
+ except NameError:
46
+ pass
47
+
48
+ try:
49
+ get_ipython().run_line_magic("matplotlib", "inline",)
50
+ except NameError:
51
+ pass
52
+
53
+ try:
54
+ get_ipython().run_line_magic("load_ext", "autoreload",)
55
+ get_ipython().run_line_magic("autoreload", "2",)
56
+ except NameError as error:
57
+ print(
58
+ "Error trying to invoke get_ipython(), "
59
+ + "possibly because not running IPython:",
60
+ error,
61
+ )
62
+ except:
63
+ pass
64
+
65
+ initialize()