ararpy 0.1.19__py3-none-any.whl → 0.1.21__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 CHANGED
@@ -16,10 +16,10 @@ from . import calc, smp, files, thermo, test
16
16
  """ Information """
17
17
 
18
18
  name = 'ararpy'
19
- version = '0.0.1.a4'
19
+ version = '0.1.21'
20
20
  __version__ = version
21
21
  full_version = version
22
- last_update = '2024-01-04'
22
+ last_update = '2024-03-28'
23
23
 
24
24
  """ ArArPy Functions """
25
25
 
@@ -116,6 +116,8 @@ Sample.plot_cl_3 = lambda _smp: smp.calculation.recalculate(
116
116
  Sample.plot_3D = lambda _smp: smp.calculation.recalculate(
117
117
  _smp, re_plot=True, isIsochron=True, isInit=False, isPlateau=False, figures=['figure_7'])
118
118
 
119
+ Sample.to_excel = lambda _smp, file_path, *args, **kwargs: smp.export.to_excel(_smp, file_path=file_path, *args, **kwargs)
120
+
119
121
  Sample.show_data = lambda _smp: \
120
122
  f"Sample Name: \n\t{_smp.name()}\n" \
121
123
  f"Doi: \n\t{_smp.doi()}\n" \
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'))
@@ -61,21 +63,22 @@ def calc_age_min(F, sF, **kwargs) -> tuple:
61
63
  Lb = arr.array_as_float(kwargs.pop('Lb'))
62
64
  sLb = arr.array_as_float(kwargs.pop('sLb') * Lb / 100)
63
65
  t = arr.array_as_float(kwargs.pop('t'))
64
- st = arr.array_as_float(kwargs.pop('st') * t / 100)
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)
66
+ st = arr.array_as_float(kwargs.pop('st'))
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
75
  sV = pow((V / f * sf) ** 2 + (V / No * sNo) ** 2 + (V / (Ab + Ae)) ** 2 * (sAb ** 2 + sAe ** 2) +
74
76
  (V / W * sW) ** 2 + (V / Y * sY) ** 2, 0.5)
77
+
75
78
  # standard age in year, change to Ma
76
79
  t = t * 1000000
77
80
  st = st * 1000000
78
- # back-calculating Ar40/Ar39 ration for the standard
81
+ # back-calculating Ar40/Ar39 of the standard
79
82
  stdR = (np.exp(t * L) - 1) / J
80
83
  # errors of standard age and decay constants were not applied
81
84
  sStdR = pow((stdR / J) ** 2 * sJ ** 2, 0.5)
@@ -84,31 +87,27 @@ def calc_age_min(F, sF, **kwargs) -> tuple:
84
87
  sR_1 = np.sqrt((sF / stdR) ** 2 + (F * sStdR / stdR ** 2) ** 2) # errors of measured 40Ar/39Ar and J value
85
88
  sR_2 = np.sqrt((sF / stdR) ** 2) # error of measured 40Ar/39Ar only
86
89
 
87
- BB = 1
88
- 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
+
89
101
  XX = BB * KK * R + 1
90
102
  k0 = V * np.log(XX)
91
- e1 = (np.log(XX) * V / f - V * BB * KK * R / (f * XX)) ** 2 * sf ** 2 # sF
92
- e2 = (np.log(XX) * V / No) ** 2 * sNo ** 2 # sNo
93
- e3 = (-1 * np.log(XX) * V / A + BB * KK * R / (A * XX)) ** 2 * sAb ** 2 # sAb
94
- e4 = (-1 * np.log(XX) * V / A - Ab * KK * R / (Ae ** 2 * XX)) ** 2 * sAe ** 2 # sAe
95
- e5 = (-1 * np.log(XX) * V / W - V * BB * KK * R / (W * XX)) ** 2 * sW ** 2 # sW
96
- e6 = (np.log(XX) * V / Y) ** 2 * sY ** 2 # sY
97
- e7 = (V * BB * KK / XX) ** 2 * sR_1 ** 2 # sR
98
- # e8 = (V * BB * KK * R / (Ap * XX)) ** 2 * sAp ** 2 # sAp
99
- # e9 = (V * BB * KK * R / (Kp * XX)) ** 2 * sKp ** 2 # sKp
100
- e8, e9 = 0, 0
101
- # useDecayConst = False
102
- # if useDecayConst: # k0 = log(L / Le * KK * R + 1) / L
103
- # e1 = (V * BB * KK * R / (f * XX)) ** 2 * sf ** 2
104
- # e2 = 0
105
- # e3 = (-1 * np.log(XX) * V / L + BB * KK * R / (L * XX)) ** 2 * sLb ** 2
106
- # e4 = (-1 * np.log(XX) * V / L - Lb * KK * R / (Le ** 2 * XX)) ** 2 * sLe ** 2
107
- # e5 = (V * BB * KK * R / (W * XX)) ** 2 * sW ** 2
108
- # e6 = 0
109
- useStandardAge = True
103
+
110
104
  if useStandardAge:
111
- 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
112
111
 
113
112
  # change to Ma
114
113
  # analytical error, error of 40Ar/39Ar only
@@ -116,7 +115,7 @@ def calc_age_min(F, sF, **kwargs) -> tuple:
116
115
  # internal error, errors of 40Ar/39Ar and J value
117
116
  s2 = np.sqrt((V * KK * BB / XX) ** 2 * sR_1 ** 2)
118
117
  # total external error
119
- s3 = np.sqrt(e1 + e2 + e3 + e4 + e5 + e6 + e7 + e8 + e9)
118
+ s3 = np.sqrt(e1 + e2 + e3)
120
119
  age = k0
121
120
  return age, s1, s2, s3
122
121
 
@@ -145,7 +144,7 @@ def calc_age_general(F, sF, J, sJ, L, sL, **kwargs):
145
144
  v1 = sF ** 2 * (J / (L * (1 + J * F))) ** 2
146
145
  v2 = sJ ** 2 * (F / (L * (1 + J * F))) ** 2
147
146
  v3 = sL ** 2 * (np.log(1 + J * F) / (L ** 2)) ** 2
148
- s1 = v1 ** .5 # analytical error
149
- s2 = (v1 + v2) ** .5 # internal error
150
- 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
151
150
  return age, s1, s2, s3
ararpy/calc/arr.py CHANGED
@@ -38,7 +38,7 @@ def mul(*args):
38
38
 
39
39
  Returns
40
40
  -------
41
- 2D list, [values, errors]
41
+ two-D list, [values, errors]
42
42
  """
43
43
  v = np.array(args)
44
44
  res = np.zeros([2, v.shape[-1]], dtype=np.float64)
@@ -67,10 +67,11 @@ def div(a, b):
67
67
  n = np.shape([a, b])[-1]
68
68
  k0, k1 = [], []
69
69
  for i in range(n):
70
- k0.append(np.divide(a[0][i], b[0][i]))
71
- k1.append(
72
- (np.divide(a[1][i] ** 2, b[0][i] ** 2) +
73
- np.divide(a[0][i] ** 2 * b[1][i] ** 2, b[0][i] ** 4)) ** .5)
70
+ try:
71
+ k0.append(np.divide(a[0][i], b[0][i]))
72
+ k1.append((np.divide(a[1][i] ** 2, b[0][i] ** 2) + np.divide(a[0][i] ** 2 * b[1][i] ** 2, b[0][i] ** 4)) ** .5)
73
+ except TypeError as e:
74
+ raise TypeError(f"a = {a[0][i]}, b = {b[0][i]}, {e}")
74
75
  return [k0, k1]
75
76
 
76
77
 
@@ -514,6 +515,15 @@ def transpose(obj, ignore: bool = True):
514
515
  raise ValueError
515
516
 
516
517
 
518
+ def remove_empty(a: list):
519
+ index = 0
520
+ for i in range(len(a)):
521
+ if not is_empty(a[-(i + 1)]):
522
+ index = len(a) - i
523
+ break
524
+ return transpose(a[:index])
525
+
526
+
517
527
  def get_item(obj: list, loc: (list, tuple, int), default: Union[str, int, float, bool] = None,
518
528
  base: Union[int, tuple, list] = 0) -> Union[str, int, float, bool]:
519
529
  """ Get item from a n-dimension list
@@ -566,7 +576,7 @@ def wtd_mean(a: list, e: list, sf: int = 1, adjust_error: bool = True):
566
576
  k0 = sum(a * wt) / sum(wt) # error weighting
567
577
  k4 = sum((a - k0) ** 2 * wt) # Chi square
568
578
  k3 = k4 / df # MSWD mentioned in Min et al., 2000
569
- if adjust_error:
579
+ if adjust_error and k3 > 1:
570
580
  k1 = (k3 / sum(wt)) ** .5
571
581
  else:
572
582
  k1 = (1 / sum(wt)) ** .5
ararpy/calc/corr.py CHANGED
@@ -72,18 +72,18 @@ def mdf(rm: float, srm: float, m1: float, m2: float, ra: float = 298.56,
72
72
  v3 = err.div((np.log(ra / rm), v1), (np.log(ratio_m), v2))
73
73
  k4 = err.div((np.log(ra / rm) / np.log(ratio_m), v3), (m1, sm1))
74
74
  except Exception:
75
- k3, k4 = "Null", "Null"
75
+ k3, k4 = 0, 0
76
76
  # pow
77
77
  try:
78
78
  k5 = pow((ra / rm), (1 / delta_m)) # Renne2009, B.D. Turrin2010
79
79
  k6 = err.pow((ra / rm, err.div((ra, sra), (rm, srm))),
80
80
  (1 / delta_m, err.div((1, 0), (delta_m, sdelta_m))))
81
81
  except Exception:
82
- k5, k6 = "Null", "Null"
83
- return k1, k2, k3, k4, k5, k6
82
+ k5, k6 = 0, 0
83
+ return k1, k2, k2, k2, k3, k4, k4, k4, k5, k6, k6, k6
84
84
  else:
85
85
  mdf_line_2 = (rm / ra - 1) / delta_m # Ryu et al., 2013
86
- return mdf_line_2, 0, 0, 0, 0, 0
86
+ return mdf_line_2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
87
87
 
88
88
 
89
89
  def discr(a0: list, e0: list, mdf: list, smdf: list, m: list, m40: list,
@@ -268,7 +268,7 @@ def Monte_Carlo_F(ar40m: Tuple[float, float], ar39m: Tuple[float, float], ar38m:
268
268
  M37: Tuple[float, float], M36: Tuple[float, float],
269
269
  G40: Tuple[float, float], G39: Tuple[float, float], G38: Tuple[float, float],
270
270
  G37: Tuple[float, float], G36: Tuple[float, float],
271
- stand_time_year: float,
271
+ stand_time_year: float, JNFactor: Tuple[float, float],
272
272
  **options):
273
273
  """
274
274
 
@@ -294,6 +294,7 @@ def Monte_Carlo_F(ar40m: Tuple[float, float], ar39m: Tuple[float, float], ar38m:
294
294
  L36cl
295
295
  MDFunc
296
296
  MDF
297
+ JNFactor
297
298
  options
298
299
 
299
300
  Returns
@@ -307,9 +308,7 @@ def Monte_Carlo_F(ar40m: Tuple[float, float], ar39m: Tuple[float, float], ar38m:
307
308
  Monte_Carlo_Size = 10000
308
309
 
309
310
  # generate random
310
- print(ar40m)
311
311
  ar40m = random_normal_absolute(*ar40m, size=Monte_Carlo_Size)
312
- print(ar40m)
313
312
  ar39m = random_normal_absolute(*ar39m, size=Monte_Carlo_Size)
314
313
  ar38m = random_normal_absolute(*ar38m, size=Monte_Carlo_Size)
315
314
  ar37m = random_normal_absolute(*ar37m, size=Monte_Carlo_Size)
@@ -347,6 +346,8 @@ def Monte_Carlo_F(ar40m: Tuple[float, float], ar39m: Tuple[float, float], ar38m:
347
346
  R38v39k = random_normal_relative(*R38v39k, size=Monte_Carlo_Size)
348
347
  R36v38clp = random_normal_relative(*R36v38clp, size=Monte_Carlo_Size)
349
348
 
349
+ JNFactor = random_normal_absolute(*JNFactor, size=Monte_Carlo_Size)
350
+
350
351
  blank_gain_corr = options.get('blank_gain_corr', True)
351
352
 
352
353
  def do_simulation():
@@ -376,6 +377,7 @@ def Monte_Carlo_F(ar40m: Tuple[float, float], ar39m: Tuple[float, float], ar38m:
376
377
  _ar36a = _ar36res - _ar36cl
377
378
  _ar40r = _ar40 - _ar36a * R40v36a[i] - _ar39k * R40v39k[i]
378
379
  _ar40ar = _ar40 - _ar39k * R40v39k[i]
380
+ _ar39k = _ar39k * JNFactor[i]
379
381
  _f = _ar40r / _ar39k
380
382
  i += 1
381
383
  # yield _f, _ar36, _ar37, _ar38, _ar39, _ar40, _ar36a, _ar37ca, _ar39k, _ar40r, _ar36cl
ararpy/calc/jvalue.py CHANGED
@@ -36,4 +36,4 @@ def j_value(age, sage, r, sr, f, rsf):
36
36
  v2 = sage ** 2 * (f * np.exp(f * age) / r) ** 2
37
37
  v3 = sr ** 2 * ((1 - np.exp(f * age)) / r ** 2) ** 2
38
38
  k1 = np.sqrt(v1 + v2 + v3)
39
- return k0, k1
39
+ return k0, k1, k1, k1
ararpy/calc/plot.py CHANGED
@@ -39,8 +39,11 @@ def get_axis_scale(data: list, count=6, increment=None, extra_count=0, min_inter
39
39
  """
40
40
  if len(data) == 0:
41
41
  return 0, 1, 5, 0.2 # Default return
42
- _max = float(np.ma.masked_invalid(data).max())
43
- _min = float(np.ma.masked_invalid(data).min())
42
+ _max = np.ma.masked_invalid(data).max()
43
+ _min = np.ma.masked_invalid(data).min()
44
+ if isinstance(_max, np.ma.core.MaskedConstant) or isinstance(_min, np.ma.core.MaskedConstant):
45
+ return 0, 1, 5, 0.2 # Default return
46
+ _max = float(_max); _min = float(_min)
44
47
  interval = (_max - _min) / count
45
48
  if interval == 0:
46
49
  interval = 10
ararpy/files/calc_file.py CHANGED
@@ -49,8 +49,7 @@ def read_calc_file(file_path: str):
49
49
  book_contents[each_sheet] = sheet_contents
50
50
  os.remove(decrypt_file_path)
51
51
  except Exception as e:
52
- print(traceback.format_exc())
53
- return False
52
+ raise
54
53
  else:
55
54
  return book_contents
56
55
 
@@ -420,7 +419,7 @@ def open_full_xls(file_path: str, sample_name: str = ''):
420
419
  try:
421
420
  res = xls.open_xls(file_path)
422
421
  except (Exception, BaseException) as e:
423
- return e
422
+ raise
424
423
  start_row = 5
425
424
  rows_num = len(res['Sample Parameters']) - 5
426
425
 
@@ -583,8 +582,6 @@ class ArArCalcFile:
583
582
 
584
583
  def open(self):
585
584
  book_contents = read_calc_file(self.file_path)
586
- if not book_contents:
587
- raise ValueError('Fail to open the file')
588
585
  # create data frames for book values
589
586
  content = pd.DataFrame(book_contents['Data Tables'])
590
587
  logs01 = pd.DataFrame(book_contents['Logs01'])
ararpy/files/raw_file.py CHANGED
@@ -274,7 +274,7 @@ def get_raw_data(file_contents: List[List[Union[int, float, str, bool, list]]],
274
274
  raise ValueError(f"Step name not found")
275
275
  except (TypeError, ValueError, IndexError):
276
276
  # When parsing the step name fails, the end of the file has been reached
277
- break
277
+ raise
278
278
 
279
279
  # other information
280
280
  options = get_sample_info(file_contents, optional_info_index, default="", base=[1, 1 - idx, 1])
@@ -345,10 +345,9 @@ def get_raw_data(file_contents: List[List[Union[int, float, str, bool, list]]],
345
345
  break
346
346
 
347
347
  step_list.append(current_step)
348
- step_index += 1
349
- idx = input_filter[32] * step_index
348
+ idx = input_filter[32] * len(step_list)
350
349
 
351
- if not check_box_index[0] or step_index >= 500: # check_box_index[0]: multiple sequences
350
+ if not check_box_index[0] or len(step_list) >= 500: # check_box_index[0]: multiple sequences
352
351
  break
353
352
 
354
353
  return step_list
ararpy/files/xls.py CHANGED
@@ -20,8 +20,7 @@ def open_xls(filepath: str):
20
20
  sheet = wb.sheet_by_name(sheet_name)
21
21
  res[sheet_name] = [[sheet.cell(row, col).value for col in range(sheet.ncols)] for row in range(sheet.nrows)]
22
22
  except biffh.XLRDError as e:
23
- print('Error in opening excel file: %s' % str(e))
24
- return e
23
+ raise
25
24
  else:
26
25
  return res
27
26
 
ararpy/smp/basic.py CHANGED
@@ -44,39 +44,97 @@ def calc_apparent_ages(smp: Sample):
44
44
  -------
45
45
 
46
46
  """
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])
47
+ if str(smp.Info.sample.type).lower() == "unknown":
48
+ v = calc_age(smp=smp)
49
+ elif str(smp.Info.sample.type).lower() == "standard":
50
+ v = calc_j(smp=smp)
51
+ elif str(smp.Info.sample.type).lower() == "air":
52
+ v = calc_mdf(smp=smp)
53
+ else:
54
+ raise TypeError(f"Sample type is not supported: {smp.Info.sample.type}")
55
+ try:
56
+ smp.ApparentAgeValues[2:6] = v[0:4]
57
+ smp.PublishValues[5:7] = copy.deepcopy(v[0:2])
58
+ except (Exception, BaseException):
59
+ raise
59
60
 
60
61
 
61
62
  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()]
63
+ params_index_dict = {
64
+ 34: 'L', 35: 'rsL', 59: 'Age', 60: 'sAge'
65
+ }
66
+ if ar40ar39 is None and smp is not None:
67
+ ar40ar39 = smp.ApparentAgeValues[0:2] # ar40ar39 air, error
68
+ if len(np.shape(ar40ar39)) == 1:
69
+ ar40ar39 = np.reshape(ar40ar39, (2, 1))
70
+ if index is None:
71
+ index = list(range(np.shape(ar40ar39)[-1]))
72
+ if smp is None and params is None:
73
+ raise ValueError(f"Parameters are required for calculating mdf, or it is empty.")
74
+ if params is not None:
75
+ for key, val in params.items():
76
+ if not isinstance(val, list):
77
+ params[key] = list(val)
78
+ if smp is not None:
79
+ try:
80
+ params_from_smp = dict(zip(
81
+ list(params_index_dict.values()),
82
+ [[smp.TotalParam[i][j] for j in index] for i in params_index_dict.keys()]
83
+ ))
84
+ except Exception:
85
+ print(traceback.format_exc())
86
+ raise ValueError(f"Parameters cannot be found in the given sample object")
87
+ if params is not None:
88
+ params_from_smp.update(params)
89
+ params = params_from_smp
90
+
91
+ j = calc.jvalue.j_value(params['Age'], params['sAge'], *ar40ar39, params['L'], params['rsL'])
92
+
93
+ if len(index) == 1:
94
+ return np.array(j).squeeze().tolist()
95
+ else:
96
+ return np.array(j).tolist()
67
97
 
68
98
 
69
99
  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
100
+ params_index_dict = {
101
+ 71: 'M36', 72: 'sM36', 79: 'M40', 80: 'sM40', 93: 'Air', 94: 'rsAir', 100: 'Discr'
102
+ }
103
+ if ar40ar36 is None and smp is not None:
104
+ ar40ar36 = smp.ApparentAgeValues[0:2] # ar40ar36 air, error
105
+ if len(np.shape(ar40ar36)) == 1:
106
+ ar40ar36 = np.reshape(ar40ar36, (2, 1))
107
+ if index is None:
108
+ index = list(range(np.shape(ar40ar36)[-1]))
109
+ if smp is None and params is None:
110
+ raise ValueError(f"Parameters are required for calculating mdf, or it is empty.")
111
+ if params is not None:
112
+ for key, val in params.items():
113
+ if not isinstance(val, list):
114
+ params[key] = list(val)
115
+ if smp is not None:
116
+ try:
117
+ params_from_smp = dict(zip(
118
+ list(params_index_dict.values()),
119
+ [[smp.TotalParam[i][j] for j in index] for i in params_index_dict.keys()]
120
+ ))
121
+ except Exception:
122
+ print(traceback.format_exc())
123
+ raise ValueError(f"Parameters cannot be found in the given sample object")
124
+ if params is not None:
125
+ params_from_smp.update(params)
126
+ params = params_from_smp
127
+
75
128
  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()
129
+ for i in range(len(index)):
130
+ k = calc.corr.mdf(ar40ar36[0][i], ar40ar36[1][i], params['M36'][i], params['M40'][i],
131
+ params['Air'][i], params['rsAir'][i]) # linear, exp, pow
132
+ mdf.append({"linear": k[0:4], "exp": k[4:8], "pow": k[8:12]}[params['Discr'][i].lower()])
133
+
134
+ if len(index) == 1:
135
+ return np.transpose(mdf).squeeze().tolist()
136
+ else:
137
+ return np.transpose(mdf).tolist()
80
138
 
81
139
 
82
140
  def calc_age(ar40ar39=None, params: dict = None, smp: Sample = None, index: list = None):
@@ -95,7 +153,8 @@ def calc_age(ar40ar39=None, params: dict = None, smp: Sample = None, index: list
95
153
  """
96
154
  params_index_dict = {
97
155
  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',
156
+ 50: 'Ae', 51: 'sAe', 52: 'Ab', 53: 'sAb', 54: 'Abp', 55: 'sAbp', 59: 't', 60: 'st',
157
+ 61: 'Ap', 62: 'sAp', 63: 'Kp', 64: 'sKp', 67: 'J', 68: 'sJ',
99
158
  81: 'W', 82: 'sW', 83: 'No', 84: 'sNo', 85: 'Y', 86: 'sY', 87: 'f', 88: 'sf', 110: 'Min'
100
159
  }
101
160
 
@@ -477,7 +536,7 @@ def get_diff_smp(backup: (dict, Sample), smp: (dict, Sample)):
477
536
  # =======================
478
537
  # Set parameters
479
538
  # =======================
480
- def set_params(smp: Sample, params: Union[List, str], flag: Optional[str] = None):
539
+ def set_params(smp: Sample, params: Union[List, str], flag: Optional[str] = None, rows: Optional[List] =None):
481
540
  """
482
541
  Parameters
483
542
  ----------
@@ -485,84 +544,76 @@ def set_params(smp: Sample, params: Union[List, str], flag: Optional[str] = None
485
544
  params
486
545
  flag : optional, should be one of 'calc', 'irra', and 'smp'. If it is not given,
487
546
  the text of the extension without a dot will be used
547
+ rows
488
548
 
489
549
  Returns
490
550
  -------
491
551
 
492
552
  """
553
+ if rows is None:
554
+ rows = []
555
+ rows = list(set(rows))
556
+
493
557
  if isinstance(params, str) and os.path.isfile(params):
494
558
  if flag is None:
495
559
  flag = params.split(".")[-1]
496
560
  return set_params(smp, read_params(params), flag=flag)
497
561
 
498
- def remove_none(old_params, new_params, rows, length):
499
- res = [[] for _ in range(length)]
562
+ def isValid(item):
563
+ valid = True
564
+ if isinstance(item, (float, int)):
565
+ valid = not np.isnan(item)
566
+ return valid and item is not None and item != ""
567
+
568
+ def remove_none(old_params, new_params, row_list, length):
569
+ res = [[old_params[i][j] if j < len(old_params[i]) else None for j in range(max(len(old_params[i]), length))] for i in range(len(old_params))]
500
570
  for index, item in enumerate(new_params):
501
- if item is None:
502
- res[index] = old_params[index]
503
- else:
504
- res[index] = [item] * rows
571
+ if isValid(item):
572
+ for row in row_list:
573
+ res[index][row] = item
505
574
  return res
506
575
 
507
576
  n = len(smp.SequenceName)
508
-
509
577
  if n == 0:
510
- raise ValueError(f"The number of sample sequences is undefined.")
578
+ raise ValueError(f"The number of sample sequences is zero")
511
579
 
512
580
  if flag == 'calc':
513
- smp.TotalParam[34:56] = remove_none(smp.TotalParam[34:56], params[0:22], n, 56 - 34)
514
- smp.TotalParam[71:97] = remove_none(smp.TotalParam[71:97], params[22:48], n, 97 - 71)
581
+ smp.TotalParam[34:56] = remove_none(smp.TotalParam[34:56], params[0:22], rows, n)
582
+ smp.TotalParam[71:97] = remove_none(smp.TotalParam[71:97], params[22:48], rows, n)
515
583
  elif flag == 'irra':
516
- smp.TotalParam[0:20] = remove_none(smp.TotalParam[0:20], params[0:20], n, 20 - 0)
517
- smp.TotalParam[56:58] = remove_none(smp.TotalParam[56:58], params[20:22], n, 57 - 55) # Cl36/38 productivity
518
- smp.TotalParam[20:27] = remove_none(smp.TotalParam[20:27], params[22:29], n, 27 - 20)
519
- # smp.TotalParam[26] = [params[26]] * n
584
+ smp.TotalParam[0:20] = remove_none(smp.TotalParam[0:20], params[0:20], rows, n)
585
+ smp.TotalParam[56:58] = remove_none(smp.TotalParam[56:58], params[20:22], rows, n) # Cl36/38 productivity
586
+ smp.TotalParam[20:27] = remove_none(smp.TotalParam[20:27], params[22:29], rows, n)
520
587
  irradiation_time = []
521
588
  duration = []
522
589
  if None not in params[29:-3] and '' not in params[29:-3]:
523
590
  for i in range(len(params[29:-3])):
524
591
  if i % 2 == 0:
525
- # [d, t] = params[29:-3][i].split('T')
526
- # [t1, t2] = t.split(':')
527
- # irradiation_time.append(d + '-' + t1 + '-' + t2 + 'D' + str(params[29:-3][i + 1]))
528
- text = params[29:-3][i]
529
- for char in ['T', ':']:
530
- text = text.replace(char, '-')
531
592
  irradiation_time.append(params[29:-3][i] + 'D' + str(params[29:-3][i + 1]))
532
593
  duration.append(float(params[29:-3][i + 1]))
533
- smp.TotalParam[27] = ['S'.join(irradiation_time)] * n
534
- smp.TotalParam[28] = [params[-3]] * n
535
- smp.TotalParam[29] = [sum(duration)] * n
594
+ smp.TotalParam[27:30] = remove_none(smp.TotalParam[27:30], ['S'.join(irradiation_time), params[-3], sum(duration)], rows, n)
536
595
  if params[-5] != '':
537
- # [a, b] = params[-5].split('T')
538
- # [b, c] = b.split(':')
539
- # smp.TotalParam[30] = [a + '-' + b + '-' + c] * n
540
- text = params[-5]
541
- for char in ['T', ':']:
542
- text = text.replace(char, '-')
543
- # smp.TotalParam[30] = [text] * n
544
- smp.TotalParam[30] = [params[-5]] * n
596
+ smp.TotalParam[30:32] = remove_none(smp.TotalParam[30:32], [params[-5], None], rows, n)
545
597
  try:
546
598
  stand_time_second = [
547
599
  calc.basic.get_datetime(*re.findall(r"\d+", smp.TotalParam[31][i])) - calc.basic.get_datetime(
548
- *re.findall(r"\d+", smp.TotalParam[30][i])) for i in range(n)]
600
+ *re.findall(r"\d+", smp.TotalParam[30][i])) for i in range(len(smp.TotalParam[30]))]
549
601
  except (BaseException, Exception):
550
602
  print(f'Error in calculate standing duration: {traceback.format_exc()}')
551
- raise
603
+ smp.TotalParam[32] = [None for index in range(n)]
552
604
  else:
553
- smp.TotalParam[32] = [i / (3600 * 24 * 365.242) for i in stand_time_second] # stand year
605
+ smp.TotalParam[32] = [item / (3600 * 24 * 365.242) if index in rows else smp.TotalParam[32][index] for index, item in enumerate(stand_time_second)] # stand year
554
606
 
555
607
  elif flag == 'smp':
556
- print(dict(zip([i for i in range(len(params))], params)))
557
- smp.TotalParam[67:71] = remove_none(smp.TotalParam[67:71], params[0:4], n, 71 - 67)
558
- smp.TotalParam[58:67] = remove_none(smp.TotalParam[58:67], params[4:13], n, 67 - 58)
559
- smp.TotalParam[97:100] = remove_none(smp.TotalParam[97:100], params[13:16], n, 100 - 97)
560
- smp.TotalParam[115:120] = remove_none(smp.TotalParam[115:120], params[16:21], n, 120 - 115)
561
- smp.TotalParam[126:136] = remove_none(smp.TotalParam[126:136], params[21:31], n, 136 - 126)
562
- # smp.TotalParam[120:123] = remove_none(smp.TotalParam[120:123], params[31:34], n, 123 - 120)
608
+ smp.TotalParam[67:71] = remove_none(smp.TotalParam[67:71], params[0:4], rows, n)
609
+ smp.TotalParam[58:67] = remove_none(smp.TotalParam[58:67], params[4:13], rows, n)
610
+ smp.TotalParam[97:100] = remove_none(smp.TotalParam[97:100], params[13:16], rows, n)
611
+ smp.TotalParam[115:120] = remove_none(smp.TotalParam[115:120], params[16:21], rows, n)
612
+ smp.TotalParam[126:136] = remove_none(smp.TotalParam[126:136], params[21:31], rows, n)
613
+ # smp.TotalParam[120:123] = remove_none(smp.TotalParam[120:123], params[31:34], rows, n)
563
614
  smp.TotalParam[100:114] = remove_none(
564
615
  smp.TotalParam[100:114],
565
- [['Linear', 'Exponential', 'Power'][params[35:38].index(True)] if True in params[35:38] else '', *params[38:]], n, 114 - 100)
616
+ [['Linear', 'Exponential', 'Power'][params[35:38].index(True)] if True in params[35:38] else '', *params[38:]], rows, n)
566
617
  pref = dict(zip(preference_keys, params[31:35]))
567
618
  smp.Info.preference.update(pref)
568
619
  for key, comp in get_components(smp).items():
@@ -570,7 +621,6 @@ def set_params(smp: Sample, params: Union[List, str], flag: Optional[str] = None
570
621
  comp.decimal_places = pref['decimalPlaces']
571
622
  comp.set_coltypes()
572
623
  smp.AgeSpectraPlot.yaxis.title.text = f"Apparent Age ({str(pref['ageUnit']).capitalize()})"
573
- print(smp.Info.preference)
574
624
 
575
625
  else:
576
626
  raise KeyError(f"{flag = } is not supported. It must be 'calc' for Calc Params, "