ararpy 0.1.199__py3-none-any.whl → 0.2.2__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 (41) hide show
  1. ararpy/Example - Check arr.py +52 -0
  2. ararpy/Example - Granite Cooling History.py +411 -0
  3. ararpy/Example - Plot temperature calibration.py +291 -0
  4. ararpy/Example - Show MDD results.py +561 -0
  5. ararpy/Example - Show all Kfs age spectra.py +344 -0
  6. ararpy/Example - Show random walk results.py +363 -0
  7. ararpy/Example - Tc calculation.py +437 -0
  8. ararpy/__init__.py +3 -4
  9. ararpy/calc/age.py +34 -36
  10. ararpy/calc/arr.py +0 -20
  11. ararpy/calc/basic.py +26 -3
  12. ararpy/calc/corr.py +131 -85
  13. ararpy/calc/jvalue.py +7 -5
  14. ararpy/calc/plot.py +1 -2
  15. ararpy/calc/raw_funcs.py +41 -2
  16. ararpy/calc/regression.py +224 -132
  17. ararpy/files/arr_file.py +2 -1
  18. ararpy/files/basic.py +0 -22
  19. ararpy/files/calc_file.py +107 -84
  20. ararpy/files/raw_file.py +242 -229
  21. ararpy/smp/basic.py +133 -34
  22. ararpy/smp/calculation.py +6 -6
  23. ararpy/smp/corr.py +339 -153
  24. ararpy/smp/diffusion_funcs.py +345 -36
  25. ararpy/smp/export.py +247 -129
  26. ararpy/smp/info.py +2 -2
  27. ararpy/smp/initial.py +93 -45
  28. ararpy/smp/json.py +2 -2
  29. ararpy/smp/plots.py +144 -164
  30. ararpy/smp/raw.py +11 -15
  31. ararpy/smp/sample.py +222 -181
  32. ararpy/smp/style.py +26 -7
  33. ararpy/smp/table.py +42 -33
  34. ararpy/thermo/atomic_level_random_walk.py +56 -48
  35. ararpy/thermo/basic.py +2 -2
  36. {ararpy-0.1.199.dist-info → ararpy-0.2.2.dist-info}/METADATA +10 -1
  37. ararpy-0.2.2.dist-info/RECORD +73 -0
  38. {ararpy-0.1.199.dist-info → ararpy-0.2.2.dist-info}/WHEEL +1 -1
  39. ararpy-0.1.199.dist-info/RECORD +0 -66
  40. {ararpy-0.1.199.dist-info → ararpy-0.2.2.dist-info}/licenses/LICENSE +0 -0
  41. {ararpy-0.1.199.dist-info → ararpy-0.2.2.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,437 @@
1
+ # Copyright (C) 2024 Yang. - All Rights Reserved
2
+ """
3
+ # ==========================================
4
+ # Copyright 2024 Yang
5
+ # ararpy - test.py
6
+ # ==========================================
7
+ #
8
+ #
9
+ #
10
+ """
11
+ import ararpy as ap
12
+ import numpy as np
13
+ import pdf_maker as pm
14
+ import os
15
+
16
+ import matplotlib
17
+
18
+ matplotlib.use('TkAgg')
19
+ import matplotlib.pyplot as plt
20
+
21
+
22
+ def export_pdf(each_line, X, Y, x, y, Tc_list, sample_name):
23
+
24
+ example_dir = r"C:\Users\Young\OneDrive\00-Projects\【2】个人项目\2022-05论文课题\初稿\封闭温度计算"
25
+
26
+ # ------ 将以下五个样品的年龄谱图组合到一起 -------
27
+ arr_files = [
28
+ os.path.join(example_dir, r'22WHA0433.arr'),
29
+ os.path.join(example_dir, r'20WHA0103.age'),
30
+ ]
31
+ colors = ['#1f3c40', '#e35000', '#e1ae0f', '#3d8ebf']
32
+ series = []
33
+
34
+ # ------ 构建数据 -------
35
+ for index, file in enumerate(arr_files):
36
+ smp = ap.from_arr(file_path=file) if file.endswith('.arr') else ap.from_age(file_path=file)
37
+ age = smp.ApparentAgeValues[2:4]
38
+ ar = smp.DegasValues[20]
39
+ data = ap.calc.spectra.get_data(*age, ar, cumulative=False)
40
+ series.append({
41
+ 'type': 'series.line', 'id': f'line{index * 2 + 0}', 'name': f'line{index * 2 + 0}', 'color': colors[index],
42
+ 'data': np.transpose([data[0], data[1]]).tolist(), 'line_caps': 'square',
43
+ })
44
+ series.append({
45
+ 'type': 'series.line', 'id': f'line{index * 2 + 1}', 'name': f'line{index * 2 + 1}', 'color': colors[index],
46
+ 'data': np.transpose([data[0], data[2]]).tolist(), 'line_caps': 'square',
47
+ })
48
+ series.append({
49
+ 'type': 'text', 'id': f'text{index * 2 + 0}', 'name': f'text{index * 2 + 0}', 'color': colors[index],
50
+ 'text': f'{smp.name()}<r>{round(smp.Info.results.age_plateau[0]["age"], 2)}',
51
+ 'size': 10, 'data': [[index * 15 + 5, 23]],
52
+ })
53
+ data = {
54
+ "data": [
55
+ {
56
+ 'xAxis': [{'extent': [0, 100], 'interval': [0, 20, 40, 60, 80, 100],
57
+ 'title': 'Cumulative <sup>39</sup>Ar Released (%)', 'nameLocation': 'middle', }],
58
+ 'yAxis': [{'extent': [0, 250], 'interval': [0, 50, 100, 150, 200, 250],
59
+ 'title': 'Apparent Age (Ma)', 'nameLocation': 'middle', }],
60
+ 'series': series
61
+ },
62
+ {
63
+ 'xAxis': [{'extent': [0, 100], 'interval': [0, 20, 40, 60, 80, 100],
64
+ 'title': 'Cumulative <sup>39</sup>Ar Released (%)', 'nameLocation': 'middle', }],
65
+ 'yAxis': [{'extent': [0, 250], 'interval': [0, 50, 100, 150, 200, 250],
66
+ 'title': 'Apparent Age (Ma)', 'nameLocation': 'middle', }],
67
+ 'series': series
68
+ }
69
+ ],
70
+ "file_name": f"{sample_name}",
71
+ "plot_names": [f"{sample_name}"],
72
+ }
73
+
74
+ # write pdf
75
+ file = pm.NewPDF(filepath=os.path.join(example_dir, f"{data['file_name']}.pdf"))
76
+ for index, each in enumerate(data['data']):
77
+ # rich text tags should follow this priority: color > script > break
78
+ file.text(page=index, x=50, y=780, line_space=1.2, size=12, base=0, h_align="left",
79
+ text=f"The PDF can be edited with Adobe Acrobat, Illustrator and CorelDRAW")
80
+ cv = ap.smp.export.export_chart_to_pdf(each)
81
+ file.canvas(page=index, base=0, margin_top=5, canvas=cv, unit="cm", h_align="middle")
82
+ if index + 1 < len(data['data']):
83
+ file.add_page()
84
+
85
+ # save pdf
86
+ file.save()
87
+
88
+
89
+ def read_sample(arr_file_path):
90
+ # 读取样品信息
91
+ if not arr_file_path.endswith('.arr'):
92
+ for root, dirs, files in os.walk(arr_file_path):
93
+ for file in files:
94
+ if file.endswith('.arr'):
95
+ arr_file_path = os.path.join(arr_file_path, file)
96
+ break
97
+ print(f"arr file: {arr_file_path}")
98
+ sample = ap.from_arr(file_path=arr_file_path)
99
+ name = sample.name()
100
+ sequence = sample.sequence()
101
+ nsteps = sequence.size
102
+ te = np.array(sample.TotalParam[124], dtype=np.float64)
103
+ ti = (np.array(sample.TotalParam[123], dtype=np.float64) / 60).round(2) # time in minute
104
+ nindex = {"40": 24, "39": 20, "38": 10, "37": 8, "36": 0}
105
+ argon = "39"
106
+ if argon in list(nindex.keys()):
107
+ ar = np.array(sample.DegasValues[nindex[argon]], dtype=np.float64) # 20-21 Argon
108
+ sar = np.array(sample.DegasValues[nindex[argon] + 1], dtype=np.float64)
109
+ elif argon == 'total':
110
+ all_ar = np.array(sample.CorrectedValues, dtype=np.float64) # 20-21 Argon
111
+ ar, sar = ap.calc.arr.add(*all_ar.reshape(5, 2, len(all_ar[0])))
112
+ ar = np.array(ar)
113
+ sar = np.array(sar)
114
+ else:
115
+ raise KeyError
116
+ age = np.array(sample.ApparentAgeValues[2], dtype=np.float64) # 2-3 age
117
+ sage = np.array(sample.ApparentAgeValues[3], dtype=np.float64)
118
+ f = np.cumsum(ar) / ar.sum()
119
+
120
+ # 组合data
121
+ dr2 = [1 for i in range(nsteps)]
122
+ ln_dr2 = [1 for i in range(nsteps)]
123
+ wt = [1 for i in range(nsteps)]
124
+ data = np.array([sequence.value, te, ti, age, sage, ar, sar, f, dr2, ln_dr2, wt]).tolist()
125
+ data.insert(0, (np.where(np.array(data[3]) > 0, True, False) & np.isfinite(data[3])).tolist())
126
+ data.insert(1, [1 for i in range(nsteps)])
127
+ for row in ap.calc.arr.transpose(data):
128
+ print(row)
129
+ return data, name
130
+
131
+
132
+ def calculate_dr2(f, ti, ar, sar, use_ln=True, logdr2_method="plane"):
133
+ try:
134
+ if str(logdr2_method).lower().startswith('plane'.lower()):
135
+ dr2, ln_dr2, wt = ap.smp.diffusion_funcs.dr2_plane(f, ti, ar=ar, sar=sar, ln=use_ln)
136
+ elif str(logdr2_method).lower() == 'yang':
137
+ dr2, ln_dr2, wt = ap.smp.diffusion_funcs.dr2_yang(f, ti, ar=ar, sar=sar, ln=use_ln)
138
+ elif str(logdr2_method).lower().startswith('sphere'.lower()):
139
+ dr2, ln_dr2, wt = ap.smp.diffusion_funcs.dr2_sphere(f, ti, ar=ar, sar=sar, ln=use_ln)
140
+ elif str(logdr2_method).lower().startswith('Thern'.lower()):
141
+ dr2, ln_dr2, wt = ap.smp.diffusion_funcs.dr2_thern(f, ti, ar=ar, sar=sar, ln=use_ln)
142
+ elif str(logdr2_method).lower().startswith('cylinder'.lower()):
143
+ dr2, ln_dr2, wt = ap.smp.diffusion_funcs.dr2_cylinder(f, ti, ar=ar, sar=sar, ln=use_ln)
144
+ elif str(logdr2_method).lower().startswith('cube'.lower()):
145
+ dr2, ln_dr2, wt = ap.smp.diffusion_funcs.dr2_cube(f, ti, ar=ar, sar=sar, ln=use_ln)
146
+ else:
147
+ raise KeyError(f"Geometric model not found: {str(logdr2_method).lower()}")
148
+ except (Exception, BaseException) as e:
149
+ raise ValueError
150
+
151
+ return dr2, ln_dr2, wt
152
+
153
+
154
+ def calculate_tc(arr_file_path, logdr2_method='plane', A=55, cooling_rate=10, radius=100, use_ln=True, index=None):
155
+ base = np.e if use_ln else 10
156
+ # [A, cooling_rate, radius] = [55, 10, 100] # 55, 10°C/Ma, 100µm
157
+
158
+ # 读取样品信息
159
+ [_, _, seq_value, te, ti, age, sage, ar, sar, f, dr2, ln_dr2, wt], name = read_sample(arr_file_path=arr_file_path)
160
+ dr2, ln_dr2, wt = calculate_dr2(f, ti, ar, sar, use_ln=use_ln, logdr2_method=logdr2_method)
161
+ te = [i + 273.15 for i in te]
162
+
163
+ @np.vectorize
164
+ def get_da2_e_Tc(b, m):
165
+ k1 = base ** b * ap.thermo.basic.SEC2YEAR # k1: da2
166
+ k2 = -10 * m * ap.thermo.basic.GAS_CONSTANT * np.log(base) # activation energy, kJ
167
+ try:
168
+ # Closure temperature
169
+ k3, _ = ap.thermo.basic.get_tc(da2=k1, sda2=0, E=k2 * 1000, sE=0, pho=0,
170
+ cooling_rate=cooling_rate, A=A)
171
+ except ValueError as e:
172
+ # print(e.args)
173
+ k3 = 999
174
+ return k1, k2, k3 # da2, E, Tc
175
+
176
+ index = np.s_[index if index is not None else list(range(len(te)))]
177
+ each_line = [np.nan for i in range(17)] # [b, sb, a, sa, ..., energy, se, tc, stc]
178
+ temp_err = 5
179
+ X, Y, wtX, wtY = 10000 / np.array(te), np.array(ln_dr2), 10000 * temp_err / np.array(te) ** 2, np.array(wt)
180
+ x, y, wtx, wty = X[index,], Y[index,], wtX[index,], wtY[index]
181
+ Tc_list = []
182
+
183
+ if len(x) > 0:
184
+
185
+ for cooling_rate in np.linspace(start=0, stop=100, num=100):
186
+ # Arrhenius line regression
187
+ # each_line[0:6] = ap.thermo.basic.fit(x, y, wtx, wty) # intercept, slop, sa, sb, chi2, q
188
+ # b (intercept), sb, a (slope), sa, mswd, dF, Di, k, r2, chi_square, p_value, avg_err_s, cov
189
+ each_line[0:13] = ap.calc.regression.york2(x, wtx, y, wty, ri=np.zeros(len(x)))
190
+ each_line[1] = each_line[1] * 1 # 1 sigma
191
+ each_line[3] = each_line[3] * 1 # 1 sigma
192
+
193
+ # monte carlo simulation with 4000 trials
194
+ cov_matrix = np.array([[each_line[1] ** 2, each_line[12]], [each_line[12], each_line[3] ** 2]])
195
+ mean_vector = np.array([each_line[0], each_line[2]])
196
+ random_numbers = np.random.multivariate_normal(mean_vector, cov_matrix, 4000)
197
+ res, cov = ap.calc.basic.monte_carlo(get_da2_e_Tc, random_numbers, confidence_level=0.95)
198
+ da2, E, Tc = res[0:3, 0]
199
+ # sda2, sE, sTc = np.diff(res[0:3, [1, 2]], axis=1).flatten() / 2
200
+ sda2, sE, sTc = 2 * cov[0, 0] ** .5, 2 * cov[1, 1] ** .5, 2 * cov[2, 2] ** .5 # 95%
201
+
202
+ each_line[13:15] = [E, sE]
203
+ each_line[15:17] = [Tc, sTc]
204
+
205
+ Tc_list.append([cooling_rate, Tc, sTc])
206
+
207
+ Tc_list = np.transpose(Tc_list)
208
+
209
+ return each_line, X, Y, x, y, Tc_list, name
210
+
211
+
212
+ def plot_Tc(file_path, index=None, radius=100, use_ln=True):
213
+ if index is None:
214
+ index = [1, 2, 3, 4, 5]
215
+ logdr2_methods = ['plane', 'cylinder', 'sphere']
216
+ As = [8.7, 27, 55]
217
+
218
+ x1_extent = [10, 0]
219
+ y1_extent = [-5, -10]
220
+
221
+ x2_extent = [0, 100]
222
+ y2_extent = [0, 450]
223
+
224
+ fig, axs = plt.subplots(len(logdr2_methods), 2, figsize=(12, 12))
225
+ for i in range(len(logdr2_methods)):
226
+ logdr2_method = logdr2_methods[i]
227
+ A = As[i]
228
+ each_line, X, Y, x, y, Tc_list, name = calculate_tc(file_path, logdr2_method=logdr2_method, A=A, radius=radius,
229
+ use_ln=use_ln, index=index, cooling_rate=10)
230
+ print(each_line)
231
+ [E, sE] = each_line[13:15]
232
+ axs[i, 0].scatter(X, Y, c='white', edgecolors='black')
233
+ axs[i, 0].scatter(x, y, c='red')
234
+ axs[i, 0].plot([min(x), max(x)], [i * each_line[2] + each_line[0] for i in [min(x), max(x)]], c='blue')
235
+ axs[i, 0].set_title(f'{name} - Arrhenius Plot - {logdr2_method}')
236
+ axs[i, 0].set_xlabel(f'10000 / T')
237
+ axs[i, 0].set_ylabel(f'ln(D/r2)' if use_ln else f'log(D/r2)')
238
+ axs[i, 0].text(axs[0, 0].get_xlim()[0], np.average(axs[0, 0].get_ylim()),
239
+ f'intercept = {each_line[0]:.6f} ± {each_line[1]:.6f}\n'
240
+ f'slope = {each_line[2]:.6f} ± {each_line[3]:.6f}\n'
241
+ f'E = {E / 4.184:.6f} ± {2 * sE / 4.184:.6f} kcal/mol (2sigma)\n'
242
+ f'log(D0/r2) = {each_line[0]:.6f} ± {2 * each_line[1]:.6f} /s (2sigma)\n'
243
+ f'A = {A}\n'
244
+ f'radius = {radius} µm')
245
+
246
+ for s in Tc_list[2]:
247
+ axs[i, 1].plot([Tc_list[0], Tc_list[0]], [Tc_list[1]-2*s, Tc_list[1]+2*s], c="#f0f0f0")
248
+ axs[i, 1].plot([Tc_list[0], Tc_list[0]], [Tc_list[1]-s, Tc_list[1]+s], c="#8e8e8e")
249
+
250
+ axs[i, 1].plot(Tc_list[0], Tc_list[1], c="black")
251
+ axs[i, 1].set_ylim(*[y2_extent])
252
+ axs[i, 1].set_xlim(*[x2_extent])
253
+ axs[i, 1].set_xlabel(f'Cooling Rate')
254
+ axs[i, 1].set_ylabel(f'Closure Temperature')
255
+
256
+ x1_extent = [min(axs[i, 0].get_xlim()[0], x1_extent[0]), max(axs[i, 0].get_xlim()[1], x1_extent[1])]
257
+ y1_extent = [min(axs[i, 0].get_ylim()[0], y1_extent[0]), max(axs[i, 0].get_ylim()[1], y1_extent[1])]
258
+
259
+
260
+ for i in range(len(logdr2_methods)):
261
+ axs[i, 0].set_xlim(*[x1_extent])
262
+ axs[i, 0].set_ylim(*[y1_extent])
263
+
264
+
265
+ print(Tc_list[0])
266
+ fig.tight_layout()
267
+ plt.show()
268
+
269
+
270
+ def export_ar_relase_curve():
271
+
272
+ plot_data = {
273
+ "data": [],
274
+ "file_name": f"-Tc",
275
+ "plot_names": [f"-Tc"],
276
+ }
277
+
278
+ plot_data['data'].append({
279
+ 'xAxis': [{
280
+ 'extent': [400, 1500], 'interval': [400, 600, 800, 1000, 1200, 1400, 1600],
281
+ 'title': f'Temperature [°C]', 'nameLocation': 'middle',
282
+ 'show_frame': True, 'label_size': 10, 'title_size': 10,
283
+ }],
284
+ 'yAxis': [{
285
+ 'extent': [0, 100], 'interval': [0, 20, 40, 60, 80, 100],
286
+ # 'extent': [-25, 0], 'interval': [-30, -25, -20, -15, -10, -5, 0],
287
+ 'title': f'Cumulative argon released [%]', 'nameLocation': 'middle',
288
+ 'show_frame': True, 'label_size': 10, 'title_size': 10,
289
+ }],
290
+ 'series': [
291
+ ]
292
+ })
293
+
294
+ plot_data['data'].append({
295
+ 'xAxis': [{
296
+ 'extent': [0, 100], 'interval': [0, 20, 40, 60, 80, 100],
297
+ 'title': 'Cooling Rate [°C/Ma]', 'nameLocation': 'middle', 'show_frame': True,
298
+ 'label_size': 10, 'title_size': 10,
299
+ }],
300
+ 'yAxis': [{
301
+ 'extent': [0, 850], 'interval': [0, 100, 200, 300, 400, 500, 600, 700, 800],
302
+ 'title': 'Closure Temperature [°C]', 'nameLocation': 'middle', 'show_frame': True,
303
+ 'label_size': 10, 'title_size': 10,
304
+ }],
305
+ 'series': []
306
+ })
307
+
308
+ colors = {"bt": 'black', 'ms': 'red', 'tour': 'grey', 'amp': 'blue', 'pl': '#a4df82', 'kfs': '#a43c82'}
309
+ sample_types = [
310
+ r"bt",
311
+ r"ms",
312
+ r"bt",
313
+ r"bt",
314
+ r"ms",
315
+ r"ms",
316
+ r"bt",
317
+ r"ms",
318
+ r"kfs",
319
+ r"kfs",
320
+ r"kfs",
321
+ r"kfs",
322
+ r"kfs",
323
+ r"kfs",
324
+ r"kfs",
325
+ r"kfs",
326
+ r"kfs",
327
+ r"kfs",
328
+ r"tour",
329
+ r"tour",
330
+ r"tour",
331
+ r"tour",
332
+ r"tour",
333
+ r"tour",
334
+ r"amp",
335
+ r"amp",
336
+ r"amp",
337
+ r"amp",
338
+ r"amp",
339
+ ]
340
+ files = [
341
+ r"D:\DjangoProjects\webarar\static\download\20241121_24FY01a.arr",
342
+ r"D:\DjangoProjects\webarar\static\download\20241123_24FY02a.arr",
343
+ r"D:\DjangoProjects\webarar\static\download\20241125_24FY03a.arr",
344
+ r"D:\DjangoProjects\webarar\static\download\20241129_24FY06a.arr",
345
+ r"D:\DjangoProjects\webarar\static\download\20241130_24FY07a.arr",
346
+ r"D:\DjangoProjects\webarar\private\upload\20241201_24FY08a.arr",
347
+ r"D:\DjangoProjects\webarar\static\download\20241202_24FY09a.arr",
348
+ r"D:\DjangoProjects\webarar\static\download\20241203_24FY10a.arr",
349
+ r"D:\DjangoProjects\webarar\private\upload\20240630_24FY49a.arr",
350
+ r"D:\DjangoProjects\webarar\private\upload\20240705_24FY50a.arr",
351
+ r"D:\DjangoProjects\webarar\private\upload\20240710_24FY51a.arr",
352
+ r"D:\DjangoProjects\webarar\private\upload\20240714_24FY52.arr",
353
+ r"D:\DjangoProjects\webarar\private\upload\20240728_24FY55a.arr",
354
+ r"D:\DjangoProjects\webarar\private\upload\20240801_24FY61.arr",
355
+ r"D:\DjangoProjects\webarar\private\upload\20241016_24FY66a.arr",
356
+ r"D:\DjangoProjects\webarar\private\upload\20240821_24FY67a.arr",
357
+ r"D:\DjangoProjects\webarar\private\upload\20240924_24FY70a.arr",
358
+ r"D:\DjangoProjects\webarar\private\upload\20240823_24FY71a.arr",
359
+ r"D:\DjangoProjects\webarar\private\upload\20241212_24FY80a.arr",
360
+ r"C:\Users\Young\OneDrive\00-Projects\【2】个人项目\2022-05论文课题\初稿\[01]ArAr\Gaowu\20241115_24FY81a.arr",
361
+ r"D:\DjangoProjects\webarar\static\download\20241210_24FY82a.arr",
362
+ r"D:\DjangoProjects\webarar\static\download\20241019_24FY83a.arr",
363
+ r"D:\DjangoProjects\webarar\private\upload\Table_M - BH04 diffusion experiment.arr",
364
+ r"D:\DjangoProjects\webarar\private\mdd\MA08-1\Table_K - MA08 diffusion experiment.arr",
365
+ r"D:\DjangoProjects\webarar\private\mdd\126KD57\126KD57-Dinh2023.arr",
366
+ r"D:\DjangoProjects\webarar\private\mdd\Growdon2013\CT0714-Growdon2013.arr",
367
+ r"D:\DjangoProjects\webarar\private\mdd\Growdon2013\CT0705A-Growdon2013.arr",
368
+ r"D:\DjangoProjects\webarar\private\mdd\Growdon2013\CT0712-Growdon2013.arr",
369
+ r"D:\DjangoProjects\webarar\private\mdd\Growdon2013\CT0726-Growdon2013.arr",
370
+ ]
371
+ for arr_file, sample_type in zip(files, sample_types):
372
+ print(f"{sample_type = }, {arr_file = }")
373
+ sample = ap.from_arr(file_path=arr_file)
374
+ te = np.array(sample.TotalParam[124], dtype=np.float64)
375
+ ar = np.array(sample.DegasValues[20], dtype=np.float64) # 20-21 Argon 39
376
+ f = np.cumsum(ar) / ar.sum() * 100
377
+
378
+ plot_data['data'][-2]['series'].append(
379
+ {
380
+ 'type': 'series.line', 'id': f'scatter_line', 'name': f'scatters_line',
381
+ 'color': colors[sample_type], 'line_width': 1,
382
+ 'data': np.transpose([te, f]).tolist(), 'line_caps': 'none',
383
+ },
384
+ )
385
+
386
+ params_list = {
387
+ "page_size": 'a4', "ppi": 72, "width": 9.5, "height": 7,
388
+ "pt_width": 0.8, "pt_height": 0.8, "pt_left": 0.16, "pt_bottom": 0.18,
389
+ "offset_top": 0, "offset_right": 0, "offset_bottom": 25, "offset_left": 35,
390
+ "plot_together": False, "show_frame": True,
391
+ }
392
+
393
+ filename = f"释放曲线"
394
+ filepath = os.path.join(r"C:\Users\Young\Downloads", f"{filename}.pdf")
395
+ cvs = [[ap.smp.export.get_cv_from_dict(plot, **params_list) for plot in plot_data['data']]]
396
+ filepath = ap.smp.export.export_chart_to_pdf(cvs, filename, filepath)
397
+
398
+
399
+
400
+ if __name__ == "__main__":
401
+ file_path = r"D:\DjangoProjects\webarar\private\mdd\Y01\20241121_24FY01a-removeHT.arr"
402
+ index = [1, 2, 3, 4, 5, 6, 7, 8]
403
+
404
+ # file_path = r"D:\DjangoProjects\webarar\private\mdd\MA08-2\Table_L - MA08 diffusion experiment.arr"
405
+ # index = [0, 1, 2, 3, 4, 5]
406
+ # # plot_Tc(file_path, index=index)
407
+ #
408
+ # file_path = r"D:\DjangoProjects\webarar\private\mdd\MA08-1\Table_K - MA08 diffusion experiment.arr"
409
+ # index = [4, 5, 6, 7, 8]
410
+ #
411
+ # file_path = r"D:\DjangoProjects\webarar\private\mdd\CR99NW\CR99NW Shi 2020.arr"
412
+ # index = list(range(10))
413
+
414
+
415
+ # file_path = r"D:\DjangoProjects\webarar\private\mdd\Y07"
416
+ # index = list(range(1, 9))
417
+ #
418
+ # plot_Tc(file_path, index=index, use_ln=True, radius=100)
419
+
420
+
421
+ # for cr in [1, 10, 20, 40, 60, 80, 100]:
422
+ # tc, _ = ap.thermo.basic.get_tc(da2=0.077 / (0.0140 ** 2) * 3600 * 24 * 365.24, sda2=0, E=47*1000 * 4.184, sE=0, pho=0,
423
+ # cooling_rate=cr, A=55)
424
+ # print(f"cooling rate = {cr}, tc = {tc}")
425
+ #
426
+ # for cr in [1, 10, 20, 40, 60, 80, 100]:
427
+ # tc, _ = ap.thermo.basic.get_tc(da2=18 * 3600 * 24 * 365.24, sda2=0, E=87*1000 * 4.184, sE=0, pho=0,
428
+ # cooling_rate=cr, A=6)
429
+ # print(f"cooling rate = {cr}, tc = {tc}")
430
+ #
431
+ # for cr in [1, 10, 20, 40, 60, 80, 100]:
432
+ # tc, _ = ap.thermo.basic.get_tc(da2=10**9.05 * 3600 * 24 * 365.24, sda2=0, E=83.79*1000 * 4.184, sE=0, pho=0,
433
+ # cooling_rate=cr, A=55)
434
+ # print(f"cooling rate = {cr}, tc = {tc}")
435
+
436
+ export_ar_relase_curve()
437
+
ararpy/__init__.py CHANGED
@@ -16,10 +16,10 @@ from . import calc, smp, files, thermo, test
16
16
  """ Information """
17
17
 
18
18
  name = 'ararpy'
19
- version = '0.1.199'
19
+ version = '0.2.2'
20
20
  __version__ = version
21
21
  full_version = version
22
- last_update = '2024-03-28'
22
+ last_update = '2026-01-01'
23
23
 
24
24
  """ ArArPy Functions """
25
25
 
@@ -62,7 +62,7 @@ Sample.results = lambda _smp: smp.basic.get_results(_smp)
62
62
  Sample.sequence = lambda _smp: smp.basic.get_sequence(_smp)
63
63
 
64
64
  Sample.initial = smp.initial.initial
65
- Sample.set_selection = lambda _smp, _index, _mark: smp.plots.set_selection(_smp, _index, _mark)
65
+ Sample.set_selection = lambda _smp, _index, _mark: smp.basic.set_selection(_smp, _index, _mark)
66
66
  Sample.update_table = lambda _smp, _data, _id: smp.table.update_handsontable(_smp, _data, _id)
67
67
 
68
68
  # Sample.unknown = lambda _smp: ArArData(name='unknown', data=_smp.SampleIntercept)
@@ -141,6 +141,5 @@ RawData.get_sequence = smp.raw.get_sequence
141
141
  RawData.to_sample = smp.initial.from_raw_data
142
142
  RawData.get_unknown = lambda _raw: smp.raw.get_sequence(_raw, True, 'is_unknown', unique=False)
143
143
  RawData.get_blank = lambda _raw: smp.raw.get_sequence(_raw, True, 'is_blank', unique=False)
144
- RawData.get_air = lambda _raw: smp.raw.get_sequence(_raw, True, 'is_air', unique=False)
145
144
  Sequence.get_data_df = lambda _seq: pd.DataFrame(_seq.data)
146
145
  Sequence.get_flag_df = lambda _seq: pd.DataFrame(_seq.flag)
ararpy/calc/age.py CHANGED
@@ -41,11 +41,13 @@ def calc_age_min(F, sF, **kwargs) -> tuple:
41
41
  J = arr.array_as_float(kwargs.pop('J'))
42
42
  sJ = arr.array_as_float(kwargs.pop('sJ') * J / 100)
43
43
  A = arr.array_as_float(kwargs.pop('A'))
44
- sA = arr.array_as_float(kwargs.pop('sA') * A / 100)
44
+ sA = arr.array_as_float(kwargs.pop('sA') * A / 100) # total A, A = Aec + (Ab+) + (Ab-). Ab- for Ca
45
45
  Ae = arr.array_as_float(kwargs.pop('Ae'))
46
- sAe = arr.array_as_float(kwargs.pop('sAe') * Ae / 100)
46
+ sAe = arr.array_as_float(kwargs.pop('sAe') * Ae / 100) # Aec
47
47
  Ab = arr.array_as_float(kwargs.pop('Ab'))
48
- sAb = arr.array_as_float(kwargs.pop('sAb') * Ab / 100)
48
+ sAb = arr.array_as_float(kwargs.pop('sAb') * Ab / 100) # Ab-
49
+ Abp = arr.array_as_float(kwargs.pop('Abp'))
50
+ sAbp = arr.array_as_float(kwargs.pop('sAbp') * Ab / 100) # Ab+
49
51
  W = arr.array_as_float(kwargs.pop('W'))
50
52
  sW = arr.array_as_float(kwargs.pop('sW') * W / 100)
51
53
  Y = arr.array_as_float(kwargs.pop('Y'))
@@ -62,21 +64,21 @@ def calc_age_min(F, sF, **kwargs) -> tuple:
62
64
  sLb = arr.array_as_float(kwargs.pop('sLb') * Lb / 100)
63
65
  t = arr.array_as_float(kwargs.pop('t'))
64
66
  st = arr.array_as_float(kwargs.pop('st'))
65
- # Ap = arr.array_as_float(kwargs.pop('Ap'))
66
- # sAp = arr.array_as_float(kwargs.pop('sAp') * Ap / 100)
67
- # Kp = arr.array_as_float(kwargs.pop('Kp'))
68
- # sKp = arr.array_as_float(kwargs.pop('sKp') * Kp / 100)
67
+ Ap = arr.array_as_float(kwargs.pop('Ap'))
68
+ sAp = arr.array_as_float(kwargs.pop('sAp') * Ap / 100)
69
+ Kp = arr.array_as_float(kwargs.pop('Kp'))
70
+ sKp = arr.array_as_float(kwargs.pop('sKp') * Kp / 100)
69
71
 
70
- # recalculation using Min et al.(2000) equation
72
+ # calculating using Min et al.(2000) equation
71
73
  # lmd = A * W * Y / (f * No)
72
74
  V = f * No / ((Ab + Ae) * W * Y)
73
- sf = 0
74
75
  sV = pow((V / f * sf) ** 2 + (V / No * sNo) ** 2 + (V / (Ab + Ae)) ** 2 * (sAb ** 2 + sAe ** 2) +
75
76
  (V / W * sW) ** 2 + (V / Y * sY) ** 2, 0.5)
77
+
76
78
  # standard age in year, change to Ma
77
79
  t = t * 1000000
78
80
  st = st * 1000000
79
- # back-calculating Ar40/Ar39 ration for the standard
81
+ # back-calculating Ar40/Ar39 of the standard
80
82
  stdR = (np.exp(t * L) - 1) / J
81
83
  # errors of standard age and decay constants were not applied
82
84
  sStdR = pow((stdR / J) ** 2 * sJ ** 2, 0.5)
@@ -85,31 +87,27 @@ def calc_age_min(F, sF, **kwargs) -> tuple:
85
87
  sR_1 = np.sqrt((sF / stdR) ** 2 + (F * sStdR / stdR ** 2) ** 2) # errors of measured 40Ar/39Ar and J value
86
88
  sR_2 = np.sqrt((sF / stdR) ** 2) # error of measured 40Ar/39Ar only
87
89
 
88
- BB = 1
89
- KK = np.exp(t / V) - 1 # 40Arr / 40K Use standard age
90
+ useStandardAge = True
91
+ if useStandardAge:
92
+ # ln part in Min 2000 equation
93
+ BB = 1
94
+ KK = np.exp(t / V) - 1 # 40Arr / 40K Use standard age
95
+ else: # use Ar40* and K concentrations of primary standard
96
+ # not fanished, this function is wrong
97
+ BB = (Ab + Ae) / Ae
98
+ KK = Ap / Kp / f
99
+ raise TypeError(f"Not use standard age. Not supported.")
100
+
90
101
  XX = BB * KK * R + 1
91
102
  k0 = V * np.log(XX)
92
- e1 = (np.log(XX) * V / f - V * BB * KK * R / (f * XX)) ** 2 * sf ** 2 # sF
93
- e2 = (np.log(XX) * V / No) ** 2 * sNo ** 2 # sNo
94
- e3 = (-1 * np.log(XX) * V / A + BB * KK * R / (A * XX)) ** 2 * sAb ** 2 # sAb
95
- e4 = (-1 * np.log(XX) * V / A - Ab * KK * R / (Ae ** 2 * XX)) ** 2 * sAe ** 2 # sAe
96
- e5 = (-1 * np.log(XX) * V / W - V * BB * KK * R / (W * XX)) ** 2 * sW ** 2 # sW
97
- e6 = (np.log(XX) * V / Y) ** 2 * sY ** 2 # sY
98
- e7 = (V * BB * KK / XX) ** 2 * sR_1 ** 2 # sR
99
- # e8 = (V * BB * KK * R / (Ap * XX)) ** 2 * sAp ** 2 # sAp
100
- # e9 = (V * BB * KK * R / (Kp * XX)) ** 2 * sKp ** 2 # sKp
101
- e8, e9 = 0, 0
102
- # useDecayConst = False
103
- # if useDecayConst: # k0 = log(L / Le * KK * R + 1) / L
104
- # e1 = (V * BB * KK * R / (f * XX)) ** 2 * sf ** 2
105
- # e2 = 0
106
- # e3 = (-1 * np.log(XX) * V / L + BB * KK * R / (L * XX)) ** 2 * sLb ** 2
107
- # e4 = (-1 * np.log(XX) * V / L - Lb * KK * R / (Le ** 2 * XX)) ** 2 * sLe ** 2
108
- # e5 = (V * BB * KK * R / (W * XX)) ** 2 * sW ** 2
109
- # e6 = 0
110
- useStandardAge = True
103
+
111
104
  if useStandardAge:
112
- e1, e9 = 0, 0
105
+ # k0 = V * ln(exp(t/V) - 1 * R + 1)
106
+ e1 = (np.log(XX) - R * (KK + 1) * t / (V * XX)) ** 2 * sV ** 2 # sV
107
+ e2 = (BB * (KK + 1) * R / XX) ** 2 * st ** 2 # st
108
+ e3 = (V * BB * KK / XX) ** 2 * sR_1 ** 2 # sR
109
+ else:
110
+ e1, e2, e3 = 0, 0, 0
113
111
 
114
112
  # change to Ma
115
113
  # analytical error, error of 40Ar/39Ar only
@@ -117,7 +115,7 @@ def calc_age_min(F, sF, **kwargs) -> tuple:
117
115
  # internal error, errors of 40Ar/39Ar and J value
118
116
  s2 = np.sqrt((V * KK * BB / XX) ** 2 * sR_1 ** 2)
119
117
  # total external error
120
- s3 = np.sqrt(e1 + e2 + e3 + e4 + e5 + e6 + e7 + e8 + e9)
118
+ s3 = np.sqrt(e1 + e2 + e3)
121
119
  age = k0
122
120
  return age, s1, s2, s3
123
121
 
@@ -146,7 +144,7 @@ def calc_age_general(F, sF, J, sJ, L, sL, **kwargs):
146
144
  v1 = sF ** 2 * (J / (L * (1 + J * F))) ** 2
147
145
  v2 = sJ ** 2 * (F / (L * (1 + J * F))) ** 2
148
146
  v3 = sL ** 2 * (np.log(1 + J * F) / (L ** 2)) ** 2
149
- s1 = v1 ** .5 # analytical error
150
- s2 = (v1 + v2) ** .5 # internal error
151
- s3 = (v1 + v2 + v3) ** .5 # full external error
147
+ s1 = v1 ** .5 # analytical error, F only
148
+ s2 = (v1 + v2) ** .5 # internal error, F and J
149
+ s3 = (v1 + v2 + v3) ** .5 # full external error. F, J and L
152
150
  return age, s1, s2, s3
ararpy/calc/arr.py CHANGED
@@ -299,26 +299,6 @@ def remove(array, old):
299
299
  return res
300
300
 
301
301
 
302
- def merge(*args):
303
- """ Merge list objects, one dimensional or two dimensional list should be passed in.
304
-
305
- Parameters
306
- ----------
307
- args : one or two dimensional list
308
-
309
- Returns
310
- -------
311
-
312
- """
313
- res = []
314
- for arg in args:
315
- if is_oneD(arg):
316
- res.append(arg)
317
- else:
318
- res = res + arg
319
- return res
320
-
321
-
322
302
  def multi_append(a, *args):
323
303
  """
324
304
  Parameters
ararpy/calc/basic.py CHANGED
@@ -10,13 +10,16 @@
10
10
  #
11
11
  """
12
12
  import copy
13
- import random
13
+ # import secrets
14
14
  import string
15
+ import random
15
16
  import numpy as np
16
17
  from scipy import stats
17
18
  from datetime import datetime, timezone, timedelta
18
19
  import pytz
19
20
 
21
+ ALPHABET = string.ascii_lowercase + string.digits
22
+
20
23
 
21
24
  def utc_dt(dt: datetime, tz: str = "utc", is_dst: bool = False) -> datetime:
22
25
  """
@@ -58,6 +61,18 @@ def get_datetime(t_year: int, t_month: int, t_day: int, t_hour: int, t_min: int,
58
61
  return ts - base
59
62
 
60
63
 
64
+ def get_timestring(timestamp: int = 0, base=None):
65
+ """
66
+ :param timestamp: timestamp (utz)
67
+ :param base: base time [y, m, d, h, m]
68
+ :return:
69
+ """
70
+ if base is None:
71
+ base = [1970, 1, 1, 0, 0]
72
+ ts = timestamp + datetime(*base, tzinfo=timezone.utc).timestamp()
73
+ return datetime.fromtimestamp(ts, tz=timezone.utc).isoformat(timespec='seconds')
74
+
75
+
61
76
  def merge_dicts(a: dict, b: dict):
62
77
  """
63
78
  a and b, two dictionary. Return updated a
@@ -100,8 +115,8 @@ def update_dicts(a: dict, b: dict):
100
115
  return res
101
116
 
102
117
 
103
- def get_random_digits(length: int = 7) -> str:
104
- return ''.join(random.choices(string.digits, k=length))
118
+ def random_choice(length: int = 8) -> str:
119
+ return ''.join(random.choices(ALPHABET, k=length))
105
120
 
106
121
 
107
122
  def monte_carlo(func, inputs, confidence_level, **kwargs):
@@ -129,3 +144,11 @@ def monte_carlo(func, inputs, confidence_level, **kwargs):
129
144
  limits = values[:, [l_range, r_range]]
130
145
 
131
146
  return np.concatenate((means, limits), axis=1), cov
147
+
148
+
149
+ def parser(v: str, t: type):
150
+ if t == bool:
151
+ if str(v).lower().rstrip() in ["true", "1"]:
152
+ return True
153
+ return t(v)
154
+