1 | # -*- coding: utf-8 -*- |
---|
2 | #GSASII image calculations: ellipse fitting & image integration |
---|
3 | ########### SVN repository information ################### |
---|
4 | # $Date: 2013-12-18 20:55:50 +0000 (Wed, 18 Dec 2013) $ |
---|
5 | # $Author: vondreele $ |
---|
6 | # $Revision: 1174 $ |
---|
7 | # $URL: trunk/GSASIIimage.py $ |
---|
8 | # $Id: GSASIIimage.py 1174 2013-12-18 20:55:50Z vondreele $ |
---|
9 | ########### SVN repository information ################### |
---|
10 | ''' |
---|
11 | *GSASIIimage: Image calc module* |
---|
12 | ================================ |
---|
13 | |
---|
14 | Ellipse fitting & image integration |
---|
15 | |
---|
16 | ''' |
---|
17 | |
---|
18 | import math |
---|
19 | import time |
---|
20 | import numpy as np |
---|
21 | import numpy.linalg as nl |
---|
22 | import numpy.ma as ma |
---|
23 | import polymask as pm |
---|
24 | from scipy.optimize import leastsq |
---|
25 | import copy |
---|
26 | import GSASIIpath |
---|
27 | GSASIIpath.SetVersionNumber("$Revision: 1174 $") |
---|
28 | import GSASIIplot as G2plt |
---|
29 | import GSASIIlattice as G2lat |
---|
30 | import GSASIIpwd as G2pwd |
---|
31 | import fellipse as fel |
---|
32 | |
---|
33 | # trig functions in degrees |
---|
34 | sind = lambda x: math.sin(x*math.pi/180.) |
---|
35 | asind = lambda x: 180.*math.asin(x)/math.pi |
---|
36 | tand = lambda x: math.tan(x*math.pi/180.) |
---|
37 | atand = lambda x: 180.*math.atan(x)/math.pi |
---|
38 | atan2d = lambda y,x: 180.*math.atan2(y,x)/math.pi |
---|
39 | cosd = lambda x: math.cos(x*math.pi/180.) |
---|
40 | acosd = lambda x: 180.*math.acos(x)/math.pi |
---|
41 | rdsq2d = lambda x,p: round(1.0/math.sqrt(x),p) |
---|
42 | #numpy versions |
---|
43 | npsind = lambda x: np.sin(x*np.pi/180.) |
---|
44 | npasind = lambda x: 180.*np.arcsin(x)/np.pi |
---|
45 | npcosd = lambda x: np.cos(x*np.pi/180.) |
---|
46 | npacosd = lambda x: 180.*np.arccos(x)/np.pi |
---|
47 | nptand = lambda x: np.tan(x*np.pi/180.) |
---|
48 | npatand = lambda x: 180.*np.arctan(x)/np.pi |
---|
49 | npatan2d = lambda y,x: 180.*np.arctan2(y,x)/np.pi |
---|
50 | |
---|
51 | def pointInPolygon(pXY,xy): |
---|
52 | 'Needs a doc string' |
---|
53 | #pXY - assumed closed 1st & last points are duplicates |
---|
54 | Inside = False |
---|
55 | N = len(pXY) |
---|
56 | p1x,p1y = pXY[0] |
---|
57 | for i in range(N+1): |
---|
58 | p2x,p2y = pXY[i%N] |
---|
59 | if (max(p1y,p2y) >= xy[1] > min(p1y,p2y)) and (xy[0] <= max(p1x,p2x)): |
---|
60 | if p1y != p2y: |
---|
61 | xinters = (xy[1]-p1y)*(p2x-p1x)/(p2y-p1y)+p1x |
---|
62 | if p1x == p2x or xy[0] <= xinters: |
---|
63 | Inside = not Inside |
---|
64 | p1x,p1y = p2x,p2y |
---|
65 | return Inside |
---|
66 | |
---|
67 | def peneCorr(tth,dep): |
---|
68 | 'Needs a doc string' |
---|
69 | return dep*(1.-npcosd(tth)) #best one |
---|
70 | # return dep*npsind(tth) #not as good as 1-cos2Q |
---|
71 | |
---|
72 | def makeMat(Angle,Axis): |
---|
73 | '''Make rotation matrix from Angle and Axis |
---|
74 | |
---|
75 | :param float Angle: in degrees |
---|
76 | :param int Axis: 0 for rotation about x, 1 for about y, etc. |
---|
77 | ''' |
---|
78 | cs = cosd(Angle) |
---|
79 | ss = sind(Angle) |
---|
80 | M = np.array(([1.,0.,0.],[0.,cs,-ss],[0.,ss,cs]),dtype=np.float32) |
---|
81 | return np.roll(np.roll(M,Axis,axis=0),Axis,axis=1) |
---|
82 | |
---|
83 | def FitEllipse(xy): |
---|
84 | |
---|
85 | def ellipse_center(p): |
---|
86 | ''' gives ellipse center coordinates |
---|
87 | ''' |
---|
88 | b,c,d,f,g,a = p[1]/2, p[2], p[3]/2, p[4]/2, p[5], p[0] |
---|
89 | num = b*b-a*c |
---|
90 | x0=(c*d-b*f)/num |
---|
91 | y0=(a*f-b*d)/num |
---|
92 | return np.array([x0,y0]) |
---|
93 | |
---|
94 | def ellipse_angle_of_rotation( p ): |
---|
95 | ''' gives rotation of ellipse major axis from x-axis |
---|
96 | range will be -90 to 90 deg |
---|
97 | ''' |
---|
98 | b,c,d,f,g,a = p[1]/2, p[2], p[3]/2, p[4]/2, p[5], p[0] |
---|
99 | return 0.5*npatand(2*b/(a-c)) |
---|
100 | |
---|
101 | def ellipse_axis_length( p ): |
---|
102 | ''' gives ellipse radii in [minor,major] order |
---|
103 | ''' |
---|
104 | b,c,d,f,g,a = p[1]/2, p[2], p[3]/2, p[4]/2, p[5], p[0] |
---|
105 | up = 2*(a*f*f+c*d*d+g*b*b-2*b*d*f-a*c*g) |
---|
106 | down1=(b*b-a*c)*( (c-a)*np.sqrt(1+4*b*b/((a-c)*(a-c)))-(c+a)) |
---|
107 | down2=(b*b-a*c)*( (a-c)*np.sqrt(1+4*b*b/((a-c)*(a-c)))-(c+a)) |
---|
108 | res1=np.sqrt(up/down1) |
---|
109 | res2=np.sqrt(up/down2) |
---|
110 | return np.array([ res2,res1]) |
---|
111 | |
---|
112 | xy = np.array(xy) |
---|
113 | x = np.asarray(xy.T[0])[:,np.newaxis] |
---|
114 | y = np.asarray(xy.T[1])[:,np.newaxis] |
---|
115 | D = np.hstack((x*x, x*y, y*y, x, y, np.ones_like(x))) |
---|
116 | S = np.dot(D.T,D) |
---|
117 | C = np.zeros([6,6]) |
---|
118 | C[0,2] = C[2,0] = 2; C[1,1] = -1 |
---|
119 | E, V = nl.eig(np.dot(nl.inv(S), C)) |
---|
120 | n = np.argmax(np.abs(E)) |
---|
121 | a = V[:,n] |
---|
122 | cent = ellipse_center(a) |
---|
123 | phi = ellipse_angle_of_rotation(a) |
---|
124 | radii = ellipse_axis_length(a) |
---|
125 | phi += 90. |
---|
126 | if radii[0] > radii[1]: |
---|
127 | radii = [radii[1],radii[0]] |
---|
128 | phi -= 90. |
---|
129 | return cent,phi,radii |
---|
130 | |
---|
131 | def FitDetector(rings,varyList,parmDict,Print=True): |
---|
132 | 'Needs a doc string' |
---|
133 | |
---|
134 | def CalibPrint(ValSig): |
---|
135 | print 'Image Parameters:' |
---|
136 | ptlbls = 'names :' |
---|
137 | ptstr = 'values:' |
---|
138 | sigstr = 'esds :' |
---|
139 | for name,fmt,value,sig in ValSig: |
---|
140 | ptlbls += "%s" % (name.rjust(12)) |
---|
141 | if name == 'phi': |
---|
142 | ptstr += fmt % (value%360.) |
---|
143 | else: |
---|
144 | ptstr += fmt % (value) |
---|
145 | if sig: |
---|
146 | sigstr += fmt % (sig) |
---|
147 | else: |
---|
148 | sigstr += 12*' ' |
---|
149 | print ptlbls |
---|
150 | print ptstr |
---|
151 | print sigstr |
---|
152 | |
---|
153 | def ellipseCalcD(B,xyd,varyList,parmDict): |
---|
154 | x,y,dsp = xyd |
---|
155 | wave = parmDict['wave'] |
---|
156 | if 'dep' in varyList: |
---|
157 | dist,x0,y0,tilt,chi,dep = B[:6] |
---|
158 | else: |
---|
159 | dist,x0,y0,tilt,chi = B[:5] |
---|
160 | dep = parmDict['dep'] |
---|
161 | if 'wave' in varyList: |
---|
162 | wave = B[-1] |
---|
163 | phi = chi-90. #get rotation of major axis from tilt axis |
---|
164 | tth = 2.0*npasind(wave/(2.*dsp)) |
---|
165 | dxy = peneCorr(tth,dep) |
---|
166 | ttth = nptand(tth) |
---|
167 | stth = npsind(tth) |
---|
168 | cosb = npcosd(tilt) |
---|
169 | tanb = nptand(tilt) |
---|
170 | tbm = nptand((tth-tilt)/2.) |
---|
171 | tbp = nptand((tth+tilt)/2.) |
---|
172 | sinb = npsind(tilt) |
---|
173 | d = dist+dxy |
---|
174 | fplus = d*tanb*stth/(cosb+stth) |
---|
175 | fminus = d*tanb*stth/(cosb-stth) |
---|
176 | vplus = d*(tanb+(1+tbm)/(1-tbm))*stth/(cosb+stth) |
---|
177 | vminus = d*(tanb+(1-tbp)/(1+tbp))*stth/(cosb-stth) |
---|
178 | R0 = np.sqrt((vplus+vminus)**2-(fplus+fminus)**2)/2. #+minor axis |
---|
179 | R1 = (vplus+vminus)/2. #major axis |
---|
180 | zdis = (fplus-fminus)/2. |
---|
181 | Robs = np.sqrt((x-x0)**2+(y-y0)**2) |
---|
182 | phi0 = npatan2d(y-y0,x-x0) |
---|
183 | rsqplus = R0**2+R1**2 |
---|
184 | rsqminus = R0**2-R1**2 |
---|
185 | R = rsqminus*npcosd(2.*phi0-2.*phi)+rsqplus |
---|
186 | Q = np.sqrt(2.)*R0*R1*np.sqrt(R-2.*zdis**2*npsind(phi0-phi)**2) |
---|
187 | P = 2.*R0**2*zdis*npcosd(phi0-phi) |
---|
188 | Rcalc = (P+Q)/R |
---|
189 | M = Robs-Rcalc |
---|
190 | return M |
---|
191 | |
---|
192 | names = ['dist','det-X','det-Y','tilt','phi','dep','wave'] |
---|
193 | fmt = ['%12.2f','%12.2f','%12.2f','%12.2f','%12.2f','%12.3f','%12.5f'] |
---|
194 | p0 = [parmDict[key] for key in varyList] |
---|
195 | result = leastsq(ellipseCalcD,p0,args=(rings.T,varyList,parmDict),full_output=True,ftol=1.e-8) |
---|
196 | chisq = np.sum(result[2]['fvec']**2) |
---|
197 | parmDict.update(zip(varyList,result[0])) |
---|
198 | vals = list(result[0]) |
---|
199 | chi = np.sqrt(np.sum(ellipseCalcD(result[0],rings.T,varyList,parmDict)**2)) |
---|
200 | sig = list(chi*np.sqrt(np.diag(result[1]))) |
---|
201 | sigList = np.zeros(7) |
---|
202 | for i,name in enumerate(names): |
---|
203 | if name in varyList: |
---|
204 | sigList[i] = sig[varyList.index(name)] |
---|
205 | ValSig = zip(names,fmt,vals,sig) |
---|
206 | if Print: |
---|
207 | CalibPrint(ValSig) |
---|
208 | return chi,chisq |
---|
209 | |
---|
210 | def ImageLocalMax(image,w,Xpix,Ypix): |
---|
211 | 'Needs a doc string' |
---|
212 | w2 = w*2 |
---|
213 | sizey,sizex = image.shape |
---|
214 | xpix = int(Xpix) #get reference corner of pixel chosen |
---|
215 | ypix = int(Ypix) |
---|
216 | if (w < xpix < sizex-w) and (w < ypix < sizey-w) and image[ypix,xpix]: |
---|
217 | Z = image[ypix-w:ypix+w,xpix-w:xpix+w] |
---|
218 | Zmax = np.argmax(Z) |
---|
219 | Zmin = np.argmin(Z) |
---|
220 | xpix += Zmax%w2-w |
---|
221 | ypix += Zmax/w2-w |
---|
222 | return xpix,ypix,np.ravel(Z)[Zmax],max(0.0001,np.ravel(Z)[Zmin]) #avoid neg/zero minimum |
---|
223 | else: |
---|
224 | return 0,0,0,0 |
---|
225 | |
---|
226 | def makeRing(dsp,ellipse,pix,reject,scalex,scaley,image): |
---|
227 | 'Needs a doc string' |
---|
228 | def ellipseC(): |
---|
229 | 'compute estimate of ellipse circumference' |
---|
230 | if radii[0] < 0: #hyperbola |
---|
231 | theta = npacosd(1./np.sqrt(1.+(radii[0]/radii[1])**2)) |
---|
232 | print theta |
---|
233 | return 0 |
---|
234 | apb = radii[1]+radii[0] |
---|
235 | amb = radii[1]-radii[0] |
---|
236 | return np.pi*apb*(1+3*(amb/apb)**2/(10+np.sqrt(4-3*(amb/apb)**2))) |
---|
237 | cent,phi,radii = ellipse |
---|
238 | cphi = cosd(phi) |
---|
239 | sphi = sind(phi) |
---|
240 | ring = [] |
---|
241 | sumI = 0 |
---|
242 | amin = 0 |
---|
243 | amax = 360 |
---|
244 | C = int(ellipseC()) |
---|
245 | for i in range(0,C,1): |
---|
246 | a = 360.*i/C |
---|
247 | x = radii[0]*cosd(a) |
---|
248 | y = radii[1]*sind(a) |
---|
249 | X = (cphi*x-sphi*y+cent[0])*scalex #convert mm to pixels |
---|
250 | Y = (sphi*x+cphi*y+cent[1])*scaley |
---|
251 | X,Y,I,J = ImageLocalMax(image,pix,X,Y) |
---|
252 | if I and J and I/J > reject: |
---|
253 | sumI += I/J |
---|
254 | X += .5 #set to center of pixel |
---|
255 | Y += .5 |
---|
256 | X /= scalex #convert to mm |
---|
257 | Y /= scaley |
---|
258 | amin = min(amin,a) |
---|
259 | amax = max(amax,a) |
---|
260 | if [X,Y,dsp] not in ring: |
---|
261 | ring.append([X,Y,dsp]) |
---|
262 | if len(ring) < 10: #want more than 10 deg |
---|
263 | ring = [] |
---|
264 | return ring |
---|
265 | |
---|
266 | def GetEllipse2(tth,dxy,dist,cent,tilt,phi): |
---|
267 | '''uses Dandelin spheres to find ellipse or hyperbola parameters from detector geometry |
---|
268 | on output |
---|
269 | radii[0] (b-minor axis) set < 0. for hyperbola |
---|
270 | |
---|
271 | ''' |
---|
272 | radii = [0,0] |
---|
273 | ttth = tand(tth) |
---|
274 | stth = sind(tth) |
---|
275 | ctth = cosd(tth) |
---|
276 | cosb = cosd(tilt) |
---|
277 | tanb = tand(tilt) |
---|
278 | tbm = tand((tth-tilt)/2.) |
---|
279 | tbp = tand((tth+tilt)/2.) |
---|
280 | sinb = sind(tilt) |
---|
281 | d = dist+dxy |
---|
282 | if tth+abs(tilt) < 90.: #ellipse |
---|
283 | fplus = d*tanb*stth/(cosb+stth) |
---|
284 | fminus = d*tanb*stth/(cosb-stth) |
---|
285 | vplus = d*(tanb+(1+tbm)/(1-tbm))*stth/(cosb+stth) |
---|
286 | vminus = d*(tanb+(1-tbp)/(1+tbp))*stth/(cosb-stth) |
---|
287 | radii[0] = np.sqrt((vplus+vminus)**2-(fplus+fminus)**2)/2. #+minor axis |
---|
288 | radii[1] = (vplus+vminus)/2. #major axis |
---|
289 | zdis = (fplus-fminus)/2. |
---|
290 | else: #hyperbola! |
---|
291 | f = d*abs(tanb)*stth/(cosb+stth) |
---|
292 | v = d*(abs(tanb)+tand(tth-abs(tilt))) |
---|
293 | delt = d*stth*(1.+stth*cosb)/(abs(sinb)*cosb*(stth+cosb)) |
---|
294 | eps = (v-f)/(delt-v) |
---|
295 | radii[0] = -eps*(delt-f)/np.sqrt(eps**2-1.) #-minor axis |
---|
296 | radii[1] = eps*(delt-f)/(eps**2-1.) #major axis |
---|
297 | if tilt > 0: |
---|
298 | zdis = f+radii[1]*eps |
---|
299 | else: |
---|
300 | zdis = -f |
---|
301 | #NB: zdis is || to major axis & phi is rotation of minor axis |
---|
302 | #thus shift from beam to ellipse center is [Z*sin(phi),-Z*cos(phi)] |
---|
303 | elcent = [cent[0]+zdis*sind(phi),cent[1]-zdis*cosd(phi)] |
---|
304 | return elcent,phi,radii |
---|
305 | |
---|
306 | def GetEllipse(dsp,data): |
---|
307 | '''uses Dandelin spheres to find ellipse or hyperbola parameters from detector geometry |
---|
308 | as given in image controls dictionary (data) and a d-spacing (dsp) |
---|
309 | ''' |
---|
310 | cent = data['center'] |
---|
311 | tilt = data['tilt'] |
---|
312 | phi = data['rotation'] |
---|
313 | dep = data['DetDepth'] |
---|
314 | tth = 2.0*asind(data['wavelength']/(2.*dsp)) |
---|
315 | dxy = peneCorr(tth,dep) |
---|
316 | dist = data['distance'] |
---|
317 | return GetEllipse2(tth,dxy,dist,cent,tilt,phi) |
---|
318 | |
---|
319 | def GetDetectorXY(dsp,azm,data): |
---|
320 | 'Needs a doc string' |
---|
321 | |
---|
322 | elcent,phi,radii = GetEllipse(dsp,data) |
---|
323 | phi = data['rotation']-90. #to give rotation of major axis |
---|
324 | tilt = data['tilt'] |
---|
325 | dist = data['distance'] |
---|
326 | cent = data['center'] |
---|
327 | tth = 2.0*asind(data['wavelength']/(2.*dsp)) |
---|
328 | ttth = tand(tth) |
---|
329 | stth = sind(tth) |
---|
330 | ctth = cosd(tth) |
---|
331 | cosb = cosd(tilt) |
---|
332 | if radii[0] > 0.: |
---|
333 | sinb = sind(tilt) |
---|
334 | tanb = tand(tilt) |
---|
335 | fplus = dist*tanb*stth/(cosb+stth) |
---|
336 | fminus = dist*tanb*stth/(cosb-stth) |
---|
337 | zdis = (fplus-fminus)/2. |
---|
338 | rsqplus = radii[0]**2+radii[1]**2 |
---|
339 | rsqminus = radii[0]**2-radii[1]**2 |
---|
340 | R = rsqminus*cosd(2.*azm-2.*phi)+rsqplus |
---|
341 | Q = np.sqrt(2.)*radii[0]*radii[1]*np.sqrt(R-2.*zdis**2*sind(azm-phi)**2) |
---|
342 | P = 2.*radii[0]**2*zdis*cosd(azm-phi) |
---|
343 | radius = (P+Q)/R |
---|
344 | xy = np.array([radius*cosd(azm),radius*sind(azm)]) |
---|
345 | xy += cent |
---|
346 | else: #hyperbola - both branches (one is way off screen!) |
---|
347 | sinb = abs(sind(tilt)) |
---|
348 | tanb = abs(tand(tilt)) |
---|
349 | f = dist*tanb*stth/(cosb+stth) |
---|
350 | v = dist*(tanb+tand(tth-abs(tilt))) |
---|
351 | delt = dist*stth*(1+stth*cosb)/(sinb*cosb*(stth+cosb)) |
---|
352 | ecc = (v-f)/(delt-v) |
---|
353 | R = radii[1]*(ecc**2-1)/(1-ecc*cosd(azm)) |
---|
354 | if tilt > 0.: |
---|
355 | offset = 2.*radii[1]*ecc+f #select other branch |
---|
356 | xy = [-R*cosd(azm)-offset,R*sind(azm)] |
---|
357 | else: |
---|
358 | offset = -f |
---|
359 | xy = [-R*cosd(azm)-offset,-R*sind(azm)] |
---|
360 | xy = -np.array([xy[0]*cosd(phi)+xy[1]*sind(phi),xy[0]*sind(phi)-xy[1]*cosd(phi)]) |
---|
361 | xy += cent |
---|
362 | return xy |
---|
363 | |
---|
364 | def GetDetXYfromThAzm(Th,Azm,data): |
---|
365 | 'Needs a doc string' |
---|
366 | dsp = data['wavelength']/(2.0*npsind(Th)) |
---|
367 | return GetDetectorXY(dsp,azm,data) |
---|
368 | |
---|
369 | def GetTthAzmDsp(x,y,data): |
---|
370 | 'Needs a doc string - checked OK for ellipses & hyperbola' |
---|
371 | wave = data['wavelength'] |
---|
372 | cent = data['center'] |
---|
373 | tilt = data['tilt'] |
---|
374 | dist = data['distance']/cosd(tilt) |
---|
375 | x0 = data['distance']*tand(tilt) |
---|
376 | phi = data['rotation'] |
---|
377 | dep = data['DetDepth'] |
---|
378 | LRazim = data['LRazimuth'] |
---|
379 | azmthoff = data['azmthOff'] |
---|
380 | dx = np.array(x-cent[0],dtype=np.float32) |
---|
381 | dy = np.array(y-cent[1],dtype=np.float32) |
---|
382 | D = ((dx-x0)**2+dy**2+data['distance']**2) #sample to pixel distance |
---|
383 | X = np.array(([dx,dy,np.zeros_like(dx)]),dtype=np.float32).T |
---|
384 | X = np.dot(X,makeMat(phi,2)) |
---|
385 | Z = np.dot(X,makeMat(tilt,0)).T[2] |
---|
386 | tth = npatand(np.sqrt(dx**2+dy**2-Z**2)/(dist-Z)) |
---|
387 | dxy = peneCorr(tth,dep) #depth corr not correct for tilted detector |
---|
388 | DX = dist-Z+dxy |
---|
389 | DY = np.sqrt(dx**2+dy**2-Z**2) |
---|
390 | tth = npatan2d(DY,DX) |
---|
391 | dsp = wave/(2.*npsind(tth/2.)) |
---|
392 | azm = (npatan2d(dy,dx)+azmthoff+720.)%360. |
---|
393 | G = D/data['distance']**2 #for geometric correction = 1/cos(2theta)^2 if tilt=0. |
---|
394 | return tth,azm,G,dsp |
---|
395 | |
---|
396 | def GetTth(x,y,data): |
---|
397 | 'Give 2-theta value for detector x,y position; calibration info in data' |
---|
398 | return GetTthAzmDsp(x,y,data)[0] |
---|
399 | |
---|
400 | def GetTthAzm(x,y,data): |
---|
401 | 'Give 2-theta, azimuth values for detector x,y position; calibration info in data' |
---|
402 | return GetTthAzmDsp(x,y,data)[0:2] |
---|
403 | |
---|
404 | def GetTthAzmD(x,y,data): |
---|
405 | '''Give 2-theta, azimuth & geometric correction values for detector x,y position; |
---|
406 | calibration info in data |
---|
407 | ''' |
---|
408 | return GetTthAzmDsp(x,y,data)[0:3] |
---|
409 | |
---|
410 | def GetDsp(x,y,data): |
---|
411 | 'Give d-spacing value for detector x,y position; calibration info in data' |
---|
412 | return GetTthAzmDsp(x,y,data)[3] |
---|
413 | |
---|
414 | def GetAzm(x,y,data): |
---|
415 | 'Give azimuth value for detector x,y position; calibration info in data' |
---|
416 | return GetTthAzmDsp(x,y,data)[1] |
---|
417 | |
---|
418 | def ImageCompress(image,scale): |
---|
419 | 'Needs a doc string' |
---|
420 | if scale == 1: |
---|
421 | return image |
---|
422 | else: |
---|
423 | return image[::scale,::scale] |
---|
424 | |
---|
425 | def checkEllipse(Zsum,distSum,xSum,ySum,dist,x,y): |
---|
426 | 'Needs a doc string' |
---|
427 | avg = np.array([distSum/Zsum,xSum/Zsum,ySum/Zsum]) |
---|
428 | curr = np.array([dist,x,y]) |
---|
429 | return abs(avg-curr)/avg < .02 |
---|
430 | |
---|
431 | def EdgeFinder(image,data): |
---|
432 | '''this makes list of all x,y where I>edgeMin suitable for an ellipse search? |
---|
433 | Not currently used but might be useful in future? |
---|
434 | ''' |
---|
435 | import numpy.ma as ma |
---|
436 | Nx,Ny = data['size'] |
---|
437 | pixelSize = data['pixelSize'] |
---|
438 | edgemin = data['edgemin'] |
---|
439 | scalex = pixelSize[0]/1000. |
---|
440 | scaley = pixelSize[1]/1000. |
---|
441 | tay,tax = np.mgrid[0:Nx,0:Ny] |
---|
442 | tax = np.asfarray(tax*scalex,dtype=np.float32) |
---|
443 | tay = np.asfarray(tay*scaley,dtype=np.float32) |
---|
444 | tam = ma.getmask(ma.masked_less(image.flatten(),edgemin)) |
---|
445 | tax = ma.compressed(ma.array(tax.flatten(),mask=tam)) |
---|
446 | tay = ma.compressed(ma.array(tay.flatten(),mask=tam)) |
---|
447 | return zip(tax,tay) |
---|
448 | |
---|
449 | def MakeFrameMask(data,frame): |
---|
450 | pixelSize = data['pixelSize'] |
---|
451 | scalex = pixelSize[0]/1000. |
---|
452 | scaley = pixelSize[1]/1000. |
---|
453 | blkSize = 512 |
---|
454 | Nx,Ny = data['size'] |
---|
455 | nXBlks = (Nx-1)/blkSize+1 |
---|
456 | nYBlks = (Ny-1)/blkSize+1 |
---|
457 | tam = ma.make_mask_none(data['size']) |
---|
458 | for iBlk in range(nXBlks): |
---|
459 | iBeg = iBlk*blkSize |
---|
460 | iFin = min(iBeg+blkSize,Nx) |
---|
461 | for jBlk in range(nYBlks): |
---|
462 | jBeg = jBlk*blkSize |
---|
463 | jFin = min(jBeg+blkSize,Ny) |
---|
464 | nI = iFin-iBeg |
---|
465 | nJ = jFin-jBeg |
---|
466 | tax,tay = np.mgrid[iBeg+0.5:iFin+.5,jBeg+.5:jFin+.5] #bin centers not corners |
---|
467 | tax = np.asfarray(tax*scalex,dtype=np.float32) |
---|
468 | tay = np.asfarray(tay*scaley,dtype=np.float32) |
---|
469 | tamp = ma.make_mask_none((1024*1024)) |
---|
470 | tamp = ma.make_mask(pm.polymask(nI*nJ,tax.flatten(), |
---|
471 | tay.flatten(),len(frame),frame,tamp)[:nI*nJ])-True #switch to exclude around frame |
---|
472 | if tamp.shape: |
---|
473 | tamp = np.reshape(tamp[:nI*nJ],(nI,nJ)) |
---|
474 | tam[iBeg:iFin,jBeg:jFin] = ma.mask_or(tamp[0:nI,0:nJ],tam[iBeg:iFin,jBeg:jFin]) |
---|
475 | else: |
---|
476 | tam[iBeg:iFin,jBeg:jFin] = True |
---|
477 | return tam.T |
---|
478 | |
---|
479 | def ImageRecalibrate(self,data,masks): |
---|
480 | 'Needs a doc string' |
---|
481 | import ImageCalibrants as calFile |
---|
482 | print 'Image recalibration:' |
---|
483 | time0 = time.time() |
---|
484 | pixelSize = data['pixelSize'] |
---|
485 | scalex = 1000./pixelSize[0] |
---|
486 | scaley = 1000./pixelSize[1] |
---|
487 | pixLimit = data['pixLimit'] |
---|
488 | cutoff = data['cutoff'] |
---|
489 | data['rings'] = [] |
---|
490 | data['ellipses'] = [] |
---|
491 | if not data['calibrant']: |
---|
492 | print 'no calibration material selected' |
---|
493 | return True |
---|
494 | skip = data['calibskip'] |
---|
495 | dmin = data['calibdmin'] |
---|
496 | Bravais,Cells = calFile.Calibrants[data['calibrant']][:2] |
---|
497 | HKL = [] |
---|
498 | for bravais,cell in zip(Bravais,Cells): |
---|
499 | A = G2lat.cell2A(cell) |
---|
500 | hkl = G2lat.GenHBravais(dmin,bravais,A) |
---|
501 | HKL += hkl |
---|
502 | HKL = G2lat.sortHKLd(HKL,True,False) |
---|
503 | varyList = ['dist','det-X','det-Y','tilt','phi'] |
---|
504 | parmDict = {'dist':data['distance'],'det-X':data['center'][0],'det-Y':data['center'][1], |
---|
505 | 'tilt':data['tilt'],'phi':data['rotation'],'wave':data['wavelength'],'dep':data['DetDepth']} |
---|
506 | Found = False |
---|
507 | wave = data['wavelength'] |
---|
508 | frame = masks['Frames'] |
---|
509 | tam = ma.make_mask_none(self.ImageZ.shape) |
---|
510 | if frame: |
---|
511 | tam = ma.mask_or(tam,MakeFrameMask(data,frame)) |
---|
512 | for iH,H in enumerate(HKL): |
---|
513 | dsp = H[3] |
---|
514 | tth = 2.0*asind(wave/(2.*dsp)) |
---|
515 | if tth+abs(data['tilt']) > 90.: |
---|
516 | print 'next line is a hyperbola - search stopped' |
---|
517 | break |
---|
518 | ellipse = GetEllipse(dsp,data) |
---|
519 | Ring = makeRing(dsp,ellipse,pixLimit,cutoff,scalex,scaley,ma.array(self.ImageZ,mask=tam)) |
---|
520 | if Ring: |
---|
521 | if iH >= skip: |
---|
522 | data['rings'].append(np.array(Ring)) |
---|
523 | data['ellipses'].append(copy.deepcopy(ellipse+('r',))) |
---|
524 | Found = True |
---|
525 | elif not Found: #skipping inner rings, keep looking until ring found |
---|
526 | continue |
---|
527 | else: #no more rings beyond edge of detector |
---|
528 | break |
---|
529 | rings = np.concatenate((data['rings']),axis=0) |
---|
530 | if data['DetDepthRef']: |
---|
531 | varyList.append('dep') |
---|
532 | FitDetector(rings,varyList,parmDict) |
---|
533 | data['distance'] = parmDict['dist'] |
---|
534 | data['center'] = [parmDict['det-X'],parmDict['det-Y']] |
---|
535 | data['rotation'] = np.mod(parmDict['phi'],360.0) |
---|
536 | data['tilt'] = parmDict['tilt'] |
---|
537 | data['DetDepth'] = parmDict['dep'] |
---|
538 | N = len(data['ellipses']) |
---|
539 | data['ellipses'] = [] #clear away individual ellipse fits |
---|
540 | for H in HKL[:N]: |
---|
541 | ellipse = GetEllipse(H[3],data) |
---|
542 | data['ellipses'].append(copy.deepcopy(ellipse+('b',))) |
---|
543 | |
---|
544 | print 'calibration time = ',time.time()-time0 |
---|
545 | G2plt.PlotImage(self,newImage=True) |
---|
546 | return True |
---|
547 | |
---|
548 | def ImageCalibrate(self,data): |
---|
549 | 'Needs a doc string' |
---|
550 | import copy |
---|
551 | import ImageCalibrants as calFile |
---|
552 | print 'Image calibration:' |
---|
553 | time0 = time.time() |
---|
554 | ring = data['ring'] |
---|
555 | pixelSize = data['pixelSize'] |
---|
556 | scalex = 1000./pixelSize[0] |
---|
557 | scaley = 1000./pixelSize[1] |
---|
558 | pixLimit = data['pixLimit'] |
---|
559 | cutoff = data['cutoff'] |
---|
560 | if len(ring) < 5: |
---|
561 | print 'not enough inner ring points for ellipse' |
---|
562 | return False |
---|
563 | |
---|
564 | #fit start points on inner ring |
---|
565 | data['ellipses'] = [] |
---|
566 | data['rings'] = [] |
---|
567 | outE = FitEllipse(ring) |
---|
568 | fmt = '%s X: %.3f, Y: %.3f, phi: %.3f, R1: %.3f, R2: %.3f' |
---|
569 | fmt2 = '%s X: %.3f, Y: %.3f, phi: %.3f, R1: %.3f, R2: %.3f, chi^2: %.3f, N: %d' |
---|
570 | if outE: |
---|
571 | print fmt%('start ellipse: ',outE[0][0],outE[0][1],outE[1],outE[2][0],outE[2][1]) |
---|
572 | ellipse = outE |
---|
573 | else: |
---|
574 | return False |
---|
575 | |
---|
576 | #setup 360 points on that ring for "good" fit |
---|
577 | data['ellipses'].append(ellipse[:]+('g',)) |
---|
578 | Ring = makeRing(1.0,ellipse,pixLimit,cutoff,scalex,scaley,self.ImageZ) |
---|
579 | if Ring: |
---|
580 | ellipse = FitEllipse(ring) |
---|
581 | Ring = makeRing(1.0,ellipse,pixLimit,cutoff,scalex,scaley,self.ImageZ) #do again |
---|
582 | ellipse = FitEllipse(ring) |
---|
583 | else: |
---|
584 | print '1st ring not sufficiently complete to proceed' |
---|
585 | return False |
---|
586 | print fmt2%('inner ring: ',ellipse[0][0],ellipse[0][1],ellipse[1],ellipse[2][0],ellipse[2][1],0.,len(Ring)) #cent,phi,radii |
---|
587 | data['ellipses'].append(ellipse[:]+('r',)) |
---|
588 | data['rings'].append(np.array(Ring)) |
---|
589 | G2plt.PlotImage(self,newImage=True) |
---|
590 | |
---|
591 | #setup for calibration |
---|
592 | data['rings'] = [] |
---|
593 | if not data['calibrant']: |
---|
594 | print 'no calibration material selected' |
---|
595 | return True |
---|
596 | |
---|
597 | skip = data['calibskip'] |
---|
598 | dmin = data['calibdmin'] |
---|
599 | #generate reflection set |
---|
600 | Bravais,Cells = calFile.Calibrants[data['calibrant']][:2] |
---|
601 | HKL = [] |
---|
602 | for bravais,cell in zip(Bravais,Cells): |
---|
603 | A = G2lat.cell2A(cell) |
---|
604 | hkl = G2lat.GenHBravais(dmin,bravais,A)[skip:] |
---|
605 | HKL += hkl |
---|
606 | HKL = G2lat.sortHKLd(HKL,True,False) |
---|
607 | wave = data['wavelength'] |
---|
608 | #set up 1st ring |
---|
609 | elcent,phi,radii = ellipse #from fit of 1st ring |
---|
610 | dsp = HKL[0][3] |
---|
611 | tth = 2.0*asind(wave/(2.*dsp)) |
---|
612 | Ring0 = makeRing(dsp,ellipse,3,cutoff,scalex,scaley,self.ImageZ) |
---|
613 | ttth = nptand(tth) |
---|
614 | stth = npsind(tth) |
---|
615 | ctth = npcosd(tth) |
---|
616 | #1st estimate of tilt; assume ellipse - don't know sign though |
---|
617 | tilt = npasind(np.sqrt(max(0.,1.-(radii[0]/radii[1])**2))*ctth) |
---|
618 | if not tilt: |
---|
619 | print 'WARNING - selected ring was fitted as a circle' |
---|
620 | print ' - if detector was tilted we suggest you skip this ring - WARNING' |
---|
621 | #1st estimate of dist: sample to detector normal to plane |
---|
622 | data['distance'] = dist = radii[0]**2/(ttth*radii[1]) |
---|
623 | #ellipse to cone axis (x-ray beam); 2 choices depending on sign of tilt |
---|
624 | zdisp = radii[1]*ttth*tand(tilt) |
---|
625 | zdism = radii[1]*ttth*tand(-tilt) |
---|
626 | #cone axis position; 2 choices. Which is right? |
---|
627 | #NB: zdisp is || to major axis & phi is rotation of minor axis |
---|
628 | #thus shift from beam to ellipse center is [Z*sin(phi),-Z*cos(phi)] |
---|
629 | centp = [elcent[0]+zdisp*sind(phi),elcent[1]-zdisp*cosd(phi)] |
---|
630 | centm = [elcent[0]+zdism*sind(phi),elcent[1]-zdism*cosd(phi)] |
---|
631 | #check get same ellipse parms either way |
---|
632 | #now do next ring; estimate either way & do a FitDetector each way; best fit is correct one |
---|
633 | dsp = HKL[1][3] |
---|
634 | tth = 2.0*asind(wave/(2.*dsp)) |
---|
635 | ellipsep = GetEllipse2(tth,0.,dist,centp,tilt,phi) |
---|
636 | print fmt%('plus ellipse :',ellipsep[0][0],ellipsep[0][1],ellipsep[1],ellipsep[2][0],ellipsep[2][1]) |
---|
637 | Ringp = makeRing(dsp,ellipsep,3,cutoff,scalex,scaley,self.ImageZ) |
---|
638 | parmDict = {'dist':dist,'det-X':centp[0],'det-Y':centp[1], |
---|
639 | 'tilt':tilt,'phi':phi,'wave':wave,'dep':0.0} |
---|
640 | varyList = ['dist','det-X','det-Y','tilt','phi'] |
---|
641 | if len(Ringp) > 10: |
---|
642 | chip,chisqp = FitDetector(np.array(Ring0+Ringp),varyList,parmDict,True) |
---|
643 | tiltp = parmDict['tilt'] |
---|
644 | phip = parmDict['phi'] |
---|
645 | centp = [parmDict['det-X'],parmDict['det-Y']] |
---|
646 | else: |
---|
647 | chip = 1e6 |
---|
648 | ellipsem = GetEllipse2(tth,0.,dist,centm,-tilt,phi) |
---|
649 | print fmt%('minus ellipse:',ellipsem[0][0],ellipsem[0][1],ellipsem[1],ellipsem[2][0],ellipsem[2][1]) |
---|
650 | Ringm = makeRing(dsp,ellipsem,3,cutoff,scalex,scaley,self.ImageZ) |
---|
651 | if len(Ringm) > 10: |
---|
652 | parmDict['tilt'] *= -1 |
---|
653 | chim,chisqm = FitDetector(np.array(Ring0+Ringm),varyList,parmDict,True) |
---|
654 | tiltm = parmDict['tilt'] |
---|
655 | phim = parmDict['phi'] |
---|
656 | centm = [parmDict['det-X'],parmDict['det-Y']] |
---|
657 | else: |
---|
658 | chim = 1e6 |
---|
659 | if chip < chim: |
---|
660 | data['tilt'] = tiltp |
---|
661 | data['center'] = centp |
---|
662 | data['rotation'] = phip |
---|
663 | else: |
---|
664 | data['tilt'] = tiltm |
---|
665 | data['center'] = centm |
---|
666 | data['rotation'] = phim |
---|
667 | data['ellipses'].append(ellipsep[:]+('b',)) |
---|
668 | data['rings'].append(np.array(Ringp)) |
---|
669 | data['ellipses'].append(ellipsem[:]+('r',)) |
---|
670 | data['rings'].append(np.array(Ringm)) |
---|
671 | G2plt.PlotImage(self,newImage=True) |
---|
672 | parmDict = {'dist':data['distance'],'det-X':data['center'][0],'det-Y':data['center'][1], |
---|
673 | 'tilt':data['tilt'],'phi':data['rotation'],'wave':data['wavelength'],'dep':data['DetDepth']} |
---|
674 | varyList = ['dist','det-X','det-Y','tilt','phi'] |
---|
675 | if data['DetDepthRef']: |
---|
676 | varyList.append('dep') |
---|
677 | data['rings'] = [] |
---|
678 | data['ellipses'] = [] |
---|
679 | for i,H in enumerate(HKL): |
---|
680 | dsp = H[3] |
---|
681 | tth = 2.0*asind(wave/(2.*dsp)) |
---|
682 | if tth+abs(data['tilt']) > 90.: |
---|
683 | print 'next line is a hyperbola - search stopped' |
---|
684 | break |
---|
685 | print 'HKLD:',H[:4],'2-theta: %.4f'%(tth) |
---|
686 | elcent,phi,radii = ellipse = GetEllipse(dsp,data) |
---|
687 | data['ellipses'].append(copy.deepcopy(ellipse+('g',))) |
---|
688 | print fmt%('predicted ellipse:',elcent[0],elcent[1],phi,radii[0],radii[1]) |
---|
689 | Ring = makeRing(dsp,ellipse,pixLimit,cutoff,scalex,scaley,self.ImageZ) |
---|
690 | if Ring: |
---|
691 | data['rings'].append(np.array(Ring)) |
---|
692 | rings = np.concatenate((data['rings']),axis=0) |
---|
693 | if i: |
---|
694 | chi,chisq = FitDetector(rings,varyList,parmDict,False) |
---|
695 | data['distance'] = parmDict['dist'] |
---|
696 | data['center'] = [parmDict['det-X'],parmDict['det-Y']] |
---|
697 | data['rotation'] = parmDict['phi'] |
---|
698 | data['tilt'] = parmDict['tilt'] |
---|
699 | data['DetDepth'] = parmDict['dep'] |
---|
700 | elcent,phi,radii = ellipse = GetEllipse(dsp,data) |
---|
701 | print fmt2%('fitted ellipse: ',elcent[0],elcent[1],phi,radii[0],radii[1],chisq,len(rings)) |
---|
702 | data['ellipses'].append(copy.deepcopy(ellipse+('r',))) |
---|
703 | # G2plt.PlotImage(self,newImage=True) |
---|
704 | else: |
---|
705 | print 'insufficient number of points in this ellipse to fit' |
---|
706 | break |
---|
707 | G2plt.PlotImage(self,newImage=True) |
---|
708 | fullSize = len(self.ImageZ)/scalex |
---|
709 | if 2*radii[1] < .9*fullSize: |
---|
710 | print 'Are all usable rings (>25% visible) used? Try reducing Min ring I/Ib' |
---|
711 | N = len(data['ellipses']) |
---|
712 | if N > 2: |
---|
713 | FitDetector(rings,varyList,parmDict) |
---|
714 | data['distance'] = parmDict['dist'] |
---|
715 | data['center'] = [parmDict['det-X'],parmDict['det-Y']] |
---|
716 | data['rotation'] = parmDict['phi'] |
---|
717 | data['tilt'] = parmDict['tilt'] |
---|
718 | data['DetDepth'] = parmDict['dep'] |
---|
719 | for H in HKL[:N]: |
---|
720 | ellipse = GetEllipse(H[3],data) |
---|
721 | data['ellipses'].append(copy.deepcopy(ellipse+('b',))) |
---|
722 | print 'calibration time = ',time.time()-time0 |
---|
723 | G2plt.PlotImage(self,newImage=True) |
---|
724 | return True |
---|
725 | |
---|
726 | def Make2ThetaAzimuthMap(data,masks,iLim,jLim): |
---|
727 | 'Needs a doc string' |
---|
728 | #transforms 2D image from x,y space to 2-theta,azimuth space based on detector orientation |
---|
729 | pixelSize = data['pixelSize'] |
---|
730 | scalex = pixelSize[0]/1000. |
---|
731 | scaley = pixelSize[1]/1000. |
---|
732 | |
---|
733 | tay,tax = np.mgrid[iLim[0]+0.5:iLim[1]+.5,jLim[0]+.5:jLim[1]+.5] #bin centers not corners |
---|
734 | tax = np.asfarray(tax*scalex,dtype=np.float32) |
---|
735 | tay = np.asfarray(tay*scaley,dtype=np.float32) |
---|
736 | nI = iLim[1]-iLim[0] |
---|
737 | nJ = jLim[1]-jLim[0] |
---|
738 | #make position masks here |
---|
739 | frame = masks['Frames'] |
---|
740 | tam = ma.make_mask_none((nI,nJ)) |
---|
741 | if frame: |
---|
742 | tamp = ma.make_mask_none((1024*1024)) |
---|
743 | tamp = ma.make_mask(pm.polymask(nI*nJ,tax.flatten(), |
---|
744 | tay.flatten(),len(frame),frame,tamp)[:nI*nJ])-True #switch to exclude around frame |
---|
745 | tam = ma.mask_or(tam.flatten(),tamp) |
---|
746 | polygons = masks['Polygons'] |
---|
747 | for polygon in polygons: |
---|
748 | if polygon: |
---|
749 | tamp = ma.make_mask_none((1024*1024)) |
---|
750 | tamp = ma.make_mask(pm.polymask(nI*nJ,tax.flatten(), |
---|
751 | tay.flatten(),len(polygon),polygon,tamp)[:nI*nJ]) |
---|
752 | tam = ma.mask_or(tam.flatten(),tamp) |
---|
753 | if tam.shape: tam = np.reshape(tam,(nI,nJ)) |
---|
754 | spots = masks['Points'] |
---|
755 | for X,Y,diam in spots: |
---|
756 | tamp = ma.getmask(ma.masked_less((tax-X)**2+(tay-Y)**2,(diam/2.)**2)) |
---|
757 | tam = ma.mask_or(tam,tamp) |
---|
758 | TA = np.array(GetTthAzmD(tax,tay,data)) #includes geom. corr. as dist**2/d0**2 |
---|
759 | TA[1] = np.where(TA[1]<0,TA[1]+360,TA[1]) |
---|
760 | return np.array(TA),tam #2-theta, azimuth & geom. corr. arrays & position mask |
---|
761 | |
---|
762 | def Fill2ThetaAzimuthMap(masks,TA,tam,image): |
---|
763 | 'Needs a doc string' |
---|
764 | Zlim = masks['Thresholds'][1] |
---|
765 | rings = masks['Rings'] |
---|
766 | arcs = masks['Arcs'] |
---|
767 | TA = np.dstack((ma.getdata(TA[1]),ma.getdata(TA[0]),ma.getdata(TA[2]))) #azimuth, 2-theta, dist |
---|
768 | tax,tay,tad = np.dsplit(TA,3) #azimuth, 2-theta, dist**2/d0**2 |
---|
769 | for tth,thick in rings: |
---|
770 | tam = ma.mask_or(tam.flatten(),ma.getmask(ma.masked_inside(tay.flatten(),max(0.01,tth-thick/2.),tth+thick/2.))) |
---|
771 | for tth,azm,thick in arcs: |
---|
772 | tamt = ma.getmask(ma.masked_inside(tay.flatten(),max(0.01,tth-thick/2.),tth+thick/2.)) |
---|
773 | tama = ma.getmask(ma.masked_inside(tax.flatten(),azm[0],azm[1])) |
---|
774 | tam = ma.mask_or(tam.flatten(),tamt*tama) |
---|
775 | taz = ma.masked_outside(image.flatten(),int(Zlim[0]),Zlim[1]) |
---|
776 | tabs = np.ones_like(taz) |
---|
777 | tam = ma.mask_or(tam.flatten(),ma.getmask(taz)) |
---|
778 | tax = ma.compressed(ma.array(tax.flatten(),mask=tam)) |
---|
779 | tay = ma.compressed(ma.array(tay.flatten(),mask=tam)) |
---|
780 | taz = ma.compressed(ma.array(taz.flatten(),mask=tam)) |
---|
781 | tad = ma.compressed(ma.array(tad.flatten(),mask=tam)) |
---|
782 | tabs = ma.compressed(ma.array(tabs.flatten(),mask=tam)) |
---|
783 | return tax,tay,taz,tad,tabs |
---|
784 | |
---|
785 | def ImageIntegrate(image,data,masks,blkSize=128,dlg=None): |
---|
786 | 'Needs a doc string' |
---|
787 | import histogram2d as h2d |
---|
788 | print 'Begin image integration' |
---|
789 | LUtth = data['IOtth'] |
---|
790 | LRazm = np.array(data['LRazimuth'],dtype=np.float64) |
---|
791 | numAzms = data['outAzimuths'] |
---|
792 | numChans = data['outChannels'] |
---|
793 | Dtth = (LUtth[1]-LUtth[0])/numChans |
---|
794 | Dazm = (LRazm[1]-LRazm[0])/numAzms |
---|
795 | if data['centerAzm']: |
---|
796 | LRazm += Dazm/2. |
---|
797 | NST = np.zeros(shape=(numAzms,numChans),order='F',dtype=np.float32) |
---|
798 | H0 = np.zeros(shape=(numAzms,numChans),order='F',dtype=np.float32) |
---|
799 | imageN = len(image) |
---|
800 | Nx,Ny = data['size'] |
---|
801 | nXBlks = (Nx-1)/blkSize+1 |
---|
802 | nYBlks = (Ny-1)/blkSize+1 |
---|
803 | Nup = nXBlks*nYBlks*3+3 |
---|
804 | t0 = time.time() |
---|
805 | Nup = 0 |
---|
806 | if dlg: |
---|
807 | dlg.Update(Nup) |
---|
808 | for iBlk in range(nYBlks): |
---|
809 | iBeg = iBlk*blkSize |
---|
810 | iFin = min(iBeg+blkSize,Ny) |
---|
811 | for jBlk in range(nXBlks): |
---|
812 | jBeg = jBlk*blkSize |
---|
813 | jFin = min(jBeg+blkSize,Nx) |
---|
814 | TA,tam = Make2ThetaAzimuthMap(data,masks,(iBeg,iFin),(jBeg,jFin)) #2-theta & azimuth arrays & create position mask |
---|
815 | |
---|
816 | Nup += 1 |
---|
817 | if dlg: |
---|
818 | dlg.Update(Nup) |
---|
819 | Block = image[iBeg:iFin,jBeg:jFin] |
---|
820 | tax,tay,taz,tad,tabs = Fill2ThetaAzimuthMap(masks,TA,tam,Block) #and apply masks |
---|
821 | Nup += 1 |
---|
822 | if dlg: |
---|
823 | dlg.Update(Nup) |
---|
824 | tax = np.where(tax > LRazm[1],tax-360.,tax) #put azm inside limits if possible |
---|
825 | tax = np.where(tax < LRazm[0],tax+360.,tax) |
---|
826 | if data['SampleAbs'][1]: |
---|
827 | muR = data['SampleAbs'][0]*(1.+npsind(tax)**2/2.)/(npcosd(tay)) |
---|
828 | tabs = G2pwd.Absorb(data['SampleShape'],muR,tay) |
---|
829 | if any([tax.shape[0],tay.shape[0],taz.shape[0]]): |
---|
830 | NST,H0 = h2d.histogram2d(len(tax),tax,tay,taz*tad*tabs,numAzms,numChans,LRazm,LUtth,Dazm,Dtth,NST,H0) |
---|
831 | Nup += 1 |
---|
832 | if dlg: |
---|
833 | dlg.Update(Nup) |
---|
834 | NST = np.array(NST) |
---|
835 | H0 = np.divide(H0,NST) |
---|
836 | H0 = np.nan_to_num(H0) |
---|
837 | del NST |
---|
838 | if Dtth: |
---|
839 | H2 = np.array([tth for tth in np.linspace(LUtth[0],LUtth[1],numChans+1)]) |
---|
840 | else: |
---|
841 | H2 = np.array(LUtth) |
---|
842 | if Dazm: |
---|
843 | H1 = np.array([azm for azm in np.linspace(LRazm[0],LRazm[1],numAzms+1)]) |
---|
844 | else: |
---|
845 | H1 = LRazm |
---|
846 | H0 /= npcosd(H2[:-1])**2 |
---|
847 | if data['Oblique'][1]: |
---|
848 | H0 /= G2pwd.Oblique(data['Oblique'][0],H2[:-1]) |
---|
849 | if 'SASD' in data['type'] and data['PolaVal'][1]: |
---|
850 | H0 /= np.array([G2pwd.Polarization(data['PolaVal'][0],H2[:-1],Azm=azm)[0] for azm in H1[:-1]+np.diff(H1)/2.]) |
---|
851 | Nup += 1 |
---|
852 | if dlg: |
---|
853 | dlg.Update(Nup) |
---|
854 | t1 = time.time() |
---|
855 | print 'Integration complete' |
---|
856 | print "Elapsed time:","%8.3f"%(t1-t0), "s" |
---|
857 | return H0,H1,H2 |
---|
858 | |
---|
859 | def FitStrSta(Image,StrSta,Controls,Masks): |
---|
860 | 'Needs a doc string' |
---|
861 | |
---|
862 | # print 'Masks:',Masks |
---|
863 | StaControls = copy.deepcopy(Controls) |
---|
864 | phi = StrSta['Sample phi'] |
---|
865 | wave = Controls['wavelength'] |
---|
866 | StaControls['distance'] += StrSta['Sample z']*cosd(phi) |
---|
867 | pixSize = StaControls['pixelSize'] |
---|
868 | scalex = 1000./pixSize[0] |
---|
869 | scaley = 1000./pixSize[1] |
---|
870 | rings = [] |
---|
871 | |
---|
872 | for ring in StrSta['d-zero']: #get observed x,y,d points for the d-zeros |
---|
873 | ellipse = GetEllipse(ring['Dset'],StaControls) |
---|
874 | Ring = makeRing(ring['Dset'],ellipse,ring['pixLimit'],ring['cutoff'],scalex,scaley,Image) |
---|
875 | Ring = np.array(Ring).T |
---|
876 | ring['ImxyObs'] = np.array(Ring[:2]) #need to apply masks to this to eliminate bad points |
---|
877 | Ring[:2] = GetTthAzm(Ring[0],Ring[1],StaControls) #convert x,y to tth,azm |
---|
878 | Ring[0] /= 2. #convert to theta |
---|
879 | if len(rings): |
---|
880 | rings = np.concatenate((rings,Ring),axis=1) |
---|
881 | else: |
---|
882 | rings = np.array(Ring) |
---|
883 | E = StrSta['strain'] |
---|
884 | p0 = [E[0][0],E[1][1],E[2][2],E[0][1],E[0][2],E[1][2]] |
---|
885 | E = FitStrain(rings,p0,wave,phi) |
---|
886 | StrSta['strain'] = E |
---|
887 | |
---|
888 | def calcFij(omg,phi,azm,th): |
---|
889 | '''Does something... |
---|
890 | |
---|
891 | Uses parameters as defined by Bob He & Kingsley Smith, Adv. in X-Ray Anal. 41, 501 (1997) |
---|
892 | |
---|
893 | :param omg: his omega = sample omega rotation; 0 when incident beam || sample surface, 90 when perp. to sample surface |
---|
894 | :param phi: his phi = sample phi rotation; usually = 0, axis rotates with omg. |
---|
895 | :param azm: his chi = azimuth around incident beam |
---|
896 | :param th: his theta = theta |
---|
897 | ''' |
---|
898 | a = npsind(th)*npcosd(omg)+npsind(azm)*npcosd(th)*npsind(omg) |
---|
899 | b = -npcosd(azm)*npcosd(th) |
---|
900 | c = npsind(th)*npsind(omg)-npsind(azm)*npcosd(th)*npcosd(omg) |
---|
901 | d = a*npcosd(phi)-b*npsind(phi) |
---|
902 | e = a*npsind(phi)+b*npcosd(phi) |
---|
903 | Fij = np.array([ |
---|
904 | [d**2,d*e,c*d], |
---|
905 | [d*e,e**2,c*e], |
---|
906 | [c*d,c*e,c**2]]) |
---|
907 | return -Fij*nptand(th) |
---|
908 | |
---|
909 | def FitStrain(rings,p0,wave,phi): |
---|
910 | 'Needs a doc string' |
---|
911 | def StrainPrint(ValSig): |
---|
912 | print 'Strain tensor:' |
---|
913 | ptlbls = 'names :' |
---|
914 | ptstr = 'values:' |
---|
915 | sigstr = 'esds :' |
---|
916 | for name,fmt,value,sig in ValSig: |
---|
917 | ptlbls += "%s" % (name.rjust(12)) |
---|
918 | ptstr += fmt % (value) |
---|
919 | if sig: |
---|
920 | sigstr += fmt % (sig) |
---|
921 | else: |
---|
922 | sigstr += 12*' ' |
---|
923 | print ptlbls |
---|
924 | print ptstr |
---|
925 | print sigstr |
---|
926 | |
---|
927 | def strainCalc(p,xyd,wave,phi): |
---|
928 | # E = np.array([[p[0],p[3],p[4]],[p[3],p[1],p[5]],[p[4],p[5],p[2]]]) |
---|
929 | E = np.array([[p[0],0,0],[0,p[1],0],[0,0,0]]) |
---|
930 | th,azm,dsp = xyd |
---|
931 | th0 = npasind(wave/(2.*dsp)) |
---|
932 | dth = 180.*np.sum(E*calcFij(phi,0.,azm,th).T)/(np.pi*1.e6) #in degrees & microstrain units |
---|
933 | th0 += dth |
---|
934 | return (th-th0)**2 |
---|
935 | |
---|
936 | names = ['e11','e22','e33','e12','e13','e23'] |
---|
937 | fmt = ['%12.2f','%12.2f','%12.2f','%12.2f','%12.2f','%12.5f'] |
---|
938 | p1 = [p0[0],p0[1]] |
---|
939 | result = leastsq(strainCalc,p1,args=(rings,wave,phi),full_output=True) |
---|
940 | vals = list(result[0]) |
---|
941 | chi = np.sqrt(np.sum(strainCalc(result[0],rings,wave,phi)**2)) |
---|
942 | sig = list(chi*np.sqrt(np.diag(result[1]))) |
---|
943 | ValSig = zip(names,fmt,vals,sig) |
---|
944 | StrainPrint(ValSig) |
---|
945 | # return np.array([[vals[0],vals[3],vals[4]],[vals[3],vals[1],vals[5]],[vals[4],vals[5],vals[2]]]) |
---|
946 | return np.array([[vals[0],0,0],[0,vals[1],0],[0,0,0]]) |
---|
947 | |
---|
948 | |
---|