1 | #GSASII computational module |
---|
2 | import sys |
---|
3 | import math |
---|
4 | import wx |
---|
5 | import time |
---|
6 | import numpy as np |
---|
7 | import numpy.linalg as nl |
---|
8 | import os.path as ospath |
---|
9 | # determine a binary path pased on the host OS and the python version, path is relative to |
---|
10 | # location of this file |
---|
11 | if sys.platform == "win32": |
---|
12 | bindir = 'binwin%d.%d' % sys.version_info[0:2] |
---|
13 | elif sys.platform == "darwin": |
---|
14 | bindir = 'binmac%d.%d' % sys.version_info[0:2] |
---|
15 | else: |
---|
16 | bindir = 'bin' |
---|
17 | |
---|
18 | if ospath.exists(ospath.join(sys.path[0],bindir)) and ospath.join(sys.path[0],bindir) not in sys.path: |
---|
19 | sys.path.insert(0,ospath.join(sys.path[0],bindir)) |
---|
20 | |
---|
21 | try: |
---|
22 | import pypowder as pyp |
---|
23 | except: |
---|
24 | # create an app to display the error, since we are still loading routines at this point |
---|
25 | app = wx.App() |
---|
26 | app.MainLoop() |
---|
27 | msg = wx.MessageDialog(None, message="Unable to load the GSAS powder computation module, pypowder", |
---|
28 | caption="Import Error", |
---|
29 | style=wx.ICON_ERROR | wx.OK | wx.STAY_ON_TOP) |
---|
30 | msg.ShowModal() |
---|
31 | # this error is non-recoverable, so just quit |
---|
32 | exit() |
---|
33 | import GSASIIplot as G2plt |
---|
34 | |
---|
35 | # trig functions in degrees |
---|
36 | sind = lambda x: math.sin(x*math.pi/180.) |
---|
37 | asind = lambda x: 180.*math.asin(x)/math.pi |
---|
38 | tand = lambda x: math.tan(x*math.pi/180.) |
---|
39 | atand = lambda x: 180.*math.atan(x)/math.pi |
---|
40 | atan2d = lambda y,x: 180.*math.atan2(y,x)/math.pi |
---|
41 | cosd = lambda x: math.cos(x*math.pi/180.) |
---|
42 | acosd = lambda x: 180.*math.acos(x)/math.pi |
---|
43 | rdsq2d = lambda x,p: round(1.0/math.sqrt(x),p) |
---|
44 | #numpy versions |
---|
45 | npsind = lambda x: np.sin(x*np.pi/180.) |
---|
46 | npasind = lambda x: 180.*np.arcsin(x)/math.pi |
---|
47 | npcosd = lambda x: np.cos(x*math.pi/180.) |
---|
48 | nptand = lambda x: np.tan(x*math.pi/180.) |
---|
49 | npatand = lambda x: 180.*np.arctan(x)/np.pi |
---|
50 | npatan2d = lambda y,x: 180.*np.arctan2(y,x)/np.pi |
---|
51 | |
---|
52 | def sec2HMS(sec): |
---|
53 | H = int(sec/3600) |
---|
54 | M = int(sec/60-H*60) |
---|
55 | S = sec-3600*H-60*M |
---|
56 | return '%d:%2d:%.2f'%(H,M,S) |
---|
57 | |
---|
58 | def ValEsd(value,esd=0,nTZ=False): |
---|
59 | # returns value(esd) string; nTZ=True for no trailing zeros |
---|
60 | # use esd < 0 for level of precision shown e.g. esd=-0.01 gives 2 places beyond decimal |
---|
61 | #get the 2 significant digits in the esd |
---|
62 | edig = lambda esd: int(round(10**(math.log10(esd) % 1+1))) |
---|
63 | #get the number of digits to represent them |
---|
64 | epl = lambda esd: 2+int(1.545-math.log10(10*edig(esd))) |
---|
65 | |
---|
66 | mdec = lambda esd: -int(math.log10(abs(esd))) |
---|
67 | ndec = lambda esd: int(1.545-math.log10(abs(esd))) |
---|
68 | if esd > 0: |
---|
69 | fmt = '"%.'+str(ndec(esd))+'f(%d)"' |
---|
70 | print fmt,ndec(esd),esd*10**(mdec(esd)+1) |
---|
71 | return fmt%(value,int(esd*10**(mdec(esd)+1))) |
---|
72 | elif esd < 0: |
---|
73 | return str(round(value,mdec(esd))) |
---|
74 | else: |
---|
75 | text = "%F"%(value) |
---|
76 | if nTZ: |
---|
77 | return text.rstrip('0') |
---|
78 | else: |
---|
79 | return text |
---|
80 | |
---|
81 | |
---|
82 | |
---|
83 | |
---|
84 | def DoPeakFit(peaks,background,limits,inst,data): |
---|
85 | |
---|
86 | def backgroundPrint(background,sigback): |
---|
87 | if background[1]: |
---|
88 | print 'Background coefficients for',background[0],'function' |
---|
89 | ptfmt = "%12.5f" |
---|
90 | ptstr = 'values:' |
---|
91 | sigstr = 'esds :' |
---|
92 | for i,back in enumerate(background[3:]): |
---|
93 | ptstr += ptfmt % (back) |
---|
94 | sigstr += ptfmt % (sigback[i+3]) |
---|
95 | print ptstr |
---|
96 | print sigstr |
---|
97 | else: |
---|
98 | print 'Background not refined' |
---|
99 | |
---|
100 | def instPrint(instVal,siginst,insLabels): |
---|
101 | print 'Instrument Parameters:' |
---|
102 | ptfmt = "%12.6f" |
---|
103 | ptlbls = 'names :' |
---|
104 | ptstr = 'values:' |
---|
105 | sigstr = 'esds :' |
---|
106 | for i,value in enumerate(instVal): |
---|
107 | ptlbls += "%s" % (insLabels[i].center(12)) |
---|
108 | ptstr += ptfmt % (value) |
---|
109 | if siginst[i]: |
---|
110 | sigstr += ptfmt % (siginst[i]) |
---|
111 | else: |
---|
112 | sigstr += 12*' ' |
---|
113 | print ptlbls |
---|
114 | print ptstr |
---|
115 | print sigstr |
---|
116 | |
---|
117 | def peaksPrint(peaks,sigpeaks): |
---|
118 | print 'Peak list=' |
---|
119 | |
---|
120 | begin = time.time() |
---|
121 | Np = len(peaks[0]) |
---|
122 | DataType = inst[1][0] |
---|
123 | instVal = inst[1][1:] |
---|
124 | Insref = inst[2][1:] |
---|
125 | insLabels = inst[3][1:] |
---|
126 | Ka2 = False |
---|
127 | Ioff = 3 |
---|
128 | if len(instVal) == 12: |
---|
129 | lamratio = instVal[1]/instVal[0] |
---|
130 | Ka2 = True |
---|
131 | Ioff = 5 |
---|
132 | insref = Insref[len(Insref)-7:-1] #just U,V,W,X,Y,SH/L |
---|
133 | for peak in peaks: |
---|
134 | dip = [] |
---|
135 | dip.append(tand(peak[0]/2.0)**2) |
---|
136 | dip.append(tand(peak[0]/2.0)) |
---|
137 | dip.append(1.0/cosd(peak[0]/2.0)) |
---|
138 | dip.append(tand(peak[0]/2.0)) |
---|
139 | peak.append(dip) |
---|
140 | B = background[2] |
---|
141 | bcof = background[3:3+B] |
---|
142 | Bv = 0 |
---|
143 | if background[1]: |
---|
144 | Bv = B |
---|
145 | x,y,w,yc,yb,yd = data #these are numpy arrays! |
---|
146 | V = [] |
---|
147 | A = [] |
---|
148 | swobs = 0.0 |
---|
149 | smin = 0.0 |
---|
150 | first = True |
---|
151 | GoOn = True |
---|
152 | Go = True |
---|
153 | dlg = wx.ProgressDialog("Elapsed time","Fitting peaks to pattern",len(x), \ |
---|
154 | style = wx.PD_ELAPSED_TIME|wx.PD_AUTO_HIDE|wx.PD_REMAINING_TIME|wx.PD_CAN_ABORT) |
---|
155 | screenSize = wx.DisplaySize() |
---|
156 | Size = dlg.GetSize() |
---|
157 | dlg.SetPosition(wx.Point(screenSize[0]-Size[0]-300,0)) |
---|
158 | try: |
---|
159 | i = 0 |
---|
160 | for xi in x: |
---|
161 | Go = dlg.Update(i)[0] |
---|
162 | if GoOn: |
---|
163 | GoOn = Go |
---|
164 | if limits[0] <= xi <= limits[1]: |
---|
165 | yb[i] = 0.0 |
---|
166 | dp = [] |
---|
167 | for j in range(B): |
---|
168 | t = (xi-limits[0])**j |
---|
169 | yb[i] += t*bcof[j] |
---|
170 | if background[1]: |
---|
171 | dp.append(t) |
---|
172 | yc[i] = yb[i] |
---|
173 | Iv = 0 |
---|
174 | for j in range(6): |
---|
175 | if insref[j]: |
---|
176 | dp.append(0.0) |
---|
177 | Iv += 1 |
---|
178 | for peak in peaks: |
---|
179 | dip = peak[-1] |
---|
180 | f = pyp.pypsvfcj(peak[2],xi-peak[0],peak[0],peak[4],peak[6],peak[8],0.0) |
---|
181 | yc[i] += f[0]*peak[2] |
---|
182 | if f[0] > 0.0: |
---|
183 | j = 0 |
---|
184 | if insref[0]: #U |
---|
185 | dp[Bv+j] += f[3]*dip[0] |
---|
186 | j += 1 |
---|
187 | if insref[1]: #V |
---|
188 | dp[Bv+j] += f[3]*dip[1] |
---|
189 | j += 1 |
---|
190 | if insref[2]: #W |
---|
191 | dp[Bv+j] += f[3] |
---|
192 | j += 1 |
---|
193 | if insref[3]: #X |
---|
194 | dp[Bv+j] += f[4]*dip[2] |
---|
195 | j += 1 |
---|
196 | if insref[4]: #Y |
---|
197 | dp[Bv+j] += f[4]*dip[3] |
---|
198 | j += 1 |
---|
199 | if insref[5]: #SH/L |
---|
200 | dp[Bv+j] += f[5] |
---|
201 | if Ka2: |
---|
202 | pos2 = 2.0*asind(lamratio*sind(peak[0]/2.0)) |
---|
203 | f2 = pyp.pypsvfcj(peak[2],xi-pos2,peak[0],peak[4],peak[6],peak[8],0.0) |
---|
204 | yc[i] += f2[0]*peak[2]*instVal[3] |
---|
205 | if f[0] > 0.0: |
---|
206 | j = 0 |
---|
207 | if insref[0]: #U |
---|
208 | dp[Bv+j] += f2[3]*dip[0]*instVal[3] |
---|
209 | j += 1 |
---|
210 | if insref[1]: #V |
---|
211 | dp[Bv+j] += f2[3]*dip[1]*instVal[3] |
---|
212 | j += 1 |
---|
213 | if insref[2]: #W |
---|
214 | dp[Bv+j] += f2[3]*instVal[3] |
---|
215 | j += 1 |
---|
216 | if insref[3]: #X |
---|
217 | dp[Bv+j] += f2[4]*dip[2]*instVal[3] |
---|
218 | j += 1 |
---|
219 | if insref[4]: #Y |
---|
220 | dp[Bv+j] += f2[4]*dip[3]*instVal[3] |
---|
221 | j += 1 |
---|
222 | if insref[5]: #SH/L |
---|
223 | dp[Bv+j] += f2[5]*instVal[3] |
---|
224 | for j in range(0,Np,2): #14s |
---|
225 | if peak[j+1]: dp.append(f[j/2+1]) |
---|
226 | yd[i] = y[i]-yc[i] |
---|
227 | swobs += w[i]*y[i]**2 |
---|
228 | t2 = w[i]*yd[i] |
---|
229 | smin += t2*yd[i] |
---|
230 | if first: |
---|
231 | first = False |
---|
232 | M = len(dp) |
---|
233 | A = np.zeros(shape=(M,M)) |
---|
234 | V = np.zeros(shape=(M)) |
---|
235 | A,V = pyp.buildmv(t2,w[i],M,dp,A,V) |
---|
236 | i += 1 |
---|
237 | finally: |
---|
238 | dlg.Destroy() |
---|
239 | print GoOn |
---|
240 | Rwp = smin/swobs |
---|
241 | Rwp = math.sqrt(Rwp)*100.0 |
---|
242 | norm = np.diag(A) |
---|
243 | for i,elm in enumerate(norm): |
---|
244 | if elm <= 0.0: |
---|
245 | print norm |
---|
246 | return False,0,0,0 |
---|
247 | for i in xrange(len(V)): |
---|
248 | norm[i] = 1.0/math.sqrt(norm[i]) |
---|
249 | V[i] *= norm[i] |
---|
250 | a = A[i] |
---|
251 | for j in xrange(len(V)): |
---|
252 | a[j] *= norm[i] |
---|
253 | A = np.transpose(A) |
---|
254 | for i in xrange(len(V)): |
---|
255 | a = A[i] |
---|
256 | for j in xrange(len(V)): |
---|
257 | a[j] *= norm[i] |
---|
258 | b = nl.solve(A,V) |
---|
259 | A = nl.inv(A) |
---|
260 | sig = np.diag(A) |
---|
261 | for i in xrange(len(V)): |
---|
262 | b[i] *= norm[i] |
---|
263 | sig[i] *= norm[i]*norm[i] |
---|
264 | sig[i] = math.sqrt(abs(sig[i])) |
---|
265 | sigback = [0,0,0] |
---|
266 | for j in range(Bv): |
---|
267 | background[j+3] += b[j] |
---|
268 | sigback.append(sig[j]) |
---|
269 | backgroundPrint(background,sigback) |
---|
270 | k = 0 |
---|
271 | delt = [] |
---|
272 | if Ka2: |
---|
273 | siginst = [0,0,0,0,0] |
---|
274 | else: |
---|
275 | siginst = [0,0,0] |
---|
276 | for j in range(6): |
---|
277 | if insref[j]: |
---|
278 | instVal[j+Ioff] += b[Bv+k]*0.5 |
---|
279 | siginst.append(sig[Bv+k]) |
---|
280 | delt.append(b[Bv+k]*0.5) |
---|
281 | k += 1 |
---|
282 | else: |
---|
283 | delt.append(0.0) |
---|
284 | siginst.append(0.0) |
---|
285 | delt.append(0.0) #dummies for azm |
---|
286 | siginst.append(0.0) |
---|
287 | instPrint(instVal,siginst,insLabels) |
---|
288 | inst[1] = [DataType,] |
---|
289 | for val in instVal: |
---|
290 | inst[1].append(val) |
---|
291 | B = Bv+Iv |
---|
292 | for peak in peaks: |
---|
293 | del peak[-1] # remove dip from end |
---|
294 | delsig = delt[0]*tand(peak[0]/2.0)**2+delt[1]*tand(peak[0]/2.0)+delt[2] |
---|
295 | delgam = delt[3]/cosd(peak[0]/2.0)+delt[4]*tand(peak[0]/2.0) |
---|
296 | delshl = delt[5] |
---|
297 | for j in range(0,len(peak[:-1]),2): |
---|
298 | if peak[j+1]: |
---|
299 | peak[j] += b[B]*0.5 |
---|
300 | B += 1 |
---|
301 | peak[4] += delsig |
---|
302 | if peak[4] < 0.0: |
---|
303 | print 'ERROR - negative sigma' |
---|
304 | return False,0,0,0,False |
---|
305 | peak[6] += delgam |
---|
306 | if peak[6] < 0.0: |
---|
307 | print 'ERROR - negative gamma' |
---|
308 | return False,0,0,0,False |
---|
309 | peak[8] += delshl |
---|
310 | if peak[8] < 0.0: |
---|
311 | print 'ERROR - negative SH/L' |
---|
312 | return False,0,0,0,False |
---|
313 | runtime = time.time()-begin |
---|
314 | data = [x,y,w,yc,yb,yd] |
---|
315 | return True,smin,Rwp,runtime,GoOn |
---|
316 | |
---|
317 | #some cell utilities |
---|
318 | #for these: H = [h,k,l]; A is as used in calc_rDsq; G - inv metric tensor, g - metric tensor; |
---|
319 | # cell - a,b,c,alp,bet,gam in A & deg |
---|
320 | |
---|
321 | def calc_rDsq(H,A): |
---|
322 | rdsq = H[0]*H[0]*A[0]+H[1]*H[1]*A[1]+H[2]*H[2]*A[2]+H[0]*H[1]*A[3]+H[0]*H[2]*A[4]+H[1]*H[2]*A[5] |
---|
323 | return rdsq |
---|
324 | |
---|
325 | def calc_rDsqZ(H,A,Z,tth,lam): |
---|
326 | rpd = math.pi/180. |
---|
327 | rdsq = calc_rDsq(H,A)+Z*math.sin(tth*rpd)*2.0*rpd/(lam*lam) |
---|
328 | return rdsq |
---|
329 | |
---|
330 | def calc_rVsq(A): |
---|
331 | rVsq = A[0]*A[1]*A[2]+0.25*(A[3]*A[4]*A[5]-A[0]*A[5]**2-A[1]*A[4]**2-A[2]*A[3]**2) |
---|
332 | if rVsq < 0: |
---|
333 | return 1 |
---|
334 | return rVsq |
---|
335 | |
---|
336 | def calc_rV(A): |
---|
337 | return math.sqrt(calc_rVsq(A)) |
---|
338 | |
---|
339 | def calc_V(A): |
---|
340 | return 1./calc_rV(A) |
---|
341 | |
---|
342 | def scaleAbyV(A,V): |
---|
343 | v = calc_V(A) |
---|
344 | scale = math.exp(math.log(v/V)/3.)**2 |
---|
345 | for i in range(6): |
---|
346 | A[i] *= scale |
---|
347 | |
---|
348 | def ranaxis(dmin,dmax): |
---|
349 | import random as rand |
---|
350 | return rand.random()*(dmax-dmin)+dmin |
---|
351 | |
---|
352 | def ran2axis(k,N): |
---|
353 | import random as rand |
---|
354 | T = 1.5+0.49*k/N |
---|
355 | # B = 0.99-0.49*k/N |
---|
356 | # B = 0.99-0.049*k/N |
---|
357 | B = 0.99-0.149*k/N |
---|
358 | R = (T-B)*rand.random()+B |
---|
359 | return R |
---|
360 | |
---|
361 | def ranNaxis(k,N): |
---|
362 | import random as rand |
---|
363 | T = 1.0+1.0*k/N |
---|
364 | B = 1.0-1.0*k/N |
---|
365 | R = (T-B)*rand.random()+B |
---|
366 | return R |
---|
367 | |
---|
368 | def ranAbyV(Bravais,dmin,dmax,V): |
---|
369 | cell = [0,0,0,0,0,0] |
---|
370 | bad = True |
---|
371 | while bad: |
---|
372 | bad = False |
---|
373 | cell = rancell(Bravais,dmin,dmax) |
---|
374 | G,g = cell2Gmat(cell) |
---|
375 | A = Gmat2A(G) |
---|
376 | if calc_rVsq(A) < 1: |
---|
377 | scaleAbyV(A,V) |
---|
378 | cell = A2cell(A) |
---|
379 | for i in range(3): |
---|
380 | bad |= cell[i] < dmin |
---|
381 | return A |
---|
382 | |
---|
383 | def ranAbyR(Bravais,A,k,N,ranFunc): |
---|
384 | R = ranFunc(k,N) |
---|
385 | if Bravais in [0,1,2]: #cubic - not used |
---|
386 | A[0] = A[1] = A[2] = A[0]*R |
---|
387 | A[3] = A[4] = A[5] = 0. |
---|
388 | elif Bravais in [3,4]: #hexagonal/trigonal |
---|
389 | A[0] = A[1] = A[3] = A[0]*R |
---|
390 | A[2] *= R |
---|
391 | A[4] = A[5] = 0. |
---|
392 | elif Bravais in [5,6]: #tetragonal |
---|
393 | A[0] = A[1] = A[0]*R |
---|
394 | A[2] *= R |
---|
395 | A[3] = A[4] = A[5] = 0. |
---|
396 | elif Bravais in [7,8,9,10]: #orthorhombic |
---|
397 | A[0] *= R |
---|
398 | A[1] *= R |
---|
399 | A[2] *= R |
---|
400 | A[3] = A[4] = A[5] = 0. |
---|
401 | elif Bravais in [11,12]: #monoclinic |
---|
402 | A[0] *= R |
---|
403 | A[1] *= R |
---|
404 | A[2] *= R |
---|
405 | A[4] *= R |
---|
406 | A[3] = A[5] = 0. |
---|
407 | else: #triclinic |
---|
408 | A[0] *= R |
---|
409 | A[1] *= R |
---|
410 | A[2] *= R |
---|
411 | A[3] *= R |
---|
412 | A[4] *= R |
---|
413 | A[5] *= R |
---|
414 | return A |
---|
415 | |
---|
416 | def rancell(Bravais,dmin,dmax): |
---|
417 | if Bravais in [0,1,2]: #cubic |
---|
418 | a = b = c = ranaxis(dmin,dmax) |
---|
419 | alp = bet = gam = 90 |
---|
420 | elif Bravais in [3,4]: #hexagonal/trigonal |
---|
421 | a = b = ranaxis(dmin,dmax) |
---|
422 | c = ranaxis(dmin,dmax) |
---|
423 | alp = bet = 90 |
---|
424 | gam = 120 |
---|
425 | elif Bravais in [5,6]: #tetragonal |
---|
426 | a = b = ranaxis(dmin,dmax) |
---|
427 | c = ranaxis(dmin,dmax) |
---|
428 | alp = bet = gam = 90 |
---|
429 | elif Bravais in [7,8,9,10]: #orthorhombic - F,I,C,P - a<b<c convention |
---|
430 | abc = [ranaxis(dmin,dmax),ranaxis(dmin,dmax),ranaxis(dmin,dmax)] |
---|
431 | abc.sort() |
---|
432 | a = abc[0] |
---|
433 | b = abc[1] |
---|
434 | c = abc[2] |
---|
435 | alp = bet = gam = 90 |
---|
436 | elif Bravais in [11,12]: #monoclinic - C,P - a<c convention |
---|
437 | ac = [ranaxis(dmin,dmax),ranaxis(dmin,dmax)] |
---|
438 | ac.sort() |
---|
439 | a = ac[0] |
---|
440 | b = ranaxis(dmin,dmax) |
---|
441 | c = ac[1] |
---|
442 | alp = gam = 90 |
---|
443 | bet = ranaxis(90.,130.) |
---|
444 | else: #triclinic - a<b<c convention |
---|
445 | abc = [ranaxis(dmin,dmax),ranaxis(dmin,dmax),ranaxis(dmin,dmax)] |
---|
446 | abc.sort() |
---|
447 | a = abc[0] |
---|
448 | b = abc[1] |
---|
449 | c = abc[2] |
---|
450 | r = 0.5*b/c |
---|
451 | alp = ranaxis(acosd(r),acosd(-r)) |
---|
452 | r = 0.5*a/c |
---|
453 | bet = ranaxis(acosd(r),acosd(-r)) |
---|
454 | r = 0.5*a/b |
---|
455 | gam = ranaxis(acosd(r),acosd(-r)) |
---|
456 | return [a,b,c,alp,bet,gam] |
---|
457 | |
---|
458 | def A2Gmat(A): |
---|
459 | G = np.zeros(shape=(3,3)) |
---|
460 | G = [[A[0],A[3]/2.,A[4]/2.], [A[3]/2.,A[1],A[5]/2.], [A[4]/2.,A[5]/2.,A[2]]] |
---|
461 | g = nl.inv(G) |
---|
462 | return G,g |
---|
463 | |
---|
464 | def fillgmat(cell): |
---|
465 | a,b,c,alp,bet,gam = cell |
---|
466 | g = np.array([[a*a,a*b*cosd(gam),a*c*cosd(bet)],[a*b*cosd(gam),b*b,b*c*cosd(alp)], |
---|
467 | [a*c*cosd(bet),b*c*cosd(alp),c*c]]) |
---|
468 | return g |
---|
469 | |
---|
470 | def cell2Gmat(cell): |
---|
471 | #returns reciprocal (G) & real (g) metric tensors |
---|
472 | g = fillgmat(cell) |
---|
473 | G = nl.inv(g) |
---|
474 | return G,g |
---|
475 | |
---|
476 | def invcell2Gmat(invcell): |
---|
477 | G = fillgmat(invcell) |
---|
478 | g = nl.inv(G) |
---|
479 | return G,g |
---|
480 | |
---|
481 | def Gmat2cell(g): |
---|
482 | #returns lattice parameters from real metric tensor (g) |
---|
483 | a = math.sqrt(max(0,g[0][0])) |
---|
484 | b = math.sqrt(max(0,g[1][1])) |
---|
485 | c = math.sqrt(max(0,g[2][2])) |
---|
486 | alp = acosd(g[2][1]/(b*c)) |
---|
487 | bet = acosd(g[2][0]/(a*c)) |
---|
488 | gam = acosd(g[0][1]/(a*b)) |
---|
489 | return a,b,c,alp,bet,gam |
---|
490 | |
---|
491 | def Gmat2A(G): |
---|
492 | return [G[0][0],G[1][1],G[2][2],2.*G[0][1],2.*G[0][2],2.*G[1][2]] |
---|
493 | |
---|
494 | def cell2A(cell): |
---|
495 | G,g = cell2Gmat(cell) |
---|
496 | return Gmat2A(G) |
---|
497 | |
---|
498 | def A2cell(A): |
---|
499 | G,g = A2Gmat(A) |
---|
500 | return Gmat2cell(g) |
---|
501 | |
---|
502 | def A2invcell(A): |
---|
503 | ainv = math.sqrt(max(0.,A[0])) |
---|
504 | binv = math.sqrt(max(0.,A[1])) |
---|
505 | cinv = math.sqrt(max(0.,A[2])) |
---|
506 | gaminv = acosd(max(-0.5,min(0.5,0.5*A[3]/(ainv*binv)))) |
---|
507 | betinv = acosd(max(-0.5,min(0.5,0.5*A[4]/(ainv*cinv)))) |
---|
508 | alpinv = acosd(max(-0.5,min(0.5,0.5*A[5]/(binv*cinv)))) |
---|
509 | return ainv,binv,cinv,alpinv,betinv,gaminv |
---|
510 | |
---|
511 | def cell2AB(cell): |
---|
512 | #from real lattice parameters - cell |
---|
513 | # returns A for Cartesian to crystal transformations A*X = x |
---|
514 | # and inverse B for crystal to Cartesian transformation B*x = X |
---|
515 | G,g = cell2Gmat(cell) #reciprocal & real metric tensors |
---|
516 | cosAlpStar = G[2][1]/math.sqrt(G[1][1]*G[2][2]) |
---|
517 | sinAlpStar = math.sqrt(1.0-cosAlpStar**2) |
---|
518 | B = np.eye(3) |
---|
519 | B *= cell[:3] |
---|
520 | A = np.zeros(shape=(3,3)) |
---|
521 | A[0][0] = 1.0 |
---|
522 | A[0][1] = cosd(cell[5]) |
---|
523 | A[1][1] = sinAlpStar*sind(cell[5]) |
---|
524 | A[1][2] = -cosAlpStar*sind(cell[5]) |
---|
525 | A[0][2] = cosd(cell[4]) |
---|
526 | A[2][2] = sind(cell[4]) |
---|
527 | B = np.dot(A,B) |
---|
528 | A = nl.inv(B) |
---|
529 | return A,B |
---|
530 | |
---|
531 | def makeMat(Angle,Axis): |
---|
532 | #Make rotation matrix from Angle in degrees,Axis =0 for rotation about x, =1 for about y, etc. |
---|
533 | cs = cosd(Angle) |
---|
534 | ss = sind(Angle) |
---|
535 | M = np.array(([1.,0.,0.],[0.,cs,-ss],[0.,ss,cs]),dtype=np.float32) |
---|
536 | return np.roll(np.roll(M,Axis,axis=0),Axis,axis=1) |
---|
537 | |
---|
538 | def MaxIndex(dmin,A): |
---|
539 | #finds maximum allowed hkl for given A within dmin |
---|
540 | Hmax = [0,0,0] |
---|
541 | try: |
---|
542 | cell = A2cell(A) |
---|
543 | except: |
---|
544 | cell = [1,1,1,90,90,90] |
---|
545 | for i in range(3): |
---|
546 | Hmax[i] = int(round(cell[i]/dmin)) |
---|
547 | return Hmax |
---|
548 | |
---|
549 | def sortHKLd(HKLd,ifreverse,ifdup): |
---|
550 | #HKLd is a list of [h,k,l,d,...]; ifreverse=True for largest d first |
---|
551 | #ifdup = True if duplicate d-spacings allowed |
---|
552 | T = [] |
---|
553 | for i,H in enumerate(HKLd): |
---|
554 | if ifdup: |
---|
555 | T.append((H[3],i)) |
---|
556 | else: |
---|
557 | T.append(H[3]) |
---|
558 | D = dict(zip(T,HKLd)) |
---|
559 | T.sort() |
---|
560 | if ifreverse: |
---|
561 | T.reverse() |
---|
562 | X = [] |
---|
563 | okey = '' |
---|
564 | for key in T: |
---|
565 | if key != okey: X.append(D[key]) #remove duplicate d-spacings |
---|
566 | okey = key |
---|
567 | return X |
---|
568 | |
---|
569 | def sortM20(cells): |
---|
570 | #cells is M20,X20,Bravais,a,b,c,alp,bet,gam |
---|
571 | #sort highest M20 1st |
---|
572 | T = [] |
---|
573 | for i,M in enumerate(cells): |
---|
574 | T.append((M[0],i)) |
---|
575 | D = dict(zip(T,cells)) |
---|
576 | T.sort() |
---|
577 | T.reverse() |
---|
578 | X = [] |
---|
579 | for key in T: |
---|
580 | X.append(D[key]) |
---|
581 | return X |
---|
582 | |
---|
583 | |
---|
584 | def GenHBravais(dmin,Bravais,A): |
---|
585 | # dmin - minimum d-spacing |
---|
586 | # Bravais in range(14) to indicate Bravais lattice; 0-2 cubic, 3,4 - hexagonal/trigonal, |
---|
587 | # 5,6 - tetragonal, 7-10 - orthorhombic, 11,12 - monoclinic, 13 - triclinic |
---|
588 | # A - as defined in calc_rDsq |
---|
589 | # returns HKL = [h,k,l,d,0] sorted so d largest first |
---|
590 | import math |
---|
591 | if Bravais in [9,11]: |
---|
592 | Cent = 'C' |
---|
593 | elif Bravais in [1,5,8]: |
---|
594 | Cent = 'I' |
---|
595 | elif Bravais in [0,7]: |
---|
596 | Cent = 'F' |
---|
597 | elif Bravais in [3]: |
---|
598 | Cent = 'R' |
---|
599 | else: |
---|
600 | Cent = 'P' |
---|
601 | Hmax = MaxIndex(dmin,A) |
---|
602 | dminsq = 1./(dmin**2) |
---|
603 | HKL = [] |
---|
604 | if Bravais == 13: #triclinic |
---|
605 | for l in range(-Hmax[2],Hmax[2]+1): |
---|
606 | for k in range(-Hmax[1],Hmax[1]+1): |
---|
607 | hmin = 0 |
---|
608 | if (k < 0): hmin = 1 |
---|
609 | if (k ==0 and l < 0): hmin = 1 |
---|
610 | for h in range(hmin,Hmax[0]+1): |
---|
611 | H=[h,k,l] |
---|
612 | rdsq = calc_rDsq(H,A) |
---|
613 | if 0 < rdsq <= dminsq: |
---|
614 | HKL.append([h,k,l,rdsq2d(rdsq,6),-1]) |
---|
615 | elif Bravais in [11,12]: #monoclinic - b unique |
---|
616 | Hmax = SwapIndx(2,Hmax) |
---|
617 | for h in range(Hmax[0]+1): |
---|
618 | for k in range(-Hmax[1],Hmax[1]+1): |
---|
619 | lmin = 0 |
---|
620 | if k < 0:lmin = 1 |
---|
621 | for l in range(lmin,Hmax[2]+1): |
---|
622 | [h,k,l] = SwapIndx(-2,[h,k,l]) |
---|
623 | H = [] |
---|
624 | if CentCheck(Cent,[h,k,l]): H=[h,k,l] |
---|
625 | if H: |
---|
626 | rdsq = calc_rDsq(H,A) |
---|
627 | if 0 < rdsq <= dminsq: |
---|
628 | HKL.append([h,k,l,rdsq2d(rdsq,6),-1]) |
---|
629 | [h,k,l] = SwapIndx(2,[h,k,l]) |
---|
630 | elif Bravais in [7,8,9,10]: #orthorhombic |
---|
631 | for h in range(Hmax[0]+1): |
---|
632 | for k in range(Hmax[1]+1): |
---|
633 | for l in range(Hmax[2]+1): |
---|
634 | H = [] |
---|
635 | if CentCheck(Cent,[h,k,l]): H=[h,k,l] |
---|
636 | if H: |
---|
637 | rdsq = calc_rDsq(H,A) |
---|
638 | if 0 < rdsq <= dminsq: |
---|
639 | HKL.append([h,k,l,rdsq2d(rdsq,6),-1]) |
---|
640 | elif Bravais in [5,6]: #tetragonal |
---|
641 | for l in range(Hmax[2]+1): |
---|
642 | for k in range(Hmax[1]+1): |
---|
643 | for h in range(k,Hmax[0]+1): |
---|
644 | H = [] |
---|
645 | if CentCheck(Cent,[h,k,l]): H=[h,k,l] |
---|
646 | if H: |
---|
647 | rdsq = calc_rDsq(H,A) |
---|
648 | if 0 < rdsq <= dminsq: |
---|
649 | HKL.append([h,k,l,rdsq2d(rdsq,6),-1]) |
---|
650 | elif Bravais in [3,4]: |
---|
651 | lmin = 0 |
---|
652 | if Bravais == 3: lmin = -Hmax[2] #hexagonal/trigonal |
---|
653 | for l in range(lmin,Hmax[2]+1): |
---|
654 | for k in range(Hmax[1]+1): |
---|
655 | hmin = k |
---|
656 | if l < 0: hmin += 1 |
---|
657 | for h in range(hmin,Hmax[0]+1): |
---|
658 | H = [] |
---|
659 | if CentCheck(Cent,[h,k,l]): H=[h,k,l] |
---|
660 | if H: |
---|
661 | rdsq = calc_rDsq(H,A) |
---|
662 | if 0 < rdsq <= dminsq: |
---|
663 | HKL.append([h,k,l,rdsq2d(rdsq,6),-1]) |
---|
664 | |
---|
665 | else: #cubic |
---|
666 | for l in range(Hmax[2]+1): |
---|
667 | for k in range(l,Hmax[1]+1): |
---|
668 | for h in range(k,Hmax[0]+1): |
---|
669 | H = [] |
---|
670 | if CentCheck(Cent,[h,k,l]): H=[h,k,l] |
---|
671 | if H: |
---|
672 | rdsq = calc_rDsq(H,A) |
---|
673 | if 0 < rdsq <= dminsq: |
---|
674 | HKL.append([h,k,l,rdsq2d(rdsq,6),-1]) |
---|
675 | return sortHKLd(HKL,True,False) |
---|
676 | |
---|
677 | def SwapXY(x,y): |
---|
678 | return [y,x] |
---|
679 | |
---|
680 | def SwapIndx(Axis,H): |
---|
681 | if Axis in [1,-1]: |
---|
682 | return H |
---|
683 | elif Axis in [2,-3]: |
---|
684 | return [H[1],H[2],H[0]] |
---|
685 | else: |
---|
686 | return [H[2],H[0],H[1]] |
---|
687 | |
---|
688 | def CentCheck(Cent,H): |
---|
689 | h,k,l = H |
---|
690 | if Cent == 'A' and (k+l)%2: |
---|
691 | return False |
---|
692 | elif Cent == 'B' and (h+l)%2: |
---|
693 | return False |
---|
694 | elif Cent == 'C' and (h+k)%2: |
---|
695 | return False |
---|
696 | elif Cent == 'I' and (h+k+l)%2: |
---|
697 | return False |
---|
698 | elif Cent == 'F' and ((h+k)%2 or (h+l)%2 or (k+l)%2): |
---|
699 | return False |
---|
700 | elif Cent == 'R' and (-h+k+l)%3: |
---|
701 | return False |
---|
702 | else: |
---|
703 | return True |
---|
704 | |
---|
705 | def GenHLaue(dmin,Laue,Cent,Axis,A): |
---|
706 | # dmin - minimum d-spacing |
---|
707 | # Laue - Laue group symbol = '-1','2/m','mmmm','4/m','6/m','4/mmm','6/mmm', |
---|
708 | # '3m1', '31m', '3', '3R', '3mR', 'm3', 'm3m' |
---|
709 | # Cent - lattice centering = 'P','A','B','C','I','F' |
---|
710 | # Axis - code for unique monoclinic axis = 'a','b','c' |
---|
711 | # A - 6 terms as defined in calc_rDsq |
---|
712 | # returns - HKL = list of [h,k,l,d] sorted with largest d first and is unique |
---|
713 | # part of reciprocal space ignoring anomalous dispersion |
---|
714 | import math |
---|
715 | Hmax = MaxIndex(dmin,A) |
---|
716 | dminsq = 1./(dmin**2) |
---|
717 | HKL = [] |
---|
718 | if Laue == '-1': #triclinic |
---|
719 | for l in range(-Hmax[2],Hmax[2]+1): |
---|
720 | for k in range(-Hmax[1],Hmax[1]+1): |
---|
721 | hmin = 0 |
---|
722 | if (k < 0) or (k ==0 and l < 0): hmin = 1 |
---|
723 | for h in range(hmin,Hmax[0]+1): |
---|
724 | H = [] |
---|
725 | if CentCheck(Cent,[h,k,l]): H=[h,k,l] |
---|
726 | rdsq = calc_rDsq(H,A) |
---|
727 | if 0 < rdsq <= dminsq: |
---|
728 | HKL.append([h,k,l,1/math.sqrt(rdsq)]) |
---|
729 | elif Laue == '2/m': #monoclinic |
---|
730 | Hmax = SwapIndx(Axis,Hmax) |
---|
731 | for h in range(Hmax[0]+1): |
---|
732 | for k in range(-Hmax[1],Hmax[1]+1): |
---|
733 | lmin = 0 |
---|
734 | if k < 0:lmin = 1 |
---|
735 | for l in range(lmin,Hmax[2]+1): |
---|
736 | [h,k,l] = SwapIndx(-Axis,[h,k,l]) |
---|
737 | H = [] |
---|
738 | if CentCheck(Cent,[h,k,l]): H=[h,k,l] |
---|
739 | if H: |
---|
740 | rdsq = calc_rDsq(H,A) |
---|
741 | if 0 < rdsq <= dminsq: |
---|
742 | HKL.append([h,k,l,1/math.sqrt(rdsq)]) |
---|
743 | [h,k,l] = SwapIndx(Axis,[h,k,l]) |
---|
744 | elif Laue in ['mmm','4/m','6/m']: #orthorhombic |
---|
745 | for l in range(Hmax[2]+1): |
---|
746 | for h in range(Hmax[0]+1): |
---|
747 | kmin = 1 |
---|
748 | if Laue == 'mmm' or h ==0: kmin = 0 |
---|
749 | for k in range(kmin,Hmax[2]+1): |
---|
750 | H = [] |
---|
751 | if CentCheck(Cent,[h,k,l]): H=[h,k,l] |
---|
752 | if H: |
---|
753 | rdsq = calc_rDsq(H,A) |
---|
754 | if 0 < rdsq <= dminsq: |
---|
755 | HKL.append([h,k,l,1/math.sqrt(rdsq)]) |
---|
756 | elif Laue in ['4/mmm','6/mmm']: #tetragonal & hexagonal |
---|
757 | for l in range(Hmax[2]+1): |
---|
758 | for h in range(Hmax[0]+1): |
---|
759 | for k in range(h+1): |
---|
760 | H = [] |
---|
761 | if CentCheck(Cent,[h,k,l]): H=[h,k,l] |
---|
762 | if H: |
---|
763 | rdsq = calc_rDsq(H,A) |
---|
764 | if 0 < rdsq <= dminsq: |
---|
765 | HKL.append([h,k,l,1/math.sqrt(rdsq)]) |
---|
766 | elif Laue in ['3m1','31m','3','3R','3mR']: #trigonals |
---|
767 | for l in range(-Hmax[2],Hmax[2]+1): |
---|
768 | hmin = 0 |
---|
769 | if l < 0: hmin = 1 |
---|
770 | for h in range(hmin,Hmax[0]+1): |
---|
771 | if Laue in ['3R','3']: |
---|
772 | kmax = h |
---|
773 | kmin = -int((h-1)/2.) |
---|
774 | else: |
---|
775 | kmin = 0 |
---|
776 | kmax = h |
---|
777 | if Laue in ['3m1','3mR'] and l < 0: kmax = h-1 |
---|
778 | if Laue == '31m' and l < 0: kmin = 1 |
---|
779 | for k in range(kmin,kmax+1): |
---|
780 | H = [] |
---|
781 | if CentCheck(Cent,[h,k,l]): H=[h,k,l] |
---|
782 | if H: |
---|
783 | rdsq = calc_rDsq(H,A) |
---|
784 | if 0 < rdsq <= dminsq: |
---|
785 | HKL.append([h,k,l,1/math.sqrt(rdsq)]) |
---|
786 | else: #cubic |
---|
787 | for h in range(Hmax[0]+1): |
---|
788 | for k in range(h+1): |
---|
789 | lmin = 0 |
---|
790 | lmax = k |
---|
791 | if Laue =='m3': |
---|
792 | lmax = h-1 |
---|
793 | if h == k: lmax += 1 |
---|
794 | for l in range(lmin,lmax+1): |
---|
795 | H = [] |
---|
796 | if CentCheck(Cent,[h,k,l]): H=[h,k,l] |
---|
797 | if H: |
---|
798 | rdsq = calc_rDsq(H,A) |
---|
799 | if 0 < rdsq <= dminsq: |
---|
800 | HKL.append([h,k,l,1/math.sqrt(rdsq)]) |
---|
801 | return sortHKLd(HKL,True,True) |
---|
802 | |
---|
803 | def calc_M20(peaks,HKL): |
---|
804 | diff = 0 |
---|
805 | X20 = 0 |
---|
806 | for Nobs20,peak in enumerate(peaks): |
---|
807 | if peak[3]: |
---|
808 | Qobs = 1.0/peak[7]**2 |
---|
809 | Qcalc = 1.0/peak[8]**2 |
---|
810 | diff += abs(Qobs-Qcalc) |
---|
811 | elif peak[2]: |
---|
812 | X20 += 1 |
---|
813 | if Nobs20 == 19: |
---|
814 | d20 = peak[7] |
---|
815 | break |
---|
816 | else: |
---|
817 | d20 = peak[7] |
---|
818 | Nobs20 = len(peaks) |
---|
819 | for N20,hkl in enumerate(HKL): |
---|
820 | if hkl[3] < d20: |
---|
821 | break |
---|
822 | eta = diff/Nobs20 |
---|
823 | Q20 = 1.0/d20**2 |
---|
824 | if diff: |
---|
825 | M20 = Q20/(2.0*diff) |
---|
826 | else: |
---|
827 | M20 = 0 |
---|
828 | M20 /= (1.+X20) |
---|
829 | return M20,X20 |
---|
830 | |
---|
831 | def IndexPeaks(peaks,HKL): |
---|
832 | import bisect |
---|
833 | hklds = [1000.0] #make bounded list of available d-spacings |
---|
834 | N = len(HKL) |
---|
835 | if N == 0: return False |
---|
836 | for hkl in HKL: |
---|
837 | hklds.append(hkl[3]) |
---|
838 | hklds.append(0.0) |
---|
839 | hklds.sort() # ascending sort - upper bound at end |
---|
840 | hklmax = [0,0,0] |
---|
841 | for ipk,peak in enumerate(peaks): |
---|
842 | if peak[2]: |
---|
843 | i = bisect.bisect_right(hklds,peak[7]) # find peak position in hkl list |
---|
844 | dm = peak[7]-hklds[i-1] # peak to neighbor hkls in list |
---|
845 | dp = hklds[i]-peak[7] |
---|
846 | pos = N-i # reverse the order |
---|
847 | if dp > dm: pos += 1 # closer to upper than lower |
---|
848 | hkl = HKL[pos] # put in hkl |
---|
849 | if hkl[4] >= 0: # peak already assigned - test if this one better |
---|
850 | opeak = peaks[hkl[4]] |
---|
851 | dold = abs(opeak[7]-hkl[3]) |
---|
852 | dnew = min(dm,dp) |
---|
853 | if dold > dnew: # new better - zero out old |
---|
854 | for j in range(3): |
---|
855 | opeak[j+4] = 0 |
---|
856 | opeak[8] = 0. |
---|
857 | else: # old better - do nothing |
---|
858 | continue |
---|
859 | hkl[4] = ipk |
---|
860 | for j in range(3): |
---|
861 | peak[j+4] = hkl[j] |
---|
862 | peak[8] = hkl[3] # fill in d-calc |
---|
863 | for peak in peaks: |
---|
864 | peak[3] = False |
---|
865 | if peak[2]: |
---|
866 | if peak[8] > 0.: |
---|
867 | for j in range(3): |
---|
868 | if abs(peak[j+4]) > hklmax[j]: hklmax[j] = abs(peak[j+4]) |
---|
869 | peak[3] = True |
---|
870 | if hklmax[0]*hklmax[1]*hklmax[2] > 0: |
---|
871 | return True |
---|
872 | else: |
---|
873 | return False |
---|
874 | |
---|
875 | def FitHKL(ibrav,peaks,A,wtP): |
---|
876 | def ShiftTest(a,b): |
---|
877 | if b < -0.1*a: |
---|
878 | b = -0.0001*a |
---|
879 | return b |
---|
880 | smin = 0. |
---|
881 | first = True |
---|
882 | for peak in peaks: |
---|
883 | if peak[2] and peak[3]: |
---|
884 | h,k,l = H = peak[4:7] |
---|
885 | Qo = 1./peak[7]**2 |
---|
886 | Qc = calc_rDsq(H,A) |
---|
887 | try: |
---|
888 | peak[8] = 1./math.sqrt(Qc) |
---|
889 | except: |
---|
890 | print A2invcell(A) |
---|
891 | delt = Qo-Qc |
---|
892 | smin += delt**2 |
---|
893 | dp = [] |
---|
894 | if ibrav in [0,1,2]: #m3m |
---|
895 | dp.append(h*h+k*k+l*l) |
---|
896 | elif ibrav in [3,4]: #R3H, P3/m & P6/mmm |
---|
897 | dp.append(h*h+k*k+h*k) |
---|
898 | dp.append(l*l) |
---|
899 | elif ibrav in [5,6]: #4/mmm |
---|
900 | dp.append(h*h+k*k) |
---|
901 | dp.append(l*l) |
---|
902 | elif ibrav in [7,8,9,10]: #mmm |
---|
903 | dp.append(h*h) |
---|
904 | dp.append(k*k) |
---|
905 | dp.append(l*l) |
---|
906 | elif ibrav in [11,12]: #2/m |
---|
907 | dp.append(h*h) |
---|
908 | dp.append(k*k) |
---|
909 | dp.append(l*l) |
---|
910 | dp.append(h*l) |
---|
911 | else: #1 |
---|
912 | # derivatives for a0*h^2+a1*k^2+a2*l^2+a3*h*k+a4*h*l+a5*k*l |
---|
913 | dp.append(h*h) |
---|
914 | dp.append(k*k) |
---|
915 | dp.append(l*l) |
---|
916 | dp.append(h*k) |
---|
917 | dp.append(h*l) |
---|
918 | dp.append(k*l) |
---|
919 | if first: |
---|
920 | first = False |
---|
921 | M = len(dp) |
---|
922 | B = np.zeros(shape=(M,M)) |
---|
923 | V = np.zeros(shape=(M)) |
---|
924 | dwt = peak[7]**wtP |
---|
925 | B,V = pyp.buildmv(delt*dwt,dwt,M,dp,B,V) |
---|
926 | if nl.det(B) > 0.0: |
---|
927 | try: |
---|
928 | b = nl.solve(B,V) |
---|
929 | B = nl.inv(B) |
---|
930 | sig = np.diag(B) |
---|
931 | except SingularMatrix: |
---|
932 | return False,0 |
---|
933 | if ibrav in [0,1,2]: #m3m |
---|
934 | A[0] += ShiftTest(A[0],b[0]) |
---|
935 | A[1] = A[2] = A[0] |
---|
936 | elif ibrav in [3,4]: #R3H, P3/m & P6/mmm |
---|
937 | A[0] += ShiftTest(A[0],b[0]) |
---|
938 | A[1] = A[3] = A[0] |
---|
939 | A[2] += ShiftTest(A[2],b[1]) |
---|
940 | elif ibrav in [5,6]: #4/mmm |
---|
941 | A[0] += ShiftTest(A[0],b[0]) |
---|
942 | A[1] = A[0] |
---|
943 | A[2] += ShiftTest(A[2],b[1]) |
---|
944 | elif ibrav in [7,8,9,10]: #mmm |
---|
945 | for i in range(3): |
---|
946 | A[i] += ShiftTest(A[i],b[i]) |
---|
947 | elif ibrav in [11,12]: #2/m |
---|
948 | for i in range(3): |
---|
949 | A[i] += ShiftTest(A[i],b[i]) |
---|
950 | A[4] += ShiftTest(A[4],b[3]) |
---|
951 | A[4] = min(1.4*math.sqrt(A[0]*A[2]),A[4]) #min beta star = 45 |
---|
952 | else: #1 |
---|
953 | oldV = math.sqrt(1./calc_rVsq(A)) |
---|
954 | oldA = A[:] |
---|
955 | for i in range(6): |
---|
956 | A[i] += b[i]*0.2 |
---|
957 | A[3] = min(1.1*math.sqrt(max(0,A[1]*A[2])),A[3]) |
---|
958 | A[4] = min(1.1*math.sqrt(max(0,A[0]*A[2])),A[4]) |
---|
959 | A[5] = min(1.1*math.sqrt(max(0,A[0]*A[1])),A[5]) |
---|
960 | ratio = math.sqrt(1./calc_rVsq(A))/oldV |
---|
961 | if 0.9 > ratio or ratio > 1.1: |
---|
962 | A = oldA |
---|
963 | # else: |
---|
964 | # print B |
---|
965 | # print V |
---|
966 | # for peak in peaks: |
---|
967 | # print peak |
---|
968 | return True,smin |
---|
969 | |
---|
970 | def FitHKLZ(ibrav,peaks,Z,A): |
---|
971 | return A,Z |
---|
972 | |
---|
973 | def rotOrthoA(A): |
---|
974 | return [A[1],A[2],A[0],0,0,0] |
---|
975 | |
---|
976 | def swapMonoA(A): |
---|
977 | return [A[2],A[1],A[0],0,A[4],0] |
---|
978 | |
---|
979 | def oddPeak(indx,peaks): |
---|
980 | noOdd = True |
---|
981 | for peak in peaks: |
---|
982 | H = peak[4:7] |
---|
983 | if H[indx] % 2: |
---|
984 | noOdd = False |
---|
985 | return noOdd |
---|
986 | |
---|
987 | def halfCell(ibrav,A,peaks): |
---|
988 | if ibrav in [0,1,2]: |
---|
989 | if oddPeak(0,peaks): |
---|
990 | A[0] *= 2 |
---|
991 | A[1] = A[2] = A[0] |
---|
992 | elif ibrav in [3,4,5,6]: |
---|
993 | if oddPeak(0,peaks): |
---|
994 | A[0] *= 2 |
---|
995 | A[1] = A[0] |
---|
996 | if oddPeak(2,peaks): |
---|
997 | A[2] *=2 |
---|
998 | else: |
---|
999 | if oddPeak(0,peaks): |
---|
1000 | A[0] *=2 |
---|
1001 | if oddPeak(1,peaks): |
---|
1002 | A[1] *=2 |
---|
1003 | if oddPeak(2,peaks): |
---|
1004 | A[2] *=2 |
---|
1005 | return A |
---|
1006 | |
---|
1007 | def getDmin(peaks): |
---|
1008 | return peaks[-1][7] |
---|
1009 | |
---|
1010 | def getDmax(peaks): |
---|
1011 | return peaks[0][7] |
---|
1012 | |
---|
1013 | def refinePeaks(peaks,ibrav,A): |
---|
1014 | dmin = getDmin(peaks) |
---|
1015 | smin = 1.0e10 |
---|
1016 | pwr = 6 |
---|
1017 | maxTries = 10 |
---|
1018 | if ibrav == 13: |
---|
1019 | pwr = 4 |
---|
1020 | maxTries = 10 |
---|
1021 | OK = False |
---|
1022 | tries = 0 |
---|
1023 | HKL = GenHBravais(dmin,ibrav,A) |
---|
1024 | while IndexPeaks(peaks,HKL): |
---|
1025 | Pwr = pwr - 2*(tries % 2) |
---|
1026 | HKL = [] |
---|
1027 | tries += 1 |
---|
1028 | osmin = smin |
---|
1029 | oldA = A |
---|
1030 | OK,smin = FitHKL(ibrav,peaks,A,Pwr) |
---|
1031 | for a in A[:3]: |
---|
1032 | if a < 0: |
---|
1033 | A = oldA |
---|
1034 | OK = False |
---|
1035 | break |
---|
1036 | if OK: |
---|
1037 | HKL = GenHBravais(dmin,ibrav,A) |
---|
1038 | if len(HKL) == 0: break #absurd cell obtained! |
---|
1039 | rat = (osmin-smin)/smin |
---|
1040 | if abs(rat) < 1.0e-5 or not OK: break |
---|
1041 | if tries > maxTries: break |
---|
1042 | if OK: |
---|
1043 | OK,smin = FitHKL(ibrav,peaks,A,4) |
---|
1044 | M20,X20 = calc_M20(peaks,HKL) |
---|
1045 | return len(HKL),M20,X20 |
---|
1046 | |
---|
1047 | def findBestCell(dlg,ncMax,A,Ntries,ibrav,peaks,V1): |
---|
1048 | # dlg & ncMax are used for wx progress bar |
---|
1049 | # A != 0 find the best A near input A, |
---|
1050 | # A = 0 for random cell, volume normalized to V1; |
---|
1051 | # returns number of generated hkls, M20, X20 & A for best found |
---|
1052 | mHKL = [3,3,3, 5,5, 5,5, 7,7,7,7, 9,9, 10] |
---|
1053 | dmin = getDmin(peaks)-0.05 |
---|
1054 | amin = 2.5 |
---|
1055 | amax = 5.*getDmax(peaks) |
---|
1056 | Asave = [] |
---|
1057 | GoOn = True |
---|
1058 | if A: |
---|
1059 | HKL = GenHBravais(dmin,ibrav,A[:]) |
---|
1060 | if len(HKL) > mHKL[ibrav]: |
---|
1061 | IndexPeaks(peaks,HKL) |
---|
1062 | Asave.append([calc_M20(peaks,HKL),A[:]]) |
---|
1063 | tries = 0 |
---|
1064 | while tries < Ntries: |
---|
1065 | if A: |
---|
1066 | Anew = ranAbyR(ibrav,A[:],tries+1,Ntries,ran2axis) |
---|
1067 | if ibrav in [11,12,13]: |
---|
1068 | Anew = ranAbyR(ibrav,A[:],tries/10+1,Ntries,ran2axis) |
---|
1069 | else: |
---|
1070 | Anew = ranAbyV(ibrav,amin,amax,V1) |
---|
1071 | HKL = GenHBravais(dmin,ibrav,Anew) |
---|
1072 | if len(HKL) > mHKL[ibrav] and IndexPeaks(peaks,HKL): |
---|
1073 | Lhkl,M20,X20 = refinePeaks(peaks,ibrav,Anew) |
---|
1074 | Asave.append([calc_M20(peaks,HKL),Anew[:]]) |
---|
1075 | if ibrav == 9: #C-centered orthorhombic |
---|
1076 | for i in range(2): |
---|
1077 | Anew = rotOrthoA(Anew[:]) |
---|
1078 | Lhkl,M20,X20 = refinePeaks(peaks,ibrav,Anew) |
---|
1079 | HKL = GenHBravais(dmin,ibrav,Anew) |
---|
1080 | IndexPeaks(peaks,HKL) |
---|
1081 | Asave.append([calc_M20(peaks,HKL),Anew[:]]) |
---|
1082 | elif ibrav == 11: #C-centered monoclinic |
---|
1083 | Anew = swapMonoA(Anew[:]) |
---|
1084 | Lhkl,M20,X20 = refinePeaks(peaks,ibrav,Anew) |
---|
1085 | HKL = GenHBravais(dmin,ibrav,Anew) |
---|
1086 | IndexPeaks(peaks,HKL) |
---|
1087 | Asave.append([calc_M20(peaks,HKL),Anew[:]]) |
---|
1088 | else: |
---|
1089 | break |
---|
1090 | Nc = len(HKL) |
---|
1091 | if Nc >= ncMax: |
---|
1092 | GoOn = False |
---|
1093 | elif dlg: |
---|
1094 | GoOn = dlg.Update(Nc)[0] |
---|
1095 | if not GoOn: |
---|
1096 | break |
---|
1097 | tries += 1 |
---|
1098 | X = sortM20(Asave) |
---|
1099 | if X: |
---|
1100 | Lhkl,M20,X20 = refinePeaks(peaks,ibrav,X[0][1]) |
---|
1101 | return GoOn,Lhkl,M20,X20,X[0][1] |
---|
1102 | else: |
---|
1103 | return GoOn,0,0,0,0 |
---|
1104 | |
---|
1105 | def monoCellReduce(ibrav,A): |
---|
1106 | a,b,c,alp,bet,gam = A2cell(A) |
---|
1107 | G,g = A2Gmat(A) |
---|
1108 | if ibrav in [11]: |
---|
1109 | u = [0,0,-1] |
---|
1110 | v = [1,0,2] |
---|
1111 | anew = math.sqrt(np.dot(np.dot(v,g),v)) |
---|
1112 | if anew < a: |
---|
1113 | cang = np.dot(np.dot(u,g),v)/(anew*c) |
---|
1114 | beta = acosd(-abs(cang)) |
---|
1115 | A = cell2A([anew,b,c,90,beta,90]) |
---|
1116 | else: |
---|
1117 | u = [-1,0,0] |
---|
1118 | v = [1,0,1] |
---|
1119 | cnew = math.sqrt(np.dot(np.dot(v,g),v)) |
---|
1120 | if cnew < c: |
---|
1121 | cang = np.dot(np.dot(u,g),v)/(a*cnew) |
---|
1122 | beta = acosd(-abs(cang)) |
---|
1123 | A = cell2A([a,b,cnew,90,beta,90]) |
---|
1124 | return A |
---|
1125 | |
---|
1126 | def DoIndexPeaks(peaks,inst,controls,bravais): |
---|
1127 | |
---|
1128 | def peakDspace(peaks,A): |
---|
1129 | for peak in peaks: |
---|
1130 | if peak[3]: |
---|
1131 | dsq = calc_rDsq(peak[4:7],A) |
---|
1132 | if dsq > 0: |
---|
1133 | peak[8] = 1./math.sqrt(dsq) |
---|
1134 | return |
---|
1135 | delt = 0.05 #lowest d-spacing cushion - can be fixed? |
---|
1136 | amin = 2.5 |
---|
1137 | amax = 5.0*getDmax(peaks) |
---|
1138 | dmin = getDmin(peaks)-delt |
---|
1139 | bravaisNames = ['Cubic-F','Cubic-I','Cubic-P','Trigonal-R','Trigonal/Hexagonal-P', |
---|
1140 | 'Tetragonal-I','Tetragonal-P','Orthorhombic-F','Orthorhombic-I','Orthorhombic-C', |
---|
1141 | 'Orthorhombic-P','Monoclinic-C','Monoclinic-P','Triclinic'] |
---|
1142 | tries = ['1st','2nd','3rd','4th','5th','6th','7th','8th','9th','10th'] |
---|
1143 | N1s = [1,1,1, 5,5, 5,5, 50,50,50,50, 50,50, 200] |
---|
1144 | N2s = [1,1,1, 2,2, 2,2, 2,2,2,2, 2,2, 4] |
---|
1145 | Nm = [1,1,1, 1,1, 1,1, 1,1,1,1, 2,2, 4] |
---|
1146 | Nobs = len(peaks) |
---|
1147 | wave = inst[1] |
---|
1148 | if len(inst) > 10: |
---|
1149 | zero = inst[3] |
---|
1150 | else: |
---|
1151 | zero = inst[2] |
---|
1152 | print "%s %8.5f %6.3f" % ('wavelength, zero =',wave,zero) |
---|
1153 | print "%s %8.3f %8.3f" % ('lattice parameter range = ',amin,amax) |
---|
1154 | ifzero,maxzero,ncno = controls[:3] |
---|
1155 | ncMax = Nobs*ncno |
---|
1156 | print "%s %d %s %d %s %d" % ('change zero =',ifzero,'Nc/No max =',ncno,' Max Nc =',ncno*Nobs) |
---|
1157 | cells = [] |
---|
1158 | for ibrav in range(14): |
---|
1159 | begin = time.time() |
---|
1160 | if bravais[ibrav]: |
---|
1161 | print 'cell search for ',bravaisNames[ibrav] |
---|
1162 | print ' M20 X20 Nc a b c alpha beta gamma volume V-test' |
---|
1163 | V1 = controls[3] |
---|
1164 | bestM20 = 0 |
---|
1165 | topM20 = 0 |
---|
1166 | cycle = 0 |
---|
1167 | while cycle < 5: |
---|
1168 | dlg = wx.ProgressDialog("Generated reflections",tries[cycle]+" cell search for "+bravaisNames[ibrav],ncMax, \ |
---|
1169 | style = wx.PD_ELAPSED_TIME|wx.PD_AUTO_HIDE|wx.PD_REMAINING_TIME|wx.PD_CAN_ABORT) |
---|
1170 | screenSize = wx.DisplaySize() |
---|
1171 | Size = dlg.GetSize() |
---|
1172 | dlg.SetPosition(wx.Point(screenSize[0]-Size[0]-300,0)) |
---|
1173 | try: |
---|
1174 | GoOn = True |
---|
1175 | while GoOn: #Loop over increment of volume |
---|
1176 | N2 = 0 |
---|
1177 | while N2 < N2s[ibrav]: #Table 2 step (iii) |
---|
1178 | if ibrav > 2: |
---|
1179 | if not N2: |
---|
1180 | GoOn,Nc,M20,X20,A = findBestCell(dlg,ncMax,0,Nm[ibrav]*N1s[ibrav],ibrav,peaks,V1) |
---|
1181 | if A: |
---|
1182 | GoOn,Nc,M20,X20,A = findBestCell(dlg,ncMax,A[:],N1s[ibrav],ibrav,peaks,0) |
---|
1183 | else: |
---|
1184 | GoOn,Nc,M20,X20,A = findBestCell(dlg,ncMax,0,Nm[ibrav]*N1s[ibrav],ibrav,peaks,V1) |
---|
1185 | if Nc >= ncMax: |
---|
1186 | GoOn = False |
---|
1187 | break |
---|
1188 | elif 3*Nc < Nobs: |
---|
1189 | N2 = 10 |
---|
1190 | break |
---|
1191 | else: |
---|
1192 | if not GoOn: |
---|
1193 | break |
---|
1194 | if M20 > 1.0: |
---|
1195 | bestM20 = max(bestM20,M20) |
---|
1196 | A = halfCell(ibrav,A[:],peaks) |
---|
1197 | if ibrav in [12]: |
---|
1198 | A = monoCellReduce(ibrav,A[:]) |
---|
1199 | HKL = GenHBravais(dmin,ibrav,A) |
---|
1200 | IndexPeaks(peaks,HKL) |
---|
1201 | a,b,c,alp,bet,gam = A2cell(A) |
---|
1202 | V = calc_V(A) |
---|
1203 | print "%10.3f %3d %3d %10.5f %10.5f %10.5f %10.3f %10.3f %10.3f %10.2f %10.2f" % (M20,X20,Nc,a,b,c,alp,bet,gam,V,V1) |
---|
1204 | if M20 >= 2.0: |
---|
1205 | cells.append([M20,X20,ibrav,a,b,c,alp,bet,gam,V,False]) |
---|
1206 | if not GoOn: |
---|
1207 | break |
---|
1208 | N2 += 1 |
---|
1209 | if ibrav < 11: |
---|
1210 | V1 *= 1.1 |
---|
1211 | elif ibrav in range(11,14): |
---|
1212 | V1 *= 1.05 |
---|
1213 | if not GoOn: |
---|
1214 | if bestM20 > topM20: |
---|
1215 | topM20 = bestM20 |
---|
1216 | if cells: |
---|
1217 | V1 = cells[0][9] |
---|
1218 | else: |
---|
1219 | V1 = 25 |
---|
1220 | ncMax += Nobs |
---|
1221 | cycle += 1 |
---|
1222 | print 'Restart search, new Max Nc = ',ncMax |
---|
1223 | else: |
---|
1224 | cycle = 10 |
---|
1225 | finally: |
---|
1226 | dlg.Destroy() |
---|
1227 | print '%s%s%s%s'%('finished cell search for ',bravaisNames[ibrav], \ |
---|
1228 | ', elapsed time = ',sec2HMS(time.time()-begin)) |
---|
1229 | |
---|
1230 | if cells: |
---|
1231 | cells = sortM20(cells) |
---|
1232 | cells[0][-1] = True |
---|
1233 | return True,dmin,cells |
---|
1234 | else: |
---|
1235 | return False,0,0 |
---|
1236 | |
---|
1237 | def FitRing(ring): |
---|
1238 | Err,parms = FitCircle(ring) |
---|
1239 | Err /= len(ring) |
---|
1240 | # print 'circle error:','%8f'%(Err) |
---|
1241 | if Err > 20000.: |
---|
1242 | eparms = FitEllipse(ring) |
---|
1243 | if eparms: |
---|
1244 | parms = eparms |
---|
1245 | return parms |
---|
1246 | |
---|
1247 | def FitCircle(ring): |
---|
1248 | import numpy.linalg as nl |
---|
1249 | |
---|
1250 | def makeParmsCircle(B): |
---|
1251 | cent = [-B[0]/2,-B[1]/2] |
---|
1252 | phi = 0. |
---|
1253 | sr1 = sr2 = math.sqrt(cent[0]**2+cent[1]**2-B[2]) |
---|
1254 | return cent,phi,[sr1,sr2] |
---|
1255 | |
---|
1256 | ring = np.array(ring) |
---|
1257 | x = np.asarray(ring.T[0]) |
---|
1258 | y = np.asarray(ring.T[1]) |
---|
1259 | |
---|
1260 | M = np.array((x,y,np.ones_like(x))) |
---|
1261 | B = np.array(-(x**2+y**2)) |
---|
1262 | result = nl.lstsq(M.T,B) |
---|
1263 | return result[1],makeParmsCircle(result[0]) |
---|
1264 | |
---|
1265 | def FitEllipse(ring): |
---|
1266 | import numpy.linalg as nl |
---|
1267 | |
---|
1268 | def makeParmsEllipse(B): |
---|
1269 | det = 4.*(1.-B[0]**2)-B[1]**2 |
---|
1270 | if det < 0.: |
---|
1271 | print 'hyperbola!' |
---|
1272 | return 0 |
---|
1273 | elif det == 0.: |
---|
1274 | print 'parabola!' |
---|
1275 | return 0 |
---|
1276 | cent = [(B[1]*B[3]-2.*(1.-B[0])*B[2])/det, \ |
---|
1277 | (B[1]*B[2]-2.*(1.+B[0])*B[3])/det] |
---|
1278 | phi = 0.5*atand(0.5*B[1]/B[0]) |
---|
1279 | |
---|
1280 | a = (1.+B[0])/cosd(2*phi) |
---|
1281 | b = 2.-a |
---|
1282 | f = (1.+B[0])*cent[0]**2+(1.-B[0])*cent[1]**2+B[1]*cent[0]*cent[1]-B[4] |
---|
1283 | if f/a < 0 or f/b < 0: |
---|
1284 | return 0 |
---|
1285 | sr1 = math.sqrt(f/a) |
---|
1286 | sr2 = math.sqrt(f/b) |
---|
1287 | if sr1 > sr2: |
---|
1288 | sr1,sr2 = SwapXY(sr1,sr2) |
---|
1289 | phi -= 90. |
---|
1290 | if phi < -90.: |
---|
1291 | phi += 180. |
---|
1292 | return cent,phi,[sr1,sr2] |
---|
1293 | |
---|
1294 | ring = np.array(ring) |
---|
1295 | x = np.asarray(ring.T[0]) |
---|
1296 | y = np.asarray(ring.T[1]) |
---|
1297 | M = np.array((x**2-y**2,x*y,x,y,np.ones_like(x))) |
---|
1298 | B = np.array(-(x**2+y**2)) |
---|
1299 | result = nl.lstsq(M.T,B) |
---|
1300 | return makeParmsEllipse(result[0]) |
---|
1301 | |
---|
1302 | def FitDetector(rings,p0,wave): |
---|
1303 | from scipy.optimize import leastsq |
---|
1304 | def ellipseCalc(B,xyd,wave): |
---|
1305 | x = xyd[0] |
---|
1306 | y = xyd[1] |
---|
1307 | dsp = xyd[2] |
---|
1308 | dist,x0,y0,phi,tilt = B |
---|
1309 | tth = 2.0*npasind(wave/(2.*dsp)) |
---|
1310 | ttth = nptand(tth) |
---|
1311 | radius = dist*ttth |
---|
1312 | stth = npsind(tth) |
---|
1313 | cosb = npcosd(tilt) |
---|
1314 | R1 = dist*stth*npcosd(tth)*cosb/(cosb**2-stth**2) |
---|
1315 | R0 = np.sqrt(R1*radius*cosb) |
---|
1316 | zdis = R1*ttth*nptand(tilt) |
---|
1317 | X = x-x0+zdis*npsind(phi) |
---|
1318 | Y = y-y0-zdis*npcosd(phi) |
---|
1319 | XR = X*npcosd(phi)-Y*npsind(phi) |
---|
1320 | YR = X*npsind(phi)+Y*npcosd(phi) |
---|
1321 | return (XR/R0)**2+(YR/R1)**2-1 |
---|
1322 | result = leastsq(ellipseCalc,p0,args=(rings.T,wave)) |
---|
1323 | return result[0] |
---|
1324 | |
---|
1325 | def ImageLocalMax(image,w,Xpix,Ypix): |
---|
1326 | w2 = w*2 |
---|
1327 | size = len(image) |
---|
1328 | if (w < Xpix < size-w) and (w < Ypix < size-w) and image[Ypix,Xpix]: |
---|
1329 | Z = image[Ypix-w:Ypix+w,Xpix-w:Xpix+w] |
---|
1330 | Zmax = np.argmax(Z) |
---|
1331 | Zmin = np.argmin(Z) |
---|
1332 | Xpix += Zmax%w2-w |
---|
1333 | Ypix += Zmax/w2-w |
---|
1334 | return Xpix,Ypix,np.ravel(Z)[Zmax],np.ravel(Z)[Zmin] |
---|
1335 | else: |
---|
1336 | return 0,0,0,0 |
---|
1337 | |
---|
1338 | def makeRing(dsp,ellipse,pix,reject,scalex,scaley,image): |
---|
1339 | cent,phi,radii = ellipse |
---|
1340 | cphi = cosd(phi) |
---|
1341 | sphi = sind(phi) |
---|
1342 | ring = [] |
---|
1343 | for a in range(0,360,2): |
---|
1344 | x = radii[0]*cosd(a) |
---|
1345 | y = radii[1]*sind(a) |
---|
1346 | X = (cphi*x-sphi*y+cent[0])*scalex #convert mm to pixels |
---|
1347 | Y = (sphi*x+cphi*y+cent[1])*scaley |
---|
1348 | X,Y,I,J = ImageLocalMax(image,pix,X,Y) |
---|
1349 | if I and J and I/J > reject: |
---|
1350 | X /= scalex #convert to mm |
---|
1351 | Y /= scaley |
---|
1352 | ring.append([X,Y,dsp]) |
---|
1353 | if len(ring) < 45: #want more than 1/4 of a circle |
---|
1354 | return [] |
---|
1355 | return ring |
---|
1356 | |
---|
1357 | def calcDist(radii,tth): |
---|
1358 | stth = sind(tth) |
---|
1359 | ctth = cosd(tth) |
---|
1360 | ttth = tand(tth) |
---|
1361 | return math.sqrt(radii[0]**4/(ttth**2*((radii[0]*ctth)**2+(radii[1]*stth)**2))) |
---|
1362 | |
---|
1363 | def calcZdisCosB(radius,tth,radii): |
---|
1364 | cosB = sinb = radii[0]**2/(radius*radii[1]) |
---|
1365 | if cosB > 1.: |
---|
1366 | return 0.,1. |
---|
1367 | else: |
---|
1368 | cosb = math.sqrt(1.-sinb**2) |
---|
1369 | ttth = tand(tth) |
---|
1370 | zdis = radii[1]*ttth*cosb/sinb |
---|
1371 | return zdis,cosB |
---|
1372 | |
---|
1373 | def GetEllipse(dsp,data): |
---|
1374 | dist = data['distance'] |
---|
1375 | cent = data['center'] |
---|
1376 | tilt = data['tilt'] |
---|
1377 | phi = data['rotation'] |
---|
1378 | radii = [0,0] |
---|
1379 | tth = 2.0*asind(data['wavelength']/(2.*dsp)) |
---|
1380 | ttth = tand(tth) |
---|
1381 | stth = sind(tth) |
---|
1382 | ctth = cosd(tth) |
---|
1383 | cosb = cosd(tilt) |
---|
1384 | radius = dist*ttth |
---|
1385 | radii[1] = dist*stth*ctth*cosb/(cosb**2-stth**2) |
---|
1386 | if radii[1] > 0: |
---|
1387 | radii[0] = math.sqrt(radii[1]*radius*cosb) |
---|
1388 | zdis = radii[1]*ttth*tand(tilt) |
---|
1389 | elcent = [cent[0]-zdis*sind(phi),cent[1]+zdis*cosd(phi)] |
---|
1390 | return elcent,phi,radii |
---|
1391 | else: |
---|
1392 | return False |
---|
1393 | |
---|
1394 | def GetDetectorXY(dsp,azm,data): |
---|
1395 | from scipy.optimize import fsolve |
---|
1396 | def func(xy,*args): |
---|
1397 | azm,phi,R0,R1,A,B = args |
---|
1398 | cp = cosd(phi) |
---|
1399 | sp = sind(phi) |
---|
1400 | x,y = xy |
---|
1401 | out = [] |
---|
1402 | out.append(y-x*tand(azm)) |
---|
1403 | out.append(R0**2*((x+A)*sp-(y+B)*cp)**2+R1**2*((x+A)*cp+(y+B)*sp)**2-(R0*R1)**2) |
---|
1404 | return out |
---|
1405 | elcent,phi,radii = GetEllipse(dsp,data) |
---|
1406 | cent = data['center'] |
---|
1407 | tilt = data['tilt'] |
---|
1408 | phi = data['rotation'] |
---|
1409 | wave = data['wavelength'] |
---|
1410 | dist = data['distance'] |
---|
1411 | tth = 2.0*asind(wave/(2.*dsp)) |
---|
1412 | ttth = tand(tth) |
---|
1413 | radius = dist*ttth |
---|
1414 | stth = sind(tth) |
---|
1415 | cosb = cosd(tilt) |
---|
1416 | R1 = dist*stth*cosd(tth)*cosb/(cosb**2-stth**2) |
---|
1417 | R0 = math.sqrt(R1*radius*cosb) |
---|
1418 | zdis = R1*ttth*tand(tilt) |
---|
1419 | A = zdis*sind(phi) |
---|
1420 | B = -zdis*cosd(phi) |
---|
1421 | xy0 = [radius*cosd(azm),radius*sind(azm)] |
---|
1422 | xy = fsolve(func,xy0,args=(azm,phi,R0,R1,A,B))+cent |
---|
1423 | return xy |
---|
1424 | |
---|
1425 | def GetTthDspAzm(x,y,data): |
---|
1426 | wave = data['wavelength'] |
---|
1427 | dist = data['distance'] |
---|
1428 | cent = data['center'] |
---|
1429 | tilt = data['tilt'] |
---|
1430 | phi = data['rotation'] |
---|
1431 | dx = np.array(x-cent[0],dtype=np.float32) |
---|
1432 | dy = np.array(y-cent[1],dtype=np.float32) |
---|
1433 | X = np.array(([dx,dy,np.zeros_like(dx)]),dtype=np.float32).T |
---|
1434 | X = np.dot(X,makeMat(phi,2)) |
---|
1435 | Z = np.dot(X,makeMat(tilt,0)).T[2] |
---|
1436 | tth = npatand(np.sqrt(dx**2+dy**2-Z**2)/(dist-Z)) |
---|
1437 | dsp = wave/(2.*npsind(tth/2.)) |
---|
1438 | azm = npatan2d(dy,dx) |
---|
1439 | return tth,azm,dsp |
---|
1440 | |
---|
1441 | def GetTth(x,y,data): |
---|
1442 | return GetTthDspAzm(x,y,data)[0] |
---|
1443 | |
---|
1444 | def GetTthAzm(x,y,data): |
---|
1445 | return GetTthDspAzm(x,y,data)[0:2] |
---|
1446 | |
---|
1447 | def GetDsp(x,y,data): |
---|
1448 | return GetTthDspAzm(x,y,data)[2] |
---|
1449 | |
---|
1450 | def ImageCompress(image,scale): |
---|
1451 | if scale == 1: |
---|
1452 | return image |
---|
1453 | else: |
---|
1454 | return image[::scale,::scale] |
---|
1455 | |
---|
1456 | def ImageCalibrate(self,data): |
---|
1457 | import copy |
---|
1458 | import ImageCalibrants as calFile |
---|
1459 | print 'image calibrate' |
---|
1460 | ring = data['ring'] |
---|
1461 | pixelSize = data['pixelSize'] |
---|
1462 | scalex = 1000./pixelSize[0] |
---|
1463 | scaley = 1000./pixelSize[1] |
---|
1464 | cutoff = data['cutoff'] |
---|
1465 | if len(ring) < 5: |
---|
1466 | print 'not enough inner ring points for ellipse' |
---|
1467 | return False |
---|
1468 | |
---|
1469 | #fit start points on inner ring |
---|
1470 | data['ellipses'] = [] |
---|
1471 | outE = FitRing(ring) |
---|
1472 | if outE: |
---|
1473 | print 'start ellipse:',outE |
---|
1474 | ellipse = outE |
---|
1475 | else: |
---|
1476 | return False |
---|
1477 | |
---|
1478 | #setup 180 points on that ring for "good" fit |
---|
1479 | Ring = makeRing(1.0,ellipse,20,cutoff,scalex,scaley,self.ImageZ) |
---|
1480 | if Ring: |
---|
1481 | ellipse = FitRing(Ring) |
---|
1482 | Ring = makeRing(1.0,ellipse,20,cutoff,scalex,scaley,self.ImageZ) #do again |
---|
1483 | ellipse = FitRing(Ring) |
---|
1484 | else: |
---|
1485 | print '1st ring not sufficiently complete to proceed' |
---|
1486 | return False |
---|
1487 | print 'inner ring:',ellipse |
---|
1488 | data['center'] = copy.copy(ellipse[0]) #not right!! (but useful for now) |
---|
1489 | data['ellipses'].append(ellipse[:]+('r',)) |
---|
1490 | G2plt.PlotImage(self) |
---|
1491 | |
---|
1492 | #setup for calibration |
---|
1493 | data['rings'] = [] |
---|
1494 | data['ellipses'] = [] |
---|
1495 | if not data['calibrant']: |
---|
1496 | print 'no calibration material selected' |
---|
1497 | return True |
---|
1498 | |
---|
1499 | Bravais,cell = calFile.Calibrants[data['calibrant']] |
---|
1500 | A = cell2A(cell) |
---|
1501 | wave = data['wavelength'] |
---|
1502 | cent = data['center'] |
---|
1503 | pixLimit = data['pixLimit'] |
---|
1504 | elcent,phi,radii = ellipse |
---|
1505 | HKL = GenHBravais(0.5,Bravais,A) |
---|
1506 | dsp = HKL[0][3] |
---|
1507 | tth = 2.0*asind(wave/(2.*dsp)) |
---|
1508 | ttth = tand(tth) |
---|
1509 | data['distance'] = dist = calcDist(radii,tth) |
---|
1510 | radius = dist*tand(tth) |
---|
1511 | zdis,cosB = calcZdisCosB(radius,tth,radii) |
---|
1512 | cent1 = [] |
---|
1513 | cent2 = [] |
---|
1514 | xSum = 0 |
---|
1515 | ySum = 0 |
---|
1516 | zxSum = 0 |
---|
1517 | zySum = 0 |
---|
1518 | phiSum = 0 |
---|
1519 | tiltSum = 0 |
---|
1520 | distSum = 0 |
---|
1521 | Zsum = 0 |
---|
1522 | for i,H in enumerate(HKL): |
---|
1523 | dsp = H[3] |
---|
1524 | tth = 2.0*asind(0.5*wave/dsp) |
---|
1525 | stth = sind(tth) |
---|
1526 | ctth = cosd(tth) |
---|
1527 | ttth = tand(tth) |
---|
1528 | radius = dist*ttth |
---|
1529 | elcent,phi,radii = ellipse |
---|
1530 | radii[1] = dist*stth*ctth*cosB/(cosB**2-stth**2) |
---|
1531 | radii[0] = math.sqrt(radii[1]*radius*cosB) |
---|
1532 | zdis,cosB = calcZdisCosB(radius,tth,radii) |
---|
1533 | zsinp = zdis*sind(phi) |
---|
1534 | zcosp = zdis*cosd(phi) |
---|
1535 | cent = data['center'] |
---|
1536 | elcent = [cent[0]+zsinp,cent[1]-zcosp] |
---|
1537 | ratio = radii[1]/radii[0] |
---|
1538 | Ring = makeRing(dsp,ellipse,pixLimit,cutoff,scalex,scaley,self.ImageZ) |
---|
1539 | if Ring: |
---|
1540 | numZ = len(Ring) |
---|
1541 | data['rings'].append(np.array(Ring)) |
---|
1542 | ellipse = FitRing(Ring) |
---|
1543 | elcent,phi,radii = ellipse |
---|
1544 | if abs(phi) > 45. and phi < 0.: |
---|
1545 | phi += 180. |
---|
1546 | dist = calcDist(radii,tth) |
---|
1547 | distR = 1.-dist/data['distance'] |
---|
1548 | if distR > 0.001: |
---|
1549 | print 'Wavelength too large?' |
---|
1550 | elif distR < -0.001: |
---|
1551 | print 'Wavelength too small?' |
---|
1552 | else: |
---|
1553 | if abs((radii[1]/radii[0]-ratio)/ratio) > 0.01: |
---|
1554 | print 'Bad fit for ring # %i. Try reducing Pixel search range'%(i) |
---|
1555 | return False |
---|
1556 | zdis,cosB = calcZdisCosB(radius,tth,radii) |
---|
1557 | Tilt = acosd(cosB) # 0 <= tilt <= 90 |
---|
1558 | zsinp = zdis*sind(ellipse[1]) |
---|
1559 | zcosp = zdis*cosd(ellipse[1]) |
---|
1560 | cent1.append(np.array([elcent[0]+zsinp,elcent[1]-zcosp])) |
---|
1561 | cent2.append(np.array([elcent[0]-zsinp,elcent[1]+zcosp])) |
---|
1562 | if i: |
---|
1563 | d1 = cent1[-1]-cent1[-2] #get shift of 2 possible center solutions |
---|
1564 | d2 = cent2[-1]-cent2[-2] |
---|
1565 | if np.dot(d2,d2) > np.dot(d1,d1): #right solution is the larger shift |
---|
1566 | data['center'] = cent1[-1] |
---|
1567 | else: |
---|
1568 | data['center'] = cent2[-1] |
---|
1569 | Zsum += numZ |
---|
1570 | phiSum += numZ*phi |
---|
1571 | distSum += numZ*dist |
---|
1572 | xSum += numZ*data['center'][0] |
---|
1573 | ySum += numZ*data['center'][1] |
---|
1574 | tiltSum += numZ*abs(Tilt) |
---|
1575 | cent = data['center'] |
---|
1576 | print 'for ring # %2i dist %.3f rotate %6.2f tilt %6.2f Xcent %.3f Ycent %.3f Npts %d' \ |
---|
1577 | %(i,dist,phi,Tilt,cent[0],cent[1],numZ) |
---|
1578 | data['ellipses'].append(copy.deepcopy(ellipse+('r',))) |
---|
1579 | G2plt.PlotImage(self) |
---|
1580 | else: |
---|
1581 | break |
---|
1582 | fullSize = len(self.ImageZ)/scalex |
---|
1583 | if 2*radii[1] < .9*fullSize: |
---|
1584 | print 'Are all usable rings (>25% visible) used? Try reducing Min ring I/Ib' |
---|
1585 | if not Zsum: |
---|
1586 | print 'Only one ring fitted. Check your wavelength.' |
---|
1587 | return False |
---|
1588 | cent = data['center'] = [xSum/Zsum,ySum/Zsum] |
---|
1589 | wave = data['wavelength'] |
---|
1590 | dist = data['distance'] = distSum/Zsum |
---|
1591 | |
---|
1592 | #possible error if no. of rings < 3! Might need trap here |
---|
1593 | d1 = cent1[-1]-cent1[1] #compare last ring to 2nd ring |
---|
1594 | d2 = cent2[-1]-cent2[1] |
---|
1595 | Zsign = 1 |
---|
1596 | len1 = math.sqrt(np.dot(d1,d1)) |
---|
1597 | len2 = math.sqrt(np.dot(d2,d2)) |
---|
1598 | t1 = d1/len1 |
---|
1599 | t2 = d2/len2 |
---|
1600 | if len2 > len1: |
---|
1601 | if -135. < atan2d(t2[1],t2[0]) < 45.: |
---|
1602 | Zsign = -1 |
---|
1603 | else: |
---|
1604 | if -135. < atan2d(t1[1],t1[0]) < 45.: |
---|
1605 | Zsign = -1 |
---|
1606 | |
---|
1607 | tilt = data['tilt'] = Zsign*tiltSum/Zsum |
---|
1608 | phi = data['rotation'] = phiSum/Zsum |
---|
1609 | rings = np.concatenate((data['rings']),axis=0) |
---|
1610 | p0 = [dist,cent[0],cent[1],phi,tilt] |
---|
1611 | result = FitDetector(rings,p0,wave) |
---|
1612 | data['distance'] = result[0] |
---|
1613 | data['center'] = result[1:3] |
---|
1614 | data['rotation'] = np.mod(result[3],360.0) |
---|
1615 | data['tilt'] = result[4] |
---|
1616 | N = len(data['ellipses']) |
---|
1617 | data['ellipses'] = [] #clear away individual ellipse fits |
---|
1618 | for H in HKL[:N]: |
---|
1619 | ellipse = GetEllipse(H[3],data) |
---|
1620 | data['ellipses'].append(copy.deepcopy(ellipse+('b',))) |
---|
1621 | G2plt.PlotImage(self) |
---|
1622 | return True |
---|
1623 | |
---|
1624 | def ImageIntegrate(self,data): |
---|
1625 | print 'image integrate' |
---|
1626 | pixelSize = data['pixelSize'] |
---|
1627 | scalex = pixelSize[0]/1000. |
---|
1628 | scaley = pixelSize[1]/1000. |
---|
1629 | LUtth = data['IOtth'] |
---|
1630 | if data['fullIntegrate']: |
---|
1631 | LRazm = [-180,180] |
---|
1632 | else: |
---|
1633 | LRazm = data['LRazimuth'] |
---|
1634 | numAzms = data['outAzimuths'] |
---|
1635 | numChans = data['outChannels'] |
---|
1636 | outGrid = np.zeros(shape=(numAzms,numChans)) |
---|
1637 | outNum = np.zeros(shape=(numAzms,numChans)) |
---|
1638 | imageN = len(self.ImageZ) |
---|
1639 | t0 = time.time() |
---|
1640 | print 'Create ',imageN,' X ',imageN,' 2-theta,azimuth map' |
---|
1641 | tax,tay = np.mgrid[0:imageN,0:imageN] |
---|
1642 | tax = np.asfarray(tax) |
---|
1643 | tay = np.asfarray(tay) |
---|
1644 | tax *= scalex |
---|
1645 | tay *= scaley |
---|
1646 | t1 = time.time() |
---|
1647 | print "Elapsed time:","%8.3f"%(t1-t0), "s" |
---|
1648 | print 'Fill map with 2-theta/azimuth values' |
---|
1649 | self.TA = GetTthAzm(tay,tax,data) #2-theta & azimuth arrays |
---|
1650 | self.TA = np.reshape(self.TA,(2,imageN,imageN)) |
---|
1651 | self.TA = np.dstack((self.TA[1],self.TA[0],self.ImageZ)) #azimuth, 2-theta, intensity order |
---|
1652 | t2 = time.time() |
---|
1653 | print "Elapsed time:","%8.3f"%(t2-t1), "s" |
---|
1654 | G2plt.PlotTRImage(self,newPlot=True) |
---|
1655 | print 'Form 1-D histograms for ',numAzms,' azimuthal angles' |
---|
1656 | print 'Integration limits:',LUtth,LRazm |
---|
1657 | tax,tay,taz = np.dsplit(self.TA,3) #azimuth, 2-theta, intensity |
---|
1658 | NST = np.histogram2d(tax.flatten(),tay.flatten(),normed=False, \ |
---|
1659 | bins=(numAzms,numChans),range=[LRazm,LUtth]) |
---|
1660 | HST = np.histogram2d(tax.flatten(),tay.flatten(),normed=False, \ |
---|
1661 | bins=(numAzms,numChans),weights=taz.flatten(),range=[LRazm,LUtth]) |
---|
1662 | t3 = time.time() |
---|
1663 | print "Elapsed time:","%8.3f"%(t3-t2), "s" |
---|
1664 | self.Integrate = [HST[0]/NST[0],HST[1],HST[2]] |
---|
1665 | G2plt.PlotIntegration(self,newPlot=True) |
---|
1666 | |
---|
1667 | |
---|
1668 | def test(): |
---|
1669 | cell = [5,5,5,90,90,90] |
---|
1670 | A = cell2A(cell) |
---|
1671 | assert ( calc_V(A) == 125. ) |
---|
1672 | |
---|
1673 | print 'test passed' |
---|
1674 | |
---|
1675 | print __name__ |
---|
1676 | if __name__ == '__main__': |
---|
1677 | test() |
---|
1678 | |
---|
1679 | |
---|