ararpy 0.1.198__py3-none-any.whl → 0.2.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.
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 +5 -24
  11. ararpy/calc/basic.py +26 -3
  12. ararpy/calc/corr.py +135 -89
  13. ararpy/calc/jvalue.py +1 -1
  14. ararpy/calc/plot.py +6 -4
  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 +202 -46
  22. ararpy/smp/calculation.py +6 -6
  23. ararpy/smp/corr.py +339 -154
  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 +105 -48
  28. ararpy/smp/json.py +2 -2
  29. ararpy/smp/plots.py +225 -218
  30. ararpy/smp/raw.py +11 -15
  31. ararpy/smp/sample.py +257 -183
  32. ararpy/smp/style.py +48 -22
  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.198.dist-info → ararpy-0.2.1.dist-info}/METADATA +1 -1
  37. ararpy-0.2.1.dist-info/RECORD +73 -0
  38. {ararpy-0.1.198.dist-info → ararpy-0.2.1.dist-info}/WHEEL +1 -1
  39. ararpy-0.1.198.dist-info/RECORD +0 -66
  40. {ararpy-0.1.198.dist-info → ararpy-0.2.1.dist-info}/licenses/LICENSE +0 -0
  41. {ararpy-0.1.198.dist-info → ararpy-0.2.1.dist-info}/top_level.txt +0 -0
ararpy/smp/basic.py CHANGED
@@ -20,7 +20,7 @@ from typing import Optional, Union, List
20
20
  from .. import calc
21
21
  from ..files.basic import (read as read_params)
22
22
  from .sample import Sample, Table, Plot, ArArData, ArArBasic, Sequence, RawData
23
- from .initial import preference_keys
23
+ from .initial import PREFERENCE_RES
24
24
 
25
25
  Set = Plot.Set
26
26
  Label = Plot.Label
@@ -30,6 +30,62 @@ Text = Plot.Text
30
30
  pd.options.mode.chained_assignment = None # default='warn'
31
31
 
32
32
 
33
+ # =======================
34
+ # Params validate
35
+ # =======================
36
+ class ParamsInvalid(Exception):
37
+ """ """
38
+ def __init__(self, code, message, context=None):
39
+ self.code = code
40
+ self.message = message
41
+ self.context = context or {}
42
+ # 调用父类构造函数,确保异常能正常抛出
43
+ super().__init__(f"{self.message}")
44
+
45
+
46
+ def validate_params(**kwargs):
47
+
48
+ def check(data, dtype, **kwargs):
49
+ k = np.array(data, dtype=dtype)
50
+ # if dtype != str:
51
+ # if np.isnan(k).any():
52
+ # raise ValueError("Array contains NaN value(s)")
53
+ # if np.isinf(k).any():
54
+ # raise ValueError("Array contains Inf value(s)")
55
+ if dtype == bool:
56
+ if not all([isinstance(i, bool) or i in [0, 1] for i in np.array(data).flatten()]):
57
+ raise ValueError("array contains non-bool value(s)")
58
+ elif dtype == int:
59
+ for each in k.flatten():
60
+ if isinstance(each, dtype):
61
+ raise ValueError(f"type error, {type(each)} is given")
62
+ if kwargs.keys().__contains__('func'):
63
+ for each in k.ravel():
64
+ try:
65
+ if not kwargs.get('func')(each):
66
+ raise ValueError
67
+ except (Exception, BaseException) as e:
68
+ raise ValueError(f"{type(e).__name__}: invalid value, {each}")
69
+
70
+ context = {'names': [], 'classnames': [], 'messages': []}
71
+ for index, (name, content) in enumerate(kwargs.items(), 1):
72
+
73
+ try:
74
+ if isinstance(content, dict):
75
+ check(**content)
76
+ elif isinstance(content, list):
77
+ for each in content:
78
+ check(**each)
79
+ except (Exception, BaseException) as e:
80
+ context['names'].append(name)
81
+ context['classnames'].append(f"k{index}")
82
+ context['messages'].append(f"{name} {str(e)}")
83
+ if not context['names']:
84
+ return True
85
+ else:
86
+ raise ParamsInvalid(400, '. '.join(context['messages']), context)
87
+
88
+
33
89
  # =======================
34
90
  # Calculate ages
35
91
  # =======================
@@ -44,39 +100,104 @@ def calc_apparent_ages(smp: Sample):
44
100
  -------
45
101
 
46
102
  """
47
- if smp.Info.sample.type == "Unknown":
48
- age = calc_age(smp=smp)
49
- smp.ApparentAgeValues[2:6] = age
50
- smp.PublishValues[5:7] = copy.deepcopy(age[0:2])
51
- if smp.Info.sample.type == "Standard":
52
- j = calc_j(smp=smp)
53
- smp.ApparentAgeValues[2:4] = j
54
- smp.PublishValues[5:7] = copy.deepcopy(j[0:2])
55
- if smp.Info.sample.type == "Air":
56
- mdf = calc_mdf(smp=smp)
57
- smp.ApparentAgeValues[2:4] = mdf
58
- smp.PublishValues[5:7] = copy.deepcopy(mdf[0:2])
103
+ try:
104
+ params_to_check = {
105
+ 'sample type': {'data': smp.Info.sample.type, 'dtype': str, 'func': lambda x: str(x).lower() in ['unknown', 'standard', 'air'],},
106
+ }
107
+ except (IndexError, AttributeError) as e:
108
+ raise
109
+ if not validate_params(**params_to_check):
110
+ return
111
+
112
+ if str(smp.Info.sample.type).lower() == "unknown":
113
+ v = calc_age(smp=smp)
114
+ elif str(smp.Info.sample.type).lower() == "standard":
115
+ v = calc_j(smp=smp)
116
+ elif str(smp.Info.sample.type).lower() == "air":
117
+ v = calc_mdf(smp=smp)
118
+ else:
119
+ raise TypeError(f"Sample type is not supported: {smp.Info.sample.type}")
120
+
121
+ smp.ApparentAgeValues[2:6] = v[0:4]
122
+ smp.PublishValues[5:7] = copy.deepcopy(v[0:2])
59
123
 
60
124
 
61
125
  def calc_j(ar40ar39=None, params: dict = None, smp: Sample = None, index: list = None):
62
- std_age, std_err = smp.TotalParam[59:61]
63
- r, sr = smp.ApparentAgeValues[0:2] # ar40ar39, error
64
- f, rsf = smp.TotalParam[34:36] # L, sL
65
- j, sj = calc.jvalue.j_value(std_age, std_err, r, sr, f, rsf)
66
- return [j.tolist(), sj.tolist()]
126
+ params_index_dict = {
127
+ 34: 'L', 35: 'rsL', 59: 'Age', 60: 'sAge'
128
+ }
129
+ if ar40ar39 is None and smp is not None:
130
+ ar40ar39 = smp.ApparentAgeValues[0:2] # ar40ar39 air, error
131
+ if len(np.shape(ar40ar39)) == 1:
132
+ ar40ar39 = np.reshape(ar40ar39, (2, 1))
133
+ if index is None:
134
+ index = list(range(np.shape(ar40ar39)[-1]))
135
+ if smp is None and params is None:
136
+ raise ValueError(f"Parameters are required for calculating mdf, or it is empty.")
137
+ if params is not None:
138
+ for key, val in params.items():
139
+ if not isinstance(val, list):
140
+ params[key] = list(val)
141
+ if smp is not None:
142
+ try:
143
+ params_from_smp = dict(zip(
144
+ list(params_index_dict.values()),
145
+ [[smp.TotalParam[i][j] for j in index] for i in params_index_dict.keys()]
146
+ ))
147
+ except Exception:
148
+ print(traceback.format_exc())
149
+ raise ValueError(f"Parameters cannot be found in the given sample object")
150
+ if params is not None:
151
+ params_from_smp.update(params)
152
+ params = params_from_smp
153
+
154
+ j = calc.jvalue.j_value(params['Age'], params['sAge'], *ar40ar39, params['L'], params['rsL'])
155
+
156
+ if len(index) == 1:
157
+ return np.array(j).squeeze().tolist()
158
+ else:
159
+ return np.array(j).tolist()
67
160
 
68
161
 
69
162
  def calc_mdf(ar40ar36=None, params: dict = None, smp: Sample = None, index: list = None):
70
- std_air, std_err = smp.TotalParam[93:95]
71
- m36, sm36 = smp.TotalParam[71:73]
72
- m40, sm40 = smp.TotalParam[79:81]
73
- air, sair = smp.ApparentAgeValues[0:2] # ar40ar36 air, error
74
- discrimination_method = smp.TotalParam[100] # L, sL
163
+ params_index_dict = {
164
+ 71: 'M36', 72: 'sM36', 79: 'M40', 80: 'sM40', 93: 'Air', 94: 'rsAir', 100: 'Discr'
165
+ }
166
+ if ar40ar36 is None and smp is not None:
167
+ ar40ar36 = smp.ApparentAgeValues[0:2] # ar40ar36 air, error
168
+ if len(np.shape(ar40ar36)) == 1:
169
+ ar40ar36 = np.reshape(ar40ar36, (2, 1))
170
+ if index is None:
171
+ index = list(range(np.shape(ar40ar36)[-1]))
172
+ if smp is None and params is None:
173
+ raise ValueError(f"Parameters are required for calculating mdf, or it is empty.")
174
+ if params is not None:
175
+ for key, val in params.items():
176
+ if not isinstance(val, list):
177
+ params[key] = list(val)
178
+ if smp is not None:
179
+ try:
180
+ params_from_smp = dict(zip(
181
+ list(params_index_dict.values()),
182
+ [[smp.TotalParam[i][j] for j in index] for i in params_index_dict.keys()]
183
+ ))
184
+ except Exception:
185
+ print(traceback.format_exc())
186
+ raise ValueError(f"Parameters cannot be found in the given sample object")
187
+ if params is not None:
188
+ params_from_smp.update(params)
189
+ params = params_from_smp
190
+
75
191
  mdf = []
76
- for i in range(len(std_air)):
77
- k = calc.corr.mdf(air[i], sair[i], m36[i], m40[i], std_air[i], std_err[i]) # linear, exp, pow
78
- mdf.append({"linear": k[0:2], "exp": k[2:4], "pow": k[4:6]}[discrimination_method[i].lower()])
79
- return np.transpose(mdf).tolist()
192
+ for i in range(len(index)):
193
+ k = calc.corr.mdf(ar40ar36[0][i], ar40ar36[1][i], params['M36'][i], params['M40'][i],
194
+ params['Air'][i], params['rsAir'][i]) # linear, exp, pow
195
+ mdf.append({"linear": k[0:4], "exp": k[4:8], "pow": k[8:12]}[params['Discr'][i].lower()])
196
+
197
+ if len(index) == 1:
198
+ return np.transpose(mdf).squeeze().tolist()
199
+ else:
200
+ return np.transpose(mdf).tolist()
80
201
 
81
202
 
82
203
  def calc_age(ar40ar39=None, params: dict = None, smp: Sample = None, index: list = None):
@@ -95,7 +216,8 @@ def calc_age(ar40ar39=None, params: dict = None, smp: Sample = None, index: list
95
216
  """
96
217
  params_index_dict = {
97
218
  34: 'L', 35: 'sL', 36: 'Le', 37: 'sLe', 38: 'Lb', 39: 'sLb', 48: 'A', 49: 'sA',
98
- 50: 'Ae', 51: 'sAe', 52: 'Ab', 53: 'sAb', 59: 't', 60: 'st', 67: 'J', 68: 'sJ',
219
+ 50: 'Ae', 51: 'sAe', 52: 'Ab', 53: 'sAb', 54: 'Abp', 55: 'sAbp', 59: 't', 60: 'st',
220
+ 61: 'Ap', 62: 'sAp', 63: 'Kp', 64: 'sKp', 67: 'J', 68: 'sJ',
99
221
  81: 'W', 82: 'sW', 83: 'No', 84: 'sNo', 85: 'Y', 86: 'sY', 87: 'f', 88: 'sf', 110: 'Min'
100
222
  }
101
223
 
@@ -131,7 +253,7 @@ def calc_age(ar40ar39=None, params: dict = None, smp: Sample = None, index: list
131
253
 
132
254
  u = 'Ma'
133
255
  try:
134
- u = smp.Info.preference['ageUnit']
256
+ u = smp.Info.preference.age_unit
135
257
  except:
136
258
  print(traceback.format_exc())
137
259
  pass
@@ -369,21 +491,22 @@ def get_merged_smp(a: Sample, b: (Sample, dict)):
369
491
  symbol_size = 10, line_type = 'solid'))
370
492
  """
371
493
 
372
- def get_similar_name(_name: str):
494
+ def get_similar_name(name: str):
373
495
  res = []
374
- for i in range(len(_name) + 1):
375
- str_list = [i for i in _name]
376
- str_list.insert(i, '_')
377
- res.append(''.join(str_list))
378
- for i in range(len(_name)):
379
- str_list = [i for i in _name]
380
- str_list[i] = str_list[i].capitalize()
381
- res.append(''.join(str_list))
382
- for i in range(len(_name)):
383
- str_list = [i for i in _name]
384
- if _name[i] in '-_':
385
- str_list.pop(i)
496
+ for _name in set([name, name.lower(), name.upper()]):
497
+ for i in range(len(_name) + 1):
498
+ str_list = [i for i in _name]
499
+ str_list.insert(i, '_')
386
500
  res.append(''.join(str_list))
501
+ for i in range(len(_name)):
502
+ str_list = [i for i in _name]
503
+ str_list[i] = str_list[i].capitalize()
504
+ res.append(''.join(str_list))
505
+ for i in range(len(_name)):
506
+ str_list = [i for i in _name]
507
+ if _name[i] in '-_':
508
+ str_list.pop(i)
509
+ res.append(''.join(str_list))
387
510
  return res
388
511
 
389
512
  if not isinstance(b, dict):
@@ -555,13 +678,13 @@ def set_params(smp: Sample, params: Union[List, str], flag: Optional[str] = None
555
678
  smp.TotalParam[100:114] = remove_none(
556
679
  smp.TotalParam[100:114],
557
680
  [['Linear', 'Exponential', 'Power'][params[35:38].index(True)] if True in params[35:38] else '', *params[38:]], rows, n)
558
- pref = dict(zip(preference_keys, params[31:35]))
559
- smp.Info.preference.update(pref)
681
+ for index, (key, val) in enumerate(PREFERENCE_RES.items()):
682
+ setattr(smp.Info.preference, key, type(val)(params[31:35][index]))
560
683
  for key, comp in get_components(smp).items():
561
684
  if isinstance(comp, Table):
562
- comp.decimal_places = pref['decimalPlaces']
685
+ comp.decimal_places = smp.Info.preference.decimal_places
563
686
  comp.set_coltypes()
564
- smp.AgeSpectraPlot.yaxis.title.text = f"Apparent Age ({str(pref['ageUnit']).capitalize()})"
687
+ smp.AgeSpectraPlot.yaxis.title.text = f"Apparent Age ({str(smp.Info.preference.age_unit).capitalize()})"
565
688
 
566
689
  else:
567
690
  raise KeyError(f"{flag = } is not supported. It must be 'calc' for Calc Params, "
@@ -603,3 +726,36 @@ def get_results(smp: Sample):
603
726
  for (key, value) in smp.Info.results.age_plateau.items()))
604
727
  )
605
728
 
729
+
730
+ def set_selection(smp: Sample, index: int, mark: int):
731
+ """
732
+ Parameters
733
+ ----------
734
+ smp : sample instance
735
+ index : int, data point index
736
+ mark : int, 0 for unselected, 1 for set1, 2 for set2
737
+
738
+ Returns
739
+ -------
740
+
741
+ """
742
+ if mark not in [1, 2, '1', '2']:
743
+ raise ValueError(f"invalid mark value: {mark}, must be 1 or 2.")
744
+
745
+ def seq(_i): return [smp.UnselectedSequence, smp.SelectedSequence1, smp.SelectedSequence2][_i]
746
+
747
+ if index in seq(mark):
748
+ seq(mark).remove(index)
749
+ smp.UnselectedSequence.append(index)
750
+ else:
751
+ for i in [0, [0, 2, 1][mark]]:
752
+ if index in seq(i):
753
+ seq(i).remove(index)
754
+ seq(mark).append(index)
755
+ smp.IsochronMark = [
756
+ '1' if i in smp.SelectedSequence1 else '2' if i in smp.SelectedSequence2 else '' for i in
757
+ range(len(smp.IsochronValues[2]))]
758
+ #
759
+ smp.Info.results.selection[0]['data'] = smp.SelectedSequence1
760
+ smp.Info.results.selection[1]['data'] = smp.SelectedSequence2
761
+ smp.Info.results.selection[2]['data'] = smp.UnselectedSequence
ararpy/smp/calculation.py CHANGED
@@ -22,7 +22,8 @@ def recalculate(
22
22
  re_corr_blank: bool = False, re_corr_massdiscr: bool = False,
23
23
  re_corr_decay: bool = False, re_degas_ca: bool = False, re_degas_k: bool = False,
24
24
  re_degas_cl: bool = False, re_degas_atm: bool = False, re_degas_r: bool = False,
25
- re_calc_ratio: bool = False, re_calc_apparent_age: bool = False, monte_carlo: bool = False,
25
+ re_calc_ratio: bool = False, re_calc_apparent_age: bool = False,
26
+ # monte_carlo: bool = False,
26
27
  re_plot: bool = False, re_plot_style: bool = False, re_set_table: bool = False,
27
28
  re_table_style: bool = False, **kwargs
28
29
  ):
@@ -42,7 +43,6 @@ def recalculate(
42
43
  re_degas_r
43
44
  re_calc_ratio
44
45
  re_calc_apparent_age
45
- monte_carlo
46
46
  re_plot
47
47
  re_plot_style
48
48
  re_set_table
@@ -59,13 +59,11 @@ def recalculate(
59
59
  # print(f"{sample.UnselectedSequence = }")
60
60
  # print(f"{sample.SelectedSequence1 = }")
61
61
  # print(f"{sample.SelectedSequence2 = }")
62
+
62
63
  # --- initializing ---
63
- re_corr_gain = re_corr_blank
64
64
  if re_initial: # 1
65
65
  initial.re_set_smp(sample)
66
66
  # --- calculating ---
67
- if re_corr_gain: # 2 2024-10-04 add
68
- corr.corr_gain(sample)
69
67
  if re_corr_blank: # 2
70
68
  corr.corr_blank(sample)
71
69
  if re_corr_massdiscr: # 3
@@ -82,8 +80,10 @@ def recalculate(
82
80
  corr.calc_degas_atm(sample)
83
81
  if re_degas_r: # 9
84
82
  corr.calc_degas_r(sample)
83
+ corr.calc_degas_c(sample)
85
84
  if re_calc_ratio: # 10
86
- corr.calc_ratio(sample, monte_carlo)
85
+ corr.calc_ratio(sample)
86
+ corr.calc_ratio_monte_carlo(sample)
87
87
  if re_calc_apparent_age: # 11
88
88
  basic.calc_apparent_ages(sample)
89
89
  # --- plot and table ---