ararpy 0.1.13__py3-none-any.whl → 0.1.14__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.
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: UTF-8 -*-
3
+ """
4
+ # ==========================================
5
+ # Copyright 2025 Yang
6
+ # webarar - __init__.py
7
+ # ==========================================
8
+ #
9
+ #
10
+ #
11
+ """
12
+ from . import main
@@ -0,0 +1,542 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: UTF-8 -*-
3
+ """
4
+ # ==========================================
5
+ # Copyright 2024 Yang
6
+ # ArgonDiffusionRandomWalk - main
7
+ # ==========================================
8
+ #
9
+ #
10
+ #
11
+ """
12
+ import os
13
+ import pickle
14
+ import numpy as np
15
+ import math
16
+ import copy
17
+ import time
18
+ from typing import List
19
+
20
+ np.set_printoptions(precision=18, threshold=10000, linewidth=np.inf)
21
+
22
+ SETUP_PRINT = "natoms = {0}, nsteps = {1}, grain_size = {2}, time_scale = {3}, size_scale = {4}, number_scale = {5}"
23
+
24
+
25
+ def _uniform_sphere_step(step_length, shape):
26
+ """
27
+ 在三维空间中生成均匀分布的球面样本,且步长严格为指定长度。
28
+
29
+ Parameters:
30
+ step_length (array, float): 步长的固定长度, (n, m)
31
+ num_samples (tuple): 步长shape, (n, m)
32
+
33
+ Returns:
34
+ np.ndarray: 形状为 (num_samples, 3) 的数组,每行是一个随机步长向量
35
+ """
36
+ # 随机生成方位角 phi 和极角的 cos(theta)
37
+ num_samples, dimension = shape
38
+ phi = np.random.uniform(0, 2 * np.pi, num_samples)
39
+ cos_theta = np.random.uniform(-1, 1, num_samples)
40
+ sin_theta = np.sqrt(1 - cos_theta ** 2) # sin(theta) = sqrt(1 - cos^2(theta))
41
+
42
+ # 将球面坐标转换为笛卡尔坐标
43
+ x = sin_theta * np.cos(phi)
44
+ y = sin_theta * np.sin(phi)
45
+ z = cos_theta
46
+
47
+ # 构建单位向量
48
+ unit_vectors = np.vstack((x, y, z)).T
49
+
50
+ # 乘以步长,得到最终的步长向量
51
+ steps = step_length * unit_vectors
52
+ return steps
53
+
54
+
55
+ def walker(pos, step_length, total_nsteps, min_bound, max_bound, scale=0., compensation=0, remove=True,
56
+ conditions=None, boundary_factor=1):
57
+
58
+ if len(pos) == 0:
59
+ return pos
60
+
61
+ dimension = pos.shape[1] if len(pos.shape) > 1 else 1
62
+
63
+ sigma = step_length * math.sqrt(scale)
64
+
65
+ if conditions is None:
66
+ if dimension == 3:
67
+ conditions = np.array([[-50, -50, -50, 50, 50, 50, 1]])
68
+ else:
69
+ conditions = np.array([[-50, -50, 50, 50, 1]])
70
+
71
+ num_big_steps = int(total_nsteps // scale) if int(scale) > 1 else 0
72
+ num_small_steps = int(total_nsteps % scale) if int(scale) > 1 else int(total_nsteps)
73
+
74
+ for _ in range(num_big_steps):
75
+ # print(f"new walker {_ = } {len(pos) = }")
76
+ # 边界判断(布尔掩码)
77
+ in_boundary_mask = np.all(
78
+ (pos >= (min_bound + sigma * compensation)) & (pos <= (max_bound - sigma * compensation)), axis=1)
79
+ in_core = pos[in_boundary_mask]
80
+ in_boundary = pos[~in_boundary_mask]
81
+
82
+ # 核心粒子随机行走
83
+ coefficients = np.ones(len(in_core))
84
+ for each in conditions:
85
+ # each = x1, y1, z1, x2, y2, z2, coeff for dimension=3
86
+ cond = np.all(
87
+ (in_core >= np.array(each[:dimension])) & (in_core <= np.array(each[dimension:int(2*dimension)])),
88
+ axis=1)
89
+ coefficients = np.where(cond, each[-1] ** 0.5, coefficients)
90
+ steps = np.random.normal(0, sigma, size=in_core.shape)
91
+ in_core += steps * coefficients[:, None]
92
+
93
+ # 将边界粒子以更小 scale 的步长模拟
94
+ if scale > 1:
95
+ in_boundary = walker(in_boundary, step_length, scale, min_bound, max_bound, scale // 2,
96
+ compensation, remove, conditions, boundary_factor)
97
+
98
+ # 拼接核心和边界粒子
99
+ pos = np.concatenate((in_boundary, in_core))
100
+
101
+ # 移除超出范围的粒子
102
+ if remove:
103
+ pos = pos[np.all((pos >= min_bound) & (pos <= max_bound), axis=1)]
104
+
105
+ # 最后处理 scale < 1 的小步模拟, boundary_factor用来缩放这里的处理步数,1 < boundary_factor <= 1如果 boundary_factor=1,将完全吻合实际
106
+ # boundary_factor < 1 将加快一些速度, boundary_factor=0 将忽略小步数
107
+ k = boundary_factor * max(conditions[:, -1])
108
+ for _ in range(int(num_small_steps * k)):
109
+ coefficients = np.ones(len(pos))
110
+ for each in conditions:
111
+ cond = np.all((pos >= np.array(each[:dimension])) & (pos <= np.array(each[dimension:int(2*dimension)])),
112
+ axis=1)
113
+ coefficients = np.where(cond, (each[-1] / k) ** 0.5, coefficients)
114
+ # coefficients = np.where(cond, coeff ** 0.5, coefficients)
115
+ steps = np.random.normal(0, step_length, size=np.shape(pos))
116
+ pos += steps * coefficients[:, None]
117
+
118
+ if remove:
119
+ pos = pos[np.all((pos >= min_bound) & (pos <= max_bound), axis=1)]
120
+
121
+ return pos
122
+
123
+
124
+ def walker2(pos: np.ndarray, duration, step_length, min_bound, max_bound, time_scale, frequency,
125
+ conditions=None, remove: bool = True):
126
+ """
127
+ :return:
128
+ """
129
+
130
+ if len(pos) == 0:
131
+ return pos
132
+
133
+ dimension = pos.shape[-1] if len(pos.shape) > 1 else 1
134
+
135
+ dt = time_scale
136
+ if conditions is None:
137
+ if dimension == 3:
138
+ conditions = np.array([[-50, -50, -50, 50, 50, 50, 1]])
139
+ else:
140
+ conditions = np.array([[-50, -50, 50, 50, 1]])
141
+
142
+ for step in range(int(1e16)):
143
+
144
+ res = np.zeros(0).reshape(0, dimension)
145
+ for index, each in enumerate(conditions):
146
+ # each = (x1, y1, z1, x2, y2, z2, gamma)
147
+ d = step_length * math.sqrt(each[-1] * frequency * time_scale)
148
+
149
+ locs = np.ones(len(pos)) * 999
150
+ for _index, _each in enumerate(conditions):
151
+ cond = np.all((pos >= np.array(_each[:dimension])) & (pos <= np.array(_each[dimension:int(2*dimension)])), axis=1)
152
+ locs = np.where(cond, _index, locs)
153
+
154
+ partial_pos = pos[locs == index]
155
+
156
+ # c = len(partial_pos)
157
+ # # 初始化步长
158
+ # steps = np.zeros(partial_pos.shape, dtype=float)
159
+ # # 移动方向, x or y or z
160
+ # directions = np.random.choice(list(range(dimension)), size=c)
161
+ # # 方向, positive or negative, 步长
162
+ # steps[np.arange(c), directions] = np.random.choice([-d, d], size=c, p=[0.5, 0.5])
163
+ steps = np.random.normal(0, d, size=partial_pos.shape)
164
+
165
+ partial_pos += steps
166
+
167
+ if remove:
168
+ partial_pos = partial_pos[np.all((partial_pos >= min_bound) & (partial_pos <= max_bound), axis=1)]
169
+
170
+ res = np.concatenate((res, partial_pos))
171
+
172
+ pos = copy.deepcopy(res)
173
+
174
+ _t = (step + 1) * dt
175
+
176
+ if abs(_t - duration) < dt:
177
+ break
178
+
179
+ return pos
180
+
181
+
182
+ class OverEpsilonError(Exception):
183
+ def __init__(self, i, d, e):
184
+ self.i = i
185
+ self.d = d
186
+ self.e = e
187
+
188
+ def __str__(self):
189
+ return f"OverEpsilonError: Index = {self.i}, d = {self.d} > e = {self.e}"
190
+
191
+
192
+ class Domain:
193
+ def __init__(self, dimension: int = 3, atom_density: float = 1e14, fraction: float = 1.0,
194
+ min_bound=None, max_bound=None, **kwargs):
195
+
196
+ self.dimension = dimension
197
+ self.size = ...
198
+ self.atom_density = atom_density
199
+ self.fraction = fraction
200
+ self.time_scale = 1
201
+ self.size_scale = 0.05
202
+
203
+ self.energy = 120 * 1000 # J/mol
204
+ self.density = 0
205
+ self.fracture = 0
206
+ self.boundary = 0
207
+ self.defect = 0
208
+ self.pho = 1
209
+ self.step_length = 0.0001 # 1 A = 0.1 nm = 0.0001 μm
210
+
211
+ self.current_temp = 273.15
212
+
213
+ self.inclusions: List[Domain] = []
214
+ self.natoms: int = 0
215
+ self.positions = []
216
+ self.min_bound = min_bound
217
+ self.max_bound = max_bound
218
+ self.remained_per_step = []
219
+ self.released_per_step = []
220
+
221
+ self.attr = {}
222
+
223
+ for key, val in kwargs.items():
224
+ if hasattr(self, key):
225
+ setattr(self, key, val)
226
+
227
+ self.setup()
228
+
229
+ def setup(self):
230
+ """
231
+ Used to set or reset positions of atoms
232
+ :return:
233
+ """
234
+
235
+ # 初始化粒子位置,随机分布在网格内
236
+ # 初始原子个数 1e14 原子密度 个/立方厘米 1e-4是单位换算 cm/µm
237
+ natoms = int(self.atom_density ** (self.dimension / 3) * (abs(max(self.max_bound) - min(self.min_bound)) * 1e-4) ** self.dimension)
238
+ self.positions = np.random.uniform(max(self.max_bound), min(self.min_bound), size=(int(natoms), self.dimension))
239
+ self.positions = self.positions[np.all((self.positions >= self.min_bound) & (self.positions <= self.max_bound), axis=1)]
240
+ for dom in self.inclusions:
241
+ self.positions = self.positions[~np.all((self.positions >= dom.min_bound) & (self.positions <= dom.max_bound), axis=1)]
242
+ self.natoms = len(self.positions)
243
+
244
+ self.remained_per_step = []
245
+ self.released_per_step = []
246
+
247
+ def get_gamma(self, energy: float = None, temperature: float = None):
248
+ r = 8.31446261815324 # J / (K * mol)
249
+ T = self.current_temp if temperature is None else temperature
250
+ e = self.energy if energy is None else energy
251
+ alpha = 1 - self.density
252
+ p1 = math.exp(- e / (r * T))
253
+ p2 = math.exp(- e / 2 / (r * T)) # p2是给定活化能的一半,用于假定晶面扩散的活化能
254
+ gamma = p1 * alpha * (1 - self.fracture) + self.fracture * p2 + self.boundary + self.defect
255
+ return gamma
256
+
257
+ def get_natoms(self, pos=None):
258
+ if pos is None:
259
+ return len(self.positions)
260
+ pos = pos[np.all((pos >= self.min_bound) & (pos <= self.max_bound), axis=1)]
261
+ for dom in self.inclusions:
262
+ pos = pos[~np.all((pos >= dom.min_bound) & (pos <= dom.max_bound), axis=1)]
263
+ return len(pos)
264
+
265
+ def set_attr(self, name, value, index=None):
266
+ if index is None:
267
+ self.attr.update({name: value})
268
+ else:
269
+ if name not in self.attr.keys():
270
+ self.attr.update({name: {}})
271
+ self.attr[name].update({index: value})
272
+
273
+
274
+ class DiffSimulation:
275
+ def __init__(self):
276
+ self.name = "example"
277
+ self.loc = "examples"
278
+ self.score = 0
279
+ self.end_at = 0
280
+ self.dimension = 3
281
+
282
+ self.size_scale = 1
283
+ self.length_scale = 1
284
+
285
+ self.atom_density = 1e14 # 原子密度 个/立方厘米
286
+ self.frequency = 1e13 # 每秒振动的次数, Debye frequency
287
+
288
+ self.grain_size = 300 # 0.3 mm = 300 μm = 300000 nm
289
+ self.grid_size = self.grain_size * self.size_scale # 网格大小
290
+ self.nsteps: int = ...
291
+ self.natoms: int = ...
292
+ self.epsilon = 1e-5
293
+ self.step_length = 0.0001 * 2.5 # 1 A = 0.1 nm = 0.0001 μm
294
+
295
+ self.seq: [List, np.ndarray] = []
296
+ self.domains: List[Domain] = []
297
+ self.positions: [List, np.ndarray] = []
298
+
299
+ self.remained_per_step = []
300
+ self.released_per_step = []
301
+
302
+ def setup(self):
303
+ """
304
+ Used to set or reset positions of atoms
305
+ :return:
306
+ """
307
+ # 网格大小和颗粒边界
308
+ self.grid_size = self.grain_size * self.size_scale # 网格大小
309
+ center = np.array([0 for i in range(self.dimension)])
310
+ self.min_bound = center - self.grid_size / 2
311
+ self.max_bound = center + self.grid_size / 2
312
+
313
+ # 粒子位置
314
+ self.positions = np.concatenate([dom.positions for dom in self.domains])
315
+ # 粒子数目
316
+ self.natoms = len(self.positions)
317
+
318
+ self.remained_per_step = []
319
+ self.released_per_step = []
320
+
321
+ def run_sequence(self, times, temperatures, statuses, targets, domains: List[Domain], nsteps_factor=None,
322
+ simulating: bool = False, epsilon=0.001, start_time=0, k=1.2, use_walker1=True,
323
+ scoring: bool = False):
324
+ pos = copy.deepcopy(self.positions)
325
+ self.seq = [] # 用于记录参数
326
+
327
+ for index, (duration, temperature, target, status) in enumerate(zip(times, temperatures, targets, statuses)):
328
+
329
+ self.seq.append({})
330
+
331
+ loop = 0
332
+ e_low = 100 * 1000
333
+ e_up = 300 * 1000
334
+
335
+ _start = time.time()
336
+ heating_duration = duration - start_time # in seconds
337
+ start_time = duration
338
+ temperature = temperature + 273.15 # in Kelvin
339
+
340
+ while loop < 50:
341
+
342
+ e = (e_low + e_up) / 2
343
+
344
+ total_steps = self.frequency * heating_duration # 振动次数
345
+ conditions = np.array(
346
+ [[*dom.min_bound, *dom.max_bound,
347
+ dom.get_gamma(temperature=temperature, energy=e if simulating else None)] for dom in domains if dom.energy != 0 and not simulating])
348
+
349
+ if use_walker1:
350
+
351
+ # print(f"调整前: {nsteps_factor = }, gamma = {conditions[0][-1]}, {total_steps = }")
352
+ nsteps_factor = 10 ** math.floor(
353
+ -math.log10(max(conditions[:, -1]))) * 1000 # 用来调节次数和步长的巨大差异,次数太大,但步程太小
354
+ while int(total_steps / nsteps_factor) < 1:
355
+ nsteps_factor /= 10
356
+ while int(total_steps / nsteps_factor) > 10000:
357
+ nsteps_factor *= 10
358
+ total_steps = int(total_steps / nsteps_factor) # 振动次数
359
+ conditions[:, -1] *= nsteps_factor
360
+ compensation = max(3, *(np.ceil(np.sqrt(conditions[:, -1])) * 3))
361
+ boundary_factor = 1
362
+ if max(conditions[:, -1]) > 1000:
363
+ # k = 0时,bf = 1, 完全无缩放 # k = 1时,bf <= 0.5 小步行走将至少缩放一半 # 推荐值 k = 1.2
364
+ boundary_factor = 0.1 ** (k * math.log10(1 + (max(conditions[:, -1]) // 1000)))
365
+ step_length = self.step_length / np.sqrt(pos.shape[1] if len(pos.shape) > 1 else 1)
366
+ scale = int(total_steps)
367
+ # print(f"调整后: {nsteps_factor = }, gamma = {conditions[0][-1]}, {total_steps = }, {compensation = }, {boundary_factor = }")
368
+
369
+ _pos = walker(
370
+ copy.deepcopy(pos), step_length=step_length, total_nsteps=total_steps,
371
+ min_bound=self.min_bound, max_bound=self.max_bound, scale=scale,
372
+ compensation=compensation, remove=True, conditions=conditions, boundary_factor=boundary_factor
373
+ )
374
+
375
+ # self.seq[index].update({
376
+ # "duration": duration, "temperature": temperature, "target": target, "step_length": step_length,
377
+ # "scale": scale, "compensation": compensation, "boundary_factor": boundary_factor, "e": e,
378
+ # "simulation": simulating, "nsteps_factor": nsteps_factor, "conditions": conditions
379
+ # })
380
+
381
+ else:
382
+ step_length = self.step_length / np.sqrt(pos.shape[1] if len(pos.shape) > 1 else 1)
383
+ scale = k
384
+ _pos = walker2(copy.deepcopy(pos), duration=heating_duration, step_length=step_length,
385
+ min_bound=self.min_bound, max_bound=self.max_bound, time_scale=scale,
386
+ frequency=self.frequency, conditions=conditions, remove=True)
387
+ boundary_factor = 1
388
+ compensation = 0
389
+
390
+ self.seq[index].update({
391
+ "duration": duration, "temperature": temperature, "target": target, "step_length": step_length,
392
+ "scale": scale, "compensation": compensation, "boundary_factor": boundary_factor, "e": e,
393
+ "simulation": simulating, "nsteps_factor": nsteps_factor, "conditions": conditions
394
+ })
395
+
396
+ released = 1 - len(_pos) / self.natoms
397
+ d = released - target
398
+ if simulating:
399
+ loop += 1
400
+ print(f"{e = }, {d = }, {abs(d) <= epsilon}")
401
+ if abs(d) <= epsilon:
402
+ break
403
+ elif d > 0:
404
+ e_low = e
405
+ else:
406
+ e_up = e
407
+ elif scoring:
408
+ self.score += (d * 100) ** 2
409
+ print(f"{self.score = }, {d = }")
410
+ if self.score > 4 * (index + 1):
411
+ raise OverEpsilonError(index, self.score, 4 * (index + 1))
412
+ else:
413
+ break
414
+ else:
415
+ break
416
+
417
+ pos = _pos
418
+
419
+ if status:
420
+ # status == True: argon collection, False: pumping
421
+ for dom in self.domains:
422
+ _c = dom.get_natoms(pos)
423
+ dom.remained_per_step.append(_c)
424
+ dom.released_per_step.append(dom.natoms - _c)
425
+ dom.set_attr("energy", float(e), index=index)
426
+
427
+ self.remained_per_step.append(len(pos))
428
+ self.released_per_step.append(self.natoms - len(pos))
429
+
430
+ print(f"{index = } {duration} - {heating_duration = } - {temperature = } - {total_steps = } - conc = {len(pos) / self.natoms * 100:.2f}% - {time.time() - _start:.5f}s")
431
+
432
+ def run_persecond(self, times, temperatures, statuses, targets, domains: List[Domain], scale=None,
433
+ simulation: bool = False, epsilon=0.001, start_time=0):
434
+ seq = []
435
+ for i in range(1, int(times[-1] + 1), 300):
436
+ for index, time in enumerate(times):
437
+ if (times[index-1] if index > 0 else 0) < i <= times[index]:
438
+ seq.append([i, temperatures[index], statuses[index], targets[index]])
439
+ seq = np.transpose(seq)
440
+ return self.run_sequence(*seq, domains=domains, nsteps_factor=scale, simulating=simulation,
441
+ epsilon=epsilon, start_time=start_time)
442
+
443
+
444
+ def run(times, temps, statuses, energies, fractions, ndoms: int = 1, grain_szie=275, atom_density=1e10, frequency=1e13,
445
+ dimension: int = 3, targets: list = None, epsilon: float = 0.001, simulation: bool = False,
446
+ file_name: str = "Y70", ignore_error: bool = False, **kwargs):
447
+ """
448
+ :param times:
449
+ :param temps:
450
+ :param statuses:
451
+ :param energies:
452
+ :param fractions:
453
+ :param dimension:
454
+ :param ndoms:
455
+ :param targets:
456
+ :param epsilon:
457
+ :param simulation:
458
+ :param file_name:
459
+ :param ignore_error:
460
+ :return:
461
+ """
462
+
463
+ demo = DiffSimulation()
464
+
465
+ def _(n, es, fs):
466
+ # fs 应从大到小,父空间在前,子空间在后
467
+
468
+ # demo.grain_size = 300
469
+ # demo.size_scale = 0.05
470
+ # demo.atom_density = 1e14 # 原子密度 个/立方厘米
471
+ demo.dimension = dimension
472
+
473
+ demo.size_scale = 1
474
+ demo.grain_size = grain_szie
475
+ demo.atom_density = atom_density # 原子密度 个/立方厘米
476
+ demo.frequency = frequency
477
+
478
+ # domains应该从外到内
479
+ domains = []
480
+ for i in range(n-1, 0-1, -1):
481
+ size = int(demo.grain_size * fs[i]) * demo.size_scale
482
+ center = np.zeros(demo.dimension)
483
+ dom = Domain(
484
+ dimension=demo.dimension, atom_density=demo.atom_density, min_bound=center - size / 2, max_bound=center + size / 2,
485
+ energy=es[i], fraction=fs[i], inclusions=[domains[-1]] if len(domains) >= 1 else []
486
+ )
487
+ domains.append(dom)
488
+ # domains应该从外到内, 上面为了inclusion以及方便不同扩散域设置不同的密度,要按照从小到大的顺序生成,但是后面行走的时候要根据不同条件设置系数,要从外到内
489
+ demo.domains = sorted(domains, key=lambda dom: dom.fraction, reverse=True)
490
+
491
+ demo.setup()
492
+
493
+ demo.name = f"{file_name}"
494
+
495
+ print(f"Total Atoms: {demo.natoms}, atoms in each dom: {[dom.natoms for dom in demo.domains]} filename: {demo.name}")
496
+
497
+ demo.run_sequence(times=times, temperatures=temps, statuses=statuses, targets=targets, domains=demo.domains,
498
+ epsilon=epsilon, simulating=simulation, **kwargs)
499
+ # demo.run_persecond(times=times, temperatures=temps, domains=demo.domains, targets=target,
500
+ # epsilon=epsilon, simulation=simulation)
501
+
502
+ return demo
503
+
504
+ try:
505
+ return _(ndoms, energies, fractions), True
506
+ except OverEpsilonError as e:
507
+ if ignore_error:
508
+ return demo, False
509
+ else:
510
+ raise
511
+
512
+
513
+ def save_ads(ads: DiffSimulation, dir_path: str = None, name: str = None):
514
+ if dir_path is None:
515
+ dir_path = ""
516
+ if name is None:
517
+ name = ads.name
518
+ if not name.endswith(".ads"):
519
+ name = f"{name}.ads"
520
+ dir_path = os.path.join(dir_path, name)
521
+ with open(dir_path, 'wb') as f:
522
+ f.write(pickle.dumps(ads))
523
+ return name
524
+
525
+
526
+ def read_ads(file_path: str) -> DiffSimulation:
527
+
528
+ class RenameUnpickler(pickle.Unpickler):
529
+ def find_class(self, module: str, name: str):
530
+ if "argon_diffusion_simulator" in module:
531
+ return super(RenameUnpickler, self).find_class(DiffSimulation().__module__, name)
532
+ else:
533
+ return super(RenameUnpickler, self).find_class(module, name)
534
+
535
+ def renamed_load(file_obj) -> DiffSimulation:
536
+ return RenameUnpickler(file_obj).load()
537
+
538
+ try:
539
+ with open(file_path, 'rb') as f:
540
+ return renamed_load(f)
541
+ except (Exception, BaseException):
542
+ raise ValueError(f"ModuleNotFoundError")
ararpy/calc/corr.py CHANGED
@@ -75,7 +75,7 @@ def mdf(rm: float, srm: float, m1: float, m2: float, ra: float = 298.56,
75
75
  k3, k4 = "Null", "Null"
76
76
  # pow
77
77
  try:
78
- k5 = pow((ra / rm), (1 / delta_m)) # A.A.P.Koppers
78
+ k5 = pow((ra / rm), (1 / delta_m)) # A.A.P.Koppers, also 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:
@@ -107,14 +107,14 @@ def discr(a0: list, e0: list, mdf: list, smdf: list, m: list, m40: list,
107
107
  for i in range(min([len(arg) for arg in [a0, e0, mdf, smdf]])):
108
108
  delta_mass = abs(m40[i] - m[i])
109
109
  ratio_mass = abs(m40[i] / m[i]) if m[i] != 0 else 1
110
- if method.lower()[0] == 'l':
110
+ if method.lower().startswith("l"):
111
111
  k0 = 1 / (delta_mass * mdf[i] - delta_mass + 1) if (delta_mass * mdf[i] - delta_mass + 1) != 0 else 0
112
112
  k1 = err.div((1, 0), (delta_mass * mdf[i] - delta_mass + 1, smdf[i] * delta_mass))
113
- elif method.lower()[0] == 'e':
113
+ elif method.lower().startswith("e"):
114
114
  k0 = 1 / (ratio_mass ** (mdf[i] * m40[i] - m[i]))
115
115
  k1 = err.div((1, 0), (ratio_mass ** (mdf[i] * m40[i] - m[i]), err.pow((ratio_mass, 0), (
116
116
  mdf[i] * m40[i] - m[i], err.mul((mdf[i], smdf[i]), (m40[i], 0))))))
117
- elif method.lower()[0] == 'p':
117
+ elif method.lower().startswith("p"):
118
118
  k0 = 1 / (mdf[i] ** delta_mass)
119
119
  k1 = err.div((1, 0), (mdf[i] ** delta_mass, err.pow((mdf[i], smdf[i]), (delta_mass, 0))))
120
120
  else:
ararpy/calc/plot.py CHANGED
@@ -13,9 +13,9 @@ import traceback
13
13
 
14
14
  import decimal
15
15
  from math import exp, log, cos, acos, ceil, sqrt, atan, sin, gamma
16
- from typing import List, Any
17
- from scipy.optimize import fsolve
18
- from scipy.stats import distributions
16
+ # from typing import List, Any
17
+ # from scipy.optimize import fsolve
18
+ # from scipy.stats import distributions
19
19
  import numpy as np
20
20
 
21
21
  math_e = 2.718281828459045
ararpy/calc/raw_funcs.py CHANGED
@@ -46,6 +46,8 @@ def get_raw_data_regression_results(points_data, unselected: list = None):
46
46
  # line_data = transpose([lines_x, res[7](lines_x)])
47
47
  line_results = res[0:4]
48
48
  reg_coeffs = res[5]
49
+ if any(np.isnan(line_results)):
50
+ raise ValueError
49
51
  # if np.isin(np.inf, line_data) or np.isin(np.nan, line_data):
50
52
  # raise ZeroDivisionError(f"Infinite value or nan value.")
51
53
  if abs(res[0] - min(y)) > 5 * (max(y) - min(y)):
ararpy/calc/regression.py CHANGED
@@ -966,11 +966,6 @@ def exponential(a0: list, a1: list):
966
966
  se_intercept = sec / errfz * errfx
967
967
  rse_intercept = se_intercept / intercept * 100
968
968
 
969
- if abs(intercept) > 10 * max(a0):
970
- raise ValueError
971
- if intercept < 0:
972
- raise ValueError
973
-
974
969
  return intercept, se_intercept, rse_intercept, r2, 'mswd', [a, b, c], 'se', \
975
970
  lambda x: [_exp_func(i, a, b, c) for i in x], m_ssresid
976
971
 
ararpy/calc/spectra.py CHANGED
@@ -13,7 +13,7 @@ import numpy as np
13
13
 
14
14
 
15
15
  def get_data(y: list, sy: list, x: list, f: int = 1, indices: list = None,
16
- cumulative: bool = False, successive: bool = True):
16
+ cumulative: bool = False, successive: bool = True, sigma: int = 1):
17
17
  """
18
18
  Get spectra data based on passed x, y, and sy.
19
19
 
@@ -28,6 +28,7 @@ def get_data(y: list, sy: list, x: list, f: int = 1, indices: list = None,
28
28
  cumulative : bool, default False.
29
29
  This parameter should be True if x is already cumulative.
30
30
  successive : If setting indices successive
31
+ sigma:
31
32
 
32
33
  Returns
33
34
  -------
@@ -35,6 +36,7 @@ def get_data(y: list, sy: list, x: list, f: int = 1, indices: list = None,
35
36
  """
36
37
  if np.issubdtype(type(f), np.integer) and f > 1:
37
38
  sy = np.divide(sy, f)
39
+ sy = np.array(sy) * sigma
38
40
  dp = np.shape([y, sy, x])[-1]
39
41
  if indices is None:
40
42
  indices = list(range(dp))
ararpy/smp/corr.py CHANGED
@@ -49,8 +49,16 @@ def corr_blank(sample: Sample):
49
49
  blank_corrected = np.zeros([10, len(sample.SequenceName)])
50
50
  try:
51
51
  for i in range(5):
52
+ b, sb = copy.deepcopy(sample.BlankIntercept[i * 2: i * 2 + 2])
53
+ f, sf = np.array(sample.TotalParam[126 + i * 2:128 + i * 2])
54
+ sf = f * sf / 100
55
+ _ = calc.corr.gain(*sample.BlankIntercept[i * 2:2 + i * 2], f, sf)
56
+ for index in range(len(sample.BlankIntercept[i * 2])):
57
+ if sample.TotalParam[111][index]: # use same parameters to correct blank intercepts
58
+ b[index] = _[0][index]
59
+ sb[index] = _[1][index]
52
60
  blank_corrected[i * 2:2 + i * 2] = calc.corr.blank(
53
- *sample.CorrectedValues[i * 2:2 + i * 2], *sample.BlankIntercept[i * 2:2 + i * 2])
61
+ *sample.CorrectedValues[i * 2:2 + i * 2], b, sb)
54
62
  except Exception as e:
55
63
  print(traceback.format_exc())
56
64
  raise ValueError('Blank correction error')