source: trunk/GSASIIimage.py @ 1228

Last change on this file since 1228 was 1228, checked in by vondreele, 9 years ago

remove diagnostic prints in image calibration stuff
some fine tuning of the image calibration
make CheMin? images "right" way around as requested by Dave Bish
Apply James Hester's fix to Pawley update

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