1 | # -*- coding: utf-8 -*- |
---|
2 | #GSASII image calculations: ellipse fitting & image integration |
---|
3 | ########### SVN repository information ################### |
---|
4 | # $Date: 2017-05-10 14:14:10 +0000 (Wed, 10 May 2017) $ |
---|
5 | # $Author: vondreele $ |
---|
6 | # $Revision: 2824 $ |
---|
7 | # $URL: trunk/GSASIIimage.py $ |
---|
8 | # $Id: GSASIIimage.py 2824 2017-05-10 14:14:10Z 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 scipy.signal as scsg |
---|
26 | import scipy.cluster.vq as scvq |
---|
27 | import copy |
---|
28 | import GSASIIpath |
---|
29 | GSASIIpath.SetVersionNumber("$Revision: 2824 $") |
---|
30 | import GSASIIplot as G2plt |
---|
31 | import GSASIIlattice as G2lat |
---|
32 | import GSASIIpwd as G2pwd |
---|
33 | import GSASIIspc as G2spc |
---|
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)/np.pi |
---|
47 | npcosd = lambda x: np.cos(x*np.pi/180.) |
---|
48 | npacosd = lambda x: 180.*np.arccos(x)/np.pi |
---|
49 | nptand = lambda x: np.tan(x*np.pi/180.) |
---|
50 | npatand = lambda x: 180.*np.arctan(x)/np.pi |
---|
51 | npatan2d = lambda y,x: 180.*np.arctan2(y,x)/np.pi |
---|
52 | debug = False |
---|
53 | |
---|
54 | def pointInPolygon(pXY,xy): |
---|
55 | 'Needs a doc string' |
---|
56 | #pXY - assumed closed 1st & last points are duplicates |
---|
57 | Inside = False |
---|
58 | N = len(pXY) |
---|
59 | p1x,p1y = pXY[0] |
---|
60 | for i in range(N+1): |
---|
61 | p2x,p2y = pXY[i%N] |
---|
62 | if (max(p1y,p2y) >= xy[1] > min(p1y,p2y)) and (xy[0] <= max(p1x,p2x)): |
---|
63 | if p1y != p2y: |
---|
64 | xinters = (xy[1]-p1y)*(p2x-p1x)/(p2y-p1y)+p1x |
---|
65 | if p1x == p2x or xy[0] <= xinters: |
---|
66 | Inside = not Inside |
---|
67 | p1x,p1y = p2x,p2y |
---|
68 | return Inside |
---|
69 | |
---|
70 | def peneCorr(tth,dep,dist,tilt=0.,azm=0.): |
---|
71 | 'Needs a doc string' |
---|
72 | # return dep*(1.-npcosd(abs(tilt*npsind(azm))-tth*npcosd(azm))) #something wrong here |
---|
73 | return dep*(1.-npcosd(tth))*dist**2/1000. #best one |
---|
74 | # return dep*npsind(tth) #not as good as 1-cos2Q |
---|
75 | |
---|
76 | def makeMat(Angle,Axis): |
---|
77 | '''Make rotation matrix from Angle and Axis |
---|
78 | |
---|
79 | :param float Angle: in degrees |
---|
80 | :param int Axis: 0 for rotation about x, 1 for about y, etc. |
---|
81 | ''' |
---|
82 | cs = npcosd(Angle) |
---|
83 | ss = npsind(Angle) |
---|
84 | M = np.array(([1.,0.,0.],[0.,cs,-ss],[0.,ss,cs]),dtype=np.float32) |
---|
85 | return np.roll(np.roll(M,Axis,axis=0),Axis,axis=1) |
---|
86 | |
---|
87 | def FitEllipse(xy): |
---|
88 | |
---|
89 | def ellipse_center(p): |
---|
90 | ''' gives ellipse center coordinates |
---|
91 | ''' |
---|
92 | b,c,d,f,a = p[1]/2, p[2], p[3]/2, p[4]/2, p[0] |
---|
93 | num = b*b-a*c |
---|
94 | x0=(c*d-b*f)/num |
---|
95 | y0=(a*f-b*d)/num |
---|
96 | return np.array([x0,y0]) |
---|
97 | |
---|
98 | def ellipse_angle_of_rotation( p ): |
---|
99 | ''' gives rotation of ellipse major axis from x-axis |
---|
100 | range will be -90 to 90 deg |
---|
101 | ''' |
---|
102 | b,c,a = p[1]/2, p[2], p[0] |
---|
103 | return 0.5*npatand(2*b/(a-c)) |
---|
104 | |
---|
105 | def ellipse_axis_length( p ): |
---|
106 | ''' gives ellipse radii in [minor,major] order |
---|
107 | ''' |
---|
108 | b,c,d,f,g,a = p[1]/2, p[2], p[3]/2, p[4]/2, p[5], p[0] |
---|
109 | up = 2*(a*f*f+c*d*d+g*b*b-2*b*d*f-a*c*g) |
---|
110 | down1=(b*b-a*c)*( (c-a)*np.sqrt(1+4*b*b/((a-c)*(a-c)))-(c+a)) |
---|
111 | down2=(b*b-a*c)*( (a-c)*np.sqrt(1+4*b*b/((a-c)*(a-c)))-(c+a)) |
---|
112 | res1=np.sqrt(up/down1) |
---|
113 | res2=np.sqrt(up/down2) |
---|
114 | return np.array([ res2,res1]) |
---|
115 | |
---|
116 | xy = np.array(xy) |
---|
117 | x = np.asarray(xy.T[0])[:,np.newaxis] |
---|
118 | y = np.asarray(xy.T[1])[:,np.newaxis] |
---|
119 | D = np.hstack((x*x, x*y, y*y, x, y, np.ones_like(x))) |
---|
120 | S = np.dot(D.T,D) |
---|
121 | C = np.zeros([6,6]) |
---|
122 | C[0,2] = C[2,0] = 2; C[1,1] = -1 |
---|
123 | E, V = nl.eig(np.dot(nl.inv(S), C)) |
---|
124 | n = np.argmax(np.abs(E)) |
---|
125 | a = V[:,n] |
---|
126 | cent = ellipse_center(a) |
---|
127 | phi = ellipse_angle_of_rotation(a) |
---|
128 | radii = ellipse_axis_length(a) |
---|
129 | phi += 90. |
---|
130 | if radii[0] > radii[1]: |
---|
131 | radii = [radii[1],radii[0]] |
---|
132 | phi -= 90. |
---|
133 | return cent,phi,radii |
---|
134 | |
---|
135 | def FitDetector(rings,varyList,parmDict,Print=True): |
---|
136 | 'Needs a doc string' |
---|
137 | |
---|
138 | def CalibPrint(ValSig,chisq,Npts): |
---|
139 | print 'Image Parameters: chi**2: %12.3g, Np: %d'%(chisq,Npts) |
---|
140 | ptlbls = 'names :' |
---|
141 | ptstr = 'values:' |
---|
142 | sigstr = 'esds :' |
---|
143 | for name,value,sig in ValSig: |
---|
144 | ptlbls += "%s" % (name.rjust(12)) |
---|
145 | if name == 'phi': |
---|
146 | ptstr += Fmt[name] % (value%360.) |
---|
147 | else: |
---|
148 | ptstr += Fmt[name] % (value) |
---|
149 | if sig: |
---|
150 | sigstr += Fmt[name] % (sig) |
---|
151 | else: |
---|
152 | sigstr += 12*' ' |
---|
153 | print ptlbls |
---|
154 | print ptstr |
---|
155 | print sigstr |
---|
156 | |
---|
157 | def ellipseCalcD(B,xyd,varyList,parmDict): |
---|
158 | |
---|
159 | x,y,dsp = xyd |
---|
160 | varyDict = dict(zip(varyList,B)) |
---|
161 | parms = {} |
---|
162 | for parm in parmDict: |
---|
163 | if parm in varyList: |
---|
164 | parms[parm] = varyDict[parm] |
---|
165 | else: |
---|
166 | parms[parm] = parmDict[parm] |
---|
167 | phi = parms['phi']-90. #get rotation of major axis from tilt axis |
---|
168 | tth = 2.0*npasind(parms['wave']/(2.*dsp)) |
---|
169 | phi0 = npatan2d(y-parms['det-Y'],x-parms['det-X']) |
---|
170 | dxy = peneCorr(tth,parms['dep'],parms['dist'],parms['tilt'],phi0) |
---|
171 | stth = npsind(tth) |
---|
172 | cosb = npcosd(parms['tilt']) |
---|
173 | tanb = nptand(parms['tilt']) |
---|
174 | tbm = nptand((tth-parms['tilt'])/2.) |
---|
175 | tbp = nptand((tth+parms['tilt'])/2.) |
---|
176 | d = parms['dist']+dxy |
---|
177 | fplus = d*tanb*stth/(cosb+stth) |
---|
178 | fminus = d*tanb*stth/(cosb-stth) |
---|
179 | vplus = d*(tanb+(1+tbm)/(1-tbm))*stth/(cosb+stth) |
---|
180 | vminus = d*(tanb+(1-tbp)/(1+tbp))*stth/(cosb-stth) |
---|
181 | R0 = np.sqrt((vplus+vminus)**2-(fplus+fminus)**2)/2. #+minor axis |
---|
182 | R1 = (vplus+vminus)/2. #major axis |
---|
183 | zdis = (fplus-fminus)/2. |
---|
184 | Robs = np.sqrt((x-parms['det-X'])**2+(y-parms['det-Y'])**2) |
---|
185 | rsqplus = R0**2+R1**2 |
---|
186 | rsqminus = R0**2-R1**2 |
---|
187 | R = rsqminus*npcosd(2.*phi0-2.*phi)+rsqplus |
---|
188 | Q = np.sqrt(2.)*R0*R1*np.sqrt(R-2.*zdis**2*npsind(phi0-phi)**2) |
---|
189 | P = 2.*R0**2*zdis*npcosd(phi0-phi) |
---|
190 | Rcalc = (P+Q)/R |
---|
191 | M = (Robs-Rcalc)*10. #why 10? does make "chi**2" more reasonable |
---|
192 | return M |
---|
193 | |
---|
194 | names = ['dist','det-X','det-Y','tilt','phi','dep','wave'] |
---|
195 | fmt = ['%12.3f','%12.3f','%12.3f','%12.3f','%12.3f','%12.4f','%12.6f'] |
---|
196 | Fmt = dict(zip(names,fmt)) |
---|
197 | p0 = [parmDict[key] for key in varyList] |
---|
198 | result = leastsq(ellipseCalcD,p0,args=(rings.T,varyList,parmDict),full_output=True,ftol=1.e-8) |
---|
199 | chisq = np.sum(result[2]['fvec']**2)/(rings.shape[0]-len(p0)) #reduced chi^2 = M/(Nobs-Nvar) |
---|
200 | parmDict.update(zip(varyList,result[0])) |
---|
201 | vals = list(result[0]) |
---|
202 | sig = list(np.sqrt(chisq*np.diag(result[1]))) |
---|
203 | sigList = np.zeros(7) |
---|
204 | for i,name in enumerate(varyList): |
---|
205 | sigList[i] = sig[varyList.index(name)] |
---|
206 | ValSig = zip(varyList,vals,sig) |
---|
207 | if Print: |
---|
208 | CalibPrint(ValSig,chisq,rings.shape[0]) |
---|
209 | return [chisq,vals,sigList] |
---|
210 | |
---|
211 | def ImageLocalMax(image,w,Xpix,Ypix): |
---|
212 | 'Needs a doc string' |
---|
213 | w2 = w*2 |
---|
214 | sizey,sizex = image.shape |
---|
215 | xpix = int(Xpix) #get reference corner of pixel chosen |
---|
216 | ypix = int(Ypix) |
---|
217 | if not w: |
---|
218 | ZMax = np.sum(image[ypix-2:ypix+2,xpix-2:xpix+2]) |
---|
219 | return xpix,ypix,ZMax,0.0001 |
---|
220 | if (w2 < xpix < sizex-w2) and (w2 < ypix < sizey-w2) and image[ypix,xpix]: |
---|
221 | ZMax = image[ypix-w:ypix+w,xpix-w:xpix+w] |
---|
222 | Zmax = np.argmax(ZMax) |
---|
223 | ZMin = image[ypix-w2:ypix+w2,xpix-w2:xpix+w2] |
---|
224 | Zmin = np.argmin(ZMin) |
---|
225 | xpix += Zmax%w2-w |
---|
226 | ypix += Zmax/w2-w |
---|
227 | return xpix,ypix,np.ravel(ZMax)[Zmax],max(0.0001,np.ravel(ZMin)[Zmin]) #avoid neg/zero minimum |
---|
228 | else: |
---|
229 | return 0,0,0,0 |
---|
230 | |
---|
231 | def makeRing(dsp,ellipse,pix,reject,scalex,scaley,image): |
---|
232 | 'Needs a doc string' |
---|
233 | def ellipseC(): |
---|
234 | 'compute estimate of ellipse circumference' |
---|
235 | if radii[0] < 0: #hyperbola |
---|
236 | theta = npacosd(1./np.sqrt(1.+(radii[0]/radii[1])**2)) |
---|
237 | print theta |
---|
238 | return 0 |
---|
239 | apb = radii[1]+radii[0] |
---|
240 | amb = radii[1]-radii[0] |
---|
241 | return np.pi*apb*(1+3*(amb/apb)**2/(10+np.sqrt(4-3*(amb/apb)**2))) |
---|
242 | |
---|
243 | cent,phi,radii = ellipse |
---|
244 | cphi = cosd(phi-90.) #convert to major axis rotation |
---|
245 | sphi = sind(phi-90.) |
---|
246 | ring = [] |
---|
247 | C = int(ellipseC()) #ring circumference |
---|
248 | azm = [] |
---|
249 | for i in range(0,C,1): #step around ring in 1mm increments |
---|
250 | a = 360.*i/C |
---|
251 | x = radii[1]*cosd(a-phi+90.) #major axis |
---|
252 | y = radii[0]*sind(a-phi+90.) |
---|
253 | X = (cphi*x-sphi*y+cent[0])*scalex #convert mm to pixels |
---|
254 | Y = (sphi*x+cphi*y+cent[1])*scaley |
---|
255 | X,Y,I,J = ImageLocalMax(image,pix,X,Y) |
---|
256 | if I and J and float(I)/J > reject: |
---|
257 | X += .5 #set to center of pixel |
---|
258 | Y += .5 |
---|
259 | X /= scalex #convert back to mm |
---|
260 | Y /= scaley |
---|
261 | if [X,Y,dsp] not in ring: #no duplicates! |
---|
262 | ring.append([X,Y,dsp]) |
---|
263 | azm.append(a) |
---|
264 | if len(ring) < 10: |
---|
265 | ring = [] |
---|
266 | azm = [] |
---|
267 | return ring,azm |
---|
268 | |
---|
269 | def GetEllipse2(tth,dxy,dist,cent,tilt,phi): |
---|
270 | '''uses Dandelin spheres to find ellipse or hyperbola parameters from detector geometry |
---|
271 | on output |
---|
272 | radii[0] (b-minor axis) set < 0. for hyperbola |
---|
273 | |
---|
274 | ''' |
---|
275 | radii = [0,0] |
---|
276 | stth = sind(tth) |
---|
277 | cosb = cosd(tilt) |
---|
278 | tanb = tand(tilt) |
---|
279 | tbm = tand((tth-tilt)/2.) |
---|
280 | tbp = tand((tth+tilt)/2.) |
---|
281 | sinb = sind(tilt) |
---|
282 | d = dist+dxy |
---|
283 | if tth+abs(tilt) < 90.: #ellipse |
---|
284 | fplus = d*tanb*stth/(cosb+stth) |
---|
285 | fminus = d*tanb*stth/(cosb-stth) |
---|
286 | vplus = d*(tanb+(1+tbm)/(1-tbm))*stth/(cosb+stth) |
---|
287 | vminus = d*(tanb+(1-tbp)/(1+tbp))*stth/(cosb-stth) |
---|
288 | radii[0] = np.sqrt((vplus+vminus)**2-(fplus+fminus)**2)/2. #+minor axis |
---|
289 | radii[1] = (vplus+vminus)/2. #major axis |
---|
290 | zdis = (fplus-fminus)/2. |
---|
291 | else: #hyperbola! |
---|
292 | f = d*abs(tanb)*stth/(cosb+stth) |
---|
293 | v = d*(abs(tanb)+tand(tth-abs(tilt))) |
---|
294 | delt = d*stth*(1.+stth*cosb)/(abs(sinb)*cosb*(stth+cosb)) |
---|
295 | eps = (v-f)/(delt-v) |
---|
296 | radii[0] = -eps*(delt-f)/np.sqrt(eps**2-1.) #-minor axis |
---|
297 | radii[1] = eps*(delt-f)/(eps**2-1.) #major axis |
---|
298 | if tilt > 0: |
---|
299 | zdis = f+radii[1]*eps |
---|
300 | else: |
---|
301 | zdis = -f |
---|
302 | #NB: zdis is || to major axis & phi is rotation of minor axis |
---|
303 | #thus shift from beam to ellipse center is [Z*sin(phi),-Z*cos(phi)] |
---|
304 | elcent = [cent[0]+zdis*sind(phi),cent[1]-zdis*cosd(phi)] |
---|
305 | return elcent,phi,radii |
---|
306 | |
---|
307 | def GetEllipse(dsp,data): |
---|
308 | '''uses Dandelin spheres to find ellipse or hyperbola parameters from detector geometry |
---|
309 | as given in image controls dictionary (data) and a d-spacing (dsp) |
---|
310 | ''' |
---|
311 | cent = data['center'] |
---|
312 | tilt = data['tilt'] |
---|
313 | phi = data['rotation'] |
---|
314 | dep = data.get('DetDepth',0.0) |
---|
315 | tth = 2.0*asind(data['wavelength']/(2.*dsp)) |
---|
316 | dist = data['distance'] |
---|
317 | dxy = peneCorr(tth,dep,dist,tilt) |
---|
318 | return GetEllipse2(tth,dxy,dist,cent,tilt,phi) |
---|
319 | |
---|
320 | def GetDetectorXY(dsp,azm,data): |
---|
321 | 'Needs a doc string' |
---|
322 | |
---|
323 | elcent,phi,radii = GetEllipse(dsp,data) |
---|
324 | phi = data['rotation']-90. #to give rotation of major axis |
---|
325 | tilt = data['tilt'] |
---|
326 | dist = data['distance'] |
---|
327 | cent = data['center'] |
---|
328 | tth = 2.0*asind(data['wavelength']/(2.*dsp)) |
---|
329 | stth = sind(tth) |
---|
330 | cosb = cosd(tilt) |
---|
331 | if radii[0] > 0.: |
---|
332 | sinb = sind(tilt) |
---|
333 | tanb = tand(tilt) |
---|
334 | fplus = dist*tanb*stth/(cosb+stth) |
---|
335 | fminus = dist*tanb*stth/(cosb-stth) |
---|
336 | zdis = (fplus-fminus)/2. |
---|
337 | rsqplus = radii[0]**2+radii[1]**2 |
---|
338 | rsqminus = radii[0]**2-radii[1]**2 |
---|
339 | R = rsqminus*cosd(2.*azm-2.*phi)+rsqplus |
---|
340 | Q = np.sqrt(2.)*radii[0]*radii[1]*np.sqrt(R-2.*zdis**2*sind(azm-phi)**2) |
---|
341 | P = 2.*radii[0]**2*zdis*cosd(azm-phi) |
---|
342 | radius = (P+Q)/R |
---|
343 | xy = np.array([radius*cosd(azm),radius*sind(azm)]) |
---|
344 | xy += cent |
---|
345 | else: #hyperbola - both branches (one is way off screen!) |
---|
346 | sinb = abs(sind(tilt)) |
---|
347 | tanb = abs(tand(tilt)) |
---|
348 | f = dist*tanb*stth/(cosb+stth) |
---|
349 | v = dist*(tanb+tand(tth-abs(tilt))) |
---|
350 | delt = dist*stth*(1+stth*cosb)/(sinb*cosb*(stth+cosb)) |
---|
351 | ecc = (v-f)/(delt-v) |
---|
352 | R = radii[1]*(ecc**2-1)/(1-ecc*cosd(azm)) |
---|
353 | if tilt > 0.: |
---|
354 | offset = 2.*radii[1]*ecc+f #select other branch |
---|
355 | xy = [-R*cosd(azm)-offset,R*sind(azm)] |
---|
356 | else: |
---|
357 | offset = -f |
---|
358 | xy = [-R*cosd(azm)-offset,-R*sind(azm)] |
---|
359 | xy = -np.array([xy[0]*cosd(phi)+xy[1]*sind(phi),xy[0]*sind(phi)-xy[1]*cosd(phi)]) |
---|
360 | xy += cent |
---|
361 | return xy |
---|
362 | |
---|
363 | def GetDetXYfromThAzm(Th,Azm,data): |
---|
364 | '''Computes a detector position from a 2theta angle and an azimultal |
---|
365 | angle (both in degrees) |
---|
366 | ''' |
---|
367 | dsp = data['wavelength']/(2.0*npsind(Th)) |
---|
368 | return GetDetectorXY(dsp,Azm,data) |
---|
369 | |
---|
370 | def GetTthAzmDsp(x,y,data): #expensive |
---|
371 | '''Computes a 2theta, etc. from a detector position and calibration constants - checked |
---|
372 | OK for ellipses & hyperbola. |
---|
373 | |
---|
374 | :returns: np.array(tth,azm,G,dsp) where tth is 2theta, azm is the azimutal angle, |
---|
375 | G is ? and dsp is the d-space |
---|
376 | ''' |
---|
377 | wave = data['wavelength'] |
---|
378 | cent = data['center'] |
---|
379 | tilt = data['tilt'] |
---|
380 | dist = data['distance']/cosd(tilt) |
---|
381 | x0 = dist*tand(tilt) |
---|
382 | phi = data['rotation'] |
---|
383 | dep = data.get('DetDepth',0.) |
---|
384 | azmthoff = data['azmthOff'] |
---|
385 | dx = np.array(x-cent[0],dtype=np.float32) |
---|
386 | dy = np.array(y-cent[1],dtype=np.float32) |
---|
387 | D = ((dx-x0)**2+dy**2+dist**2) #sample to pixel distance |
---|
388 | X = np.array(([dx,dy,np.zeros_like(dx)]),dtype=np.float32).T |
---|
389 | X = np.dot(X,makeMat(phi,2)) |
---|
390 | Z = np.dot(X,makeMat(tilt,0)).T[2] |
---|
391 | tth = npatand(np.sqrt(dx**2+dy**2-Z**2)/(dist-Z)) |
---|
392 | dxy = peneCorr(tth,dep,dist,tilt,npatan2d(dy,dx)) |
---|
393 | DX = dist-Z+dxy |
---|
394 | DY = np.sqrt(dx**2+dy**2-Z**2) |
---|
395 | tth = npatan2d(DY,DX) |
---|
396 | dsp = wave/(2.*npsind(tth/2.)) |
---|
397 | azm = (npatan2d(dy,dx)+azmthoff+720.)%360. |
---|
398 | G = D/dist**2 #for geometric correction = 1/cos(2theta)^2 if tilt=0. |
---|
399 | return np.array([tth,azm,G,dsp]) |
---|
400 | |
---|
401 | def GetTth(x,y,data): |
---|
402 | 'Give 2-theta value for detector x,y position; calibration info in data' |
---|
403 | return GetTthAzmDsp(x,y,data)[0] |
---|
404 | |
---|
405 | def GetTthAzm(x,y,data): |
---|
406 | 'Give 2-theta, azimuth values for detector x,y position; calibration info in data' |
---|
407 | return GetTthAzmDsp(x,y,data)[0:2] |
---|
408 | |
---|
409 | def GetTthAzmG(x,y,data): |
---|
410 | '''Give 2-theta, azimuth & geometric corr. values for detector x,y position; |
---|
411 | calibration info in data - only used in integration |
---|
412 | ''' |
---|
413 | 'Needs a doc string - checked OK for ellipses & hyperbola' |
---|
414 | tilt = data['tilt'] |
---|
415 | dist = data['distance']/npcosd(tilt) |
---|
416 | x0 = data['distance']*nptand(tilt) |
---|
417 | MN = -np.inner(makeMat(data['rotation'],2),makeMat(tilt,0)) |
---|
418 | distsq = data['distance']**2 |
---|
419 | dx = x-data['center'][0] |
---|
420 | dy = y-data['center'][1] |
---|
421 | G = ((dx-x0)**2+dy**2+distsq)/distsq #for geometric correction = 1/cos(2theta)^2 if tilt=0. |
---|
422 | X = np.dstack([dx.T,dy.T,np.zeros_like(dx.T)]) |
---|
423 | Z = np.dot(X,MN).T[2] |
---|
424 | xyZ = dx**2+dy**2-Z**2 |
---|
425 | tth = npatand(np.sqrt(xyZ)/(dist-Z)) |
---|
426 | dxy = peneCorr(tth,data['DetDepth'],dist,tilt,npatan2d(dy,dx)) |
---|
427 | tth = npatan2d(np.sqrt(xyZ),dist-Z+dxy) |
---|
428 | azm = (npatan2d(dy,dx)+data['azmthOff']+720.)%360. |
---|
429 | return tth,azm,G |
---|
430 | |
---|
431 | def GetDsp(x,y,data): |
---|
432 | 'Give d-spacing value for detector x,y position; calibration info in data' |
---|
433 | return GetTthAzmDsp(x,y,data)[3] |
---|
434 | |
---|
435 | def GetAzm(x,y,data): |
---|
436 | 'Give azimuth value for detector x,y position; calibration info in data' |
---|
437 | return GetTthAzmDsp(x,y,data)[1] |
---|
438 | |
---|
439 | def meanAzm(a,b): |
---|
440 | AZM = lambda a,b: npacosd(0.5*(npsind(2.*b)-npsind(2.*a))/(np.pi*(b-a)/180.))/2. |
---|
441 | azm = AZM(a,b) |
---|
442 | # quad = int((a+b)/180.) |
---|
443 | # if quad == 1: |
---|
444 | # azm = 180.-azm |
---|
445 | # elif quad == 2: |
---|
446 | # azm += 180. |
---|
447 | # elif quad == 3: |
---|
448 | # azm = 360-azm |
---|
449 | return azm |
---|
450 | |
---|
451 | def ImageCompress(image,scale): |
---|
452 | ''' Reduces size of image by selecting every n'th point |
---|
453 | param: image array: original image |
---|
454 | param: scale int: intervsl between selected points |
---|
455 | returns: array: reduced size image |
---|
456 | ''' |
---|
457 | if scale == 1: |
---|
458 | return image |
---|
459 | else: |
---|
460 | return image[::scale,::scale] |
---|
461 | |
---|
462 | def checkEllipse(Zsum,distSum,xSum,ySum,dist,x,y): |
---|
463 | 'Needs a doc string' |
---|
464 | avg = np.array([distSum/Zsum,xSum/Zsum,ySum/Zsum]) |
---|
465 | curr = np.array([dist,x,y]) |
---|
466 | return abs(avg-curr)/avg < .02 |
---|
467 | |
---|
468 | def EdgeFinder(image,data): |
---|
469 | '''this makes list of all x,y where I>edgeMin suitable for an ellipse search? |
---|
470 | Not currently used but might be useful in future? |
---|
471 | ''' |
---|
472 | import numpy.ma as ma |
---|
473 | Nx,Ny = data['size'] |
---|
474 | pixelSize = data['pixelSize'] |
---|
475 | edgemin = data['edgemin'] |
---|
476 | scalex = pixelSize[0]/1000. |
---|
477 | scaley = pixelSize[1]/1000. |
---|
478 | tay,tax = np.mgrid[0:Nx,0:Ny] |
---|
479 | tax = np.asfarray(tax*scalex,dtype=np.float32) |
---|
480 | tay = np.asfarray(tay*scaley,dtype=np.float32) |
---|
481 | tam = ma.getmask(ma.masked_less(image.flatten(),edgemin)) |
---|
482 | tax = ma.compressed(ma.array(tax.flatten(),mask=tam)) |
---|
483 | tay = ma.compressed(ma.array(tay.flatten(),mask=tam)) |
---|
484 | return zip(tax,tay) |
---|
485 | |
---|
486 | def MakeFrameMask(data,frame): |
---|
487 | pixelSize = data['pixelSize'] |
---|
488 | scalex = pixelSize[0]/1000. |
---|
489 | scaley = pixelSize[1]/1000. |
---|
490 | blkSize = 512 |
---|
491 | Nx,Ny = data['size'] |
---|
492 | nXBlks = (Nx-1)/blkSize+1 |
---|
493 | nYBlks = (Ny-1)/blkSize+1 |
---|
494 | tam = ma.make_mask_none(data['size']) |
---|
495 | for iBlk in range(nXBlks): |
---|
496 | iBeg = iBlk*blkSize |
---|
497 | iFin = min(iBeg+blkSize,Nx) |
---|
498 | for jBlk in range(nYBlks): |
---|
499 | jBeg = jBlk*blkSize |
---|
500 | jFin = min(jBeg+blkSize,Ny) |
---|
501 | nI = iFin-iBeg |
---|
502 | nJ = jFin-jBeg |
---|
503 | tax,tay = np.mgrid[iBeg+0.5:iFin+.5,jBeg+.5:jFin+.5] #bin centers not corners |
---|
504 | tax = np.asfarray(tax*scalex,dtype=np.float32) |
---|
505 | tay = np.asfarray(tay*scaley,dtype=np.float32) |
---|
506 | tamp = ma.make_mask_none((1024*1024)) |
---|
507 | tamp = ma.make_mask(pm.polymask(nI*nJ,tax.flatten(), |
---|
508 | tay.flatten(),len(frame),frame,tamp)[:nI*nJ])-True #switch to exclude around frame |
---|
509 | if tamp.shape: |
---|
510 | tamp = np.reshape(tamp[:nI*nJ],(nI,nJ)) |
---|
511 | tam[iBeg:iFin,jBeg:jFin] = ma.mask_or(tamp[0:nI,0:nJ],tam[iBeg:iFin,jBeg:jFin]) |
---|
512 | else: |
---|
513 | tam[iBeg:iFin,jBeg:jFin] = True |
---|
514 | return tam.T |
---|
515 | |
---|
516 | def ImageRecalibrate(G2frame,data,masks): |
---|
517 | '''Called to repeat the calibration on an image, usually called after |
---|
518 | calibration is done initially to improve the fit. |
---|
519 | ''' |
---|
520 | import ImageCalibrants as calFile |
---|
521 | print 'Image recalibration:' |
---|
522 | time0 = time.time() |
---|
523 | pixelSize = data['pixelSize'] |
---|
524 | scalex = 1000./pixelSize[0] |
---|
525 | scaley = 1000./pixelSize[1] |
---|
526 | pixLimit = data['pixLimit'] |
---|
527 | cutoff = data['cutoff'] |
---|
528 | data['rings'] = [] |
---|
529 | data['ellipses'] = [] |
---|
530 | if data['DetDepth'] > 0.5: #patch - redefine DetDepth |
---|
531 | data['DetDepth'] /= data['distance'] |
---|
532 | if not data['calibrant']: |
---|
533 | print 'no calibration material selected' |
---|
534 | return [] |
---|
535 | skip = data['calibskip'] |
---|
536 | dmin = data['calibdmin'] |
---|
537 | Bravais,SGs,Cells = calFile.Calibrants[data['calibrant']][:3] |
---|
538 | HKL = [] |
---|
539 | for bravais,sg,cell in zip(Bravais,SGs,Cells): |
---|
540 | A = G2lat.cell2A(cell) |
---|
541 | if sg: |
---|
542 | SGData = G2spc.SpcGroup(sg)[1] |
---|
543 | hkl = G2pwd.getHKLpeak(dmin,SGData,A) |
---|
544 | HKL += hkl |
---|
545 | else: |
---|
546 | hkl = G2lat.GenHBravais(dmin,bravais,A) |
---|
547 | HKL += hkl |
---|
548 | HKL = G2lat.sortHKLd(HKL,True,False) |
---|
549 | varyList = [item for item in data['varyList'] if data['varyList'][item]] |
---|
550 | parmDict = {'dist':data['distance'],'det-X':data['center'][0],'det-Y':data['center'][1], |
---|
551 | 'setdist':data.get('setdist',data['distance']), |
---|
552 | 'tilt':data['tilt'],'phi':data['rotation'],'wave':data['wavelength'],'dep':data['DetDepth']} |
---|
553 | Found = False |
---|
554 | wave = data['wavelength'] |
---|
555 | frame = masks['Frames'] |
---|
556 | tam = ma.make_mask_none(G2frame.ImageZ.shape) |
---|
557 | if frame: |
---|
558 | tam = ma.mask_or(tam,MakeFrameMask(data,frame)) |
---|
559 | for iH,H in enumerate(HKL): |
---|
560 | if debug: print H |
---|
561 | dsp = H[3] |
---|
562 | tth = 2.0*asind(wave/(2.*dsp)) |
---|
563 | if tth+abs(data['tilt']) > 90.: |
---|
564 | print 'next line is a hyperbola - search stopped' |
---|
565 | break |
---|
566 | ellipse = GetEllipse(dsp,data) |
---|
567 | Ring = makeRing(dsp,ellipse,pixLimit,cutoff,scalex,scaley,ma.array(G2frame.ImageZ,mask=tam))[0] |
---|
568 | if Ring: |
---|
569 | if iH >= skip: |
---|
570 | data['rings'].append(np.array(Ring)) |
---|
571 | data['ellipses'].append(copy.deepcopy(ellipse+('r',))) |
---|
572 | Found = True |
---|
573 | elif not Found: #skipping inner rings, keep looking until ring found |
---|
574 | continue |
---|
575 | else: #no more rings beyond edge of detector |
---|
576 | data['ellipses'].append([]) |
---|
577 | continue |
---|
578 | if not data['rings']: |
---|
579 | print 'no rings found; try lower Min ring I/Ib' |
---|
580 | return [] |
---|
581 | |
---|
582 | rings = np.concatenate((data['rings']),axis=0) |
---|
583 | [chisq,vals,sigList] = FitDetector(rings,varyList,parmDict) |
---|
584 | data['wavelength'] = parmDict['wave'] |
---|
585 | data['distance'] = parmDict['dist'] |
---|
586 | data['center'] = [parmDict['det-X'],parmDict['det-Y']] |
---|
587 | data['rotation'] = np.mod(parmDict['phi'],360.0) |
---|
588 | data['tilt'] = parmDict['tilt'] |
---|
589 | data['DetDepth'] = parmDict['dep'] |
---|
590 | data['chisq'] = chisq |
---|
591 | N = len(data['ellipses']) |
---|
592 | data['ellipses'] = [] #clear away individual ellipse fits |
---|
593 | for H in HKL[:N]: |
---|
594 | ellipse = GetEllipse(H[3],data) |
---|
595 | data['ellipses'].append(copy.deepcopy(ellipse+('b',))) |
---|
596 | print 'calibration time = %.3f'%(time.time()-time0) |
---|
597 | G2plt.PlotImage(G2frame,newImage=True) |
---|
598 | return [vals,varyList,sigList,parmDict] |
---|
599 | |
---|
600 | def ImageCalibrate(G2frame,data): |
---|
601 | '''Called to perform an initial image calibration after points have been |
---|
602 | selected for the inner ring. |
---|
603 | ''' |
---|
604 | import copy |
---|
605 | import ImageCalibrants as calFile |
---|
606 | print 'Image calibration:' |
---|
607 | time0 = time.time() |
---|
608 | ring = data['ring'] |
---|
609 | pixelSize = data['pixelSize'] |
---|
610 | scalex = 1000./pixelSize[0] |
---|
611 | scaley = 1000./pixelSize[1] |
---|
612 | pixLimit = data['pixLimit'] |
---|
613 | cutoff = data['cutoff'] |
---|
614 | varyDict = data['varyList'] |
---|
615 | if varyDict['dist'] and varyDict['wave']: |
---|
616 | print 'ERROR - you can not simultaneously calibrate distance and wavelength' |
---|
617 | return False |
---|
618 | if len(ring) < 5: |
---|
619 | print 'ERROR - not enough inner ring points for ellipse' |
---|
620 | return False |
---|
621 | |
---|
622 | #fit start points on inner ring |
---|
623 | data['ellipses'] = [] |
---|
624 | data['rings'] = [] |
---|
625 | outE = FitEllipse(ring) |
---|
626 | fmt = '%s X: %.3f, Y: %.3f, phi: %.3f, R1: %.3f, R2: %.3f' |
---|
627 | fmt2 = '%s X: %.3f, Y: %.3f, phi: %.3f, R1: %.3f, R2: %.3f, chi**2: %.3f, Np: %d' |
---|
628 | if outE: |
---|
629 | print fmt%('start ellipse: ',outE[0][0],outE[0][1],outE[1],outE[2][0],outE[2][1]) |
---|
630 | ellipse = outE |
---|
631 | else: |
---|
632 | return False |
---|
633 | |
---|
634 | #setup 360 points on that ring for "good" fit |
---|
635 | data['ellipses'].append(ellipse[:]+('g',)) |
---|
636 | Ring = makeRing(1.0,ellipse,pixLimit,cutoff,scalex,scaley,G2frame.ImageZ)[0] |
---|
637 | if Ring: |
---|
638 | ellipse = FitEllipse(Ring) |
---|
639 | Ring = makeRing(1.0,ellipse,pixLimit,cutoff,scalex,scaley,G2frame.ImageZ)[0] #do again |
---|
640 | ellipse = FitEllipse(Ring) |
---|
641 | else: |
---|
642 | print '1st ring not sufficiently complete to proceed' |
---|
643 | return False |
---|
644 | if debug: |
---|
645 | print fmt2%('inner ring: ',ellipse[0][0],ellipse[0][1],ellipse[1], |
---|
646 | ellipse[2][0],ellipse[2][1],0.,len(Ring)) #cent,phi,radii |
---|
647 | data['ellipses'].append(ellipse[:]+('r',)) |
---|
648 | data['rings'].append(np.array(Ring)) |
---|
649 | G2plt.PlotImage(G2frame,newImage=True) |
---|
650 | |
---|
651 | #setup for calibration |
---|
652 | data['rings'] = [] |
---|
653 | if not data['calibrant']: |
---|
654 | print 'no calibration material selected' |
---|
655 | return True |
---|
656 | |
---|
657 | skip = data['calibskip'] |
---|
658 | dmin = data['calibdmin'] |
---|
659 | #generate reflection set |
---|
660 | Bravais,SGs,Cells = calFile.Calibrants[data['calibrant']][:3] |
---|
661 | HKL = [] |
---|
662 | for bravais,sg,cell in zip(Bravais,SGs,Cells): |
---|
663 | A = G2lat.cell2A(cell) |
---|
664 | if sg: |
---|
665 | SGData = G2spc.SpcGroup(sg)[1] |
---|
666 | hkl = G2pwd.getHKLpeak(dmin,SGData,A) |
---|
667 | HKL += hkl |
---|
668 | else: |
---|
669 | hkl = G2lat.GenHBravais(dmin,bravais,A) |
---|
670 | HKL += hkl |
---|
671 | HKL = G2lat.sortHKLd(HKL,True,False)[skip:] |
---|
672 | #set up 1st ring |
---|
673 | elcent,phi,radii = ellipse #from fit of 1st ring |
---|
674 | dsp = HKL[0][3] |
---|
675 | print '1st ring: try %.4f'%(dsp) |
---|
676 | if varyDict['dist']: |
---|
677 | wave = data['wavelength'] |
---|
678 | tth = 2.0*asind(wave/(2.*dsp)) |
---|
679 | else: #varyDict['wave']! |
---|
680 | dist = data['distance'] |
---|
681 | tth = npatan2d(radii[0],dist) |
---|
682 | data['wavelength'] = wave = 2.0*dsp*sind(tth/2.0) |
---|
683 | Ring0 = makeRing(dsp,ellipse,3,cutoff,scalex,scaley,G2frame.ImageZ)[0] |
---|
684 | ttth = nptand(tth) |
---|
685 | ctth = npcosd(tth) |
---|
686 | #1st estimate of tilt; assume ellipse - don't know sign though |
---|
687 | if varyDict['tilt']: |
---|
688 | tilt = npasind(np.sqrt(max(0.,1.-(radii[0]/radii[1])**2))*ctth) |
---|
689 | if not tilt: |
---|
690 | print 'WARNING - selected ring was fitted as a circle' |
---|
691 | print ' - if detector was tilted we suggest you skip this ring - WARNING' |
---|
692 | else: |
---|
693 | tilt = data['tilt'] |
---|
694 | #1st estimate of dist: sample to detector normal to plane |
---|
695 | if varyDict['dist']: |
---|
696 | data['distance'] = dist = radii[0]**2/(ttth*radii[1]) |
---|
697 | else: |
---|
698 | dist = data['distance'] |
---|
699 | if varyDict['tilt']: |
---|
700 | #ellipse to cone axis (x-ray beam); 2 choices depending on sign of tilt |
---|
701 | zdisp = radii[1]*ttth*tand(tilt) |
---|
702 | zdism = radii[1]*ttth*tand(-tilt) |
---|
703 | #cone axis position; 2 choices. Which is right? |
---|
704 | #NB: zdisp is || to major axis & phi is rotation of minor axis |
---|
705 | #thus shift from beam to ellipse center is [Z*sin(phi),-Z*cos(phi)] |
---|
706 | centp = [elcent[0]+zdisp*sind(phi),elcent[1]-zdisp*cosd(phi)] |
---|
707 | centm = [elcent[0]+zdism*sind(phi),elcent[1]-zdism*cosd(phi)] |
---|
708 | #check get same ellipse parms either way |
---|
709 | #now do next ring; estimate either way & do a FitDetector each way; best fit is correct one |
---|
710 | fail = True |
---|
711 | i2 = 1 |
---|
712 | while fail: |
---|
713 | dsp = HKL[i2][3] |
---|
714 | print '2nd ring: try %.4f'%(dsp) |
---|
715 | tth = 2.0*asind(wave/(2.*dsp)) |
---|
716 | ellipsep = GetEllipse2(tth,0.,dist,centp,tilt,phi) |
---|
717 | print fmt%('plus ellipse :',ellipsep[0][0],ellipsep[0][1],ellipsep[1],ellipsep[2][0],ellipsep[2][1]) |
---|
718 | Ringp = makeRing(dsp,ellipsep,3,cutoff,scalex,scaley,G2frame.ImageZ)[0] |
---|
719 | parmDict = {'dist':dist,'det-X':centp[0],'det-Y':centp[1], |
---|
720 | 'tilt':tilt,'phi':phi,'wave':wave,'dep':0.0} |
---|
721 | varyList = [item for item in varyDict if varyDict[item]] |
---|
722 | if len(Ringp) > 10: |
---|
723 | chip = FitDetector(np.array(Ring0+Ringp),varyList,parmDict,True)[0] |
---|
724 | tiltp = parmDict['tilt'] |
---|
725 | phip = parmDict['phi'] |
---|
726 | centp = [parmDict['det-X'],parmDict['det-Y']] |
---|
727 | fail = False |
---|
728 | else: |
---|
729 | chip = 1e6 |
---|
730 | ellipsem = GetEllipse2(tth,0.,dist,centm,-tilt,phi) |
---|
731 | print fmt%('minus ellipse:',ellipsem[0][0],ellipsem[0][1],ellipsem[1],ellipsem[2][0],ellipsem[2][1]) |
---|
732 | Ringm = makeRing(dsp,ellipsem,3,cutoff,scalex,scaley,G2frame.ImageZ)[0] |
---|
733 | if len(Ringm) > 10: |
---|
734 | parmDict['tilt'] *= -1 |
---|
735 | chim = FitDetector(np.array(Ring0+Ringm),varyList,parmDict,True)[0] |
---|
736 | tiltm = parmDict['tilt'] |
---|
737 | phim = parmDict['phi'] |
---|
738 | centm = [parmDict['det-X'],parmDict['det-Y']] |
---|
739 | fail = False |
---|
740 | else: |
---|
741 | chim = 1e6 |
---|
742 | if fail: |
---|
743 | i2 += 1 |
---|
744 | if chip < chim: |
---|
745 | data['tilt'] = tiltp |
---|
746 | data['center'] = centp |
---|
747 | data['rotation'] = phip |
---|
748 | else: |
---|
749 | data['tilt'] = tiltm |
---|
750 | data['center'] = centm |
---|
751 | data['rotation'] = phim |
---|
752 | data['ellipses'].append(ellipsep[:]+('b',)) |
---|
753 | data['rings'].append(np.array(Ringp)) |
---|
754 | data['ellipses'].append(ellipsem[:]+('r',)) |
---|
755 | data['rings'].append(np.array(Ringm)) |
---|
756 | G2plt.PlotImage(G2frame,newImage=True) |
---|
757 | if data['DetDepth'] > 0.5: #patch - redefine DetDepth |
---|
758 | data['DetDepth'] /= data['distance'] |
---|
759 | parmDict = {'dist':data['distance'],'det-X':data['center'][0],'det-Y':data['center'][1], |
---|
760 | 'tilt':data['tilt'],'phi':data['rotation'],'wave':data['wavelength'],'dep':data['DetDepth']} |
---|
761 | varyList = [item for item in varyDict if varyDict[item]] |
---|
762 | data['rings'] = [] |
---|
763 | data['ellipses'] = [] |
---|
764 | for i,H in enumerate(HKL): |
---|
765 | dsp = H[3] |
---|
766 | tth = 2.0*asind(wave/(2.*dsp)) |
---|
767 | if tth+abs(data['tilt']) > 90.: |
---|
768 | print 'next line is a hyperbola - search stopped' |
---|
769 | break |
---|
770 | if debug: print 'HKLD:',H[:4],'2-theta: %.4f'%(tth) |
---|
771 | elcent,phi,radii = ellipse = GetEllipse(dsp,data) |
---|
772 | data['ellipses'].append(copy.deepcopy(ellipse+('g',))) |
---|
773 | if debug: print fmt%('predicted ellipse:',elcent[0],elcent[1],phi,radii[0],radii[1]) |
---|
774 | Ring = makeRing(dsp,ellipse,pixLimit,cutoff,scalex,scaley,G2frame.ImageZ)[0] |
---|
775 | if Ring: |
---|
776 | data['rings'].append(np.array(Ring)) |
---|
777 | rings = np.concatenate((data['rings']),axis=0) |
---|
778 | if i: |
---|
779 | chisq = FitDetector(rings,varyList,parmDict,False)[0] |
---|
780 | data['distance'] = parmDict['dist'] |
---|
781 | data['center'] = [parmDict['det-X'],parmDict['det-Y']] |
---|
782 | data['rotation'] = parmDict['phi'] |
---|
783 | data['tilt'] = parmDict['tilt'] |
---|
784 | data['DetDepth'] = parmDict['dep'] |
---|
785 | data['chisq'] = chisq |
---|
786 | elcent,phi,radii = ellipse = GetEllipse(dsp,data) |
---|
787 | if debug: print fmt2%('fitted ellipse: ',elcent[0],elcent[1],phi,radii[0],radii[1],chisq,len(rings)) |
---|
788 | data['ellipses'].append(copy.deepcopy(ellipse+('r',))) |
---|
789 | # G2plt.PlotImage(G2frame,newImage=True) |
---|
790 | else: |
---|
791 | if debug: print 'insufficient number of points in this ellipse to fit' |
---|
792 | # break |
---|
793 | G2plt.PlotImage(G2frame,newImage=True) |
---|
794 | fullSize = len(G2frame.ImageZ)/scalex |
---|
795 | if 2*radii[1] < .9*fullSize: |
---|
796 | print 'Are all usable rings (>25% visible) used? Try reducing Min ring I/Ib' |
---|
797 | N = len(data['ellipses']) |
---|
798 | if N > 2: |
---|
799 | FitDetector(rings,varyList,parmDict)[0] |
---|
800 | data['wavelength'] = parmDict['wave'] |
---|
801 | data['distance'] = parmDict['dist'] |
---|
802 | data['center'] = [parmDict['det-X'],parmDict['det-Y']] |
---|
803 | data['rotation'] = parmDict['phi'] |
---|
804 | data['tilt'] = parmDict['tilt'] |
---|
805 | data['DetDepth'] = parmDict['dep'] |
---|
806 | for H in HKL[:N]: |
---|
807 | ellipse = GetEllipse(H[3],data) |
---|
808 | data['ellipses'].append(copy.deepcopy(ellipse+('b',))) |
---|
809 | print 'calibration time = %.3f'%(time.time()-time0) |
---|
810 | G2plt.PlotImage(G2frame,newImage=True) |
---|
811 | return True |
---|
812 | |
---|
813 | def Make2ThetaAzimuthMap(data,masks,iLim,jLim,times): #most expensive part of integration! |
---|
814 | 'Needs a doc string' |
---|
815 | #transforms 2D image from x,y space to 2-theta,azimuth space based on detector orientation |
---|
816 | pixelSize = data['pixelSize'] |
---|
817 | scalex = pixelSize[0]/1000. |
---|
818 | scaley = pixelSize[1]/1000. |
---|
819 | |
---|
820 | tay,tax = np.mgrid[iLim[0]+0.5:iLim[1]+.5,jLim[0]+.5:jLim[1]+.5] #bin centers not corners |
---|
821 | tax = np.asfarray(tax*scalex,dtype=np.float32) |
---|
822 | tay = np.asfarray(tay*scaley,dtype=np.float32) |
---|
823 | nI = iLim[1]-iLim[0] |
---|
824 | nJ = jLim[1]-jLim[0] |
---|
825 | t0 = time.time() |
---|
826 | #make position masks here |
---|
827 | frame = masks['Frames'] |
---|
828 | tam = ma.make_mask_none((nI,nJ)) |
---|
829 | if frame: |
---|
830 | tamp = ma.make_mask_none((1024*1024)) |
---|
831 | tamp = ma.make_mask(pm.polymask(nI*nJ,tax.flatten(), |
---|
832 | tay.flatten(),len(frame),frame,tamp)[:nI*nJ])-True #switch to exclude around frame |
---|
833 | tam = ma.mask_or(tam.flatten(),tamp) |
---|
834 | polygons = masks['Polygons'] |
---|
835 | for polygon in polygons: |
---|
836 | if polygon: |
---|
837 | tamp = ma.make_mask_none((1024*1024)) |
---|
838 | tamp = ma.make_mask(pm.polymask(nI*nJ,tax.flatten(), |
---|
839 | tay.flatten(),len(polygon),polygon,tamp)[:nI*nJ]) |
---|
840 | tam = ma.mask_or(tam.flatten(),tamp) |
---|
841 | if tam.shape: tam = np.reshape(tam,(nI,nJ)) |
---|
842 | spots = masks['Points'] |
---|
843 | for X,Y,diam in spots: |
---|
844 | tamp = ma.getmask(ma.masked_less((tax-X)**2+(tay-Y)**2,(diam/2.)**2)) |
---|
845 | tam = ma.mask_or(tam,tamp) |
---|
846 | times[0] += time.time()-t0 |
---|
847 | t0 = time.time() |
---|
848 | TA = np.array(GetTthAzmG(tax,tay,data)) #includes geom. corr. as dist**2/d0**2 - most expensive step |
---|
849 | times[1] += time.time()-t0 |
---|
850 | TA[1] = np.where(TA[1]<0,TA[1]+360,TA[1]) |
---|
851 | return np.array(TA),tam #2-theta, azimuth & geom. corr. arrays & position mask |
---|
852 | |
---|
853 | def Fill2ThetaAzimuthMap(masks,TA,tam,image): |
---|
854 | 'Needs a doc string' |
---|
855 | Zlim = masks['Thresholds'][1] |
---|
856 | rings = masks['Rings'] |
---|
857 | arcs = masks['Arcs'] |
---|
858 | TA = np.dstack((ma.getdata(TA[1]),ma.getdata(TA[0]),ma.getdata(TA[2]))) #azimuth, 2-theta, dist |
---|
859 | tax,tay,tad = np.dsplit(TA,3) #azimuth, 2-theta, dist**2/d0**2 |
---|
860 | for tth,thick in rings: |
---|
861 | tam = ma.mask_or(tam.flatten(),ma.getmask(ma.masked_inside(tay.flatten(),max(0.01,tth-thick/2.),tth+thick/2.))) |
---|
862 | for tth,azm,thick in arcs: |
---|
863 | tamt = ma.getmask(ma.masked_inside(tay.flatten(),max(0.01,tth-thick/2.),tth+thick/2.)) |
---|
864 | tama = ma.getmask(ma.masked_inside(tax.flatten(),azm[0],azm[1])) |
---|
865 | tam = ma.mask_or(tam.flatten(),tamt*tama) |
---|
866 | taz = ma.masked_outside(image.flatten(),int(Zlim[0]),Zlim[1]) |
---|
867 | tabs = np.ones_like(taz) |
---|
868 | tam = ma.mask_or(tam.flatten(),ma.getmask(taz)) |
---|
869 | tax = ma.compressed(ma.array(tax.flatten(),mask=tam)) #azimuth |
---|
870 | tay = ma.compressed(ma.array(tay.flatten(),mask=tam)) #2-theta |
---|
871 | taz = ma.compressed(ma.array(taz.flatten(),mask=tam)) #intensity |
---|
872 | tad = ma.compressed(ma.array(tad.flatten(),mask=tam)) #dist**2/d0**2 |
---|
873 | tabs = ma.compressed(ma.array(tabs.flatten(),mask=tam)) #ones - later used for absorption corr. |
---|
874 | return tax,tay,taz,tad,tabs |
---|
875 | |
---|
876 | def ImageIntegrate(image,data,masks,blkSize=128,returnN=False): |
---|
877 | 'Integrate an image; called from OnIntegrateAll and OnIntegrate in G2imgGUI' #for q, log(q) bins need data['binType'] |
---|
878 | import histogram2d as h2d |
---|
879 | print 'Begin image integration' |
---|
880 | CancelPressed = False |
---|
881 | LUtth = np.array(data['IOtth']) |
---|
882 | LRazm = np.array(data['LRazimuth'],dtype=np.float64) |
---|
883 | numAzms = data['outAzimuths'] |
---|
884 | numChans = data['outChannels'] |
---|
885 | Dazm = (LRazm[1]-LRazm[0])/numAzms |
---|
886 | if '2-theta' in data.get('binType','2-theta'): |
---|
887 | lutth = LUtth |
---|
888 | elif 'log(q)' in data['binType']: |
---|
889 | lutth = np.log(4.*np.pi*npsind(LUtth/2.)/data['wavelength']) |
---|
890 | elif 'q' == data['binType'].lower(): |
---|
891 | lutth = 4.*np.pi*npsind(LUtth/2.)/data['wavelength'] |
---|
892 | dtth = (lutth[1]-lutth[0])/numChans |
---|
893 | muT = data.get('SampleAbs',[0.0,''])[0] |
---|
894 | if data['DetDepth'] > 0.5: #patch - redefine DetDepth |
---|
895 | data['DetDepth'] /= data['distance'] |
---|
896 | if 'SASD' in data['type']: |
---|
897 | muT = -np.log(muT)/2. #Transmission to 1/2 thickness muT |
---|
898 | NST = np.zeros(shape=(numAzms,numChans),order='F',dtype=np.float32) |
---|
899 | H0 = np.zeros(shape=(numAzms,numChans),order='F',dtype=np.float32) |
---|
900 | Nx,Ny = data['size'] |
---|
901 | nXBlks = (Nx-1)/blkSize+1 |
---|
902 | nYBlks = (Ny-1)/blkSize+1 |
---|
903 | tbeg = time.time() |
---|
904 | times = [0,0,0,0,0] |
---|
905 | for iBlk in range(nYBlks): |
---|
906 | iBeg = iBlk*blkSize |
---|
907 | iFin = min(iBeg+blkSize,Ny) |
---|
908 | for jBlk in range(nXBlks): |
---|
909 | jBeg = jBlk*blkSize |
---|
910 | jFin = min(jBeg+blkSize,Nx) |
---|
911 | # next is most expensive step! |
---|
912 | TA,tam = Make2ThetaAzimuthMap(data,masks,(iBeg,iFin),(jBeg,jFin),times) #2-theta & azimuth arrays & create position mask |
---|
913 | Block = image[iBeg:iFin,jBeg:jFin] |
---|
914 | t0 = time.time() |
---|
915 | tax,tay,taz,tad,tabs = Fill2ThetaAzimuthMap(masks,TA,tam,Block) #and apply masks |
---|
916 | del TA; del tam |
---|
917 | times[2] += time.time()-t0 |
---|
918 | tax = np.where(tax > LRazm[1],tax-360.,tax) #put azm inside limits if possible |
---|
919 | tax = np.where(tax < LRazm[0],tax+360.,tax) |
---|
920 | if data.get('SampleAbs',[0.0,''])[1]: |
---|
921 | if 'Cylind' in data['SampleShape']: |
---|
922 | muR = muT*(1.+npsind(tax)**2/2.)/(npcosd(tay)) #adjust for additional thickness off sample normal |
---|
923 | tabs = G2pwd.Absorb(data['SampleShape'],muR,tay) |
---|
924 | elif 'Fixed' in data['SampleShape']: #assumes flat plate sample normal to beam |
---|
925 | tabs = G2pwd.Absorb('Fixed',muT,tay) |
---|
926 | if 'log(q)' in data.get('binType',''): |
---|
927 | tay = np.log(4.*np.pi*npsind(tay/2.)/data['wavelength']) |
---|
928 | elif 'q' == data.get('binType','').lower(): |
---|
929 | tay = 4.*np.pi*npsind(tay/2.)/data['wavelength'] |
---|
930 | t0 = time.time() |
---|
931 | taz = np.array((taz*tad/tabs),dtype='float32') |
---|
932 | if any([tax.shape[0],tay.shape[0],taz.shape[0]]): |
---|
933 | NST,H0 = h2d.histogram2d(len(tax),tax,tay,taz, |
---|
934 | numAzms,numChans,LRazm,lutth,Dazm,dtth,NST,H0) |
---|
935 | times[3] += time.time()-t0 |
---|
936 | del tax; del tay; del taz; del tad; del tabs |
---|
937 | t0 = time.time() |
---|
938 | NST = np.array(NST,dtype=np.float) |
---|
939 | H0 = np.divide(H0,NST) |
---|
940 | H0 = np.nan_to_num(H0) |
---|
941 | H2 = np.array([tth for tth in np.linspace(lutth[0],lutth[1],numChans+1)]) |
---|
942 | if 'log(q)' in data.get('binType',''): |
---|
943 | H2 = 2.*npasind(np.exp(H2)*data['wavelength']/(4.*np.pi)) |
---|
944 | elif 'q' == data.get('binType','').lower(): |
---|
945 | H2 = 2.*npasind(H2*data['wavelength']/(4.*np.pi)) |
---|
946 | if Dazm: |
---|
947 | H1 = np.array([azm for azm in np.linspace(LRazm[0],LRazm[1],numAzms+1)]) |
---|
948 | else: |
---|
949 | H1 = LRazm |
---|
950 | H0 /= npcosd(H2[:-1]) #**2? I don't think so, **1 is right for powders |
---|
951 | if 'SASD' in data['type']: |
---|
952 | H0 /= npcosd(H2[:-1]) #one more for small angle scattering data? |
---|
953 | if data['Oblique'][1]: |
---|
954 | H0 /= G2pwd.Oblique(data['Oblique'][0],H2[:-1]) |
---|
955 | if 'SASD' in data['type'] and data['PolaVal'][1]: |
---|
956 | #NB: in G2pwd.Polarization azm is defined from plane of polarization, not image x axis! |
---|
957 | H0 /= np.array([G2pwd.Polarization(data['PolaVal'][0],H2[:-1],Azm=azm-90.)[0] for azm in (H1[:-1]+np.diff(H1)/2.)]) |
---|
958 | times[4] += time.time()-t0 |
---|
959 | print 'Step times: \n apply masks %8.3fs xy->th,azm %8.3fs fill map %8.3fs \ |
---|
960 | \n binning %8.3fs cleanup %8.3fs'%(times[0],times[1],times[2],times[3],times[4]) |
---|
961 | print "Elapsed time:","%8.3fs"%(time.time()-tbeg) |
---|
962 | print 'Integration complete' |
---|
963 | if returnN: #As requested by Steven Weigand |
---|
964 | return H0,H1,H2,NST,CancelPressed |
---|
965 | else: |
---|
966 | return H0,H1,H2,CancelPressed |
---|
967 | |
---|
968 | def MakeStrStaRing(ring,Image,Controls): |
---|
969 | ellipse = GetEllipse(ring['Dset'],Controls) |
---|
970 | pixSize = Controls['pixelSize'] |
---|
971 | scalex = 1000./pixSize[0] |
---|
972 | scaley = 1000./pixSize[1] |
---|
973 | Ring = np.array(makeRing(ring['Dset'],ellipse,ring['pixLimit'],ring['cutoff'],scalex,scaley,Image)[0]).T #returns x,y,dsp for each point in ring |
---|
974 | if len(Ring): |
---|
975 | ring['ImxyObs'] = copy.copy(Ring[:2]) |
---|
976 | TA = GetTthAzm(Ring[0],Ring[1],Controls) #convert x,y to tth,azm |
---|
977 | TA[0] = Controls['wavelength']/(2.*npsind(TA[0]/2.)) #convert 2th to d |
---|
978 | ring['ImtaObs'] = TA |
---|
979 | ring['ImtaCalc'] = np.zeros_like(ring['ImtaObs']) |
---|
980 | Ring[0] = TA[0] |
---|
981 | Ring[1] = TA[1] |
---|
982 | return Ring,ring |
---|
983 | else: |
---|
984 | ring['ImxyObs'] = [[],[]] |
---|
985 | ring['ImtaObs'] = [[],[]] |
---|
986 | ring['ImtaCalc'] = [[],[]] |
---|
987 | return [],[] #bad ring; no points found |
---|
988 | |
---|
989 | def FitStrSta(Image,StrSta,Controls): |
---|
990 | 'Needs a doc string' |
---|
991 | |
---|
992 | StaControls = copy.deepcopy(Controls) |
---|
993 | phi = StrSta['Sample phi'] |
---|
994 | wave = Controls['wavelength'] |
---|
995 | pixelSize = Controls['pixelSize'] |
---|
996 | scalex = 1000./pixelSize[0] |
---|
997 | scaley = 1000./pixelSize[1] |
---|
998 | StaType = StrSta['Type'] |
---|
999 | StaControls['distance'] += StrSta['Sample z']*cosd(phi) |
---|
1000 | |
---|
1001 | for ring in StrSta['d-zero']: #get observed x,y,d points for the d-zeros |
---|
1002 | dset = ring['Dset'] |
---|
1003 | Ring,R = MakeStrStaRing(ring,Image,StaControls) |
---|
1004 | if len(Ring): |
---|
1005 | ring.update(R) |
---|
1006 | p0 = ring['Emat'] |
---|
1007 | val,esd = FitStrain(Ring,p0,dset,wave,phi,StaType) |
---|
1008 | ring['Emat'] = val |
---|
1009 | ring['Esig'] = esd |
---|
1010 | ellipse = FitEllipse(R['ImxyObs'].T) |
---|
1011 | ringxy,ringazm = makeRing(ring['Dcalc'],ellipse,0,0.,scalex,scaley,Image) |
---|
1012 | ring['ImxyCalc'] = np.array(ringxy).T[:2] |
---|
1013 | ringint = np.array([float(Image[int(x*scalex),int(y*scaley)]) for y,x in np.array(ringxy)[:,:2]]) |
---|
1014 | ringint /= np.mean(ringint) |
---|
1015 | ring['Ivar'] = np.var(ringint) |
---|
1016 | print 'Variance in normalized ring intensity: %.3f'%(ring['Ivar']) |
---|
1017 | CalcStrSta(StrSta,Controls) |
---|
1018 | |
---|
1019 | def IntStrSta(Image,StrSta,Controls): |
---|
1020 | StaControls = copy.deepcopy(Controls) |
---|
1021 | pixelSize = Controls['pixelSize'] |
---|
1022 | scalex = 1000./pixelSize[0] |
---|
1023 | scaley = 1000./pixelSize[1] |
---|
1024 | phi = StrSta['Sample phi'] |
---|
1025 | StaControls['distance'] += StrSta['Sample z']*cosd(phi) |
---|
1026 | RingsAI = [] |
---|
1027 | for ring in StrSta['d-zero']: #get observed x,y,d points for the d-zeros |
---|
1028 | Ring,R = MakeStrStaRing(ring,Image,StaControls) |
---|
1029 | if len(Ring): |
---|
1030 | ellipse = FitEllipse(R['ImxyObs'].T) |
---|
1031 | ringxy,ringazm = makeRing(ring['Dcalc'],ellipse,0,0.,scalex,scaley,Image) |
---|
1032 | ring['ImxyCalc'] = np.array(ringxy).T[:2] |
---|
1033 | ringint = np.array([float(Image[int(x*scalex),int(y*scaley)]) for y,x in np.array(ringxy)[:,:2]]) |
---|
1034 | ringint /= np.mean(ringint) |
---|
1035 | print ' %s %.3f %s %.3f'%('d-spacing',ring['Dcalc'],'sig(MRD):',np.sqrt(np.var(ringint))) |
---|
1036 | RingsAI.append(np.array(zip(ringazm,ringint)).T) |
---|
1037 | return RingsAI |
---|
1038 | |
---|
1039 | def CalcStrSta(StrSta,Controls): |
---|
1040 | |
---|
1041 | wave = Controls['wavelength'] |
---|
1042 | phi = StrSta['Sample phi'] |
---|
1043 | StaType = StrSta['Type'] |
---|
1044 | for ring in StrSta['d-zero']: |
---|
1045 | Eij = ring['Emat'] |
---|
1046 | E = [[Eij[0],Eij[1],0],[Eij[1],Eij[2],0],[0,0,0]] |
---|
1047 | th,azm = ring['ImtaObs'] |
---|
1048 | th0 = np.ones_like(azm)*npasind(wave/(2.*ring['Dset'])) |
---|
1049 | V = -np.sum(np.sum(E*calcFij(90.,phi,azm,th0).T/1.e6,axis=2),axis=1) |
---|
1050 | if StaType == 'True': |
---|
1051 | ring['ImtaCalc'] = np.array([np.exp(V)*ring['Dset'],azm]) |
---|
1052 | else: |
---|
1053 | ring['ImtaCalc'] = np.array([(V+1.)*ring['Dset'],azm]) |
---|
1054 | dmin = np.min(ring['ImtaCalc'][0]) |
---|
1055 | dmax = np.max(ring['ImtaCalc'][0]) |
---|
1056 | if ring.get('fixDset',True): |
---|
1057 | if abs(Eij[0]) < abs(Eij[2]): #tension |
---|
1058 | ring['Dcalc'] = dmin+(dmax-dmin)/4. |
---|
1059 | else: #compression |
---|
1060 | ring['Dcalc'] = dmin+3.*(dmax-dmin)/4. |
---|
1061 | else: |
---|
1062 | ring['Dcalc'] = np.mean(ring['ImtaCalc'][0]) |
---|
1063 | |
---|
1064 | def calcFij(omg,phi,azm,th): |
---|
1065 | ''' Uses parameters as defined by Bob He & Kingsley Smith, Adv. in X-Ray Anal. 41, 501 (1997) |
---|
1066 | |
---|
1067 | :param omg: his omega = sample omega rotation; 0 when incident beam || sample surface, |
---|
1068 | 90 when perp. to sample surface |
---|
1069 | :param phi: his phi = sample phi rotation; usually = 0, axis rotates with omg. |
---|
1070 | :param azm: his chi = azimuth around incident beam |
---|
1071 | :param th: his theta = theta |
---|
1072 | ''' |
---|
1073 | a = npsind(th)*npcosd(omg)+npsind(azm)*npcosd(th)*npsind(omg) |
---|
1074 | b = -npcosd(azm)*npcosd(th) |
---|
1075 | c = npsind(th)*npsind(omg)-npsind(azm)*npcosd(th)*npcosd(omg) |
---|
1076 | d = a*npsind(phi)+b*npcosd(phi) |
---|
1077 | e = a*npcosd(phi)-b*npsind(phi) |
---|
1078 | Fij = np.array([ |
---|
1079 | [d**2,d*e,c*d], |
---|
1080 | [d*e,e**2,c*e], |
---|
1081 | [c*d,c*e,c**2]]) |
---|
1082 | return -Fij |
---|
1083 | |
---|
1084 | def FitStrain(rings,p0,dset,wave,phi,StaType): |
---|
1085 | 'Needs a doc string' |
---|
1086 | def StrainPrint(ValSig,dset): |
---|
1087 | print 'Strain tensor for Dset: %.6f'%(dset) |
---|
1088 | ptlbls = 'names :' |
---|
1089 | ptstr = 'values:' |
---|
1090 | sigstr = 'esds :' |
---|
1091 | for name,fmt,value,sig in ValSig: |
---|
1092 | ptlbls += "%s" % (name.rjust(12)) |
---|
1093 | ptstr += fmt % (value) |
---|
1094 | if sig: |
---|
1095 | sigstr += fmt % (sig) |
---|
1096 | else: |
---|
1097 | sigstr += 12*' ' |
---|
1098 | print ptlbls |
---|
1099 | print ptstr |
---|
1100 | print sigstr |
---|
1101 | |
---|
1102 | def strainCalc(p,xyd,dset,wave,phi,StaType): |
---|
1103 | E = np.array([[p[0],p[1],0],[p[1],p[2],0],[0,0,0]]) |
---|
1104 | dspo,azm,dsp = xyd |
---|
1105 | th = npasind(wave/(2.0*dspo)) |
---|
1106 | V = -np.sum(np.sum(E*calcFij(90.,phi,azm,th).T/1.e6,axis=2),axis=1) |
---|
1107 | if StaType == 'True': |
---|
1108 | dspc = dset*np.exp(V) |
---|
1109 | else: |
---|
1110 | dspc = dset*(V+1.) |
---|
1111 | return dspo-dspc |
---|
1112 | |
---|
1113 | names = ['e11','e12','e22'] |
---|
1114 | fmt = ['%12.2f','%12.2f','%12.2f'] |
---|
1115 | result = leastsq(strainCalc,p0,args=(rings,dset,wave,phi,StaType),full_output=True) |
---|
1116 | vals = list(result[0]) |
---|
1117 | chisq = np.sum(result[2]['fvec']**2)/(rings.shape[1]-3) #reduced chi^2 = M/(Nobs-Nvar) |
---|
1118 | sig = list(np.sqrt(chisq*np.diag(result[1]))) |
---|
1119 | ValSig = zip(names,fmt,vals,sig) |
---|
1120 | StrainPrint(ValSig,dset) |
---|
1121 | return vals,sig |
---|
1122 | |
---|
1123 | def AutoSpotMasks(Image,Masks,Controls): |
---|
1124 | print 'auto spot search' |
---|
1125 | maxPks = 500 |
---|
1126 | dmax = 1.5 #just beyond diamond 111 @ 2.0596 |
---|
1127 | wave = Controls['wavelength'] |
---|
1128 | tthMax = 2.0*asind(wave/(2.*dmax)) |
---|
1129 | pixelSize = Controls['pixelSize'] |
---|
1130 | lap = np.array([[0,1,0],[1,-4,1],[0,1,0]],np.float32) |
---|
1131 | ck = scsg.cspline2d(Image.T,24.0) |
---|
1132 | spotMask1=-scsg.convolve2d(ck,lap,mode='same',boundary='symm') |
---|
1133 | for mul in range(10): |
---|
1134 | spotMask = ma.array(Image,mask=(spotMask1<(mul+1)*1.e4)) |
---|
1135 | indx = np.transpose(spotMask.nonzero()) |
---|
1136 | if not len(indx): #smooth image - no sharp points |
---|
1137 | break |
---|
1138 | pts,distort = scvq.kmeans(np.array(indx,np.float32),maxPks,thresh=1.0) |
---|
1139 | peaks = pts*pixelSize/1000. |
---|
1140 | tths = GetTth(peaks.T[0],peaks.T[1],Controls) |
---|
1141 | masktths = ma.getmask(ma.array(tths,mask=tths>tthMax)) |
---|
1142 | pts = pts[masktths,:] |
---|
1143 | A,B = np.mgrid[0:len(pts),0:len(pts)] |
---|
1144 | M = np.sqrt(np.sum((pts[A]-pts[B])**2,axis=-1)) |
---|
1145 | MX = ma.array(M,mask=(M<10.)) |
---|
1146 | Indx = ma.nonzero(ma.getmask(MX)) |
---|
1147 | print 'Spots found: ',mul,len(pts),distort,len(Indx[0]) |
---|
1148 | if distort < .3: |
---|
1149 | break |
---|
1150 | if not len(Indx[0]): |
---|
1151 | print 'no auto search spots found' |
---|
1152 | return None |
---|
1153 | if distort > 2.: |
---|
1154 | print 'no big spots found' |
---|
1155 | return None |
---|
1156 | #use clustered points to get position & spread |
---|
1157 | |
---|
1158 | Indx = np.sort(Indx,axis=0).T |
---|
1159 | Nmax = np.max(Indx) |
---|
1160 | nums = [list(set([ind[1] for ind in Indx if ind[1]>=jnd and ind[0] == jnd])) for jnd in range(Nmax+1)] |
---|
1161 | delList = [] |
---|
1162 | for Num in nums: |
---|
1163 | delList += list(np.sort(Num))[1:] |
---|
1164 | delList = list(set(delList)) |
---|
1165 | Nums = [num for inum,num in enumerate(nums) if inum not in delList] |
---|
1166 | points = [] |
---|
1167 | esds = [] |
---|
1168 | for num in Nums: |
---|
1169 | points.append(np.mean(pts[num],axis=0)) |
---|
1170 | esds.append(np.mean(np.var(pts[num],axis=0))) |
---|
1171 | peaks = (np.array(points)+np.array([.5,.5]))*pixelSize/1000. |
---|
1172 | Points = np.ones((peaks.shape[0],3))*2. |
---|
1173 | Points[:,2] += np.array(esds)*pixelSize[0]/1000. |
---|
1174 | Points[:,:2] = peaks |
---|
1175 | Masks['Points'] = list(Points) |
---|
1176 | return None |
---|
1177 | |
---|
1178 | # rollImage = lambda rho,roll: np.roll(np.roll(rho,roll[0],axis=0),roll[1],axis=1) |
---|
1179 | # print 'auto spot search' |
---|
1180 | # pixelSize = Controls['pixelSize'] |
---|
1181 | # spotMask = ma.array(Image,mask=(Image<np.mean(Image))) |
---|
1182 | # indices = (-1,0,1) |
---|
1183 | # rolls = np.array([[ix,iy] for ix in indices for iy in indices]) |
---|
1184 | # for roll in rolls: |
---|
1185 | # if np.any(roll): #avoid [0,0] |
---|
1186 | # spotMask = ma.array(spotMask,mask=(spotMask-rollImage(Image,roll)<0.)) |
---|
1187 | # mags = spotMask[spotMask.nonzero()] |
---|
1188 | # indx = np.transpose(spotMask.nonzero()) |
---|
1189 | # nx,ny = Image.shape |
---|
1190 | # jndx = [] |
---|
1191 | # for [ind,mag] in zip(indx,mags): |
---|
1192 | # if (1 < ind[0] < nx-2) and (1 < ind[1] < ny-2): |
---|
1193 | # cent = np.zeros((3,3)) |
---|
1194 | # cent[1,1] = mag |
---|
1195 | # msk = np.array(Image[ind[0]-2:ind[0]+3,ind[1]-2:ind[1]+3]) |
---|
1196 | # msk = ma.array(msk,mask=(msk==mag)) |
---|
1197 | # if mag > 1.5*ma.mean(msk): |
---|
1198 | # jndx.append([ind[1]+.5,ind[0]+.5]) |
---|
1199 | # print 'Spots found: ',len(jndx) |
---|
1200 | # jndx = np.array(jndx) |
---|
1201 | # peaks = jndx*pixelSize/1000. |
---|
1202 | # tth = GetTth(peaks.T[0],peaks.T[1],Controls) |
---|
1203 | # histth,bins = np.histogram(tth,2500) |
---|
1204 | # for shft in [-1,1]: |
---|
1205 | # histmsk = ma.array(histth,mask=-(histth-np.roll(histth,shft)<2.)) |
---|
1206 | # histmsk = ma.array(histmsk,mask=(histmsk>5)) |
---|
1207 | # binmsk = np.array(ma.nonzero(histmsk)) |
---|
1208 | # digts = np.digitize(tth,bins)-1 |
---|
1209 | # PeaksList = [] |
---|
1210 | # for digt,peak in zip(digts,peaks): |
---|
1211 | # if digt in binmsk: |
---|
1212 | # PeaksList.append(peak) |
---|
1213 | # #should be able to filter out spotty Bragg rings here |
---|
1214 | # PeaksList = np.array(PeaksList) |
---|
1215 | # Points = np.ones((PeaksList.shape[0],3)) |
---|
1216 | # Points[:,:2] = PeaksList |
---|
1217 | # Masks['Points'] = list(Points) |
---|
1218 | # return None |
---|
1219 | |
---|
1220 | |
---|
1221 | |
---|
1222 | |
---|