PyXplore 2025.5.6__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 (82) hide show
  1. PyXplore/Amorphous/QuantitativeCalculation/AmorphousRDF.py +182 -0
  2. PyXplore/Amorphous/QuantitativeCalculation/__init__.py +1 -0
  3. PyXplore/Amorphous/__init__.py +11 -0
  4. PyXplore/Amorphous/fitting/AmorphousFitting.py +342 -0
  5. PyXplore/Amorphous/fitting/__init__.py +1 -0
  6. PyXplore/Background/BacDeduct.py +474 -0
  7. PyXplore/Background/__init__.py +1 -0
  8. PyXplore/DecomposePlot/__init__.py +11 -0
  9. PyXplore/DecomposePlot/plot.py +472 -0
  10. PyXplore/EMBraggOpt/BraggLawDerivation.py +651 -0
  11. PyXplore/EMBraggOpt/EMBraggSolver.py +1199 -0
  12. PyXplore/EMBraggOpt/WPEMFuns/SolverFuns.py +356 -0
  13. PyXplore/EMBraggOpt/WPEMFuns/__init__.py +1 -0
  14. PyXplore/EMBraggOpt/__init__.py +1 -0
  15. PyXplore/Extinction/CifReader.py +238 -0
  16. PyXplore/Extinction/Relaxer.py +71 -0
  17. PyXplore/Extinction/XRDpre.py +892 -0
  18. PyXplore/Extinction/__init__.py +1 -0
  19. PyXplore/Extinction/m3gnet/__init__.py +4 -0
  20. PyXplore/Extinction/m3gnet/callbacks.py +26 -0
  21. PyXplore/Extinction/m3gnet/cli.py +112 -0
  22. PyXplore/Extinction/m3gnet/config.py +53 -0
  23. PyXplore/Extinction/m3gnet/graph/__init__.py +31 -0
  24. PyXplore/Extinction/m3gnet/graph/_batch.py +270 -0
  25. PyXplore/Extinction/m3gnet/graph/_compute.py +184 -0
  26. PyXplore/Extinction/m3gnet/graph/_converters.py +224 -0
  27. PyXplore/Extinction/m3gnet/graph/_structure.py +72 -0
  28. PyXplore/Extinction/m3gnet/graph/_types.py +387 -0
  29. PyXplore/Extinction/m3gnet/layers/__init__.py +57 -0
  30. PyXplore/Extinction/m3gnet/layers/_aggregate.py +60 -0
  31. PyXplore/Extinction/m3gnet/layers/_atom.py +107 -0
  32. PyXplore/Extinction/m3gnet/layers/_atom_ref.py +168 -0
  33. PyXplore/Extinction/m3gnet/layers/_base.py +87 -0
  34. PyXplore/Extinction/m3gnet/layers/_basis.py +63 -0
  35. PyXplore/Extinction/m3gnet/layers/_bond.py +232 -0
  36. PyXplore/Extinction/m3gnet/layers/_core.py +246 -0
  37. PyXplore/Extinction/m3gnet/layers/_cutoff.py +36 -0
  38. PyXplore/Extinction/m3gnet/layers/_gn.py +255 -0
  39. PyXplore/Extinction/m3gnet/layers/_readout.py +266 -0
  40. PyXplore/Extinction/m3gnet/layers/_state.py +101 -0
  41. PyXplore/Extinction/m3gnet/layers/_three_body.py +73 -0
  42. PyXplore/Extinction/m3gnet/layers/_two_body.py +48 -0
  43. PyXplore/Extinction/m3gnet/models/__init__.py +16 -0
  44. PyXplore/Extinction/m3gnet/models/_base.py +261 -0
  45. PyXplore/Extinction/m3gnet/models/_dynamics.py +384 -0
  46. PyXplore/Extinction/m3gnet/models/_m3gnet.py +369 -0
  47. PyXplore/Extinction/m3gnet/trainers/__init__.py +5 -0
  48. PyXplore/Extinction/m3gnet/trainers/_metrics.py +33 -0
  49. PyXplore/Extinction/m3gnet/trainers/_potential.py +266 -0
  50. PyXplore/Extinction/m3gnet/trainers/_property.py +288 -0
  51. PyXplore/Extinction/m3gnet/type.py +11 -0
  52. PyXplore/Extinction/m3gnet/utils/__init__.py +49 -0
  53. PyXplore/Extinction/m3gnet/utils/_general.py +73 -0
  54. PyXplore/Extinction/m3gnet/utils/_math.py +386 -0
  55. PyXplore/Extinction/m3gnet/utils/_tf.py +157 -0
  56. PyXplore/Extinction/wyckoff/__init__.py +1 -0
  57. PyXplore/Extinction/wyckoff/wyckoff_dict.py +237 -0
  58. PyXplore/GraphStructure/__init__.py +1 -0
  59. PyXplore/GraphStructure/graph.py +358 -0
  60. PyXplore/Plot/UnitCell.py +125 -0
  61. PyXplore/Plot/__init__.py +1 -0
  62. PyXplore/Refinement/VolumeFractionDertermination.py +223 -0
  63. PyXplore/Refinement/__init__.py +1 -0
  64. PyXplore/StructureOpt/SiteOpt.py +378 -0
  65. PyXplore/StructureOpt/__init__.py +1 -0
  66. PyXplore/WPEM.py +678 -0
  67. PyXplore/WPEMXAS/EXAFS.py +334 -0
  68. PyXplore/WPEMXAS/__init__.py +1 -0
  69. PyXplore/WPEMXAS/fftdemo.ipynb +207 -0
  70. PyXplore/WPEMXPS/XPSEM.py +1010 -0
  71. PyXplore/WPEMXPS/__init__.py +1 -0
  72. PyXplore/XRDSimulation/DiffractionGrometry/__init__.py +1 -0
  73. PyXplore/XRDSimulation/DiffractionGrometry/atom.py +6 -0
  74. PyXplore/XRDSimulation/Simulation.py +628 -0
  75. PyXplore/XRDSimulation/__init__.py +1 -0
  76. PyXplore/__init__.py +11 -0
  77. PyXplore/refs/International_Union_of_Crystallography.pdf +0 -0
  78. PyXplore/refs/WPEM_Manual.pdf +0 -0
  79. PyXplore-2025.5.6.dist-info/METADATA +60 -0
  80. PyXplore-2025.5.6.dist-info/RECORD +82 -0
  81. PyXplore-2025.5.6.dist-info/WHEEL +5 -0
  82. PyXplore-2025.5.6.dist-info/top_level.txt +1 -0
@@ -0,0 +1,182 @@
1
+ # Amorphous Quantitative Description Module
2
+ # Author: Bin CAO <binjacobcao@gmail.com>
3
+
4
+ import pandas as pd
5
+ import numpy as np
6
+ import os
7
+ import matplotlib.pyplot as plt
8
+
9
+ class RadialDistribution(object):
10
+ # radial distribution function
11
+ def __init__(self,wavelength, r_max = 5,work_dir =None):
12
+ self.wavelength = wavelength
13
+ # the maximum of radius from a center
14
+ self.r_max = r_max
15
+ self.work_dir = work_dir
16
+
17
+ # Define the font of the image
18
+ plt.rcParams['font.family'] = 'sans-serif'
19
+ plt.rcParams['font.size'] = 12
20
+
21
+ def RDF(self,amor_file=None,density_zero=None,Nf2=None,highlight= 4,value=0.6):
22
+
23
+ if self.work_dir is None:
24
+ DCfolder = 'DecomposedComponents'
25
+ else:
26
+ DCfolder = os.path.join(work_dir, 'DecomposedComponents')
27
+
28
+ os.makedirs(DCfolder, exist_ok=True)
29
+
30
+ # density_zero : the average density of the sample in atoms per cc.
31
+ # Nf2 : N is the effective number of atoms in the sample ; Aa is the atom scatter intensity
32
+ # value : assuming that the scattering can be taken as independent at sin(theta/lamda) =0.6,
33
+ if amor_file == None:
34
+ data = pd.read_csv(os.path.join(DCfolder, "Amorphous.csv"), header=None, names=['ang','int'])
35
+ b_data = pd.read_csv(os.path.join(DCfolder,"M_background_amorphous_stripped.csv"), header=None, names=['ang','int'])
36
+ else :
37
+ data = pd.read_csv(amor_file, header=None, names=['ang','int'])
38
+
39
+ if self.wavelength*value > 1:
40
+ print('The input value must be smaller than % f' % 1/self.wavelength*value)
41
+
42
+ # Define the high angle and intercept the K value
43
+ angle = np.arcsin(self.wavelength*value) * 180 / np.pi
44
+
45
+ # N is the effective number of atoms in the sample
46
+ # Aa is the atom scatter intensity
47
+ # at large angles of scattering I(k) approaches Nf2
48
+ if Nf2 == None:
49
+ # ref :
50
+ if amor_file == None:
51
+ # read from the amorphous background
52
+ for idx, ang_value in enumerate(b_data.ang):
53
+ if ang_value >= angle:
54
+ mean_int = b_data.int[idx:].mean()
55
+ print('Nf2 = {Nf2}, is evaluated at angel {angle}'.format(Nf2= mean_int, angle = angle))
56
+ break
57
+
58
+ else:
59
+ for idx, ang_value in enumerate(data.ang):
60
+ if ang_value >= angle:
61
+ mean_int = data.int[idx:].mean()
62
+ print('Nf2 = {Nf2}, is evaluated at angel {angle}'.format(Nf2= mean_int, angle = angle))
63
+ break
64
+ else:
65
+ Nf2 = Nf2
66
+
67
+ plt.xlabel('2\u03b8\u00B0', )
68
+ plt.ylabel('I (a.u.)')
69
+ plt.plot(data.ang, data.int,label="Amorphous diffraction pattern")
70
+ plt.legend() # fontsize = 15
71
+ plt.savefig(os.path.join(DCfolder,'Amorphous_DP.png'), dpi=800)
72
+ plt.show()
73
+ plt.clf()
74
+
75
+ k = 4 * np.pi / self.wavelength * np.sin(data.ang/2)
76
+ # 𝑖(𝑘)𝑘 ; k(I(k)-1)
77
+ # reduced interference function
78
+ int_k = (data.int / Nf2 -1) * k
79
+
80
+ r = np.arange(0,self.r_max,0.01)
81
+ RDF_r_list = []
82
+ for i in r:
83
+ RDF_r = cal_RDF(k, int_k, i)
84
+ RDF_r_list.append(RDF_r)
85
+
86
+ circle_x, circle_y, dis= peak_detect(r,RDF_r_list,highlight)
87
+ plt.xlabel('r/A\u00b0', )
88
+ plt.ylabel('RDF(r)', )
89
+ plt.plot(r, RDF_r_list,color='k',label="4Pir\u00b2Pu(r)-4Pir\u00b2Pu\u2080(r)")
90
+ plt.axhline(0.0, color='b', linestyle='--',)
91
+ plt.scatter(circle_x,circle_y, color='white', marker='o', edgecolors='g', s=200)
92
+ plt.legend()
93
+ plt.savefig(os.path.join(DCfolder,'RDF.png'), dpi=800)
94
+ plt.savefig(os.path.join(DCfolder,'RDF.svg'), dpi=800)
95
+ plt.show()
96
+ plt.clf()
97
+ if density_zero == None: density_zero =40,
98
+ elif type(density_zero) == float or type(density_zero) == int: pass
99
+ plt.xlabel('r/A\u00b0',)
100
+ plt.ylabel('RDF(r)', )
101
+ base = 4 * np.pi * r**2 * density_zero
102
+ circle_x, circle_y, dis= peak_detect_based(r,RDF_r_list,base,highlight)
103
+ plt.plot(r, base, color='b',linestyle='--',label="4Pir\u00b2Ru\u2080(r)")
104
+ plt.plot(r, RDF_r_list+ base,color='k',label="4Pir\u00b2Ru(r)")
105
+ plt.scatter(circle_x,circle_y, color='white', marker='o', edgecolors='g', s=200)
106
+ plt.legend()
107
+ plt.savefig(os.path.join(DCfolder,'RDF_hasbase.png'), dpi=800)
108
+ plt.savefig(os.path.join(DCfolder,'RDF_hasbase.svg'), dpi=800)
109
+ plt.show()
110
+ plt.clf()
111
+
112
+ print('interatomic distances is %f A\u00b0' % np.round(dis,3))
113
+
114
+ return circle_x
115
+
116
+ def cal_RDF(k, int_k, r):
117
+ """
118
+ Calculate RDF
119
+ :param k:
120
+ :param int_k:
121
+ :param r:
122
+ :return:
123
+ """
124
+ # 𝑖(𝑘)𝑘𝑠𝑖𝑛𝑘𝑟
125
+ x = np.array(k)
126
+ y = np.array(int_k) * np.sin(x *r )
127
+ n = len(x) - 1
128
+ area = 0
129
+ for i in range(n):
130
+ h = (y[i] + y[i + 1]) / 2
131
+ l = x[i + 1] -x[i]
132
+ area += h * l
133
+ return area*2*r/np.pi
134
+
135
+ # calculate the peak location and intervals
136
+ def peak_detect(r,RDF_r_list,highlight):
137
+ """
138
+ Peak detection / 1d array
139
+ :param r: x
140
+ :param RDF_r_list: y
141
+ :return:
142
+ """
143
+ b_index = [0]
144
+ for i in range(len(RDF_r_list)-1):
145
+ if RDF_r_list[i] * RDF_r_list[i+1] < 0:
146
+ b_index.append(i)
147
+ circle_x = []
148
+ circle_y = []
149
+ index = 0
150
+ for hl in range(highlight):
151
+ left = b_index[hl]
152
+ right = b_index[hl+1]
153
+ index = int(np.flatnonzero(np.abs(np.array(RDF_r_list)) ==np.abs(np.array(RDF_r_list[left:right])).max()))
154
+ circle_y.append(RDF_r_list[index])
155
+ circle_x.append(r[index])
156
+ return circle_x, circle_y, circle_x[2]-circle_x[0]
157
+
158
+ def peak_detect_based(r,RDF_r_list,base, highlight):
159
+ """
160
+ Peak detection / 1d array
161
+ :param r: x
162
+ :param RDF_r_list: y
163
+ :return:
164
+ """
165
+ b_index = [0]
166
+ for i in range(len(RDF_r_list)-1):
167
+ if RDF_r_list[i] * RDF_r_list[i+1] < 0:
168
+ b_index.append(i)
169
+ circle_x = []
170
+ circle_y = []
171
+ index = 0
172
+ for hl in range(highlight):
173
+ left = b_index[hl]
174
+ right = b_index[hl+1]
175
+ index = int(np.flatnonzero(np.abs(np.array(RDF_r_list)) ==np.abs(np.array(RDF_r_list[left:right])).max()))
176
+ circle_y.append(RDF_r_list[index] + base[index])
177
+ circle_x.append(r[index])
178
+
179
+ return circle_x, circle_y,circle_x[2]-circle_x[0]
180
+
181
+
182
+
@@ -0,0 +1,11 @@
1
+ __description__ = 'A powder X-ray diffraction analysis package'
2
+ __url__ = 'https://github.com/Bin-Cao/WPEM'
3
+ __author__ = 'Bin Cao, Advanced Materials Thrust, Hong Kong University of Science and Technology (Guangzhou)'
4
+ __author_email__ = 'binjacobcao@gmail.com'
5
+
6
+
7
+
8
+
9
+
10
+
11
+
@@ -0,0 +1,342 @@
1
+ # Amorphous Qualitative Description Module
2
+ # Author: Bin CAO <binjacobcao@gmail.com>
3
+
4
+ import math
5
+ import heapq
6
+ import os
7
+ import copy
8
+ import numpy as np
9
+ import matplotlib.pyplot as plt
10
+ import pandas as pd
11
+ from math import sin, pi
12
+
13
+ def Amorphous_fitting(mix_component, amor_file = None, ang_range = None, sigma2_coef = 5, max_iter = 5000, peak_location = None,Wavelength = 1.54184,work_dir=None):
14
+ """
15
+ Amorphous Qualitative Description Module
16
+
17
+ :param mix_component : the number of amorphous peaks
18
+
19
+ :param amor_file : the amorphous file location
20
+
21
+ :param ang_range : default is None
22
+ two theta range of study
23
+
24
+ :param sigma2_coef : default is 0.5
25
+ sigma2 of gaussian peak
26
+
27
+ :param max_iter : default is 5000
28
+ the maximum number of iterations of solver
29
+
30
+ : param peak_location : default is None
31
+ the initial peak position of the amorphous peaks
32
+ can input as a list, e.g.,
33
+ peak_location = [20,30,40]
34
+ the peak position can be frozen by the assigned input,
35
+ peak_location = [20,30,40,'fixed']
36
+
37
+ : param Wavelength : Wavelength of ray, default is 1.54184 (Cu)
38
+ """
39
+ if work_dir is None:
40
+ DCfolder = 'DecomposedComponents'
41
+ else:
42
+ DCfolder = os.path.join(work_dir, 'DecomposedComponents')
43
+
44
+ os.makedirs(DCfolder, exist_ok=True)
45
+
46
+ if amor_file == None:
47
+ # range: (0,90) angle range
48
+ data = pd.read_csv(os.path.join(DCfolder, "upbackground.csv"), header=None, names=['ang','int'])
49
+ else:
50
+ data = pd.read_csv(amor_file, header=None, names=['ang','int'])
51
+
52
+ full_ang = copy.deepcopy(np.array(data.ang))
53
+ ori_int = copy.deepcopy(np.array(data.int))
54
+ if ang_range == None:
55
+ pass
56
+ else:
57
+ x_list = np.array(data.ang)
58
+ y_list = np.array(data.int)
59
+ index = np.where( (data.ang < ang_range[0]) | (data.ang > ang_range[1]) )
60
+ data = data.drop(index[0])
61
+
62
+ x_list = np.array(data.ang)
63
+ y_list = np.array(data.int)
64
+
65
+ # remove constant
66
+ NAa = y_list.min()
67
+ y_list -= NAa
68
+
69
+ singal = False
70
+ # initializ the parameters
71
+ sigma2_list = sigma2_coef * np.ones((mix_component, 1), dtype=float)
72
+ w_list = np.ones((mix_component, 1), dtype=float)/mix_component
73
+ if type(peak_location) == list:
74
+ if peak_location[-1] == 'fixed':
75
+ singal = True
76
+ mu_list = np.array(peak_location[:-1])
77
+ elif type(peak_location[-1]) == float or int:
78
+ mu_list = np.array(peak_location)
79
+ else:
80
+ print('Type Error - only \'fixed\' is allowed')
81
+
82
+ elif peak_location == None:
83
+ mu_list = initalize(mix_component,x_list,y_list)
84
+ else:
85
+ print('type error! : peak_location, please input as a list')
86
+
87
+ new_w_list = w_list
88
+ new_mu_list = mu_list
89
+ new_sigma2_list = sigma2_list
90
+ gamma_list = gamma_ji_list(x_list, w_list, mu_list, sigma2_list)
91
+ denominator = denominator_list(w_list, gamma_list,y_list)
92
+
93
+ int_area = theta_intensity_area(x_list, y_list)
94
+
95
+ i_ter = 0
96
+ while (True):
97
+ i_ter += 1
98
+ w_list = new_w_list
99
+ mu_list = new_mu_list
100
+ sigma2_list = new_sigma2_list
101
+ if singal == False:
102
+ new_mu_list = solve_mu_list(x_list, gamma_list, denominator,y_list)
103
+ else:
104
+ pass
105
+ new_sigma2_list = solve_sigma2_list(x_list, gamma_list, w_list, mu_list, denominator,y_list)
106
+ new_w_list = solve_w_list(y_list, denominator,int_area)
107
+ gamma_list = gamma_ji_list(x_list, new_w_list, new_mu_list, new_sigma2_list)
108
+ denominator = denominator_list(new_w_list, gamma_list,y_list)
109
+
110
+ if i_ter % 200 == 0:
111
+ print("Number of Iterations: %s" % i_ter)
112
+ print("W_list: %s" % new_w_list)
113
+ print("mu_list: %s" % new_mu_list)
114
+ print("sigma2_list: %s" % new_sigma2_list)
115
+
116
+ if compare_list(w_list, new_w_list, 1e-6):
117
+ if compare_list(mu_list, new_mu_list, 1e-6):
118
+ if compare_list(sigma2_list, new_sigma2_list, 1e-6):
119
+ print("Convergence get at %s iterations!" % i_ter)
120
+ break
121
+
122
+ if i_ter > max_iter:
123
+ break
124
+
125
+ print("W_list: %s" % new_w_list)
126
+ print("mu_list: %s" % new_mu_list)
127
+ print("sigma2_list: %s" % new_sigma2_list)
128
+
129
+ # estimated
130
+ d = 1.23 * Wavelength / 2 / sin(new_mu_list[0]/2 * pi / 180)
131
+ print('estimated interatomic distances : %f' % d)
132
+
133
+ part_y_cal = np.array(mixture_normal_density(x_list, new_w_list, new_mu_list, new_sigma2_list))
134
+
135
+ # cal the fitting goodness
136
+ error_p = []
137
+
138
+ for i in range(len(y_list)):
139
+ error_p.append(abs(y_list[i] - part_y_cal[i]))
140
+ error_p_sum = sum(error_p)
141
+ y_sum = sum(y_list)
142
+
143
+ Rp = error_p_sum / y_sum * 100
144
+ print("Rp = ", error_p_sum / y_sum * 100)
145
+
146
+ # cal intensities on entire diffraction range
147
+ y_cal = np.array(mixture_normal_density(full_ang, new_w_list, new_mu_list, new_sigma2_list))
148
+
149
+ with open(os.path.join(DCfolder, 'M_Amorphous_peaks.csv'), 'w') as wfid:
150
+ print('wi', end=',', file=wfid)
151
+ print('mu_i', end=',', file=wfid)
152
+ print('sigma2_i', end=',', file=wfid)
153
+ print('Rp: %f ' % Rp, file=wfid)
154
+ for j in range(mix_component):
155
+ print(new_w_list[j], end=',', file=wfid)
156
+ print(new_mu_list[j], end=',', file=wfid)
157
+ print(new_sigma2_list[j], file=wfid)
158
+
159
+ # updata background
160
+ # (amorphous) up_bac = y_list + constant
161
+ # up_up_bac = y_list + constant - y_fit = up_bac - y_fit
162
+ up_up_bac = ori_int - y_cal
163
+ if up_up_bac.min() < 0:
164
+ print('warning! the fitting profile of amorphous is overflow \n ','please choise another set of reasonable paras. in model AmorphousFitting ')
165
+ else:
166
+ pass
167
+
168
+ # write up_up_bac
169
+ with open(os.path.join(DCfolder, 'M_background_amorphous_stripped.csv'), 'w') as wfid:
170
+ for j in range(len(full_ang)):
171
+ print(full_ang[j], end=', ', file=wfid)
172
+ print(float(up_up_bac[j]), file=wfid)
173
+
174
+
175
+ # write amorphous fitting profile
176
+ with open(os.path.join(DCfolder, 'Amorphous.csv'), 'w') as wfid:
177
+ for j in range(len(full_ang)):
178
+ print(full_ang[j], end=', ', file=wfid)
179
+ print(float(y_cal[j]), file=wfid)
180
+
181
+ # Define the font of the image
182
+ plt.rcParams['font.family'] = 'sans-serif'
183
+ plt.rcParams['font.size'] = 12
184
+
185
+ plt.xlabel('2\u03b8\u00B0')
186
+ plt.ylabel('I (a.u.)')
187
+ plt.title('Amorphous decomposited components')
188
+ plt.plot(x_list,y_list, label="Real intensity")
189
+
190
+ show_fit_profile = np.zeros(len(x_list))
191
+ for com in range(mix_component):
192
+ y_com = new_w_list[com] * np.array(normal_density(x_list,new_mu_list[com], new_sigma2_list[com]))
193
+ plt.plot(x_list, y_com,label="components {num}".format(num = com))
194
+ show_fit_profile += y_com
195
+
196
+ # write amorphous components
197
+ entire_y_com = new_w_list[com] * np.array(normal_density(full_ang,new_mu_list[com], new_sigma2_list[com]))
198
+ with open(os.path.join(DCfolder, 'M_Amorphous_components{num}.csv'.format(num = com)), 'w') as wfid:
199
+ for j in range(len(full_ang)):
200
+ print(full_ang[j], end=', ', file=wfid)
201
+ print(float(entire_y_com[j]), file=wfid)
202
+
203
+ plt.plot(x_list,show_fit_profile, label="WPEM fitting intensity")
204
+ plt.xlabel('2\u03b8\u00B0')
205
+ plt.ylabel('I (a.u.)')
206
+ plt.legend()
207
+ plt.savefig(os.path.join(DCfolder, 'M_Amorphous_components.png'), dpi=800)
208
+ plt.show()
209
+ plt.clf()
210
+
211
+ ################################################################
212
+
213
+ def normal_density(x, mu, sigma2):
214
+ """
215
+ :param x: sample data
216
+ :param mu: mean
217
+ :param sigma2:
218
+ :return: variance
219
+ Return the probability density of Normal distribution x~N(mu,sigma2)
220
+ """
221
+ density = (1 / np.sqrt(2 * np.pi * sigma2)) * np.exp(-((x - mu) ** 2) / (2 * sigma2))
222
+ return density
223
+
224
+
225
+ def mixture_normal_density(x, w_list, mu_list, sigma2_list):
226
+ """
227
+ Input paramters:
228
+ x_list -> sample data from generated sample j, start from 0
229
+ w_list -> list of mixture coefficients
230
+ mu_list -> list of mu
231
+ sigma2_list-> list of sigma2
232
+ Return the mixture probability density of Normal distribution sum(x~N(mu,sigma2))
233
+ """
234
+ k = len(w_list) # the number of mixture normal distributions
235
+ mix_density = 0
236
+ for i in range(k):
237
+ mix_density += w_list[i] * normal_density(x, mu_list[i], sigma2_list[i])
238
+ return mix_density
239
+
240
+
241
+ def gamma_ji_list(x_list, w_list, mu_list, sigma2_list):
242
+ """
243
+ :param x_list: sample data
244
+ :param w_list: list of mixture coefficients
245
+ :param mu_list: list of mu
246
+ :param sigma2_list: list of sigma2
247
+ :return: the matrix of post-probability of x_j at distribution i, i,j start from 0
248
+ """
249
+ m = len(x_list) # number of data
250
+ k = len(w_list) # the number of mixture normal distributions
251
+ gamma_ji = np.ones((m, k), dtype=float) # data * peak
252
+ for j in range(m):
253
+ denominator = 0.0
254
+ numerator = np.linspace(0., 0., k)
255
+ for i_m in range(k):
256
+ denominator += w_list[i_m] * normal_density(x_list[j], mu_list[i_m], sigma2_list[i_m])
257
+ numerator[i_m] = w_list[i_m] * normal_density(x_list[j], mu_list[i_m], sigma2_list[i_m])
258
+ for i in range(k):
259
+ # numerator = w_list[i] * normal_density(x_list[j], mu_list[i], sigma2_list[i])
260
+ gamma_ji[j][i] = numerator[i] / (denominator + 1e-10)
261
+ # gamma_ji[j][:] = numerator / denominator
262
+ return gamma_ji # m*k
263
+
264
+
265
+ def denominator_list(w_list, gamma_list,int_list):
266
+ # int_list : array in the shape of x_list (m, 1)
267
+ k = len(w_list) # the number of mixture normal distributions
268
+ denominator_i = np.linspace(0., 0., k)
269
+ for i in range(k):
270
+ denominator_i[i] = np.multiply(int_list,gamma_list[:, i]).sum()
271
+ return denominator_i # k * 1
272
+
273
+
274
+ def solve_mu_list(x_list, gamma_list, denominator, int_list):
275
+ """
276
+ Return new_mu_list which makes likelihood reaches maximum
277
+ """
278
+ k = len(denominator) # the number of mixture normal distributions
279
+ numerator = np.linspace(0., 0., k)
280
+ for i in range(k):
281
+ numerator[i] = np.multiply(np.multiply(int_list,gamma_list[:, i]), x_list).sum()
282
+ new_mu_list = numerator / (denominator + 1e-12)
283
+ return new_mu_list
284
+
285
+ def solve_sigma2_list(x_list, gamma_list, w_list, mu_list, denominator,int_list):
286
+ """
287
+ mu_list maybe the new_mu_list
288
+ Return new_sigma2_list which makes likelihood reaches maximum
289
+ """
290
+ k = len(w_list)
291
+ numerator = np.linspace(0., 0., k)
292
+ for i in range(k):
293
+ x_list_i = (x_list - mu_list[i])
294
+ x_list_i2 = np.multiply(x_list_i, x_list_i) # m*1
295
+ numerator[i] = np.multiply(np.multiply(int_list,gamma_list[:, i]), x_list_i2).sum()
296
+ new_sigma2_list = (numerator / (denominator + 1e-12))
297
+ return new_sigma2_list
298
+
299
+ def solve_w_list(int_list, denominator,int_area):
300
+ """
301
+ Return new_sigma2_list which makes likelihood reaches maximum
302
+ """
303
+ new_w_list = int_area/int_list.sum() * denominator
304
+ return new_w_list
305
+
306
+ def compare_list(old_list, new_list, tor):
307
+ length = len(old_list)
308
+ tot_error = 0
309
+ for i in range(length):
310
+ tot_error += (abs(old_list[i] - new_list[i])) / old_list[i]
311
+ tot_error /= length
312
+ if tot_error <= tor:
313
+ return True
314
+ else:
315
+ return
316
+
317
+ def theta_intensity_area(x_list, int_list):
318
+ n = len(x_list) - 1
319
+ __area = 0
320
+ for i in range(n):
321
+ __h = (int_list[i] + int_list[i + 1]) / 2
322
+ __l = x_list[i + 1] - x_list[i]
323
+ __area += __h * __l
324
+ return __area
325
+
326
+ def chunks(arr, m):
327
+ n = int(math.ceil(len(arr) / float(m)))
328
+ return [arr[i:i + n] for i in range(0, len(arr), n)]
329
+
330
+ def initalize(mix_component,x_list,y_list):
331
+ peak_index = []
332
+ split_angle_part = chunks(y_list,mix_component)
333
+ for peak in range(mix_component):
334
+ peak_index.append(
335
+ (heapq.nlargest(1, enumerate(split_angle_part[peak]),key=lambda x: x[1]))[0][0]
336
+ + peak * len(split_angle_part[0])
337
+ )
338
+ mu_list = []
339
+ for j in range(len(peak_index)):
340
+ mu_list.append(x_list[peak_index[j]])
341
+
342
+ return np.array(mu_list)
@@ -0,0 +1 @@
1
+