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 +178 -0
- ararpy/calc/__init__.py +11 -0
- ararpy/calc/age.py +161 -0
- ararpy/calc/arr.py +490 -0
- ararpy/calc/basic.py +57 -0
- ararpy/calc/corr.py +240 -0
- ararpy/calc/err.py +117 -0
- ararpy/calc/histogram.py +166 -0
- ararpy/calc/isochron.py +194 -0
- ararpy/calc/jvalue.py +38 -0
- ararpy/calc/plot.py +68 -0
- ararpy/calc/raw_funcs.py +118 -0
- ararpy/calc/regression.py +961 -0
- ararpy/calc/spectra.py +63 -0
- ararpy/files/__init__.py +2 -0
- ararpy/files/arr_file.py +86 -0
- ararpy/files/basic.py +100 -0
- ararpy/files/calc_file.py +683 -0
- ararpy/files/export.py +1181 -0
- ararpy/files/json.py +49 -0
- ararpy/files/new_file.py +31 -0
- ararpy/files/raw.py +115 -0
- ararpy/files/raw_file.py +14 -0
- ararpy/files/xls.py +27 -0
- ararpy/smp/__init__.py +17 -0
- ararpy/smp/basic.py +371 -0
- ararpy/smp/calculation.py +94 -0
- ararpy/smp/consts.py +20 -0
- ararpy/smp/corr.py +376 -0
- ararpy/smp/initial.py +232 -0
- ararpy/smp/plots.py +636 -0
- ararpy/smp/sample.py +911 -0
- ararpy/smp/style.py +191 -0
- ararpy/smp/table.py +131 -0
- ararpy-0.0.1a1.dist-info/LICENSE +21 -0
- ararpy-0.0.1a1.dist-info/METADATA +269 -0
- ararpy-0.0.1a1.dist-info/RECORD +39 -0
- ararpy-0.0.1a1.dist-info/WHEEL +5 -0
- ararpy-0.0.1a1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,683 @@
|
|
|
1
|
+
|
|
2
|
+
"""
|
|
3
|
+
# ==========================================
|
|
4
|
+
# Copyright 2023 Yang
|
|
5
|
+
# ararpy - files - calc_file
|
|
6
|
+
# ==========================================
|
|
7
|
+
|
|
8
|
+
Open age files from ArArCALC. It currently supports version: 25.2 and 24.0.
|
|
9
|
+
Version 25.2 is preferred to 24.0 as containing more detailed parameters than 24.0.
|
|
10
|
+
|
|
11
|
+
ArArCalcFile(file_path, file_name: optional)
|
|
12
|
+
-> open()
|
|
13
|
+
-> get content and sample info ()
|
|
14
|
+
|
|
15
|
+
"""
|
|
16
|
+
import traceback
|
|
17
|
+
import pandas as pd
|
|
18
|
+
import numpy as np
|
|
19
|
+
import re
|
|
20
|
+
from xlrd import open_workbook, biffh
|
|
21
|
+
import os
|
|
22
|
+
import msoffcrypto
|
|
23
|
+
# from programs.ararpy.calc.basic import get_datetime
|
|
24
|
+
# from programs.ararpy import smp, calc
|
|
25
|
+
# from programs.ararpy.files import xls
|
|
26
|
+
from ..files import xls
|
|
27
|
+
from ..smp.initial import create_sample_from_df, create_sample_from_dict
|
|
28
|
+
from ..calc.basic import get_datetime
|
|
29
|
+
from ..calc import arr, err, isochron
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def to_sample(file_path: str, **kwargs):
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
Parameters
|
|
36
|
+
----------
|
|
37
|
+
file_path
|
|
38
|
+
|
|
39
|
+
Returns
|
|
40
|
+
-------
|
|
41
|
+
|
|
42
|
+
"""
|
|
43
|
+
file = ArArCalcFile(file_path=file_path, **kwargs).open()
|
|
44
|
+
sample = create_sample_from_df(file.get_content(), file.get_smp_info())
|
|
45
|
+
return sample
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def read_calc_file(file_path: str):
|
|
49
|
+
"""
|
|
50
|
+
:param file_path: file with suffix of .age or .air
|
|
51
|
+
:return: dict, keys are sheet name, value are list of [[col 0], [col 1], ...] of corresponding sheet
|
|
52
|
+
"""
|
|
53
|
+
PASSWORD = 'aapkop' # password to open age file, the password to unhide worksheets is boris
|
|
54
|
+
decrypt_file_path = file_path + '_decrypt.xls'
|
|
55
|
+
try:
|
|
56
|
+
# opening excel in decrypt function would reveal the hidden sheet without protect
|
|
57
|
+
with open(file_path, 'rb') as age_file:
|
|
58
|
+
office_file = msoffcrypto.OfficeFile(age_file)
|
|
59
|
+
office_file.load_key(password=PASSWORD)
|
|
60
|
+
office_file.decrypt(open(decrypt_file_path, 'wb'))
|
|
61
|
+
wb = open_workbook(decrypt_file_path)
|
|
62
|
+
worksheets = wb.sheet_names()
|
|
63
|
+
book_contents = dict()
|
|
64
|
+
for each_sheet in worksheets:
|
|
65
|
+
sheet = wb.sheet_by_name(each_sheet)
|
|
66
|
+
sheet_contents = [
|
|
67
|
+
[sheet.cell(row, col).value for col in range(sheet.ncols)]
|
|
68
|
+
for row in range(sheet.nrows)
|
|
69
|
+
]
|
|
70
|
+
book_contents[each_sheet] = sheet_contents
|
|
71
|
+
os.remove(decrypt_file_path)
|
|
72
|
+
except Exception as e:
|
|
73
|
+
print(traceback.format_exc())
|
|
74
|
+
return False
|
|
75
|
+
else:
|
|
76
|
+
return book_contents
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def open_252(data: pd.DataFrame, logs01: pd.DataFrame, logs02: pd.DataFrame):
|
|
80
|
+
"""
|
|
81
|
+
Open 25.2 version ArArCALC files
|
|
82
|
+
:param data:
|
|
83
|
+
:param logs01:
|
|
84
|
+
:param logs02:
|
|
85
|
+
:return:
|
|
86
|
+
"""
|
|
87
|
+
# add default columns for 999, -999, and -1 index
|
|
88
|
+
data[-999] = [0] * data.index.size
|
|
89
|
+
data[999] = [1] * data.index.size
|
|
90
|
+
data[-1] = [np.nan] * data.index.size
|
|
91
|
+
# rows_unm --> 样品阶段数
|
|
92
|
+
sequence_index = [1, 2, ]
|
|
93
|
+
sample_values_index = [16, 17, 21, 22, 26, 27, 31, 32, 36, 37,]
|
|
94
|
+
blank_values_index = [3, 4, 5, 6, 7, 8, 9, 10, 11, 12,]
|
|
95
|
+
corrected_values_index = [
|
|
96
|
+
188, 189, 190, 191, 192, 193, 194, 195, 196, 197,]
|
|
97
|
+
degas_values_index = [
|
|
98
|
+
138, 139, 140, 141, 142, 143, 144, 145, # 36 a, c, ca, cl 0-9
|
|
99
|
+
146, 147, # 37 ca 10-11
|
|
100
|
+
156, 157, 148, 149, 150, 151, 152, 153, 154, 155, # 38 cl, a, c, k, ca 12-21
|
|
101
|
+
158, 159, 160, 161, # 39 k, ca 22-25
|
|
102
|
+
162, 163, 164, 165, 166, 167, 168, 169, # 40 r, a, c, k 26-33
|
|
103
|
+
]
|
|
104
|
+
publish_values_index = [
|
|
105
|
+
101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
|
|
106
|
+
]
|
|
107
|
+
apparent_age_values_index = [
|
|
108
|
+
198, 199, 200, 201, -999, -999, 202, 203, # f, sf, ages, s, s, s, 40Arr%, 39Ar%
|
|
109
|
+
]
|
|
110
|
+
isochron_values_index = [
|
|
111
|
+
116, 117, 118, 119, 122, # normal isochron
|
|
112
|
+
-1, 127, 128, 129, 130, 133, # inverse
|
|
113
|
+
-1, -999, -999, -999, -999, -999, # 39/38 vs 40/38
|
|
114
|
+
-1, -999, -999, -999, -999, -999, # 39/40 vs 39/40
|
|
115
|
+
-1, -999, -999, -999, -999, -999, # 38/39 vs 40/39
|
|
116
|
+
-1, -999, -999, -999, -999, -999, -999, # 3D isochron, 36/39, 38/39, 40/39
|
|
117
|
+
]
|
|
118
|
+
isochron_mark_index = [115,]
|
|
119
|
+
total_param_index = [
|
|
120
|
+
71, 72, 73, 74, 75, 76, 77, 78, 79, 80, # 0-9
|
|
121
|
+
81, 82, 83, 84, 85, 86, 87, 88, 89, 90, # 10-19
|
|
122
|
+
91, 92, 93, 94, 95, 96, -999, -999, 63, -999, # 20-29
|
|
123
|
+
-999, -999, -1, -1, -999, -999, -999, -999, -999, -999, # 30-39
|
|
124
|
+
-999, -999, -999, -999, -999, -999, -999, -999, -999, -999, # 40-49
|
|
125
|
+
-999, -999, -999, -999, -999, -999, -999, -999, 67, 49, # 50-59
|
|
126
|
+
50, -999, -999, -999, -999, -999, -999, 51, 52, 53, # 60-69
|
|
127
|
+
54, -999, -999, -999, -999, -999, -999, -999, -999, -999, # 70-79
|
|
128
|
+
-999, -999, -999, -999, -999, -999, -999, -999, -999, -999, # 80-89
|
|
129
|
+
-999, -999, -999, -999, -999, -999, -999, -999, -999, -999, # 90-99
|
|
130
|
+
-999, -999, -999, -999, -999, -999, -999, -999, -999, -999, # 100-109
|
|
131
|
+
-999, -999, -999, -999, -1, # 110-114
|
|
132
|
+
-999, -999, -999, -999, -999, -999, -999, -999, # 115-122
|
|
133
|
+
]
|
|
134
|
+
|
|
135
|
+
# double transpose to remove keys
|
|
136
|
+
get_data = lambda df, index: pd.concat([df[index].transpose()], ignore_index=True).transpose()
|
|
137
|
+
|
|
138
|
+
sample_values = get_data(data, sample_values_index)
|
|
139
|
+
blank_values = get_data(data, blank_values_index)
|
|
140
|
+
corrected_values = get_data(data, corrected_values_index)
|
|
141
|
+
degas_values = get_data(data, degas_values_index)
|
|
142
|
+
publish_values = get_data(data, publish_values_index)
|
|
143
|
+
apparent_age_values = get_data(data, apparent_age_values_index)
|
|
144
|
+
isochron_values = get_data(data, isochron_values_index)
|
|
145
|
+
total_param = get_data(data, total_param_index)
|
|
146
|
+
isochron_mark = get_data(data, isochron_mark_index)
|
|
147
|
+
sequence = get_data(data, sequence_index)
|
|
148
|
+
|
|
149
|
+
# adjustment
|
|
150
|
+
isochron_mark.replace({4.0: 1}, inplace=True)
|
|
151
|
+
total_param[83] = logs01[1][9] # No
|
|
152
|
+
total_param[84] = logs01[1][10] # %SD
|
|
153
|
+
total_param[81] = logs01[1][11] # K mass
|
|
154
|
+
total_param[82] = logs01[1][12] # K mass %SD
|
|
155
|
+
|
|
156
|
+
total_param[85] = logs01[1][13] # How many seconds in a year
|
|
157
|
+
total_param[86] = 0 # %SD
|
|
158
|
+
|
|
159
|
+
total_param[87] = logs01[1][14] # The constant of 40K/K
|
|
160
|
+
total_param[88] = logs01[1][15] # %SD
|
|
161
|
+
|
|
162
|
+
total_param[89] = logs01[1][16] # The constant of 35Cl/37Cl
|
|
163
|
+
total_param[90] = logs01[1][17] # %SD
|
|
164
|
+
total_param[56] = logs01[1][18] # The constant of 36/38Cl productivity
|
|
165
|
+
total_param[57] = logs01[1][19] # %SD
|
|
166
|
+
total_param[91] = logs01[1][24] # The constant of HCl/Cl
|
|
167
|
+
total_param[92] = logs01[1][25] # %SD
|
|
168
|
+
|
|
169
|
+
total_param[50] = logs01[1][26] # 40K(EC) activities param
|
|
170
|
+
total_param[51] = logs01[1][27] # %SD
|
|
171
|
+
total_param[52] = logs01[1][28] # 40K(\beta-) activities param
|
|
172
|
+
total_param[53] = logs01[1][29] # %SD
|
|
173
|
+
total_param[48] = logs01[1][26] + logs01[1][28] # 40K(EC) activities param
|
|
174
|
+
total_param[49] = 100 / total_param[48] * pow(
|
|
175
|
+
(logs01[1][27] / 100 * logs01[1][26]) ** 2 + (logs01[1][29] / 100 * logs01[1][28]) ** 2, 0.5) # %SD
|
|
176
|
+
|
|
177
|
+
total_param[34] = logs01[1][36] # decay constant of 40K total
|
|
178
|
+
total_param[35] = logs01[1][37] # %SD
|
|
179
|
+
total_param[36] = logs01[1][30] # decay constant of 40K EC
|
|
180
|
+
total_param[37] = logs01[1][31] # %SD
|
|
181
|
+
total_param[38] = logs01[1][32] # decay constant of 40K \beta-
|
|
182
|
+
total_param[39] = logs01[1][33] # %SD
|
|
183
|
+
total_param[40] = 0 # decay constant of 40K \beta+
|
|
184
|
+
total_param[41] = 0 # %SD
|
|
185
|
+
total_param[46] = logs01[1][34] # decay constant of 36Cl
|
|
186
|
+
total_param[47] = logs01[1][35] # %SD
|
|
187
|
+
total_param[42] = logs01[1][38] # decay constant of 39Ar
|
|
188
|
+
total_param[43] = logs01[1][39] # %SD
|
|
189
|
+
total_param[44] = logs01[1][40] # decay constant of 37Ar
|
|
190
|
+
total_param[45] = logs01[1][41] # %SD
|
|
191
|
+
|
|
192
|
+
# logs01[1][49]] # 1 for using weighted YORK isochron regression, 2 for unweighted
|
|
193
|
+
# logs01[1][50]] # True for including errors on irradiation constants, False for excluding those
|
|
194
|
+
# [logs01[1][67]] # MDF method, 'LIN'
|
|
195
|
+
total_param[93] = logs01[1][70] # 40Ar/36Ar air
|
|
196
|
+
total_param[94] = logs01[1][71] # %SD
|
|
197
|
+
|
|
198
|
+
total_param[97] = 'York-2' # Fitting method
|
|
199
|
+
total_param[98] = logs01[1][0] # Convergence
|
|
200
|
+
total_param[99] = logs01[1][1] # Iterations number
|
|
201
|
+
total_param[100] = logs01[1][67] # MDF method
|
|
202
|
+
total_param[101] = logs01[1][65] # force negative to zero when correct blank
|
|
203
|
+
total_param[102] = True # Apply 37Ar decay
|
|
204
|
+
total_param[103] = True # Apply 39Ar decay
|
|
205
|
+
total_param[104] = logs01[1][6] # Apply 37Ar decay
|
|
206
|
+
total_param[105] = logs01[1][7] # Apply 39Ar decay
|
|
207
|
+
total_param[106] = True # Apply K degas
|
|
208
|
+
total_param[107] = True # Apply Ca degas
|
|
209
|
+
total_param[108] = True # Apply Air degas
|
|
210
|
+
total_param[109] = logs01[1][8] # Apply Cl degas
|
|
211
|
+
|
|
212
|
+
total_param[110] = True if logs01[1][5] == 'MIN' else False # Calculating ages using Min equation [True] or conventional equation [False]
|
|
213
|
+
total_param[111] = logs01[1][89] # Use primary standard or not
|
|
214
|
+
total_param[112] = logs01[1][91] # Use standard age or not
|
|
215
|
+
total_param[113] = logs01[1][92] # Use primary ratio or not
|
|
216
|
+
|
|
217
|
+
# irradiation time
|
|
218
|
+
total_param = general_adjustment(
|
|
219
|
+
total_param.copy(), logs02, get_data(data, [59, 58, 57, 60, 61]), data[63][0]
|
|
220
|
+
)
|
|
221
|
+
return [
|
|
222
|
+
sample_values, blank_values, corrected_values, degas_values, publish_values,
|
|
223
|
+
apparent_age_values, isochron_values, total_param, isochron_mark,
|
|
224
|
+
sequence,
|
|
225
|
+
]
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
def open_240(data: pd.DataFrame, logs01: pd.DataFrame, logs02: pd.DataFrame):
|
|
229
|
+
"""
|
|
230
|
+
Open 24.0 version ArArCALC files
|
|
231
|
+
:param data:
|
|
232
|
+
:param logs01:
|
|
233
|
+
:param logs02:
|
|
234
|
+
:return:
|
|
235
|
+
"""
|
|
236
|
+
# add default columns for 999, -999, and -1 index
|
|
237
|
+
data[-999] = [0] * data.index.size
|
|
238
|
+
data[999] = [1] * data.index.size
|
|
239
|
+
data[-1] = [np.nan] * data.index.size
|
|
240
|
+
# values index
|
|
241
|
+
sequence_index = [1, 2, ]
|
|
242
|
+
sample_values_index = [16, 17, 21, 22, 26, 27, 31, 32, 36, 37,]
|
|
243
|
+
blank_values_index = [3, 4, 5, 6, 7, 8, 9, 10, 11, 12,]
|
|
244
|
+
corrected_values_index = [
|
|
245
|
+
-999, -999, -999, -999, -999, -999, -999, -999, -999, -999,]
|
|
246
|
+
degas_values_index = [
|
|
247
|
+
# 36 a, c, ca, cl
|
|
248
|
+
136, -999, 137, -999, 139, -999, 138, -999,
|
|
249
|
+
# 37 ca,
|
|
250
|
+
140, -999,
|
|
251
|
+
# 38 cl, a, c, k, ca,
|
|
252
|
+
145, -999, 141, -999, 142, -999, 143, -999, 144, -999,
|
|
253
|
+
# 39 k, ca
|
|
254
|
+
146, -999, 147, -999,
|
|
255
|
+
# 40 r, a, c, k
|
|
256
|
+
148, -999, 149, -999, 150, -999, 151, -999,
|
|
257
|
+
]
|
|
258
|
+
publish_values_index = [
|
|
259
|
+
99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109,
|
|
260
|
+
]
|
|
261
|
+
apparent_age_values_index = [
|
|
262
|
+
# f, sf, ages, s, s, s, 39Ar%
|
|
263
|
+
156, 157, 104, 105, -999, -999, 106, 107,
|
|
264
|
+
]
|
|
265
|
+
isochron_values_index = [
|
|
266
|
+
# normal isochron
|
|
267
|
+
114, 115, 116, 117, 120,
|
|
268
|
+
# inverse
|
|
269
|
+
-1, 125, 126, 127, 128, 131,
|
|
270
|
+
# 39/38 vs 40/38
|
|
271
|
+
-1, -999, -999, -999, -999, -999,
|
|
272
|
+
# 39/40 vs 39/40
|
|
273
|
+
-1, -999, -999, -999, -999, -999,
|
|
274
|
+
# 38/39 vs 40/39
|
|
275
|
+
-1, -999, -999, -999, -999, -999,
|
|
276
|
+
# 3D isochron, 36/39, 38/39, 40/39, r1, r2, r3
|
|
277
|
+
-1, -999, -999, -999, -999, -999, -999, -999, -999, -999,
|
|
278
|
+
]
|
|
279
|
+
isochron_mark_index = [113,]
|
|
280
|
+
total_param_index = [
|
|
281
|
+
# 0-9
|
|
282
|
+
69, 70, 71, 72, 73, 74, 75, 76, 77, 78,
|
|
283
|
+
# 10-19
|
|
284
|
+
79, 80, 81, 82, 83, 84, 85, 86, 87, 88,
|
|
285
|
+
# 20-29
|
|
286
|
+
89, 90, 91, 92, 93, 94, -999, -999, 63, -999,
|
|
287
|
+
# 30-39
|
|
288
|
+
-999, -999, -1, -1, -999, -999, -999, -999, -999, -999,
|
|
289
|
+
# 40-49
|
|
290
|
+
-999, -999, -999, -999, -999, -999, -999, -999, -999, -999,
|
|
291
|
+
# 50-59
|
|
292
|
+
-999, -999, -999, -999, -999, -999, -999, -999, 65, 49,
|
|
293
|
+
# 60-69
|
|
294
|
+
50, -999, -999, -999, -999, -999, -999, 51, 52, 53,
|
|
295
|
+
# 70-79
|
|
296
|
+
54, -999, -999, -999, -999, -999, -999, -999, -999, -999,
|
|
297
|
+
# 80-89
|
|
298
|
+
-999, -999, -999, -999, -999, -999, -999, -999, -999, -999,
|
|
299
|
+
# 90-99
|
|
300
|
+
-999, -999, -999, -999, -999, -999, -999, -999, -999, -999,
|
|
301
|
+
# 100-99909
|
|
302
|
+
-999, -999, -999, -999, -999, -999, -999, -999, -999, -999,
|
|
303
|
+
# 110-114
|
|
304
|
+
-999, -999, -999, -999, -1,
|
|
305
|
+
# 115-122
|
|
306
|
+
-999, -999, -999, -999, -999, -999, -999, -999,
|
|
307
|
+
]
|
|
308
|
+
|
|
309
|
+
# double transpose to remove keys
|
|
310
|
+
get_data = lambda df, index: pd.concat([df[index].transpose()], ignore_index=True).transpose()
|
|
311
|
+
|
|
312
|
+
sample_values = get_data(data, sample_values_index)
|
|
313
|
+
blank_values = get_data(data, blank_values_index)
|
|
314
|
+
corrected_values = get_data(data, corrected_values_index)
|
|
315
|
+
degas_values = get_data(data, degas_values_index)
|
|
316
|
+
publish_values = get_data(data, publish_values_index)
|
|
317
|
+
apparent_age_values = get_data(data, apparent_age_values_index)
|
|
318
|
+
isochron_values = get_data(data, isochron_values_index)
|
|
319
|
+
total_param = get_data(data, total_param_index)
|
|
320
|
+
isochron_mark = get_data(data, isochron_mark_index)
|
|
321
|
+
sequence = get_data(data, sequence_index)
|
|
322
|
+
|
|
323
|
+
# irradiation time
|
|
324
|
+
total_param = general_adjustment(
|
|
325
|
+
total_param.copy(), logs02, get_data(data, [59, 58, 57, 60, 61]), data[63][0]
|
|
326
|
+
)
|
|
327
|
+
# Do adjustment
|
|
328
|
+
isochron_mark.replace({4.0: 1}, inplace=True)
|
|
329
|
+
total_param[44] = logs01[1][40]
|
|
330
|
+
total_param[45] = logs01[1][41]
|
|
331
|
+
total_param[42] = logs01[1][38]
|
|
332
|
+
total_param[43] = logs01[1][39]
|
|
333
|
+
total_param[34] = logs01[1][36]
|
|
334
|
+
total_param[35] = logs01[1][37]
|
|
335
|
+
|
|
336
|
+
return [
|
|
337
|
+
sample_values, blank_values, corrected_values, degas_values, publish_values,
|
|
338
|
+
apparent_age_values, isochron_values, total_param, isochron_mark,
|
|
339
|
+
sequence,
|
|
340
|
+
]
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
def change_error_type(data: pd.DataFrame, header: pd.Series):
|
|
344
|
+
"""
|
|
345
|
+
:param data: 2D DataFrame
|
|
346
|
+
:param header: 1D Series, headers
|
|
347
|
+
:return:
|
|
348
|
+
"""
|
|
349
|
+
# 2 sigma to 1 sigma
|
|
350
|
+
tochange = np.flatnonzero(header.where(header.str.contains('2s'), other=False))
|
|
351
|
+
data[tochange.tolist()] = data[tochange.tolist()] / 2
|
|
352
|
+
|
|
353
|
+
# 2 sigma to 1 sigma
|
|
354
|
+
tochange = np.flatnonzero(header.where(header.str.contains('%1s|%2s', regex=True), other=False))
|
|
355
|
+
data[tochange.tolist()] = \
|
|
356
|
+
data[tochange.tolist()] * abs(data[(tochange - 1).tolist()].rename(lambda x: x + 1, axis='columns')) / 100
|
|
357
|
+
|
|
358
|
+
return data
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
def general_adjustment(
|
|
362
|
+
total_param: pd.DataFrame, logs02: pd.DataFrame, experimental_time: pd.DataFrame,
|
|
363
|
+
irradiation_name: str
|
|
364
|
+
):
|
|
365
|
+
"""
|
|
366
|
+
General handle for all age files, including set irradiaition time, initial ratios, error display
|
|
367
|
+
:param total_param:
|
|
368
|
+
:param logs02:
|
|
369
|
+
:param experimental_time:
|
|
370
|
+
:param irradiation_name:
|
|
371
|
+
:return:
|
|
372
|
+
"""
|
|
373
|
+
irra_project = pd.Series(logs02[1].copy())
|
|
374
|
+
irradiation_index = np.flatnonzero(irra_project.where(irra_project.str.fullmatch(irradiation_name), other=False))[0]
|
|
375
|
+
irradiation_info = logs02[32][irradiation_index].split('\n')
|
|
376
|
+
# 处理辐照时间
|
|
377
|
+
month_convert = {
|
|
378
|
+
r'^(?i)Jan$': '01', r'^(?i)Feb$': '02', r'^(?i)Mar$': '03', r'^(?i)Apr$': '04', r'^(?i)May$': '05', r'^(?i)Jun$': '06',
|
|
379
|
+
r'^(?i)Jul$': '07', r'^(?i)Aug$': '08', r'^(?i)Sep$': '09', r'^(?i)Oct$': '10', r'^(?i)Nov$': '11', r'^(?i)Dec$': '12'}
|
|
380
|
+
duration_hour = []
|
|
381
|
+
end_time_second = []
|
|
382
|
+
irradiation_end_time = []
|
|
383
|
+
last_time = []
|
|
384
|
+
for each_date in irradiation_info:
|
|
385
|
+
if '/' in each_date:
|
|
386
|
+
_year = each_date.split(' ')[1].split('/')[2]
|
|
387
|
+
_month = each_date.split(' ')[1].split('/')[1].capitalize()
|
|
388
|
+
for pat, val in month_convert.items():
|
|
389
|
+
if re.match(pat, _month):
|
|
390
|
+
_month = val
|
|
391
|
+
break
|
|
392
|
+
_day = each_date.split(' ')[1].split('/')[0]
|
|
393
|
+
_hour = each_date.split(' ')[2].split('.')[0]
|
|
394
|
+
_min = each_date.split(' ')[2].split('.')[1]
|
|
395
|
+
end_time_second.append(get_datetime(
|
|
396
|
+
t_year=int(_year), t_month=int(_month), t_day=int(_day),
|
|
397
|
+
t_hour=int(_hour), t_min=int(_min)))
|
|
398
|
+
each_duration_hour = each_date.split(' ')[0].split('.')[0]
|
|
399
|
+
each_duration_min = each_date.split(' ')[0].split('.')[1]
|
|
400
|
+
each_duration = int(each_duration_hour) + round(int(each_duration_min) / 60, 2)
|
|
401
|
+
duration_hour.append(each_duration)
|
|
402
|
+
irradiation_end_time.append(f"{_year}-{_month}-{_day}-{_hour}-{_min}D{each_duration}")
|
|
403
|
+
last_time = [_year, _month, _day, _hour, _min]
|
|
404
|
+
|
|
405
|
+
experimental_time: pd.DataFrame = experimental_time.apply(pd.to_numeric, errors='ignore', downcast='integer')
|
|
406
|
+
experimental_time: pd.DataFrame = experimental_time.replace(to_replace=month_convert, regex=True)
|
|
407
|
+
total_param[31] = [f"{i[0]}-{i[1]}-{i[2]}T{i[3]}:{i[4]}Z" for i in experimental_time.values.tolist()]
|
|
408
|
+
total_param[26] = len(irradiation_end_time)
|
|
409
|
+
total_param[27] = 'S'.join(irradiation_end_time)
|
|
410
|
+
total_param[29] = sum(duration_hour)
|
|
411
|
+
total_param[30] = '-'.join(last_time)
|
|
412
|
+
|
|
413
|
+
stand_time_second = [
|
|
414
|
+
get_datetime(*i) - get_datetime(*last_time) for i in experimental_time.values.tolist()]
|
|
415
|
+
total_param[32] = [i / (3600 * 24 * 365.242) for i in stand_time_second] # stand year
|
|
416
|
+
|
|
417
|
+
# initial ratios & error display settings
|
|
418
|
+
total_param[115] = 0
|
|
419
|
+
total_param[116] = 298.56
|
|
420
|
+
total_param[117] = 0.31
|
|
421
|
+
total_param[118] = 298.56
|
|
422
|
+
total_param[119] = 0.31
|
|
423
|
+
total_param[120] = 1
|
|
424
|
+
total_param[121] = 1
|
|
425
|
+
total_param[122] = 1
|
|
426
|
+
|
|
427
|
+
return total_param
|
|
428
|
+
|
|
429
|
+
|
|
430
|
+
def full_to_sample(file_path: str, sample_name: str = None):
|
|
431
|
+
"""
|
|
432
|
+
Parameters
|
|
433
|
+
----------
|
|
434
|
+
file_path
|
|
435
|
+
sample_name
|
|
436
|
+
|
|
437
|
+
Returns
|
|
438
|
+
-------
|
|
439
|
+
|
|
440
|
+
"""
|
|
441
|
+
if sample_name is None:
|
|
442
|
+
sample_name = str(os.path.split(file_path)[-1]).split('.')[0]
|
|
443
|
+
content, sample_info = open_full_xls(file_path, sample_name)
|
|
444
|
+
sample = create_sample_from_dict(content=content, smp_info=sample_info)
|
|
445
|
+
return sample
|
|
446
|
+
|
|
447
|
+
|
|
448
|
+
def open_full_xls(file_path: str, sample_name: str = ''):
|
|
449
|
+
"""
|
|
450
|
+
filepath: absolute full path of input file
|
|
451
|
+
return sample instance
|
|
452
|
+
"""
|
|
453
|
+
try:
|
|
454
|
+
res = xls.open_xls(file_path)
|
|
455
|
+
except (Exception, BaseException) as e:
|
|
456
|
+
return e
|
|
457
|
+
start_row = 5
|
|
458
|
+
rows_num = len(res['Sample Parameters']) - 5
|
|
459
|
+
for key, val in res.items():
|
|
460
|
+
res[key] = arr.transpose(val[:start_row + rows_num])
|
|
461
|
+
# 2倍误差改回1倍
|
|
462
|
+
for i in range(len(res[key])):
|
|
463
|
+
if res[key][i][2] in ['2s', '%2s', '± 2s']:
|
|
464
|
+
_temp = []
|
|
465
|
+
for j in range(rows_num):
|
|
466
|
+
try:
|
|
467
|
+
_temp.append(res[key][i][start_row + j] / 2)
|
|
468
|
+
except TypeError:
|
|
469
|
+
_temp.append('')
|
|
470
|
+
res[key][i][start_row: start_row + rows_num] = _temp
|
|
471
|
+
if res['Incremental Heating Summary'][13][2] == 'K/Ca':
|
|
472
|
+
_temp, _s = [], []
|
|
473
|
+
for j in range(rows_num):
|
|
474
|
+
try:
|
|
475
|
+
_temp.append(1 / res['Relative Abundances'][13][start_row + j])
|
|
476
|
+
_s.append(err.div((1, 0), (
|
|
477
|
+
res['Relative Abundances'][13][start_row + j], res['Relative Abundances'][14][start_row + j])))
|
|
478
|
+
except TypeError:
|
|
479
|
+
_temp.append(None)
|
|
480
|
+
_s.append(None)
|
|
481
|
+
res['Incremental Heating Summary'][13][start_row: start_row + rows_num] = _temp
|
|
482
|
+
res['Incremental Heating Summary'][13][start_row: start_row + rows_num] = _s
|
|
483
|
+
|
|
484
|
+
# degas相对误差改为绝对误差
|
|
485
|
+
for i in range(len(res['Degassing Patterns'])):
|
|
486
|
+
if res['Degassing Patterns'][i][2] in ['%1s', '%2s']:
|
|
487
|
+
_temp = []
|
|
488
|
+
for j in range(rows_num):
|
|
489
|
+
try:
|
|
490
|
+
_temp.append(res['Degassing Patterns'][i][start_row + j] * res['Degassing Patterns'][i - 1][
|
|
491
|
+
start_row + j] / 100)
|
|
492
|
+
except TypeError:
|
|
493
|
+
_temp.append('')
|
|
494
|
+
res['Degassing Patterns'][i][start_row: start_row + rows_num] = _temp
|
|
495
|
+
rows = list(range(start_row, rows_num))
|
|
496
|
+
sequence_name = arr.partial(res['Procedure Blanks'], rows, 1)
|
|
497
|
+
sequence_value = arr.partial(res['Procedure Blanks'], rows, 2)
|
|
498
|
+
blank_values = arr.partial(
|
|
499
|
+
res['Procedure Blanks'], rows, [3, 4, 5, 6, 7, 8, 9, 10, 11, 12])
|
|
500
|
+
sample_values = arr.partial(
|
|
501
|
+
res['Intercept Values'], rows, [3, 4, 8, 9, 13, 14, 18, 19, 23, 24])
|
|
502
|
+
corrected_values = arr.partial(
|
|
503
|
+
res['Relative Abundances'], rows, [4, 5, 6, 7, 8, 9, 10, 11, 12, 13])
|
|
504
|
+
degas_values = arr.partial(
|
|
505
|
+
res['Degassing Patterns'], rows, [
|
|
506
|
+
4, 5, 6, 7, 8, 9, 10, 11,
|
|
507
|
+
12, 13,
|
|
508
|
+
22, 23, 14, 15, 16, 17, 18, 19, 20, 21,
|
|
509
|
+
24, 25, 26, 27,
|
|
510
|
+
28, 29, 30, 31, 32, 33, 34, 35])
|
|
511
|
+
publish_values = arr.partial(
|
|
512
|
+
res['Incremental Heating Summary'], rows, [4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14])
|
|
513
|
+
apparent_age_values = arr.partial(
|
|
514
|
+
res['Relative Abundances'], rows, [14, 15, 16, 17, -1, -1, 18, 19])
|
|
515
|
+
isochron_values = [[np.nan] * len(rows)] * 39
|
|
516
|
+
isochron_values[0:5] = arr.partial(
|
|
517
|
+
res['Normal Isochron Table'], rows, [4, 5, 6, 7, 10])
|
|
518
|
+
isochron_values[6:11] = arr.partial(
|
|
519
|
+
res['Inverse Isochron Table'], rows, [4, 5, 6, 7, 10])
|
|
520
|
+
total_param = arr.partial(
|
|
521
|
+
res['Sample Parameters'], rows, [
|
|
522
|
+
# 1, 2, # 0-1
|
|
523
|
+
-1, -1, -1, -1, # 2-5
|
|
524
|
+
-1, -1, -1, -1, # 6-9
|
|
525
|
+
-1, -1, -1, -1, -1, -1, # 10-15
|
|
526
|
+
-1, -1, -1, -1, # 16-19
|
|
527
|
+
-1, -1, # 20-21
|
|
528
|
+
23, 24, -1, -1, -1, -1, # 22-27
|
|
529
|
+
-1, -1, # 28-29
|
|
530
|
+
22, -1, -1, -1, # 30-33
|
|
531
|
+
-1, -1, # 34-35
|
|
532
|
+
-1, -1, # 36-37
|
|
533
|
+
-1, -1, # 38-39
|
|
534
|
+
-1, -1, # 40-41
|
|
535
|
+
-1, -1, # 42-43
|
|
536
|
+
-1, -1, # 44-45
|
|
537
|
+
-1, -1, # 46-47
|
|
538
|
+
-1, -1, # 48-49
|
|
539
|
+
-1, -1, # 50-51
|
|
540
|
+
-1, -1, # 52-53
|
|
541
|
+
-1, -1, # 54-55
|
|
542
|
+
-1, -1, # 56-57
|
|
543
|
+
-1, -1, # 58-59
|
|
544
|
+
-1, -1, -1, -1, -1, -1, -1, -1, -1, # 60-68
|
|
545
|
+
10, 11, 12, 13, #
|
|
546
|
+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, #
|
|
547
|
+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, #
|
|
548
|
+
-1, -1, -1, -1, #
|
|
549
|
+
-1, -1, -1, -1, #
|
|
550
|
+
-1, -1, -1, -1, -1, #
|
|
551
|
+
-1, -1, -1, -1, #
|
|
552
|
+
-1, -1, -1, -1, #
|
|
553
|
+
-1, #
|
|
554
|
+
])
|
|
555
|
+
|
|
556
|
+
month_convert = {'Jan': '01', 'Feb': '02', 'Mar': '03', 'Apr': '04', 'May': '05', 'Jun': '06',
|
|
557
|
+
'Jul': '07', 'Aug': '08', 'Sep': '09', 'Oct': '10', 'Nov': '11', 'Dec': '12'}
|
|
558
|
+
experiment_start_time = []
|
|
559
|
+
for i in arr.transpose(
|
|
560
|
+
arr.partial(res['Sample Parameters'], rows, [18, 17, 16, 19, 20])):
|
|
561
|
+
_year = str(i[0]) if '.' not in str(i[0]) else str(i[0]).split('.')[0]
|
|
562
|
+
_month = str(month_convert[str(i[1]).capitalize()]) if str(i[1]).capitalize() in month_convert.keys() else str(
|
|
563
|
+
i[1]).capitalize()
|
|
564
|
+
_day = str(i[2]) if '.' not in str(i[2]) else str(i[2]).split('.')[0]
|
|
565
|
+
_hour = str(i[3]) if '.' not in str(i[3]) else str(i[3]).split('.')[0]
|
|
566
|
+
_min = str(i[4]) if '.' not in str(i[4]) else str(i[4]).split('.')[0]
|
|
567
|
+
experiment_start_time.append([_year, _month, _day, _hour, _min])
|
|
568
|
+
|
|
569
|
+
total_param[31] = ['-'.join(i) for i in experiment_start_time]
|
|
570
|
+
total_param[0:26] = arr.partial(
|
|
571
|
+
res['Irradiation Constants'], rows,
|
|
572
|
+
[3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28])
|
|
573
|
+
|
|
574
|
+
isochron_values[11] = [''] * len(isochron_values[0])
|
|
575
|
+
isochron_values[17] = [''] * len(isochron_values[0])
|
|
576
|
+
isochron_values[23] = [''] * len(isochron_values[0])
|
|
577
|
+
isochron_values[12:17] = isochron.get_data(
|
|
578
|
+
degas_values[20], degas_values[21], degas_values[24], degas_values[25], degas_values[10], degas_values[11]
|
|
579
|
+
) # 39/38, 40/38
|
|
580
|
+
isochron_values[18:23] = isochron.get_data(
|
|
581
|
+
degas_values[20], degas_values[21], degas_values[10], degas_values[11], degas_values[24], degas_values[25]
|
|
582
|
+
) # 39/40, 38/40
|
|
583
|
+
isochron_values[24:29] = isochron.get_data(
|
|
584
|
+
degas_values[10], degas_values[11], degas_values[24], degas_values[25], degas_values[20], degas_values[21]
|
|
585
|
+
) # 38/39, 40/39
|
|
586
|
+
isochron_mark = [1 if i == 'P' else '' for i in arr.partial(
|
|
587
|
+
res['Normal Isochron Table'], rows, 3)]
|
|
588
|
+
|
|
589
|
+
sample_info = {
|
|
590
|
+
'sample': {'name': sample_name, 'material': 'MATERIAL', 'location': 'LOCATION'},
|
|
591
|
+
'researcher': {'name': 'RESEARCHER', 'addr': 'ADDRESS'},
|
|
592
|
+
'laboratory': {'name': 'LABORATORY', 'addr': 'ADDRESS', 'analyst': 'ANALYST'}
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
res = [sample_values, blank_values, corrected_values, degas_values, publish_values,
|
|
596
|
+
apparent_age_values, isochron_values, total_param, [isochron_mark],
|
|
597
|
+
[sequence_name, sequence_value]]
|
|
598
|
+
|
|
599
|
+
return dict(zip(['smp', 'blk', 'cor', 'deg', 'pub', 'age', 'iso', 'pam', 'mak', 'seq'], res)), sample_info
|
|
600
|
+
|
|
601
|
+
|
|
602
|
+
class ArArCalcFile:
|
|
603
|
+
def __init__(self, file_path: str, sample_name: str = ""):
|
|
604
|
+
self.file_path = file_path
|
|
605
|
+
self.sample_name = sample_name
|
|
606
|
+
self.supported_versions = ['25.2', '24.0']
|
|
607
|
+
self.content = pd.DataFrame([])
|
|
608
|
+
self.sample_info = {
|
|
609
|
+
'sample': {'name': 'undefined', 'material': 'undefined',},
|
|
610
|
+
'researcher': {'name': 'undefined'},
|
|
611
|
+
'laboratory': {'name': 'undefined', 'analyst': 'undefined', 'info': 'undefined',}
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
def open(self):
|
|
615
|
+
book_contents = read_calc_file(self.file_path)
|
|
616
|
+
if not book_contents:
|
|
617
|
+
raise ValueError('Fail to open the file')
|
|
618
|
+
# create data frames for book values
|
|
619
|
+
content = pd.DataFrame(book_contents['Data Tables'])
|
|
620
|
+
logs01 = pd.DataFrame(book_contents['Logs01'])
|
|
621
|
+
logs02 = pd.DataFrame(book_contents['Logs02'])
|
|
622
|
+
logs03 = pd.DataFrame(book_contents['Logs03'])
|
|
623
|
+
|
|
624
|
+
start_row = 5
|
|
625
|
+
sequence_num = int(logs03[2][0])
|
|
626
|
+
header = content.loc[2]
|
|
627
|
+
data = pd.concat([content.loc[list(range(start_row, start_row + sequence_num))]], ignore_index=True).apply(
|
|
628
|
+
pd.to_numeric, errors='ignore'
|
|
629
|
+
)
|
|
630
|
+
|
|
631
|
+
# check version
|
|
632
|
+
version = logs03[3][0]
|
|
633
|
+
if version == '25.2':
|
|
634
|
+
handler = open_252
|
|
635
|
+
material = data[45][0]
|
|
636
|
+
analyst = data[47][0]
|
|
637
|
+
elif version == '24.0':
|
|
638
|
+
handler = open_240
|
|
639
|
+
material = data[46][0]
|
|
640
|
+
analyst = data[48][0]
|
|
641
|
+
else:
|
|
642
|
+
raise ValueError(f'non-supported version: {version}')
|
|
643
|
+
|
|
644
|
+
# change error type, 2sigma to 1sigma...
|
|
645
|
+
data = change_error_type(data, header)
|
|
646
|
+
|
|
647
|
+
# get full data frames
|
|
648
|
+
# ['smp', 'blk', 'cor', 'deg', 'pub', 'age', 'iso', 'pam', 'inf', 'mak', 'seq',] are abbreviations for
|
|
649
|
+
# [sample_values, blank_values, corrected_values, degas_values, publish_values,
|
|
650
|
+
# apparent_age_values, isochron_values, total_param, sample_info, isochron_mark,
|
|
651
|
+
# sequence_name, sequence_value]
|
|
652
|
+
self.content = pd.concat(
|
|
653
|
+
handler(data.copy(), logs01, logs02), axis=1,
|
|
654
|
+
keys=['smp', 'blk', 'cor', 'deg', 'pub', 'age', 'iso', 'pam', 'mak', 'seq', ],
|
|
655
|
+
)
|
|
656
|
+
|
|
657
|
+
# sample info
|
|
658
|
+
self.sample_info = {
|
|
659
|
+
'sample': {
|
|
660
|
+
'name': self.sample_name or data[44][0],
|
|
661
|
+
'material': material, 'location': 'LOCATION'
|
|
662
|
+
},
|
|
663
|
+
'researcher': {'name': data[64][0]},
|
|
664
|
+
'laboratory': {
|
|
665
|
+
'name': logs01[1][44],
|
|
666
|
+
'analyst': analyst,
|
|
667
|
+
'info': '\n'.join([logs01[1][45], logs01[1][46], logs01[1][47]]),
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
return self
|
|
672
|
+
|
|
673
|
+
def get_content(self):
|
|
674
|
+
return self.content
|
|
675
|
+
|
|
676
|
+
def get_smp_info(self):
|
|
677
|
+
return self.sample_info
|
|
678
|
+
|
|
679
|
+
def get_df(self):
|
|
680
|
+
return self.content
|
|
681
|
+
|
|
682
|
+
def get_list(self):
|
|
683
|
+
return self.content
|