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.
- PyXplore/Amorphous/QuantitativeCalculation/AmorphousRDF.py +182 -0
- PyXplore/Amorphous/QuantitativeCalculation/__init__.py +1 -0
- PyXplore/Amorphous/__init__.py +11 -0
- PyXplore/Amorphous/fitting/AmorphousFitting.py +342 -0
- PyXplore/Amorphous/fitting/__init__.py +1 -0
- PyXplore/Background/BacDeduct.py +474 -0
- PyXplore/Background/__init__.py +1 -0
- PyXplore/DecomposePlot/__init__.py +11 -0
- PyXplore/DecomposePlot/plot.py +472 -0
- PyXplore/EMBraggOpt/BraggLawDerivation.py +651 -0
- PyXplore/EMBraggOpt/EMBraggSolver.py +1199 -0
- PyXplore/EMBraggOpt/WPEMFuns/SolverFuns.py +356 -0
- PyXplore/EMBraggOpt/WPEMFuns/__init__.py +1 -0
- PyXplore/EMBraggOpt/__init__.py +1 -0
- PyXplore/Extinction/CifReader.py +238 -0
- PyXplore/Extinction/Relaxer.py +71 -0
- PyXplore/Extinction/XRDpre.py +892 -0
- PyXplore/Extinction/__init__.py +1 -0
- PyXplore/Extinction/m3gnet/__init__.py +4 -0
- PyXplore/Extinction/m3gnet/callbacks.py +26 -0
- PyXplore/Extinction/m3gnet/cli.py +112 -0
- PyXplore/Extinction/m3gnet/config.py +53 -0
- PyXplore/Extinction/m3gnet/graph/__init__.py +31 -0
- PyXplore/Extinction/m3gnet/graph/_batch.py +270 -0
- PyXplore/Extinction/m3gnet/graph/_compute.py +184 -0
- PyXplore/Extinction/m3gnet/graph/_converters.py +224 -0
- PyXplore/Extinction/m3gnet/graph/_structure.py +72 -0
- PyXplore/Extinction/m3gnet/graph/_types.py +387 -0
- PyXplore/Extinction/m3gnet/layers/__init__.py +57 -0
- PyXplore/Extinction/m3gnet/layers/_aggregate.py +60 -0
- PyXplore/Extinction/m3gnet/layers/_atom.py +107 -0
- PyXplore/Extinction/m3gnet/layers/_atom_ref.py +168 -0
- PyXplore/Extinction/m3gnet/layers/_base.py +87 -0
- PyXplore/Extinction/m3gnet/layers/_basis.py +63 -0
- PyXplore/Extinction/m3gnet/layers/_bond.py +232 -0
- PyXplore/Extinction/m3gnet/layers/_core.py +246 -0
- PyXplore/Extinction/m3gnet/layers/_cutoff.py +36 -0
- PyXplore/Extinction/m3gnet/layers/_gn.py +255 -0
- PyXplore/Extinction/m3gnet/layers/_readout.py +266 -0
- PyXplore/Extinction/m3gnet/layers/_state.py +101 -0
- PyXplore/Extinction/m3gnet/layers/_three_body.py +73 -0
- PyXplore/Extinction/m3gnet/layers/_two_body.py +48 -0
- PyXplore/Extinction/m3gnet/models/__init__.py +16 -0
- PyXplore/Extinction/m3gnet/models/_base.py +261 -0
- PyXplore/Extinction/m3gnet/models/_dynamics.py +384 -0
- PyXplore/Extinction/m3gnet/models/_m3gnet.py +369 -0
- PyXplore/Extinction/m3gnet/trainers/__init__.py +5 -0
- PyXplore/Extinction/m3gnet/trainers/_metrics.py +33 -0
- PyXplore/Extinction/m3gnet/trainers/_potential.py +266 -0
- PyXplore/Extinction/m3gnet/trainers/_property.py +288 -0
- PyXplore/Extinction/m3gnet/type.py +11 -0
- PyXplore/Extinction/m3gnet/utils/__init__.py +49 -0
- PyXplore/Extinction/m3gnet/utils/_general.py +73 -0
- PyXplore/Extinction/m3gnet/utils/_math.py +386 -0
- PyXplore/Extinction/m3gnet/utils/_tf.py +157 -0
- PyXplore/Extinction/wyckoff/__init__.py +1 -0
- PyXplore/Extinction/wyckoff/wyckoff_dict.py +237 -0
- PyXplore/GraphStructure/__init__.py +1 -0
- PyXplore/GraphStructure/graph.py +358 -0
- PyXplore/Plot/UnitCell.py +125 -0
- PyXplore/Plot/__init__.py +1 -0
- PyXplore/Refinement/VolumeFractionDertermination.py +223 -0
- PyXplore/Refinement/__init__.py +1 -0
- PyXplore/StructureOpt/SiteOpt.py +378 -0
- PyXplore/StructureOpt/__init__.py +1 -0
- PyXplore/WPEM.py +678 -0
- PyXplore/WPEMXAS/EXAFS.py +334 -0
- PyXplore/WPEMXAS/__init__.py +1 -0
- PyXplore/WPEMXAS/fftdemo.ipynb +207 -0
- PyXplore/WPEMXPS/XPSEM.py +1010 -0
- PyXplore/WPEMXPS/__init__.py +1 -0
- PyXplore/XRDSimulation/DiffractionGrometry/__init__.py +1 -0
- PyXplore/XRDSimulation/DiffractionGrometry/atom.py +6 -0
- PyXplore/XRDSimulation/Simulation.py +628 -0
- PyXplore/XRDSimulation/__init__.py +1 -0
- PyXplore/__init__.py +11 -0
- PyXplore/refs/International_Union_of_Crystallography.pdf +0 -0
- PyXplore/refs/WPEM_Manual.pdf +0 -0
- PyXplore-2025.5.6.dist-info/METADATA +60 -0
- PyXplore-2025.5.6.dist-info/RECORD +82 -0
- PyXplore-2025.5.6.dist-info/WHEEL +5 -0
- 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 @@
|
|
|
1
|
+
|
|
@@ -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
|
+
|