PyXplore 2025.7.17__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 (75) hide show
  1. PyXplore/Background/BacDeduct.py +474 -0
  2. PyXplore/Background/__init__.py +1 -0
  3. PyXplore/EMBraggOpt/BraggLawDerivation.py +651 -0
  4. PyXplore/EMBraggOpt/EMBraggSolver.py +1199 -0
  5. PyXplore/EMBraggOpt/WPEMFuns/SolverFuns.py +356 -0
  6. PyXplore/EMBraggOpt/WPEMFuns/__init__.py +1 -0
  7. PyXplore/EMBraggOpt/__init__.py +1 -0
  8. PyXplore/Extinction/CifReader.py +238 -0
  9. PyXplore/Extinction/Relaxer.py +71 -0
  10. PyXplore/Extinction/XRDpre.py +892 -0
  11. PyXplore/Extinction/__init__.py +1 -0
  12. PyXplore/Extinction/m3gnet/__init__.py +4 -0
  13. PyXplore/Extinction/m3gnet/callbacks.py +26 -0
  14. PyXplore/Extinction/m3gnet/cli.py +112 -0
  15. PyXplore/Extinction/m3gnet/config.py +53 -0
  16. PyXplore/Extinction/m3gnet/graph/__init__.py +31 -0
  17. PyXplore/Extinction/m3gnet/graph/_batch.py +270 -0
  18. PyXplore/Extinction/m3gnet/graph/_compute.py +184 -0
  19. PyXplore/Extinction/m3gnet/graph/_converters.py +224 -0
  20. PyXplore/Extinction/m3gnet/graph/_structure.py +72 -0
  21. PyXplore/Extinction/m3gnet/graph/_types.py +387 -0
  22. PyXplore/Extinction/m3gnet/layers/__init__.py +57 -0
  23. PyXplore/Extinction/m3gnet/layers/_aggregate.py +60 -0
  24. PyXplore/Extinction/m3gnet/layers/_atom.py +107 -0
  25. PyXplore/Extinction/m3gnet/layers/_atom_ref.py +168 -0
  26. PyXplore/Extinction/m3gnet/layers/_base.py +87 -0
  27. PyXplore/Extinction/m3gnet/layers/_basis.py +63 -0
  28. PyXplore/Extinction/m3gnet/layers/_bond.py +232 -0
  29. PyXplore/Extinction/m3gnet/layers/_core.py +246 -0
  30. PyXplore/Extinction/m3gnet/layers/_cutoff.py +36 -0
  31. PyXplore/Extinction/m3gnet/layers/_gn.py +255 -0
  32. PyXplore/Extinction/m3gnet/layers/_readout.py +266 -0
  33. PyXplore/Extinction/m3gnet/layers/_state.py +101 -0
  34. PyXplore/Extinction/m3gnet/layers/_three_body.py +73 -0
  35. PyXplore/Extinction/m3gnet/layers/_two_body.py +48 -0
  36. PyXplore/Extinction/m3gnet/models/__init__.py +16 -0
  37. PyXplore/Extinction/m3gnet/models/_base.py +261 -0
  38. PyXplore/Extinction/m3gnet/models/_dynamics.py +384 -0
  39. PyXplore/Extinction/m3gnet/models/_m3gnet.py +369 -0
  40. PyXplore/Extinction/m3gnet/trainers/__init__.py +5 -0
  41. PyXplore/Extinction/m3gnet/trainers/_metrics.py +33 -0
  42. PyXplore/Extinction/m3gnet/trainers/_potential.py +266 -0
  43. PyXplore/Extinction/m3gnet/trainers/_property.py +288 -0
  44. PyXplore/Extinction/m3gnet/type.py +11 -0
  45. PyXplore/Extinction/m3gnet/utils/__init__.py +49 -0
  46. PyXplore/Extinction/m3gnet/utils/_general.py +73 -0
  47. PyXplore/Extinction/m3gnet/utils/_math.py +386 -0
  48. PyXplore/Extinction/m3gnet/utils/_tf.py +157 -0
  49. PyXplore/Extinction/wyckoff/__init__.py +1 -0
  50. PyXplore/Extinction/wyckoff/wyckoff_dict.py +237 -0
  51. PyXplore/GraphStructure/__init__.py +1 -0
  52. PyXplore/GraphStructure/graph.py +358 -0
  53. PyXplore/Plot/UnitCell.py +125 -0
  54. PyXplore/Plot/__init__.py +1 -0
  55. PyXplore/Refinement/VolumeFractionDertermination.py +223 -0
  56. PyXplore/Refinement/__init__.py +1 -0
  57. PyXplore/StructureOpt/SiteOpt.py +378 -0
  58. PyXplore/StructureOpt/__init__.py +1 -0
  59. PyXplore/WPEM.py +678 -0
  60. PyXplore/WPEMXAS/EXAFS.py +334 -0
  61. PyXplore/WPEMXAS/__init__.py +1 -0
  62. PyXplore/WPEMXAS/fftdemo.ipynb +207 -0
  63. PyXplore/WPEMXPS/XPSEM.py +1010 -0
  64. PyXplore/WPEMXPS/__init__.py +1 -0
  65. PyXplore/XRDSimulation/DiffractionGrometry/__init__.py +1 -0
  66. PyXplore/XRDSimulation/DiffractionGrometry/atom.py +6 -0
  67. PyXplore/XRDSimulation/Simulation.py +628 -0
  68. PyXplore/XRDSimulation/__init__.py +1 -0
  69. PyXplore/__init__.py +11 -0
  70. PyXplore/refs/International_Union_of_Crystallography.pdf +0 -0
  71. PyXplore/refs/WPEM_Manual.pdf +0 -0
  72. PyXplore-2025.7.17.dist-info/METADATA +60 -0
  73. PyXplore-2025.7.17.dist-info/RECORD +75 -0
  74. PyXplore-2025.7.17.dist-info/WHEEL +5 -0
  75. PyXplore-2025.7.17.dist-info/top_level.txt +1 -0
@@ -0,0 +1,651 @@
1
+ # The Bragg step defined in WPEM
2
+ # Author: Bin CAO <binjacobcao@gmail.com>
3
+
4
+ from sympy import *
5
+ import copy
6
+ import random
7
+ import numpy as np
8
+
9
+ class BraggLawDerivation:
10
+ # Defined the interplanar spacing formulae of seven crystal systems.
11
+ # ref: https://github.com/Bin-Cao/MPhil_SHU/tree/main/thesis_BInCAO table (1.1)
12
+ def d_spcing(self, crystal_system):
13
+ # ! angle shuond be converted to radians
14
+ # imput the code of crystal_system
15
+ sym_h, sym_k, sym_l, sym_a, sym_b, sym_c, angle1, angle2, angle3 = \
16
+ symbols('sym_h sym_k sym_l sym_a sym_b sym_c angle1 angle2 angle3')
17
+ if crystal_system == 1: # Cubic
18
+ d_hkl = sym_a / sqrt(sym_h ** 2 + sym_k ** 2 + sym_l ** 2)
19
+ elif crystal_system == 2: # Hexagonal
20
+ d_hkl = sqrt(3) / 2 / sqrt(
21
+ ((sym_h ** 2 + sym_k ** 2 + sym_h * sym_k) / sym_a ** 2) + 3 * sym_l ** 2 / 4 / sym_c ** 2)
22
+ elif crystal_system == 3: # Tetragonal
23
+ d_hkl = 1 / sqrt((sym_h ** 2 + sym_k ** 2) / sym_a ** 2 + sym_l ** 2 / sym_c ** 2)
24
+ elif crystal_system == 4: # Orthorhombic
25
+ d_hkl = 1 / sqrt((sym_h / sym_a) ** 2 + (sym_k / sym_b) ** 2 + (sym_l / sym_c) ** 2)
26
+ elif crystal_system == 5: # Rhombohedral
27
+ d_hkl = sym_a * sqrt((1 - 3 * cos(angle1) ** 2 + 2 * cos(angle1) ** 3) /
28
+ ((sym_h ** 2 + sym_k ** 2 + sym_l ** 2) * sin(angle1) ** 2
29
+ + 2 * (sym_h * sym_k + sym_k * sym_l + sym_h * sym_l) * cos(angle1) ** 2 - cos(
30
+ angle1)))
31
+ elif crystal_system == 6: # Monoclinic
32
+ d_hkl = sin(angle2) / sqrt(
33
+ sym_h ** 2 / sym_a ** 2 + sym_k ** 2 * sin(angle2) ** 2 / sym_b ** 2 + sym_l ** 2 / sym_c ** 2 -
34
+ 2 * sym_h * sym_l * cos(angle2) / (sym_a * sym_c))
35
+ elif crystal_system == 7: # Triclinic
36
+ __m = sqrt(
37
+ sin(angle3) ** 2 - cos(angle1) ** 2 + cos(angle2) ** 2 + 2 * cos(angle1) * cos(angle2) * cos(angle3))
38
+ __p = cos(angle1) - cos(angle2) * cos(angle3)
39
+ __n = cos(angle2) - cos(angle1) * cos(angle3)
40
+ __q = cos(angle3) - cos(angle1) * cos(angle2)
41
+ d_hkl = __m / sqrt((sym_h / sym_a) ** 2 * sin(angle1) ** 2 + (sym_k / sym_b) ** 2 * sin(angle2) ** 2 +
42
+ (sym_l / sym_c) ** 2 * sin(angle3) ** 2 - 2 * sym_h * sym_k * __q / (sym_a * sym_b)
43
+ - 2 * sym_h * sym_l * __n / (sym_a * sym_c) - 2 * sym_k * sym_l * __p / (sym_b * sym_c))
44
+ else:
45
+ d_hkl = -1
46
+ return d_hkl
47
+
48
+ # The diffraction peak positions obtained by WPEM algorithm are sorted in a certain order
49
+ def get_angle_sort(self, mui_cal_em_list, mui_abc_list):
50
+ __mui_abc_copy = copy.deepcopy( mui_abc_list)
51
+ __mui_abc_copy.sort()
52
+ __mui_cal_em_matching = []
53
+ __j_index = []
54
+ for i in range(len( mui_cal_em_list)):
55
+ for j in range(len( mui_cal_em_list)):
56
+ if mui_abc_list[i] == __mui_abc_copy[j] and j not in __j_index:
57
+ __mui_cal_em_matching.append( mui_cal_em_list[j])
58
+ __j_index.append(j)
59
+ break
60
+ return __mui_cal_em_matching
61
+
62
+ # The diffraction peak positions obtained by Bragg law are sorted in a certain order
63
+ def get_mui_sort(self, mui_1, mui_2, mui_new_list):
64
+ __mui_out = []
65
+ __j_index = []
66
+ for i in range(len( mui_1)):
67
+ for j in range(len( mui_1)):
68
+ if mui_1[i] == mui_2[j] and j not in __j_index:
69
+ __mui_out.append( mui_new_list[j])
70
+ __j_index.append(j)
71
+ break
72
+ return __mui_out
73
+
74
+ # Get the interplanar spacing generating the diffraction.
75
+ def get_d_space(self, crystal_sys, h, k, l, a, b, c, la1, la2, la3):
76
+ d_f = self.d_spcing(crystal_sys)
77
+ sym_h, sym_k, sym_l, sym_a, sym_b, sym_c, angle1, angle2, angle3 = \
78
+ symbols('sym_h sym_k sym_l sym_a sym_b sym_c angle1 angle2 angle3')
79
+
80
+ d_f_derivative = [diff(d_f, sym_a, 1)]
81
+ if crystal_sys == 2 or crystal_sys == 3:
82
+ d_f_derivative.append(diff(d_f, sym_c, 1))
83
+ elif crystal_sys == 4:
84
+ d_f_derivative.append(diff(d_f, sym_b, 1))
85
+ d_f_derivative.append(diff(d_f, sym_c, 1))
86
+ elif crystal_sys == 5:
87
+ d_f_derivative.append(diff(d_f, angle1, 1))
88
+ elif crystal_sys == 6:
89
+ d_f_derivative.append(diff(d_f, sym_b, 1))
90
+ d_f_derivative.append(diff(d_f, sym_c, 1))
91
+ d_f_derivative.append(diff(d_f, angle2, 1))
92
+ elif crystal_sys == 7:
93
+ d_f_derivative.append(diff(d_f, sym_b, 1))
94
+ d_f_derivative.append(diff(d_f, sym_c, 1))
95
+ d_f_derivative.append(diff(d_f, angle1, 1))
96
+ d_f_derivative.append(diff(d_f, angle2, 1))
97
+ d_f_derivative.append(diff(d_f, angle3, 1))
98
+
99
+ peak_n = len(h)
100
+
101
+ # defined a list for storing the interplanar spacing of each combination of diffraction index [HKL --> d]
102
+ d_list = []
103
+ # defined a list for storing the derivations of interplanar spacing of each diffraction index [HKL --> d(spaceing)/d(variables, a,b,c,...]
104
+ d_der_list = []
105
+ for i in range(peak_n):
106
+ d_list.append(
107
+ float(d_f.subs({sym_h: h[i], sym_k: k[i], sym_l: l[i], sym_a: a, sym_b: b,
108
+ sym_c: c, angle1: la1*np.pi/180, angle2: la2*np.pi/180, angle3: la3*np.pi/180})))
109
+ d_der_term = []
110
+ for j in range(len(d_f_derivative)):
111
+ d_der_term.append(
112
+ float(d_f_derivative[j].subs({sym_h: h[i], sym_k: k[i], sym_l: l[i], sym_a: a,
113
+ sym_b: b, sym_c: c, angle1: la1*np.pi/180, angle2: la2*np.pi/180,
114
+ angle3: la3*np.pi/180}))
115
+ )
116
+ d_der_list.append(d_der_term)
117
+ return d_list, d_der_list, len(d_f_derivative)
118
+
119
+ # Get the interplanar spacing generating the diffraction of multi-task
120
+ def get_d_space_multitask(self, crystal_sys_set, hkl_dat, Lattice_constants):
121
+ d_list_set = []
122
+ for task in range(len(Lattice_constants)):
123
+ d_f = self.d_spcing(crystal_sys_set[task])
124
+ sym_h, sym_k, sym_l, sym_a, sym_b, sym_c, angle1, angle2, angle3 = \
125
+ symbols('sym_h sym_k sym_l sym_a sym_b sym_c angle1 angle2 angle3')
126
+
127
+ peak_n = len(hkl_dat[task][1])
128
+ d_list = []
129
+ for i in range(peak_n):
130
+ d_list.append(float(d_f.subs({sym_h: hkl_dat[task][0][i],
131
+ sym_k: hkl_dat[task][1][i],
132
+ sym_l: hkl_dat[task][2][i],
133
+ sym_a: Lattice_constants[task][0],
134
+ sym_b: Lattice_constants[task][1],
135
+ sym_c: Lattice_constants[task][2],
136
+ angle1: Lattice_constants[task][3] * np.pi/180,
137
+ angle2: Lattice_constants[task][4] * np.pi/180,
138
+ angle3: Lattice_constants[task][5] * np.pi/180})))
139
+ d_list_set.append(d_list) # task * peak
140
+
141
+ return d_list_set
142
+
143
+ # Auxiliary function of gradient descent method
144
+ def get_derivative_term(self, d_spac, d_derivative, n_para, wavelength):
145
+ lmb = len(wavelength)
146
+ peak_n = len(d_spac)
147
+ mui_abc = []
148
+ update_term = []
149
+ for i in range(peak_n):
150
+ for j in range(lmb):
151
+ # f_term --> 2theta, the diffraction angles of Bargg Law
152
+ f_term = 2 * (np.arcsin(wavelength[j] / 2 / d_spac[i]) * 180 / np.pi)
153
+ s_term = 1 / np.sqrt(1 - wavelength[j] ** 2 / d_spac[i] ** 2 / 4)
154
+ t_term = wavelength[j] / d_spac[i] ** 2
155
+ mui_abc.append(f_term)
156
+ update_para = []
157
+ for up_j in range(n_para):
158
+ update_para.append(s_term * t_term * d_derivative[i][up_j])
159
+ update_term.append(update_para)
160
+ return update_term, mui_abc
161
+
162
+ # The first derivative.
163
+ def update_derivative(self, crystal_sys, total_peak_n, h, k, l, a, b, c, la1, la2, la3, wavelength, mui_cal_em_match):
164
+ d_list, d_der_list, n_para = self.get_d_space(crystal_sys, h, k, l, a, b, c,la1, la2, la3)
165
+ update_term, mui_fit = self.get_derivative_term(d_list, d_der_list, n_para,wavelength)
166
+
167
+ mui_error = []
168
+ for i in range(len(mui_cal_em_match)):
169
+ mui_error.append(mui_cal_em_match[i] - mui_fit[i])
170
+
171
+ deri_sum = []
172
+ for j in range(n_para):
173
+ two_der_mui_fit = []
174
+ for i in range(len(mui_error)):
175
+ two_der_mui_fit.append(mui_error[i] * update_term[i][j])
176
+ deri_sum.append(sum(two_der_mui_fit) / total_peak_n)
177
+ return deri_sum
178
+
179
+ # Auxiliary function of the difference quotient , used in learning rate
180
+ def two_up_derivative(self, crystal_sys, h, k, l, a, b, c, la1, la2, la3, der_term, wavelength, mui_fit_abc):
181
+ d_f = self.d_spcing(crystal_sys)
182
+ sym_h, sym_k, sym_l, sym_a, sym_b, sym_c, angle1, angle2, angle3 = \
183
+ symbols('sym_h sym_k sym_l sym_a sym_b sym_c angle1 angle2 angle3')
184
+
185
+ if der_term == 1:
186
+ __d_f_derivative = diff(d_f, sym_a, 1)
187
+ elif der_term == 2:
188
+ __d_f_derivative = diff(d_f, sym_b, 1)
189
+ elif der_term == 3:
190
+ __d_f_derivative = diff(d_f, sym_c, 1)
191
+ elif der_term == 4:
192
+ __d_f_derivative = diff(d_f, angle1, 1)
193
+ elif der_term == 5:
194
+ __d_f_derivative = diff(d_f, angle2, 1)
195
+ elif der_term == 6:
196
+ __d_f_derivative = diff(d_f, angle3, 1)
197
+ else:
198
+ print('please input the derivative variable')
199
+
200
+ peak_n = len(h)
201
+ d_list = []
202
+ d_der_list = []
203
+ for i in range(peak_n):
204
+ d_list.append(
205
+ float(d_f.subs({sym_h: h[i], sym_k:k[i], sym_l: l[i], sym_a: a, sym_b: b,
206
+ sym_c:c, angle1:la1*np.pi/180, angle2:la2*np.pi/180, angle3:la3*np.pi/180})))
207
+
208
+ d_der_list.append(float(__d_f_derivative.subs(
209
+ {sym_h:h[i], sym_k:k[i], sym_l:l[i], sym_a:a, sym_b: b,
210
+ sym_c: c, angle1:la1*np.pi/180, angle2:la2*np.pi/180, angle3:la3*np.pi/180})))
211
+
212
+ lmb = len(wavelength)
213
+ peak_n = len(d_list)
214
+ mui_abc = []
215
+ update_term = []
216
+ for i in range(peak_n):
217
+ for j in range(lmb):
218
+ f_term = 2 * (np.arcsin(wavelength[j] / 2 / d_list[i]) * 180 / np.pi)
219
+ s_term = 1 / np.sqrt(1 - wavelength[j] ** 2 / d_list[i] ** 2 / 4)
220
+ t_term = wavelength[j] / d_list[i] ** 2
221
+ mui_abc.append(f_term)
222
+ update_term.append(s_term * t_term * d_der_list[i])
223
+
224
+ mui_error = []
225
+ for i in range(len( mui_fit_abc)):
226
+ mui_error.append( mui_fit_abc[i] - mui_abc[i])
227
+
228
+ two_der_mui_fit = []
229
+ for i in range(len(mui_error)):
230
+ two_der_mui_fit.append(mui_error[i] * update_term[i])
231
+ return sum(two_der_mui_fit) / len( mui_fit_abc)
232
+
233
+ # Calculate the new diffraction peak positions
234
+ def get_new_mui(self, d_spac, wavelength):
235
+ lmb = len( wavelength)
236
+ peak_n = len( d_spac)
237
+ mui_abc = []
238
+ for i in range(peak_n):
239
+ for j in range(lmb):
240
+ f_term = 2 * (np.arcsin( wavelength[j] / 2 / d_spac[i]) * 180 / np.pi)
241
+ mui_abc.append(f_term)
242
+ return mui_abc
243
+
244
+ # Calculate the new diffraction peak positions
245
+ def get_new_mui_multitask(self, d_spac_set, wavelength):
246
+ lmb = len(wavelength)
247
+ mui_abc_set = []
248
+ for task in range(len(d_spac_set)):
249
+ peak_n = len(d_spac_set[task])
250
+ mui_abc = []
251
+ for i in range(peak_n):
252
+ for j in range(lmb):
253
+ f_term = 2 * (np.arcsin(wavelength[j] / 2 / d_spac_set[task][i]) * 180 / np.pi)
254
+ mui_abc.append(f_term)
255
+ mui_abc_set.append(mui_abc)
256
+
257
+ return mui_abc_set # peak*task
258
+
259
+ # Get the optimal lattice constants.
260
+ def OptmialLatticeConstant(self, crystal_sys, old_p1_list, p1_list, subset_number, low_bound, up_bound, lattice_h,
261
+ lattice_k,lattice_l, ini_a, ini_b, ini_c, ini_la1, ini_la2, ini_la3, wavelength,fixed =False, tao=0.05):
262
+ if fixed == False:
263
+ # updata latt params by Bragg
264
+ # defined for mixed rays have two wavelength
265
+ if len( wavelength) == 2:
266
+ error_fit = []
267
+ for i in range(int(len( old_p1_list) / 2)):
268
+ mui_error1 = ( p1_list[2 * i] - old_p1_list[2 * i]) ** 2
269
+ mui_error2 = ( p1_list[2 * i + 1] - old_p1_list[2 * i + 1]) ** 2
270
+ if mui_error1 >= mui_error2:
271
+ error_fit.append(mui_error1)
272
+ else:
273
+ error_fit.append(mui_error2)
274
+ error_fit_sort = copy.deepcopy(error_fit)
275
+ error_fit_sort.sort()
276
+
277
+ h_fit_abc, k_fit_abc, l_fit_abc = [], [], []
278
+ mui_fit_abc_list = []
279
+
280
+ # search index
281
+ for i_err in range(len(error_fit)):
282
+ for j in range(len(error_fit)):
283
+ if error_fit_sort[i_err] == error_fit[j] and low_bound <= p1_list[2 * j] <= up_bound:
284
+ for t in range(len( wavelength)):
285
+ mui_fit_abc_list.append(p1_list[2 * j + t])
286
+ h_fit_abc.append(lattice_h[j])
287
+ k_fit_abc.append(lattice_k[j])
288
+ l_fit_abc.append(lattice_l[j])
289
+ if len(h_fit_abc) == subset_number:
290
+ break
291
+ total_peak_n = len(mui_fit_abc_list)
292
+
293
+ elif len(wavelength) == 1:
294
+ error_fit = []
295
+ for i in range(len(old_p1_list)):
296
+ mui_error = (p1_list[i] - old_p1_list[i]) ** 2
297
+ error_fit.append(mui_error)
298
+
299
+ error_fit_sort = copy.deepcopy(error_fit)
300
+ error_fit_sort.sort()
301
+
302
+ h_fit_abc, k_fit_abc, l_fit_abc = [], [], []
303
+ mui_fit_abc_list = []
304
+
305
+ # search index
306
+ for i_err in range(len(error_fit)):
307
+ for j in range(len(error_fit)):
308
+ if error_fit_sort[i_err] == error_fit[j] and low_bound <= p1_list[j] <= up_bound:
309
+ mui_fit_abc_list.append( p1_list[j])
310
+ h_fit_abc.append(lattice_h[j])
311
+ k_fit_abc.append(lattice_k[j])
312
+ l_fit_abc.append(lattice_l[j])
313
+ if len(h_fit_abc) == subset_number:
314
+ break
315
+ total_peak_n = len(mui_fit_abc_list)
316
+
317
+ else:
318
+ print('only for mixed rays with one or two wavelength')
319
+
320
+ i_ter = 0
321
+ if crystal_sys == 1:
322
+ cal_a = copy.deepcopy(ini_a)
323
+ while (True):
324
+ i_ter += 1
325
+ ini_a = copy.deepcopy(cal_a)
326
+
327
+ derive_term = self.update_derivative(crystal_sys, total_peak_n, h_fit_abc, k_fit_abc, l_fit_abc,
328
+ ini_a, ini_a, ini_a, ini_la1, ini_la2, ini_la3, wavelength, mui_fit_abc_list)
329
+
330
+ lef_derive = self.two_up_derivative( crystal_sys, h_fit_abc, k_fit_abc, l_fit_abc, ini_a - tao,
331
+ ini_a, ini_a, ini_la1, ini_la2, ini_la3, 1, wavelength, mui_fit_abc_list)
332
+
333
+ right_derive = self.two_up_derivative(crystal_sys, h_fit_abc, k_fit_abc, l_fit_abc, ini_a + tao,
334
+ ini_a, ini_a, ini_la1, ini_la2, ini_la3, 1, wavelength, mui_fit_abc_list)
335
+
336
+ learning_rate = 2 * tao / (right_derive - lef_derive)
337
+
338
+ cal_a = ini_a - derive_term[0] * learning_rate
339
+
340
+ if abs(cal_a - ini_a) <= 1e-8:
341
+ break
342
+
343
+ if i_ter >= 800:
344
+ break
345
+ d_list, _, _ = self.get_d_space( crystal_sys, lattice_h, lattice_k,
346
+ lattice_l, cal_a, cal_a, cal_a, ini_la1, ini_la2, ini_la3)
347
+ mui_fit = self.get_new_mui(d_list, wavelength)
348
+
349
+ return cal_a, cal_a, cal_a, ini_la1, ini_la2, ini_la3, mui_fit
350
+
351
+ elif crystal_sys == 2 or crystal_sys == 3:
352
+ cal_a = copy.deepcopy(ini_a)
353
+ cal_c = copy.deepcopy(ini_c)
354
+
355
+ while (True):
356
+ i_ter += 1
357
+ ini_a = copy.deepcopy(cal_a)
358
+ ini_c = copy.deepcopy(cal_c)
359
+
360
+ derive_term = self.update_derivative( crystal_sys, total_peak_n, h_fit_abc, k_fit_abc, l_fit_abc,
361
+ ini_a, ini_a, ini_c, ini_la1, ini_la2, ini_la3, wavelength,
362
+ mui_fit_abc_list)
363
+
364
+ a_lef_derive = self.two_up_derivative(crystal_sys, h_fit_abc, k_fit_abc, l_fit_abc,
365
+ ini_a - tao, ini_a, ini_c, ini_la1, ini_la2, ini_la3, 1,
366
+ wavelength, mui_fit_abc_list)
367
+ c_lef_derive = self.two_up_derivative(crystal_sys, h_fit_abc, k_fit_abc, l_fit_abc, ini_a, ini_a,
368
+ ini_c - tao, ini_la1, ini_la2, ini_la3, 3,wavelength, mui_fit_abc_list)
369
+
370
+ a_right_derive = self.two_up_derivative(crystal_sys, h_fit_abc, k_fit_abc, l_fit_abc,
371
+ ini_a + tao, ini_a, ini_c, ini_la1, ini_la2, ini_la3, 1,
372
+ wavelength, mui_fit_abc_list)
373
+ c_right_derive = self.two_up_derivative( crystal_sys, h_fit_abc, k_fit_abc, l_fit_abc, ini_a, ini_a,
374
+ ini_c + tao, ini_la1, ini_la2, ini_la3, 3, wavelength, mui_fit_abc_list)
375
+
376
+ a_learning_rate = 2 * tao / (a_right_derive - a_lef_derive)
377
+ c_learning_rate = 2 * tao / (c_right_derive - c_lef_derive)
378
+
379
+ cal_a = ini_a - derive_term[0] * a_learning_rate
380
+ cal_c = ini_c - derive_term[1] * c_learning_rate
381
+
382
+ if abs(cal_a - ini_a) <= 1e-8 and abs(cal_c - ini_c) <= 1e-8:
383
+ break
384
+
385
+ if i_ter >= 800:
386
+ break
387
+ d_list, _, _ = self.get_d_space(crystal_sys, lattice_h,lattice_k,
388
+ lattice_l, cal_a, cal_a, cal_c, ini_la1, ini_la2, ini_la3)
389
+ mui_fit = self.get_new_mui(d_list, wavelength)
390
+
391
+ return cal_a, cal_a, cal_c, ini_la1, ini_la2, ini_la3, mui_fit
392
+
393
+ elif crystal_sys == 4:
394
+ cal_a = copy.deepcopy(ini_a)
395
+ cal_b = copy.deepcopy(ini_b)
396
+ cal_c = copy.deepcopy(ini_c)
397
+
398
+ while (True):
399
+ i_ter += 1
400
+ ini_a = copy.deepcopy(cal_a)
401
+ ini_b = copy.deepcopy(cal_b)
402
+ ini_c = copy.deepcopy(cal_c)
403
+
404
+ derive_term = self.update_derivative(crystal_sys, total_peak_n, h_fit_abc, k_fit_abc, l_fit_abc,
405
+ ini_a, ini_b, ini_c, ini_la1, ini_la2, ini_la3, wavelength,
406
+ mui_fit_abc_list)
407
+
408
+ a_lef_derive = self.two_up_derivative(crystal_sys, h_fit_abc, k_fit_abc, l_fit_abc, ini_a - tao, ini_b,
409
+ ini_c, ini_la1, ini_la2, ini_la3, 1, wavelength, mui_fit_abc_list)
410
+ b_lef_derive = self.two_up_derivative(crystal_sys, h_fit_abc, k_fit_abc, l_fit_abc, ini_a,ini_b - tao,
411
+ ini_c, ini_la1, ini_la2, ini_la3, 2, wavelength, mui_fit_abc_list)
412
+ c_lef_derive = self.two_up_derivative(crystal_sys, h_fit_abc, k_fit_abc, l_fit_abc, ini_a, ini_b, ini_c - tao, ini_la1, ini_la2, ini_la3, 3,
413
+ wavelength, mui_fit_abc_list)
414
+
415
+ a_right_derive = self.two_up_derivative(crystal_sys, h_fit_abc, k_fit_abc, l_fit_abc,ini_a + tao, ini_b,
416
+ ini_c, ini_la1, ini_la2, ini_la3, 1,wavelength, mui_fit_abc_list)
417
+
418
+ b_right_derive = self.two_up_derivative(crystal_sys, h_fit_abc, k_fit_abc, l_fit_abc, ini_a,
419
+ ini_b + tao, ini_c, ini_la1, ini_la2, ini_la3, 2,wavelength, mui_fit_abc_list)
420
+ c_right_derive = self.two_up_derivative(crystal_sys, h_fit_abc, k_fit_abc, l_fit_abc, ini_a, ini_b,
421
+ ini_c + tao, ini_la1, ini_la2, ini_la3, 3, wavelength, mui_fit_abc_list)
422
+
423
+ a_learning_rate = 2 * tao / (a_right_derive - a_lef_derive)
424
+ b_learning_rate = 2 * tao / (b_right_derive - b_lef_derive)
425
+ c_learning_rate = 2 * tao / (c_right_derive - c_lef_derive)
426
+
427
+ cal_a = ini_a - derive_term[0] * a_learning_rate
428
+ cal_b = ini_b - derive_term[1] * b_learning_rate
429
+ cal_c = ini_c - derive_term[2] * c_learning_rate
430
+
431
+ if abs(cal_a - ini_a) <= 1e-8 and abs(cal_b - ini_b) <= 1e-8 and abs(cal_c - ini_c) <= 1e-8 or abs(cal_a - ini_a) >= 0.01 *ini_a or abs(cal_b - ini_b) >= 0.01*ini_b or abs(cal_c - ini_c) >= 0.01*ini_c:
432
+ break
433
+
434
+ if i_ter >= 400:
435
+ break
436
+ d_list, _, _ = self.get_d_space(crystal_sys, lattice_h, lattice_k,
437
+ lattice_l, cal_a, cal_b, cal_c, ini_la1, ini_la2, ini_la3)
438
+ mui_fit = self.get_new_mui(d_list,wavelength)
439
+
440
+ return cal_a, cal_b, cal_c, ini_la1, ini_la2, ini_la3, mui_fit
441
+
442
+ elif crystal_sys == 5:
443
+ cal_a = copy.deepcopy(ini_a)
444
+ cal_la1 = copy.deepcopy(ini_la1)
445
+
446
+ while (True):
447
+ i_ter += 1
448
+ ini_a = copy.deepcopy(cal_a)
449
+ ini_la1 = copy.deepcopy(cal_la1)
450
+
451
+ derive_term = self.update_derivative(crystal_sys, total_peak_n, h_fit_abc, k_fit_abc, l_fit_abc,
452
+ ini_a, ini_a, ini_a, ini_la1, ini_la1, ini_la1, wavelength,
453
+ mui_fit_abc_list)
454
+
455
+ a_lef_derive = self.two_up_derivative( crystal_sys, h_fit_abc, k_fit_abc, l_fit_abc,
456
+ ini_a - tao, ini_a, ini_a, ini_la1, ini_la1, ini_la1, 1, wavelength,
457
+ mui_fit_abc_list)
458
+ la1_lef_derive = self.two_up_derivative( crystal_sys, h_fit_abc, k_fit_abc, l_fit_abc, ini_a, ini_a,
459
+ ini_a, ini_la1 - tao, ini_la1, ini_la1, 4, wavelength,
460
+ mui_fit_abc_list)
461
+
462
+ a_right_derive = self.two_up_derivative( crystal_sys, h_fit_abc, k_fit_abc, l_fit_abc,
463
+ ini_a + tao, ini_a, ini_a, ini_la1, ini_la1, ini_la1, 1, wavelength,
464
+ mui_fit_abc_list)
465
+ la1_right_derive = self.two_up_derivative( crystal_sys, h_fit_abc, k_fit_abc, l_fit_abc, ini_a,
466
+ ini_a, ini_a, ini_la1 + tao, ini_la1, ini_la1, 4, wavelength,
467
+ mui_fit_abc_list)
468
+
469
+ a_learning_rate = 2 * tao / (a_right_derive - a_lef_derive)
470
+ la1_learning_rate = 2 * tao / (la1_right_derive - la1_lef_derive)
471
+
472
+ cal_a = ini_a - derive_term[0] * a_learning_rate
473
+ cal_la1 = ini_la1 - derive_term[1] * la1_learning_rate
474
+
475
+ if abs(cal_a - ini_a) <= 1e-8 and abs(cal_la1 - ini_la1) <= 1e-8:
476
+ break
477
+
478
+ if i_ter >= 800:
479
+ break
480
+ d_list, _, _ = self.get_d_space( crystal_sys, lattice_h, lattice_k, lattice_l, cal_a, cal_a,
481
+ cal_a, cal_la1, cal_la1, cal_la1)
482
+ mui_fit = self.get_new_mui(d_list, wavelength)
483
+
484
+ return cal_a, cal_a, cal_a, cal_la1, cal_la1, cal_la1, mui_fit
485
+
486
+ elif crystal_sys == 6:
487
+ cal_a = copy.deepcopy(ini_a)
488
+ cal_b = copy.deepcopy(ini_b)
489
+ cal_c = copy.deepcopy(ini_c)
490
+ cal_la2 = copy.deepcopy(ini_la2)
491
+
492
+ while (True):
493
+ i_ter += 1
494
+ ini_a = copy.deepcopy(cal_a)
495
+ ini_b = copy.deepcopy(cal_b)
496
+ ini_c = copy.deepcopy(cal_c)
497
+ ini_la2 = copy.deepcopy(cal_la2)
498
+
499
+ derive_term = self.update_derivative(crystal_sys, total_peak_n, h_fit_abc, k_fit_abc, l_fit_abc,
500
+ ini_a, ini_b, ini_c, ini_la1, ini_la2, ini_la3, wavelength,
501
+ mui_fit_abc_list)
502
+
503
+ # each time we only update one lattice constant randomly
504
+ random_number = random.randint(0, 3)
505
+ if random_number <= 2:
506
+ a_lef_derive = self.two_up_derivative(crystal_sys, h_fit_abc, k_fit_abc, l_fit_abc, ini_a - tao, ini_b,
507
+ ini_c, ini_la1, ini_la2, ini_la3, 1, wavelength, mui_fit_abc_list)
508
+ b_lef_derive = self.two_up_derivative(crystal_sys, h_fit_abc, k_fit_abc, l_fit_abc, ini_a,ini_b - tao,
509
+ ini_c, ini_la1, ini_la2, ini_la3, 2, wavelength, mui_fit_abc_list)
510
+ c_lef_derive = self.two_up_derivative(crystal_sys, h_fit_abc, k_fit_abc, l_fit_abc, ini_a, ini_b, ini_c - tao,
511
+ ini_la1, ini_la2, ini_la3, 3, wavelength, mui_fit_abc_list)
512
+
513
+ a_right_derive = self.two_up_derivative(crystal_sys, h_fit_abc, k_fit_abc, l_fit_abc,ini_a + tao, ini_b,
514
+ ini_c, ini_la1, ini_la2, ini_la3, 1,wavelength, mui_fit_abc_list)
515
+
516
+ b_right_derive = self.two_up_derivative(crystal_sys, h_fit_abc, k_fit_abc, l_fit_abc, ini_a,
517
+ ini_b + tao, ini_c, ini_la1, ini_la2, ini_la3, 2,wavelength, mui_fit_abc_list)
518
+ c_right_derive = self.two_up_derivative(crystal_sys, h_fit_abc, k_fit_abc, l_fit_abc, ini_a, ini_b,
519
+ ini_c + tao, ini_la1, ini_la2, ini_la3, 3, wavelength, mui_fit_abc_list)
520
+
521
+ a_learning_rate = 2 * tao / (a_right_derive - a_lef_derive)
522
+ b_learning_rate = 2 * tao / (b_right_derive - b_lef_derive)
523
+ c_learning_rate = 2 * tao / (c_right_derive - c_lef_derive)
524
+
525
+ cal_a = ini_a - derive_term[0] * a_learning_rate
526
+ cal_b = ini_b - derive_term[1] * b_learning_rate
527
+ cal_c = ini_c - derive_term[2] * c_learning_rate
528
+
529
+ if abs(cal_a - ini_a) <= 1e-8 and abs(cal_b - ini_b) <= 1e-8 and abs(cal_c - ini_c) <= 1e-8 or abs(cal_a - ini_a) >= 0.01 *ini_a or abs(cal_b - ini_b) >= 0.01*ini_b or abs(cal_c - ini_c) >= 0.01*ini_c:
530
+ break
531
+
532
+ if i_ter >= 400:
533
+ break
534
+ d_list, _, _ = self.get_d_space(crystal_sys,lattice_h,lattice_k, lattice_l, cal_a, cal_b, cal_c,ini_la1, ini_la2,ini_la3)
535
+ mui_fit = self.get_new_mui(d_list,wavelength)
536
+ return cal_a, cal_b, cal_c, ini_la1, ini_la2, ini_la3, mui_fit
537
+
538
+ else:
539
+ la2_lef_derive = self.two_up_derivative(crystal_sys, h_fit_abc, k_fit_abc, l_fit_abc, ini_a, ini_b,
540
+ ini_c, ini_la1, ini_la2 - tao, ini_la3, 5, wavelength, mui_fit_abc_list)
541
+ la2_right_derive = self.two_up_derivative(crystal_sys, h_fit_abc, k_fit_abc, l_fit_abc, ini_a,
542
+ ini_b, ini_c, ini_la1, ini_la2 + tao, ini_la3, 5,wavelength, mui_fit_abc_list)
543
+ la2_learning_rate = 2 * tao / (la2_right_derive - la2_lef_derive)
544
+ cal_la2 = ini_la2 - derive_term[3] * la2_learning_rate
545
+ if abs(cal_la2 - ini_la2) <= 1e-8 or abs(cal_la2 - ini_la2) > 0.01*ini_la2:
546
+ break
547
+ if i_ter >= 400:
548
+ break
549
+ d_list, _, _ = self.get_d_space(crystal_sys,lattice_h,lattice_k, lattice_l, ini_a, ini_b, ini_c,ini_la1, cal_la2,ini_la3)
550
+ mui_fit = self.get_new_mui(d_list,wavelength)
551
+ return ini_a, ini_b, ini_c, ini_la1, cal_la2, ini_la3, mui_fit
552
+
553
+ elif crystal_sys == 7:
554
+ # original version Sep 19 2023
555
+ cal_a = copy.deepcopy(ini_a)
556
+ cal_b = copy.deepcopy(ini_b)
557
+ cal_c = copy.deepcopy(ini_c)
558
+ cal_la1 = copy.deepcopy(ini_la1)
559
+ cal_la2 = copy.deepcopy(ini_la2)
560
+ cal_la3 = copy.deepcopy(ini_la3)
561
+
562
+ while (True):
563
+ i_ter += 1
564
+ ini_a = copy.deepcopy(cal_a)
565
+ ini_b = copy.deepcopy(cal_b)
566
+ ini_c = copy.deepcopy(cal_c)
567
+ ini_la1 = copy.deepcopy(cal_la1)
568
+ ini_la2 = copy.deepcopy(cal_la2)
569
+ ini_la3 = copy.deepcopy(cal_la3)
570
+
571
+ derive_term = self.update_derivative(crystal_sys, total_peak_n, h_fit_abc, k_fit_abc, l_fit_abc,
572
+ ini_a, ini_b, ini_c, ini_la1, ini_la2, ini_la3, wavelength,
573
+ mui_fit_abc_list)
574
+
575
+ a_lef_derive = self.two_up_derivative(crystal_sys, h_fit_abc, k_fit_abc, l_fit_abc,
576
+ ini_a - tao, ini_b, ini_c, ini_la1, ini_la2, ini_la3, 1, wavelength,
577
+ mui_fit_abc_list)
578
+
579
+ b_lef_derive = self.two_up_derivative(crystal_sys, h_fit_abc, k_fit_abc, l_fit_abc, ini_a,
580
+ ini_b - tao, ini_c, ini_la1, ini_la2, ini_la3, 2, wavelength,
581
+ mui_fit_abc_list)
582
+
583
+ c_lef_derive = self.two_up_derivative(crystal_sys, h_fit_abc, k_fit_abc, l_fit_abc, ini_a, ini_b,
584
+ ini_c - tao, ini_la1, ini_la2, ini_la3, 3, wavelength, mui_fit_abc_list)
585
+
586
+ la1_lef_derive = self.two_up_derivative(crystal_sys, h_fit_abc, k_fit_abc, l_fit_abc, ini_a, ini_b,
587
+ ini_c, ini_la1 - tao, ini_la2, ini_la3, 4, wavelength,mui_fit_abc_list)
588
+
589
+ la2_lef_derive = self.two_up_derivative(crystal_sys, h_fit_abc, k_fit_abc, l_fit_abc, ini_a, ini_b,
590
+ ini_c, ini_la1, ini_la2 - tao, ini_la3, 5, wavelength,mui_fit_abc_list)
591
+
592
+ la3_lef_derive = self.two_up_derivative(crystal_sys, h_fit_abc, k_fit_abc, l_fit_abc, ini_a, ini_b,
593
+ ini_c, ini_la1, ini_la2, ini_la3 - tao, 6, wavelength,mui_fit_abc_list)
594
+
595
+ a_right_derive = self.two_up_derivative(crystal_sys, h_fit_abc, k_fit_abc, l_fit_abc,
596
+ ini_a + tao, ini_b, ini_c, ini_la1, ini_la2, ini_la3, 1, wavelength,
597
+ mui_fit_abc_list)
598
+
599
+ b_right_derive = self.two_up_derivative(crystal_sys, h_fit_abc, k_fit_abc, l_fit_abc, ini_a,
600
+ ini_b + tao, ini_c, ini_la1, ini_la2, ini_la3, 2,wavelength,
601
+ mui_fit_abc_list)
602
+
603
+ c_right_derive = self.two_up_derivative(crystal_sys, h_fit_abc, k_fit_abc, l_fit_abc, ini_a, ini_b,
604
+ ini_c + tao, ini_la1, ini_la2, ini_la3, 3, wavelength,
605
+ mui_fit_abc_list)
606
+
607
+ la1_right_derive = self.two_up_derivative(crystal_sys, h_fit_abc, k_fit_abc, l_fit_abc, ini_a,
608
+ ini_b, ini_c, ini_la1 + tao, ini_la2, ini_la3, 4, wavelength,
609
+ mui_fit_abc_list)
610
+
611
+ la2_right_derive = self.two_up_derivative(crystal_sys, h_fit_abc, k_fit_abc, l_fit_abc, ini_a,
612
+ ini_b, ini_c, ini_la1, ini_la2 + tao, ini_la3, 5, wavelength,
613
+ mui_fit_abc_list)
614
+
615
+ la3_right_derive = self.two_up_derivative(crystal_sys, h_fit_abc, k_fit_abc, l_fit_abc, ini_a,
616
+ ini_b, ini_c, ini_la1, ini_la2, ini_la3 + tao, 6, wavelength,
617
+ mui_fit_abc_list)
618
+
619
+ a_learning_rate = 2 * tao / (a_right_derive - a_lef_derive)
620
+ b_learning_rate = 2 * tao / (b_right_derive - b_lef_derive)
621
+ c_learning_rate = 2 * tao / (c_right_derive - c_lef_derive)
622
+ la1_learning_rate = 2 * tao / (la1_right_derive - la1_lef_derive)
623
+ la2_learning_rate = 2 * tao / (la2_right_derive - la2_lef_derive)
624
+ la3_learning_rate = 2 * tao / (la3_right_derive - la3_lef_derive)
625
+
626
+ cal_a = ini_a - derive_term[0] * a_learning_rate
627
+ cal_b = ini_b - derive_term[1] * b_learning_rate
628
+ cal_c = ini_c - derive_term[2] * c_learning_rate
629
+ cal_la1 = ini_la1 - derive_term[3] * la1_learning_rate
630
+ cal_la2 = ini_la2 - derive_term[4] * la2_learning_rate
631
+ cal_la3 = ini_la3 - derive_term[5] * la3_learning_rate
632
+
633
+ if abs(cal_a - ini_a) <= 1e-8 and abs(cal_b - ini_b) <= 1e-8 and abs(cal_c - ini_c) <= 1e-8 \
634
+ and abs(cal_la1 - ini_la1) <= 1e-8 and abs(cal_la2 - ini_la2) <= 1e-8 and abs(
635
+ cal_la3 - ini_la3) <= 1e-8:
636
+ break
637
+
638
+ if i_ter >= 400:
639
+ break
640
+ d_list, _, _ = self.get_d_space(crystal_sys, lattice_h, lattice_k,
641
+ lattice_l, cal_a, cal_b,cal_c, cal_la1, cal_la2, cal_la3)
642
+ mui_fit = self.get_new_mui(d_list, wavelength)
643
+
644
+ return cal_a, cal_b, cal_c, cal_la1, cal_la2, cal_la3, mui_fit
645
+
646
+ else:
647
+ return -1
648
+
649
+ if fixed == True:
650
+ return ini_a, ini_b , ini_c , ini_la1 , ini_la2, ini_la3, old_p1_list
651
+