ararpy 0.0.1a1__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.
ararpy/__init__.py ADDED
@@ -0,0 +1,178 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: UTF-8 -*-
3
+ """
4
+ # ==========================================
5
+ # Copyright 2023 Yang
6
+ # webarar - __init__.py
7
+ # ==========================================
8
+ #
9
+ # ArArPy
10
+ #
11
+ """
12
+ import os
13
+
14
+ import pandas as pd
15
+ from . import calc, smp, files
16
+
17
+ """ classes """
18
+ Sample = smp.samples.Sample
19
+ Info = smp.samples.Info
20
+ Table = smp.samples.Table
21
+ Plot = smp.samples.Plot
22
+ Set = smp.samples.Plot.Set
23
+ Label = smp.samples.Plot.Label
24
+ Axis = smp.samples.Plot.Axis
25
+ Text = smp.samples.Plot.Text
26
+
27
+
28
+ class ArArBasic:
29
+ def __init__(self, **kwargs):
30
+ for k, v in kwargs.items():
31
+ setattr(self, k, v)
32
+
33
+
34
+ class ArArData(ArArBasic):
35
+ def __init__(self, **kwargs):
36
+ self.data: list = []
37
+ self.header: list = []
38
+ super().__init__(**kwargs)
39
+ if not isinstance(self.data, list):
40
+ raise TypeError(f"Data must be a list.")
41
+ if len(self.header) != len(self.data):
42
+ self.header = [*self.header, *list(range(len(self.header), len(self.data)))][:len(self.data)]
43
+
44
+ def to_df(self) -> pd.DataFrame: return pd.DataFrame(self.data, index=self.header).transpose()
45
+ def to_list(self) -> list: return self.data
46
+
47
+
48
+ """ information for ararpy """
49
+ name = 'ararpy'
50
+ version = '0.0.1.a1'
51
+ __version__ = version
52
+ full_version = version
53
+ last_update = '2023-12-17'
54
+
55
+ """ functions and attributions for ararpy """
56
+ from_arr = files.arr_file.to_sample
57
+ from_age = files.calc_file.to_sample
58
+ from_full = files.calc_file.full_to_sample
59
+ from_empty = files.new_file.to_sample
60
+
61
+ """ define functions and attributions for Sample class """
62
+ Sample.name = lambda _smp: _smp.Info.sample.name
63
+ Sample.doi = lambda _smp: _smp.Doi
64
+ Sample.sample = lambda _smp: _smp.Info.sample
65
+ Sample.researcher = lambda _smp: _smp.Info.researcher
66
+ Sample.laboratory = lambda _smp: _smp.Info.laboratory
67
+
68
+ Sample.results = lambda _smp: ArArBasic(
69
+ isochron=ArArBasic(**dict(
70
+ (
71
+ {
72
+ 'figure_2': 'normal', 'figure_3': 'inverse', 'figure_4': 'cl_1',
73
+ 'figure_5': 'cl_2', 'figure_6': 'cl_3', 'figure_7': 'three_d'
74
+ }[key],
75
+ ArArBasic(
76
+ **dict(
77
+ (
78
+ {2: 'unselected', 0: 'set1', 1: 'set2'}[_key],
79
+ ArArBasic(**_value)
80
+ ) for (_key, _value) in value.items()
81
+ )
82
+ )
83
+ ) for (key, value) in _smp.Info.results.isochron.items())),
84
+ age_plateau=ArArBasic(
85
+ **dict(({2: 'unselected', 0: 'set1', 1: 'set2'}[key], ArArBasic(**value))
86
+ for (key, value) in _smp.Info.results.age_plateau.items()))
87
+ )
88
+ Sample.sequence = lambda _smp: ArArBasic(
89
+ size=len(_smp.SequenceName), name=_smp.SequenceName,
90
+ value=_smp.SequenceValue, unit=_smp.SequenceUnit,
91
+ mark=ArArBasic(
92
+ size=len(_smp.IsochronMark),
93
+ set1=ArArBasic(
94
+ size=sum([1 if i == 1 else 0 for i in _smp.IsochronMark]),
95
+ index=[index for index, _ in enumerate(_smp.IsochronMark) if _ == 1],
96
+ ),
97
+ set2=ArArBasic(
98
+ size=sum([1 if i == 2 else 0 for i in _smp.IsochronMark]),
99
+ index=[index for index, _ in enumerate(_smp.IsochronMark) if _ == 2],
100
+ ),
101
+ unselected=ArArBasic(
102
+ size=sum([0 if i == 2 or i == 1 else 1 for i in _smp.IsochronMark]),
103
+ index=[index for index, _ in enumerate(_smp.IsochronMark) if _ != 1 and _ != 2],
104
+ ),
105
+ value=_smp.IsochronMark,
106
+ )
107
+ )
108
+
109
+ Sample.initial = smp.initial.initial
110
+ Sample.set_selection = lambda _smp, _index, _mark: smp.plots.set_selection(_smp, _index, _mark)
111
+ Sample.update_table = lambda _smp, _data, _id: smp.table.update_handsontable(_smp, _data, _id)
112
+
113
+ Sample.unknown = lambda _smp: ArArData(
114
+ name='unknown', data=_smp.SampleIntercept
115
+ )
116
+ Sample.blank = lambda _smp: ArArData(
117
+ name='blank', data=_smp.BlankIntercept
118
+ )
119
+ Sample.parameters = lambda _smp: ArArData(
120
+ name='parameters', data=_smp.TotalParam
121
+ )
122
+ Sample.corrected = lambda _smp: ArArData(
123
+ name='parameters', data=_smp.CorrectedValues
124
+ )
125
+ Sample.degas = lambda _smp: ArArData(
126
+ name='parameters', data=_smp.DegasValues
127
+ )
128
+ Sample.isochron = lambda _smp: ArArData(
129
+ name='isochron', data=_smp.IsochronValues
130
+ )
131
+ Sample.apparent_ages = lambda _smp: ArArData(
132
+ name='apparent_ages', data=_smp.ApparentAgeValues
133
+ )
134
+ Sample.publish = lambda _smp: ArArData(
135
+ name='publish', data=_smp.PublishValues
136
+ )
137
+
138
+ Sample.corr_blank = smp.corr.corr_blank
139
+ Sample.corr_massdiscr = smp.corr.corr_massdiscr
140
+ Sample.corr_decay = smp.corr.corr_decay
141
+ Sample.corr_ca = smp.corr.calc_degas_ca
142
+ Sample.corr_k = smp.corr.calc_degas_k
143
+ Sample.corr_cl = smp.corr.calc_degas_cl
144
+ Sample.corr_atm = smp.corr.calc_degas_atm
145
+ Sample.corr_r = smp.corr.calc_degas_r
146
+ Sample.calc_ratio = smp.corr.calc_ratio
147
+
148
+ Sample.recalculate = lambda _smp, **kwargs: smp.calculation.recalculate(_smp, **kwargs)
149
+
150
+ Sample.show_data = lambda _smp: \
151
+ f"Sample Name: \n\t{_smp.name()}\n" \
152
+ f"Doi: \n\t{_smp.doi()}\n" \
153
+ f"Corrected Values: \n\t{_smp.corrected().to_df()}\n" \
154
+ f"Parameters: \n\t{_smp.parameters().to_df()}\n" \
155
+ f"Isochron Values: \n\t{_smp.isochron().to_df()}\n" \
156
+ f"Apparent Ages: \n\t{_smp.apparent_ages().to_df()}\n" \
157
+ f"Publish Table: \n\t{_smp.publish().to_df()}\n"
158
+
159
+ __tab = "\t"
160
+ Sample.help = f"" \
161
+ f"builtin methods:\n " \
162
+ f"{__tab.join([func for func in dir(Sample) if callable(getattr(Sample, func)) and func.startswith('__')])}\n" \
163
+ f"dunder-excluded methods:\n " \
164
+ f"{__tab.join([func for func in dir(Sample) if callable(getattr(Sample, func)) and not func.startswith('__')])}\n"
165
+
166
+
167
+ def test():
168
+ example_dir = os.path.join(os.getcwd(), r'examples')
169
+ print(f"Running: ararpy.test()")
170
+ print(f"============= Open an example .arr file =============")
171
+ file_path = os.path.join(example_dir, r'22WHA0433.arr')
172
+ print(f"{file_path = }")
173
+ print(f"sample = from_arr(file_path=file_path)")
174
+ sample = from_arr(file_path=file_path)
175
+ print(f"{sample.name() = }")
176
+ print(f"{sample.help = }")
177
+ print(f"sample.parameters() = {sample.parameters()}")
178
+ print(f"sample.parameters().to_df() = \n{sample.parameters().to_df()}")
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: UTF-8 -*-
3
+ """
4
+ # ==========================================
5
+ # Copyright 2023 Yang
6
+ # ararpy - calc - __init__.py
7
+ # ==========================================
8
+ """
9
+
10
+ from . import arr, err, spectra, isochron, regression, age, plot, basic, \
11
+ histogram, corr, jvalue, raw_funcs
ararpy/calc/age.py ADDED
@@ -0,0 +1,161 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: UTF-8 -*-
3
+ """
4
+ # ==========================================
5
+ # Copyright 2023 Yang
6
+ # ararpy - calc - age
7
+ # ==========================================
8
+ #
9
+ #
10
+ #
11
+ """
12
+
13
+ # === Internal import ===
14
+ from . import arr
15
+
16
+ # === External import ===
17
+ import numpy as np
18
+
19
+
20
+ def calc_age_min(F, sF, **kwargs) -> tuple:
21
+ """
22
+ Calculate ArAr ages using Min et al. (2000) equation.
23
+ Parameters
24
+ ----------
25
+ F : array-like
26
+ sF : array-like
27
+ kwargs :
28
+ keys : [
29
+ 'F', 'sF', 'L', 'sL', 'Le', 'sLe', 'Lb', 'sLb', 'A', 'sA', 'Ae', 'sAe', 'Ab', 'sAb',
30
+ 't', 'st', 'J', 'sJ', 'W', 'sW', 'No', 'sNo', 'Y', 'sY', 'f', 'sf', 'Min'
31
+ ].
32
+ values : array-like objects.
33
+
34
+ Returns
35
+ -------
36
+
37
+ """
38
+ """
39
+
40
+ kwargs keys: [
41
+ 'F', 'sF', 'L', 'sL', 'Le', 'sLe', 'Lb', 'sLb', 'A', 'sA', 'Ae', 'sAe', 'Ab', 'sAb',
42
+ 't', 'st', 'J', 'sJ', 'W', 'sW', 'No', 'sNo', 'Y', 'sY', 'f', 'sf', 'Min'
43
+ ]. values are array-like objects
44
+ :param F:
45
+ :param sF:
46
+ :param kwargs:
47
+ :return:
48
+ """
49
+ F, sF = arr.array_as_float([F, sF]).astype(float)
50
+ J = arr.array_as_float(kwargs.pop('J'))
51
+ sJ = arr.array_as_float(kwargs.pop('sJ') * J / 100)
52
+ A = arr.array_as_float(kwargs.pop('A'))
53
+ sA = arr.array_as_float(kwargs.pop('sA') * A / 100)
54
+ Ae = arr.array_as_float(kwargs.pop('Ae'))
55
+ sAe = arr.array_as_float(kwargs.pop('sAe') * Ae / 100)
56
+ Ab = arr.array_as_float(kwargs.pop('Ab'))
57
+ sAb = arr.array_as_float(kwargs.pop('sAb') * Ab / 100)
58
+ W = arr.array_as_float(kwargs.pop('W'))
59
+ sW = arr.array_as_float(kwargs.pop('sW') * W / 100)
60
+ Y = arr.array_as_float(kwargs.pop('Y'))
61
+ sY = arr.array_as_float(kwargs.pop('sY') * Y / 100)
62
+ f = arr.array_as_float(kwargs.pop('f'))
63
+ sf = arr.array_as_float(kwargs.pop('sf') * f / 100)
64
+ No = arr.array_as_float(kwargs.pop('No'))
65
+ sNo = arr.array_as_float(kwargs.pop('sNo') * No / 100)
66
+ L = arr.array_as_float(kwargs.pop('L'))
67
+ sL = arr.array_as_float(kwargs.pop('sL') * L / 100)
68
+ Le = arr.array_as_float(kwargs.pop('Le'))
69
+ sLe = arr.array_as_float(kwargs.pop('sLe') * Le / 100)
70
+ Lb = arr.array_as_float(kwargs.pop('Lb'))
71
+ sLb = arr.array_as_float(kwargs.pop('sLb') * Lb / 100)
72
+ t = arr.array_as_float(kwargs.pop('t'))
73
+ st = arr.array_as_float(kwargs.pop('st') * t / 100)
74
+ # Ap = arr.array_as_float(kwargs.pop('Ap'))
75
+ # sAp = arr.array_as_float(kwargs.pop('sAp') * Ap / 100)
76
+ # Kp = arr.array_as_float(kwargs.pop('Kp'))
77
+ # sKp = arr.array_as_float(kwargs.pop('sKp') * Kp / 100)
78
+
79
+ # recalculation using Min et al.(2000) equation
80
+ # lmd = A * W * Y / (f * No)
81
+ V = f * No / ((Ab + Ae) * W * Y)
82
+ sf = 0 # the error of f was not considered by Koppers
83
+ sV = pow((V / f * sf) ** 2 + (V / No * sNo) ** 2 + (V / (Ab + Ae)) ** 2 * (sAb ** 2 + sAe ** 2) +
84
+ (V / W * sW) ** 2 + (V / Y * sY) ** 2, 0.5)
85
+ # standard age in year, change to Ma
86
+ t = t * 1000000
87
+ st = st * 1000000
88
+ # back-calculating Ar40/Ar39 ration for the standard
89
+ stdR = (np.exp(t * L) - 1) / J
90
+ # errors of standard age and decay constants were not applied
91
+ sStdR = pow((stdR / J) ** 2 * sJ ** 2, 0.5)
92
+ # normalize the measured 40Ar/39Ar
93
+ R = F / stdR
94
+ sR_1 = np.sqrt((sF / stdR) ** 2 + (F * sStdR / stdR ** 2) ** 2) # errors of measured 40Ar/39Ar and J value
95
+ sR_2 = np.sqrt((sF / stdR) ** 2) # error of measured 40Ar/39Ar only
96
+
97
+ BB = 1
98
+ KK = np.exp(t / V) - 1 # 40Arr / 40K Use standard age
99
+ XX = BB * KK * R + 1
100
+ k0 = V * np.log(XX)
101
+ e1 = (np.log(XX) * V / f - V * BB * KK * R / (f * XX)) ** 2 * sf ** 2 # sFr
102
+ e2 = (np.log(XX) * V / No) ** 2 * sNo ** 2 # sNo
103
+ e3 = (-1 * np.log(XX) * V / A + BB * KK * R / (A * XX)) ** 2 * sAb ** 2 # sAb
104
+ e4 = (-1 * np.log(XX) * V / A - Ab * KK * R / (Ae ** 2 * XX)) ** 2 * sAe ** 2 # sAe
105
+ e5 = (-1 * np.log(XX) * V / W - V * BB * KK * R / (W * XX)) ** 2 * sW ** 2 # sW
106
+ e6 = (np.log(XX) * V / Y) ** 2 * sY ** 2 # sY
107
+ e7 = (V * BB * KK / XX) ** 2 * sR_1 ** 2 # sR
108
+ # e8 = (V * BB * KK * R / (Ap * XX)) ** 2 * sAp ** 2 # sAp
109
+ # e9 = (V * BB * KK * R / (Kp * XX)) ** 2 * sKp ** 2 # sKp
110
+ e8, e9 = 0, 0
111
+ useDecayConst = False
112
+ if useDecayConst: # k0 = log(L / Le * KK * R + 1) / L
113
+ e1 = (V * BB * KK * R / (f * XX)) ** 2 * sf ** 2
114
+ e2 = 0
115
+ e3 = (-1 * np.log(XX) * V / L + BB * KK * R / (L * XX)) ** 2 * sLb ** 2
116
+ e4 = (-1 * np.log(XX) * V / L - Lb * KK * R / (Le ** 2 * XX)) ** 2 * sLe ** 2
117
+ e5 = (V * BB * KK * R / (W * XX)) ** 2 * sW ** 2
118
+ e6 = 0
119
+ useStandardAge = True
120
+ if useStandardAge:
121
+ e1, e9 = 0, 0
122
+
123
+ # change to Ma
124
+ # analytical error, error of 40Ar/39Ar only
125
+ s1 = np.sqrt((V * KK * R / (R * XX)) ** 2 * sR_2 ** 2) / 1000000
126
+ # internal error, errors of 40Ar/39Ar and J value
127
+ s2 = np.sqrt((V * KK * R / (R * XX)) ** 2 * sR_1 ** 2) / 1000000
128
+ # total external error
129
+ s3 = np.sqrt(e1 + e2 + e3 + e4 + e5 + e6 + e7 + e8 + e9) / 1000000
130
+ age = k0 / 1000000
131
+ return age, s1, s2, s3
132
+
133
+
134
+ def calc_age_general(F, sF, J, sJ, L, sL, **kwargs):
135
+ """
136
+ All passed args should be array-like with the same length
137
+ Parameters
138
+ ----------
139
+ F : array-like object
140
+ sF : array-like object
141
+ J : array-like object
142
+ sJ : array-like object
143
+ L : array-like object
144
+ sL : array-like object
145
+ kwargs
146
+
147
+ Returns
148
+ -------
149
+ tuple of array objects, (age, s1, s2, s3)
150
+ """
151
+ F, sF, J, sJ, L, sL = np.array([F, sF, J, sJ, L, sL])
152
+ sJ = sJ * J / 100
153
+ sL = sL * L / 100
154
+ age = np.log(1 + J * F) / L
155
+ v1 = sF ** 2 * (J / (L * (1 + J * F))) ** 2
156
+ v2 = sJ ** 2 * (F / (L * (1 + J * F))) ** 2
157
+ v3 = sL ** 2 * (np.log(1 + J * F) / (L ** 2)) ** 2
158
+ s1 = v1 ** .5 # analytical error
159
+ s2 = (v1 + v2) ** .5 # internal error
160
+ s3 = (v1 + v2 + v3) ** .5 # full external error
161
+ return age / 1000000, s1 / 1000000, s2 / 1000000, s3 / 1000000