def fitGaussian(I=None, p0=None, bounds=None, nGaussians=1, display=False): ''' Takes an nxm matrix and returns an nxm matrix which is the gaussian fit of the first. p0 is a list of parameters [xorigin, yorigin, sigma,amplitude] 0-19 should be [-.2889 -.3265 -.3679 -.4263 -.5016 -.6006 ... -.0228 .01913] ''' x=np.arange(I.shape[0]) y=np.arange(I.shape[1]) if display: data=Puff3d(I,'Original Data') X=[x,y] p0=[round(p,3) for p in p0] if nGaussians==1: p, cov_x, infodic, mesg, ier = leastsqbound(err, p0,args=(I,X),bounds = bounds,ftol=.0000001,full_output=True) #xorigin,yorigin,sigmax,sigmay,angle,amplitude=p I_fit=gaussian(x[:,None], y[None,:],*p) if not display: return p, I_fit, I_fit else: fitted_data=Puff3d(I_fit,'Fitted') return data, fitted_data, p elif nGaussians>=2: p, cov_x, infodic, mesg, ier = leastsqbound(err2, p0,args=(I,X),bounds = bounds,ftol=.0000001,full_output=True) #xorigin,yorigin,sigmax,sigmay,angle,amplitude=p I_fit=gaussian(x[:,None], y[None,:],*(p[:4])) I_fit2=gaussian2(x[:,None], y[None,:],*p) return p[:4], I_fit, I_fit2
def fitGaussian(I, r, maxSigmaForGaussianFit, rotatedFit): # takes an nxm matrix and returns an nxm matrix which is the gaussian fit # of the first. c is a list of parameters [zoffset, scale, xorigin, yorigin, sigma] I[I<0]=0 startx=round(np.mean(r[0:2])) starty=round(np.mean(r[2:4])) center=I[r[0]:r[1],r[2]:r[3]] scale=np.max(center.ravel()) if scale>0: I=np.divide(I,scale) n,m=np.shape(I) Y,X=np.meshgrid(range(1, m+1),range(1, n+1)) x = np.zeros((np.size(X), 2)) x[:, 0] = X.ravel('F') x[:, 1] = Y.ravel('F') I_col=I.ravel('F') if not rotatedFit: # fun = e ^ (-()) def fun(c, x, minus=True): if minus==False: return np.exp(-((x[:, 0]-c[0])/c[2])**2-((x[:, 1]-c[1])/c[2])**2) return I_col - np.exp(-((x[:, 0]-c[0])/c[2])**2-((x[:, 1]-c[1])/c[2])**2) #% [ xorigin, yorigin, sigma] c0=[startx,starty,m] #starting parameters lb=[r[0],r[2],1 ] #lower bounds on the parameters ub=[r[1],r[3],maxSigmaForGaussianFit] #upper bounds on the parameters for i in range(len(c0)): c0[i] = max(lb[i], c0[i]) c0[i] = min(ub[i], c0[i]) c = leastsqbound(fun, c0, args=(x,), bounds = zip(lb, ub), ftol = 1.0e-4, maxfev=100) else: #if we are fitting to a 2d rotating gaussian fit def fun(c, x, minus=True): if not minus: return np.exp(-(((x[:, 0] - c[0])*cosd(c[4])+(x[:, 1] - c[1])*sind(c[4]))/c[2])**2 - (((x[:, 0] - c[0])*sind(c[4])+(x[:, 1] - c[1])*cosd(c[4]))/c[3])**2) return I_col - np.exp(-(((x[:, 0] - c[0])*cosd(c[4])+(x[:, 1] - c[1])*sind(c[4]))/c[2])**2 - (((x[:, 0] - c[0])*sind(c[4])+(x[:, 1] - c[1])*cosd(c[4]))/c[3])**2) #% [xorigin yorigin sigmax sigmay angle] c0=[startx, starty, m, m, 90] #starting parameters lb=[r[0], r[2], 1, 1, 0] #lower bounds on the parameters ub=[r[1], r[3], maxSigmaForGaussianFit, maxSigmaForGaussianFit, 180] #upper bounds on the parameters for i in range(len(c0)): c0[i] = max(lb[i], c0[i]) c0[i] = min(ub[i], c0[i]) c = leastsqbound(fun, c0, args=(x,), bounds = zip(lb, ub), ftol = 1.0e-6, maxfev=100) c = c[0] Ifit=fun(c, np.double(x), minus=False) Ifit=np.reshape(Ifit,(n, m), 'F') graph_args = [I, Ifit, X, Y] return c, graph_args
def run_leastsq_bound(problem, ftol, xtol, gtol, jac, scaling=None, **kwargs): bounds, lb, ub = scipy_bounds(problem) if scaling is None: diag = np.ones_like(problem.x0) else: diag = None if jac in ['2-point', '3-point']: jac = None else: jac = problem.jac x, cov_x, info, mesg, ier = leastsqbound( problem.fun, problem.x0, bounds=bounds, full_output=True, Dfun=jac, ftol=ftol, xtol=xtol, gtol=gtol, diag=diag, **kwargs) x = make_strictly_feasible(x, lb, ub) f = problem.fun(x) g = problem.grad(x) optimality = CL_optimality(x, g, lb, ub) active = find_active_constraints(x, lb, ub) return (info['nfev'], optimality, 0.5 * np.dot(f, f), np.sum(active != 0), ier)
def execute(self, *args, **kwargs): """ Run fitting and initiate a fit report with the result. :return: FitResults object """ popt, cov_x, infodic, mesg, ier = leastsqbound( self.error, self.get_initial_guesses(), args=(self.scipy_func, self.xdata, self.ydata), bounds=self.get_bounds(), Dfun=self.get_jacobian, full_output=True, *args, **kwargs ) s_sq = (infodic['fvec']**2).sum()/(len(self.ydata)-len(popt)) # For fixed parameters, there is no stdev. pcov = cov_x*s_sq self.fit_results = FitResults( params=self.params, popt=popt, pcov=pcov, infodic=infodic, mesg=mesg, ier=ier, ydata=self.ydata, # Needed to calculate R^2 ) return self.fit_results
def run_leastsq_bound(problem, ftol, xtol, gtol, jac, scaling=None, **kwargs): bounds, lb, ub = scipy_bounds(problem) if scaling is None: diag = np.ones_like(problem.x0) else: diag = None if jac in ['2-point', '3-point']: jac = None else: jac = problem.jac x, cov_x, info, mesg, ier = leastsqbound(problem.fun, problem.x0, bounds=bounds, full_output=True, Dfun=jac, ftol=ftol, xtol=xtol, gtol=gtol, diag=diag, **kwargs) x = make_strictly_feasible(x, lb, ub) f = problem.fun(x) g = problem.grad(x) optimality = CL_optimality(x, g, lb, ub) active = find_active_constraints(x, lb, ub) return (info['nfev'], optimality, 0.5 * np.dot(f, f), np.sum(active != 0), ier)
def fit_exponential(x,y,order=1): p0=(1,.0005)*order popt, cov_x, infodic, mesg, ier = leastsqbound(err, p0, args=(y,x), full_output=True) if order==1: yfit=exp_decay_1st_order(x, *popt) elif order==2: yfit=exp_decay_2nd_order(x, *popt) elif order==3: yfit=exp_decay_3rd_order(x, *popt) return popt,yfit
def fit_curve(f, xdata, ydata, guess, bounds): """Fit a curve to data.""" def residual(p, x, y): return f(p, x) - y params, ier = leastsqbound(residual, guess, args=(xdata, ydata), bounds=bounds) if 0 < ier < 5: err = rmse(f, params, xdata, ydata) else: err = np.inf return params, err
def fit_exponential(x, y, order=1): p0 = (1, .0005) * order popt, cov_x, infodic, mesg, ier = leastsqbound(err, p0, args=(y, x), full_output=True) if order == 1: yfit = exp_decay_1st_order(x, *popt) elif order == 2: yfit = exp_decay_2nd_order(x, *popt) elif order == 3: yfit = exp_decay_3rd_order(x, *popt) return popt, yfit
def fitGaussian(I=None, p0=None, bounds=None): ''' Takes an nxm matrix and returns an nxm matrix which is the gaussian fit of the first. p0 is a list of parameters [xorigin, yorigin, sigma,amplitude] ''' x=np.arange(I.shape[0]) y=np.arange(I.shape[1]) X=[x,y] p0=[round(p,3) for p in p0] p, cov_x, infodic, mesg, ier = leastsqbound(err, p0,args=(I,X),bounds = bounds,ftol=.0000001,full_output=True) #xorigin,yorigin,sigmax,sigmay,angle,amplitude=p I_fit=gaussian(x[:,None], y[None,:],*p) return p, I_fit, I_fit
def fitGaussian(I=None, p0=None, bounds=None): ''' Takes an nxm matrix and returns an nxm matrix which is the gaussian fit of the first. p0 is a list of parameters [xorigin, yorigin, sigma,amplitude] ''' x = np.arange(I.shape[0]) y = np.arange(I.shape[1]) X = [x, y] p0 = [round(p, 3) for p in p0] p, cov_x, infodic, mesg, ier = leastsqbound(err, p0, args=(I, X), bounds=bounds, ftol=.0000001, full_output=True) #xorigin,yorigin,sigmax,sigmay,angle,amplitude=p I_fit = gaussian(x[:, None], y[None, :], *p) return p, I_fit, I_fit
def leastsq_oracle(x, y, kernel, initial=None, bounds=None): """ This is a generic oracle function that uses bounded least squares to find the parameters in each iteration of EBP, and requires initial parameters. Parameters ---------- x : ndarray Input to the kernel function. y : ndarray Data to fit to. kernel : callalble The kernel function to be specified by this oracle. initial : list/array initial setting for the parameters of the function. This has to be something that kernel knows what to do with. """ return lsq.leastsqbound(err_func, initial, args=(x, y, kernel), bounds=bounds)[0]
def Fit_ExpDecFunction(x, y, bounders, guess): ########## # Fitting the data -- Least Squares Method ########## # Exp Decay fitting import scipy, numpy as np, leastsqbound fitfunc = lambda p, x: p[0]*np.exp(-p[1]*x) + p[2]#target fun. notice this is a linear fun. errfunc = lambda p, x, y: (y - fitfunc(p, x)) #distance from our target fun pinit = guess #inital parameter guess pfinal,covar,infodict,mesg,ier = leastsqbound.leastsqbound(errfunc, pinit, args=(x, y), bounds=bounders,full_output=1) index = pfinal[1] amp = pfinal[0] asmp = pfinal[2] ss_err = (infodict['fvec']**2).sum() ss_tot = ((y-y.mean())**2).sum() rsquared = 1-(ss_err/ss_tot) dof = len(x)-len(pfinal) rmse = np.sqrt(ss_err/dof) return (rmse, index, amp, asmp, rsquared)
def f_NDregion(region,ls_classes,p0,p_bounds,n_peaks,wmask,**kw): """ Fit an arbitrary dimensional regions containing one or more peaks using a contrained Levenberg-Marquard optmization algorithm. Parameters: * region N-dimensional region to fit * ls_classes List of lineshape classes * p0 Initial parameter guesses * p_bounds (min,max) pairs for each element of p0 * n_peaks Number of peaks Additional keyword are passed directly to leastsqbound and in turn passed to scipy.optimize.leastsq after variable transformation. """ args = (region,region.shape,ls_classes,n_peaks,wmask) p_best = leastsqbound(err_NDregion,p0,bounds=p_bounds,args=args,**kw) return p_best
def fitGaussian(I=None, p0=None, bounds=None): """ SYMETRICAL GAUSSIAN Takes an nxm matrix and returns an nxm matrix which is the gaussian fit of the first. p0 is a list of parameters [xorigin, yorigin, sigma,amplitude] 0-19 should be [-.2889 -.3265 -.3679 -.4263 -.5016 -.6006 ... -.0228 .01913] """ x = np.arange(I.shape[0]) y = np.arange(I.shape[1]) X = [x, y] p0 = [round(p, 3) for p in p0] p, cov_x, infodic, mesg, ier = leastsqbound(err, p0, args=(I, X), bounds=bounds, maxfev=100, full_output=True) # xorigin, yorigin, sigma, amplitude=p I_fit = gaussian(x[:, None], y[None, :], *p) return p, I_fit, I_fit
def leastsqboundWrapper(func, x0, args=(), bounds=None, Dfun=None, full_output=0, col_deriv=0, ftol=1.49012e-8, xtol=1.49012e-8, gtol=0.0, maxfev=0, epsfcn=0.0, factor=100, diag=None): '''Sometimes leastsqbound has a problem where if the input parameters have too many decimals, it won't change at all from the initial guess. This is a hack around that by checking if the first two parameters have changed. If they haven't, narrow the bounds by half and try again. ''' x0=[round(x,3) for x in x0] p, cov_x, infodic, mesg, ier = leastsqbound(func, x0, args, bounds, Dfun, full_output, col_deriv, ftol, xtol, gtol, maxfev, epsfcn, factor, diag) if p[0]==x0[0]: idx=0 if p[1]==x0[1]: idx=1 else: return p spread=bounds[idx][1]-bounds[idx][0] spread=spread/4 if spread<.1 or p[-1]<.1: print('Origin did not shift during Gaussian Fitting') return p bounds=bounds[:] #this is required or else you permanently change the bounds bounds[idx]=(bounds[idx][0]+spread,bounds[idx][1]-spread) p=leastsqboundWrapper(func, x0, args, bounds, Dfun, full_output, col_deriv, ftol, xtol, gtol, maxfev, epsfcn, factor, diag) return p
# print out results print "Standard Least Squares fitting results:" print "p:", p print "cov_x:", cov_x print "infodic['nfev']:", infodic['nfev'] print "infodic['fvec']:", infodic['fvec'] print "infodic['fjac']:", infodic['fjac'] print "infodic['ipvt']:", infodic['ipvt'] print "infodic['qtf']:", infodic['qtf'] print "mesg:", mesg print "ier:", ier print "" # same as above using no bounds p0 = [1.0, 0.0] p, cov_x, infodic, mesg, ier = leastsqbound(err, p0, args=(y, x), full_output=True) # print out results print "Bounded Least Squares fitting with no bounds results:" print "p:", p print "cov_x:", cov_x print "infodic['nfev']:", infodic['nfev'] print "infodic['fvec']:", infodic['fvec'] print "infodic['fjac']:", infodic['fjac'] print "infodic['ipvt']:", infodic['ipvt'] print "infodic['qtf']:", infodic['qtf'] print "mesg:", mesg print "ier:", ier print ""
def getLine(image,angle=None): """ This function takes a boolean image of a rodent, performs several steps, and returns a line running down the middle of the rodent from nose to tail. The steps are: 1) Find the point at the center of mass. 2) Draw a horizontal line through this point. 3) Find the mean distance from the line to every point in the rodent. Rotate the line and find the angle which gives the minimum such distance. Keep the line at this angle. This line gives a good approximation for position. 4) Draw 7 points on the line: one at the midpoint, two at the ends, two 3/4 away from the midpoint, and two halfway between the ends and the midpoint. 5) Construct 7 lines which run through the 7 points at an angle perpendicular to the main line. 6) Draw 6 boxes between these 7 lines. Find the center of mass for each box along the axes parallel to these lines. Move each of the 7 points (except the midpoint) along their lines to the center of mass of their respective region. 7) Draw a box around the end segment of the line. The bounds for the box lie parallel and perpendicular to this segment. Fixing the inner point and allowing the end point to vary, fit the segment so that the average distance from the segment to the points in the box are a minimum. This step is done for both ends of the line, because we don't as yet know which end is the head and which is the tail. """ pts=np.where(image) pts_array=np.column_stack((pts[0],pts[1])) pts=MultiPoint([(pts[0][i],pts[1][i]) for i in np.arange(len(pts[0]))]) # STEP 1 x0,y0=center_of_mass(image) center=Point(x0,y0) bounds=pts.bounds b_len=((bounds[2]-bounds[0])**2+(bounds[3]-bounds[1])**2)**(1/2) #this is the length of the diagonal, the maximum possible length of an object inside a box # STEP 2 line=pts2line([translate(center,b_len),translate(center,-b_len)]) # STEP 3 if angle is None: angles=np.arange(-90,90,10) else: angles=np.arange(angle-20,angle+20,10) #this assumes the angle changes at most 10 degrees between frames distances=np.zeros(angles.shape,dtype=np.float) for i in np.arange(len(angles)): distances[i]=getMeanDistance(rotate(line,angles[i]),pts) angle=angles[np.argmin(distances)] line=rotate(line,angle) line=crop_line(line,pts_array) # STEP 4 & 5 # now that we have the approximate line down the main axis, let's divide it in half and allow the endpoints and midpoint to be translated along the perpendicular axis start,end=list(line.coords) start=np.array(start); end=np.array(end) mid=(start+end)/2 mid_axis=rotate(line,90) mid_axis=crop_line(mid_axis,pts_array) axis1=translate(mid_axis,xoff=start[0]-mid[0],yoff=start[1]-mid[1]) axis2=translate(mid_axis,xoff=(start[0]-mid[0])/(4./3),yoff=(start[1]-mid[1])/(4./3.)) axis3=translate(mid_axis,xoff=(start[0]-mid[0])/2,yoff=(start[1]-mid[1])/2.) axis4=translate(mid_axis,xoff=(end[0]-mid[0])/2,yoff=(end[1]-mid[1])/2) axis5=translate(mid_axis,xoff=(end[0]-mid[0])/(4./3.),yoff=(end[1]-mid[1])/(4./3.)) axis6=translate(mid_axis,xoff=end[0]-mid[0],yoff=end[1]-mid[1]) # STEP 6 pt1=getMeanPoint(axis1,axis2,pts_array) pt2=getMeanPoint(axis2,axis3,pts_array) pt3=getMeanPoint(axis3,mid_axis,pts_array) pt4=getMeanPoint(axis4,mid_axis,pts_array) pt5=getMeanPoint(axis5,axis4,pts_array) pt6=getMeanPoint(axis6,axis5,pts_array) # STEP 7 start=pt1.coords[0] end=pt2.coords[0] headLine=LineString([start,end]) headLine=scale(headLine,2,2) start=np.array(start); end=np.array(end) mid=(start+end)/2 mid_axis=rotate(headLine,90) axis1=translate(mid_axis,xoff=(start[0]-mid[0])*2,yoff=(start[1]-mid[1])*2) axis2=translate(mid_axis,xoff=end[0]-mid[0],yoff=end[1]-mid[1]) #poly=Polygon([p for p in axis1.coords]+[p for p in reversed(axis2.coords)]) #draws a box around one half of the mouse #pts_inside=MultiPoint([pt for pt in pts if poly.contains(pt)]) poly=np.array([p for p in axis1.coords]+[p for p in reversed(axis2.coords)]) rr, cc = polygon(poly[:, 0], poly[:, 1]) box_array=np.column_stack((rr,cc)) pts_inside=multidim_intersect(pts_array,box_array) if len(pts_inside)==0: #this only happens when the object lies completely outside of the box at the end of the line pts_inside=pts_array pts_inside=MultiPoint([tuple(p) for p in pts_inside]) coor=np.array([np.array(s) for s in axis1.coords]) pt=end p0=(.5,) bounds=[(0.0,1.0)] p, cov_x, infodic, mesg, ier = leastsqbound(err, p0,args=(coor,pts_inside,pt),bounds = bounds,ftol=.1, full_output=True) headLine=LineString([coor[0]+p[0]*(coor[1]-coor[0]),pt]) headLine=crop_line(headLine,np.array([np.array([p.x,p.y]) for p in pts_inside])) pt1=Point(headLine.coords[1]) start=pt6.coords[0] end=pt5.coords[0] headLine=LineString([start,end]) headLine=scale(headLine,2,2) start=np.array(start); end=np.array(end) mid=(start+end)/2 mid_axis=rotate(headLine,90) axis1=translate(mid_axis,xoff=(start[0]-mid[0])*2,yoff=(start[1]-mid[1])*2) axis2=translate(mid_axis,xoff=end[0]-mid[0],yoff=end[1]-mid[1]) #poly=Polygon([p for p in axis1.coords]+[p for p in reversed(axis2.coords)]) #draws a box around one half of the mouse #pts_inside=MultiPoint([pt for pt in pts if poly.contains(pt)]) poly=np.array([p for p in axis1.coords]+[p for p in reversed(axis2.coords)]) rr, cc = polygon(poly[:, 0], poly[:, 1]) box_array=np.column_stack((rr,cc)) pts_inside=multidim_intersect(pts_array,box_array) if len(pts_inside)==0: #this only happens when the object lies completely outside of the box at the end of the line pts_inside=pts_array pts_inside=MultiPoint([tuple(p) for p in pts_inside]) coor=np.array([np.array(s) for s in axis1.coords]) pt=end p0=(.5,) bounds=[(0.0,1.0)] p, cov_x, infodic, mesg, ier = leastsqbound(err, p0,args=(coor,pts_inside,pt),bounds = bounds,ftol=.1, full_output=True) headLine=LineString([coor[0]+p[0]*(coor[1]-coor[0]),pt]) headLine=crop_line(headLine,np.array([np.array([p.x,p.y]) for p in pts_inside])) pt6=Point(headLine.coords[1]) line=pts2line([pt1,pt2,pt3,pt4,pt5,pt6]) return line, angle, center
def leastsq(self, x, y, parameters=None, sigma=None): logger = logging.getLogger(__name__) # Ensure all values of sigma or non zero by replacing with the minimum nonzero value if sigma is not None and self.useErrorBars: nonzerosigma = sigma[sigma>0] sigma[sigma==0] = numpy.min(nonzerosigma) if len(nonzerosigma)>0 else 1.0 else: sigma = None if parameters is None: parameters = [float(param) for param in self.startParameters] if self.useSmartStartValues: smartParameters = self.smartStartValues(x, y, parameters, self.parameterEnabled) if smartParameters is not None: parameters = [ smartparam if enabled else param for enabled, param, smartparam in zip(self.parameterEnabled, parameters, smartParameters)] myEnabledBounds = self.enabledBounds() if myEnabledBounds: enabledOnlyParameters, cov_x, infodict, self.mesg, self.ier = leastsqbound(self.residuals, self.enabledStartParameters(parameters, bounded=True), args=(y, x, sigma), epsfcn=self.epsfcn, full_output=True, bounds=myEnabledBounds) else: enabledOnlyParameters, cov_x, infodict, self.mesg, self.ier = leastsq(self.residuals, self.enabledStartParameters(parameters), args=(y, x, sigma), epsfcn=self.epsfcn, full_output=True) self.setEnabledFitParameters(enabledOnlyParameters) self.update(self.parameters) logger.info( "chisq {0}".format( sum(infodict["fvec"]*infodict["fvec"]) ) ) # calculate final chi square self.chisq=sum(infodict["fvec"]*infodict["fvec"]) self.dof = max( len(x)-len(parameters), 1) RMSres = Q(sqrt(self.chisq/self.dof)) RMSres.significantDigits = 3 self.results['RMSres'].value = RMSres # chisq, sqrt(chisq/dof) agrees with gnuplot logger.info( "success {0} {1}".format( self.ier, self.mesg ) ) logger.info( "Converged with chi squared {0}".format(self.chisq) ) logger.info( "degrees of freedom, dof {0}".format( self.dof ) ) logger.info( "RMS of residuals (i.e. sqrt(chisq/dof)) {0}".format( RMSres ) ) logger.info( "Reduced chisq (i.e. variance of residuals) {0}".format( self.chisq/self.dof ) ) # uncertainties are calculated as per gnuplot, "fixing" the result # for non unit values of the reduced chisq. # values at min match gnuplot enabledParameterNames = self.enabledParameterNames() if cov_x is not None: enabledOnlyParametersConfidence = numpy.sqrt(numpy.diagonal(cov_x))*sqrt(self.chisq/self.dof) self.setEnabledConfidenceParameters(enabledOnlyParametersConfidence) logger.info( "Fitted parameters at minimum, with 68% C.I.:" ) for i, pmin in enumerate(enabledOnlyParameters): logger.info( "%2i %-10s %12f +/- %10f"%(i, enabledParameterNames[i], pmin, sqrt(max(cov_x[i, i], 0))*sqrt(self.chisq/self.dof)) ) logger.info( "Correlation matrix" ) # correlation matrix close to gnuplot messagelist = [" "] for i in range(len(enabledOnlyParameters)): messagelist.append( "%-10s"%(enabledParameterNames[i],) ) logger.info( " ".join(messagelist)) messagelist = [] for i in range(len(enabledOnlyParameters)): messagelist.append( "%10s"%enabledParameterNames[i] ) for j in range(i+1): messagelist.append( "%10f"%(cov_x[i, j]/sqrt(abs(cov_x[i, i]*cov_x[j, j])),) ) logger.info( " ".join(messagelist)) #----------------------------------------------- else: self.parametersConfidence = [None]*len(self.parametersConfidence) return self.parameters
def getLine(image, angle=None): """ This function takes a boolean image of a rodent, performs several steps, and returns a line running down the middle of the rodent from nose to tail. The steps are: 1) Find the point at the center of mass. 2) Draw a horizontal line through this point. 3) Find the mean distance from the line to every point in the rodent. Rotate the line and find the angle which gives the minimum such distance. Keep the line at this angle. This line gives a good approximation for position. 4) Draw 7 points on the line: one at the midpoint, two at the ends, two 3/4 away from the midpoint, and two halfway between the ends and the midpoint. 5) Construct 7 lines which run through the 7 points at an angle perpendicular to the main line. 6) Draw 6 boxes between these 7 lines. Find the center of mass for each box along the axes parallel to these lines. Move each of the 7 points (except the midpoint) along their lines to the center of mass of their respective region. 7) Draw a box around the end segment of the line. The bounds for the box lie parallel and perpendicular to this segment. Fixing the inner point and allowing the end point to vary, fit the segment so that the average distance from the segment to the points in the box are a minimum. This step is done for both ends of the line, because we don't as yet know which end is the head and which is the tail. """ pts = np.where(image) pts_array = np.column_stack((pts[0], pts[1])) pts = MultiPoint([(pts[0][i], pts[1][i]) for i in np.arange(len(pts[0]))]) # STEP 1 x0, y0 = center_of_mass(image) center = Point(x0, y0) bounds = pts.bounds b_len = ((bounds[2] - bounds[0])**2 + (bounds[3] - bounds[1])**2)**( 1 / 2 ) #this is the length of the diagonal, the maximum possible length of an object inside a box # STEP 2 line = pts2line([translate(center, b_len), translate(center, -b_len)]) # STEP 3 if angle is None: angles = np.arange(-90, 90, 10) else: angles = np.arange( angle - 20, angle + 20, 10 ) #this assumes the angle changes at most 10 degrees between frames distances = np.zeros(angles.shape, dtype=np.float) for i in np.arange(len(angles)): distances[i] = getMeanDistance(rotate(line, angles[i]), pts) angle = angles[np.argmin(distances)] line = rotate(line, angle) line = crop_line(line, pts_array) # STEP 4 & 5 # now that we have the approximate line down the main axis, let's divide it in half and allow the endpoints and midpoint to be translated along the perpendicular axis start, end = list(line.coords) start = np.array(start) end = np.array(end) mid = (start + end) / 2 mid_axis = rotate(line, 90) mid_axis = crop_line(mid_axis, pts_array) axis1 = translate(mid_axis, xoff=start[0] - mid[0], yoff=start[1] - mid[1]) axis2 = translate(mid_axis, xoff=(start[0] - mid[0]) / (4. / 3), yoff=(start[1] - mid[1]) / (4. / 3.)) axis3 = translate(mid_axis, xoff=(start[0] - mid[0]) / 2, yoff=(start[1] - mid[1]) / 2.) axis4 = translate(mid_axis, xoff=(end[0] - mid[0]) / 2, yoff=(end[1] - mid[1]) / 2) axis5 = translate(mid_axis, xoff=(end[0] - mid[0]) / (4. / 3.), yoff=(end[1] - mid[1]) / (4. / 3.)) axis6 = translate(mid_axis, xoff=end[0] - mid[0], yoff=end[1] - mid[1]) # STEP 6 pt1 = getMeanPoint(axis1, axis2, pts_array) pt2 = getMeanPoint(axis2, axis3, pts_array) pt3 = getMeanPoint(axis3, mid_axis, pts_array) pt4 = getMeanPoint(axis4, mid_axis, pts_array) pt5 = getMeanPoint(axis5, axis4, pts_array) pt6 = getMeanPoint(axis6, axis5, pts_array) # STEP 7 start = pt1.coords[0] end = pt2.coords[0] headLine = LineString([start, end]) headLine = scale(headLine, 2, 2) start = np.array(start) end = np.array(end) mid = (start + end) / 2 mid_axis = rotate(headLine, 90) axis1 = translate(mid_axis, xoff=(start[0] - mid[0]) * 2, yoff=(start[1] - mid[1]) * 2) axis2 = translate(mid_axis, xoff=end[0] - mid[0], yoff=end[1] - mid[1]) #poly=Polygon([p for p in axis1.coords]+[p for p in reversed(axis2.coords)]) #draws a box around one half of the mouse #pts_inside=MultiPoint([pt for pt in pts if poly.contains(pt)]) poly = np.array([p for p in axis1.coords] + [p for p in reversed(axis2.coords)]) rr, cc = polygon(poly[:, 0], poly[:, 1]) box_array = np.column_stack((rr, cc)) pts_inside = multidim_intersect(pts_array, box_array) if len( pts_inside ) == 0: #this only happens when the object lies completely outside of the box at the end of the line pts_inside = pts_array pts_inside = MultiPoint([tuple(p) for p in pts_inside]) coor = np.array([np.array(s) for s in axis1.coords]) pt = end p0 = (.5, ) bounds = [(0.0, 1.0)] p, cov_x, infodic, mesg, ier = leastsqbound(err, p0, args=(coor, pts_inside, pt), bounds=bounds, ftol=.1, full_output=True) headLine = LineString([coor[0] + p[0] * (coor[1] - coor[0]), pt]) headLine = crop_line(headLine, np.array([np.array([p.x, p.y]) for p in pts_inside])) pt1 = Point(headLine.coords[1]) start = pt6.coords[0] end = pt5.coords[0] headLine = LineString([start, end]) headLine = scale(headLine, 2, 2) start = np.array(start) end = np.array(end) mid = (start + end) / 2 mid_axis = rotate(headLine, 90) axis1 = translate(mid_axis, xoff=(start[0] - mid[0]) * 2, yoff=(start[1] - mid[1]) * 2) axis2 = translate(mid_axis, xoff=end[0] - mid[0], yoff=end[1] - mid[1]) #poly = Polygon([p for p in axis1.coords]+[p for p in reversed(axis2.coords)]) #draws a box around one half of the mouse #pts_inside = MultiPoint([pt for pt in pts if poly.contains(pt)]) poly = np.array([p for p in axis1.coords] + [p for p in reversed(axis2.coords)]) rr, cc = polygon(poly[:, 0], poly[:, 1]) box_array = np.column_stack((rr, cc)) pts_inside = multidim_intersect(pts_array, box_array) if len( pts_inside ) == 0: #this only happens when the object lies completely outside of the box at the end of the line pts_inside = pts_array pts_inside = MultiPoint([tuple(p) for p in pts_inside]) coor = np.array([np.array(s) for s in axis1.coords]) pt = end p0 = (.5, ) bounds = [(0.0, 1.0)] p, cov_x, infodic, mesg, ier = leastsqbound(err, p0, args=(coor, pts_inside, pt), bounds=bounds, ftol=.1, full_output=True) headLine = LineString([coor[0] + p[0] * (coor[1] - coor[0]), pt]) headLine = crop_line(headLine, np.array([np.array([p.x, p.y]) for p in pts_inside])) pt6 = Point(headLine.coords[1]) line = pts2line([pt1, pt2, pt3, pt4, pt5, pt6]) return line, angle, center
def leastsqFit(func, x, params, y, err=None, fitOnly=None, verbose=False, doNotFit=[], epsfcn=1e-7, ftol=1e-4, fullOuput=True,bounds={}): """ - params is a Dict containing the first guess. - bounds = {"theta":[-0.1,3.24]} even if after it will be a list with same indexation as fitOnly - fits 'y +- err = func(x,params)'. errors are optionnal. - fitOnly is a LIST of keywords to fit. By default, it fits all parameters in 'params'. Alternatively, one can give a list of parameters not to be fitted, as 'doNotFit=' - doNotFit has a similar purpose: for example if params={'a0':, 'a1': 'b1':, 'b2':}, doNotFit=['a'] will result in fitting only the 'b1' and 'b2'. WARNING: if you name parameter 'A' and another one 'AA', you cannot use doNotFit to exclude only 'A' since 'AA' will be excluded as well... returns bestparam, uncertainties, chi2_reduced, func(x, bestparam) """ # fit all parameters by default if fitOnly is None: if len(doNotFit)>0: fitOnly = filter(lambda x: x not in doNotFit, params.keys()) else: fitOnly = params.keys() # build fitted parameters vector: pfit = [params[k] for k in fitOnly] # built fixed parameters dict: pfix = {} for k in params.keys(): if k not in fitOnly: pfix[k]=params[k] if verbose: print '[dpfit] FITTED parameters:', fitOnly # NO BOUNDS if bounds == {} : # actual fit plsq, cov, info, mesg, ier = \ scipy.optimize.leastsq(fitFunc, pfit, args=(fitOnly,x,y,err,func,pfix, verbose), full_output=True, epsfcn=epsfcn, ftol=ftol) # WITH BOUNDS else : #including bounds != {} bounds_to_fit=[[None,None]]*len(fitOnly) # now it is a list for key in bounds.keys() : if key in fitOnly : # becauser could be in notToFit bounds_to_fit[fitOnly.index(key)] = bounds[key] plsq, cov, info, mesg, ier = \ leastsqbound(fitFunc, pfit, bounds=bounds_to_fit, args=(fitOnly,x,y,err,func,pfix, verbose), full_output=True, epsfcn=epsfcn, ftol=ftol) # best fit -> agregate to pfix for i,k in enumerate(fitOnly): pfix[k] = plsq[i] # reduced chi2 model = func(x,pfix) chi2 = (np.array(fitFunc(plsq, fitOnly, x, y, err, func, pfix))**2).sum() reducedChi2 = chi2/float(reduce(lambda x,y: x+y, [1 if np.isscalar(i) else len(i) for i in y])-len(pfit)+1) # uncertainties: uncer = {} for k in pfix.keys(): if not k in fitOnly: uncer[k]=0 # not fitted, uncertatinties to 0 else: i = fitOnly.index(k) if cov is None: uncer[k]=-1 else: uncer[k]= np.sqrt(np.abs(np.diag(cov)[i]*reducedChi2)) if verbose: print '-'*20 print 'REDUCED CHI2=', reducedChi2 tmp = pfix.keys(); tmp.sort() for k in tmp: print k, '=', pfix[k], if uncer[k]!=0: print '+/-', uncer[k] else: print '' # result: return pfix, uncer, chi2, model , {"reduced_chi2":reducedChi2,"cov":cov,"plsq":plsq,"pfit":pfit,"fitOnly":fitOnly,"bounds":bounds}
print "Standard Least Squares fitting results:" print "p:", p print "cov_x:", cov_x print "infodic['nfev']:", infodic['nfev'] print "infodic['fvec']:", infodic['fvec'] print "infodic['fjac']:", infodic['fjac'] print "infodic['ipvt']:", infodic['ipvt'] print "infodic['qtf']:", infodic['qtf'] print "mesg:", mesg print "ier:", ier print "" # same as above using no bounds p0 = [1.0, 0.0] p, cov_x, infodic, mesg, ier = leastsqbound(err, p0, args=(y, x), full_output=True) # print out results print "Bounded Least Squares fitting with no bounds results:" print "p:", p print "cov_x:", cov_x print "infodic['nfev']:", infodic['nfev'] print "infodic['fvec']:", infodic['fvec'] print "infodic['fjac']:", infodic['fjac'] print "infodic['ipvt']:", infodic['ipvt'] print "infodic['qtf']:", infodic['qtf'] print "mesg:", mesg print "ier:", ier print ""
def main(): # # y axis is horizontal # z axis is vertical # # #load height profile # input_file = "tmpHeights.dat" a = numpy.loadtxt(input_file) y0 = a[:, 0] z0 = a[:, 1] z0 -= z0.min() # #load slopes profile # input_file = "tmpSlopes.dat" a = numpy.loadtxt(input_file) yp0 = a[:, 0] zp0 = a[:, 1] L = y0[-1] - y0[0] print("Mirror data from file: %s :" % input_file) print(" Mirror length is: %.3f m" % L) N = y0.size print(" Mirror contains %d points" % N) slope_error_rms = zp0.std() print(" Mirror slope error RMS is %.3f urad = %.3f arcsec" % (slope_error_rms * 1e6, slope_error_rms * 180 / numpy.pi * 3600)) # #aspheric fit # # fit_method = 0 fit aspherical heights, use curve_fit on heights (NOT WORKING) # fit_method = 1 fit aspherical heights, use leastsq on heights (NOT WORKING) # fit_method = 2 fit aspherical heights, use bounded leastsq on heights (NOT WORKING) # fit_method = 3 fit elliptical heights # fit_method = 4 fit elliptical slopes # fit_method = 5 fit elliptical heights using Xianbo method fit_method = 4 if fit_method == 0: # use curve_fit popt, pcov = curve_fit(func_aspheric, y0, z0) print("popt: ", repr(popt)) print("pcov: ", repr(pcov)) z2 = func_aspheric(y0, popt[0], popt[1]) if fit_method == 1: # use lestsq fitfunc = lambda p, x: func_aspheric(x, p[0], p[1]) #z2 = fitfunc([radius*1.2,0.0],y0) errfunc = lambda p, x, y: fitfunc(p, x) - y #z2 = errfunc([radius*1.2,0.0],y0,z0) #print(errfunc([radius,0.0],y0,z0)) p0 = [radius, 0.0] # initial guess #popt, success = leastsq(errfunc, p0[:], args=(y0, z0)) #print("popt: ",repr(popt)) #print("success: ",repr(success)) popt, cov_x, infodic, mesg, ier = leastsq(errfunc, p0, args=(y0, z0), full_output=True) print("Standard Least Squares fitting results:") print("p0:", p0) print("cov_x:", cov_x) print("infodic['nfev']:", infodic['nfev']) print("infodic['fvec']:", infodic['fvec']) print("infodic['fjac']:", infodic['fjac']) print("infodic['ipvt']:", infodic['ipvt']) print("infodic['qtf']:", infodic['qtf']) print("mesg:", mesg) print("ier:", ier) print(">>>>> popt: ", repr(popt)) print("") z2 = func_aspheric(y0, popt[0], popt[1]) if fit_method == 2: # use lestsq fitfunc = lambda p, x: func_aspheric(x, p[0], p[1]) #z2 = fitfunc([radius*1.2,0.0],y0) errfunc = lambda p, x, y: fitfunc(p, x) - y #z2 = errfunc([radius*1.2,0.0],y0,z0) #print(errfunc([radius,0.0],y0,z0)) p0 = [radius, -0.9999999999] # initial guess # https://github.com/jjhelmus/leastsqbound-scipy from leastsqbound import leastsqbound bounds = [(radius * 0.5, radius * 1.5), (-1.0, -0.9)] popt, cov_x, infodic, mesg, ier = leastsqbound(errfunc, p0, args=(y0, z0), bounds=bounds, full_output=True) # print out results print("Bounded Least Squares fitting with no bounds results:") print("p0:", p0) print("cov_x:", cov_x) print("infodic['nfev']:", infodic['nfev']) print("infodic['fvec']:", infodic['fvec']) print("infodic['fjac']:", infodic['fjac']) print("infodic['ipvt']:", infodic['ipvt']) print("infodic['qtf']:", infodic['qtf']) print("mesg:", mesg) print("ier:", ier) print(">>>>> popt: ", repr(popt)) print("") z2 = func_aspheric(y0, popt[0], popt[1]) #z2 = func_aspheric(y0, popt[0], -0.99999996025050053) if fit_method == 3: # ellipse fitting heights ibounded = 0 #=0 curve_fit (no guess), 1=leastsq, 2=bounded print("======== Fitting heights =======") if ibounded == 0: print("======== Curve fitting without guess =======") popt, cov_x = curve_fit(func_ellipse, y0, z0, maxfev=10000) else: #dabam-4 (Amparo) # p0 = 98.00 # q0 = 0.0775 # theta0 = 3.9e-3 # # # #dabam-6 (Soleil) p=499.14 mm q= 4500 mm teta = 34.99 mrad p0 = 499.14e-3 q0 = 4500e-3 theta0 = 34.99e-3 # # # #dabam-19 #design parameter of ellipse: entrance arm: 420000mm; exit arm: 900mm; angle of incidence 3.052mrad # p0 = 420.0 # q0 = 0.9 # theta0 = 3.052e-3 # # # #dabam-20 #design parameter of ellipse: entrance arm 9000mm; exit arm: 350mm; angle of incidence: 2.5deg # p0 = 9.0 # q0 = 0.35 # theta0 = 2.5*numpy.pi/180 # #TODO: # zp0 = -zp0 # # # #dabam-21 #design parameter of ellipse: entrance arm: 7500mm; exit arm: 2500mm; angle of incidence 0.6deg # p0 = 7.5 # q0 = 2.5 # theta0 = 0.6*numpy.pi/180 p_guess = [p0, q0, theta0] z1 = func_ellipse_amparo(yp0, p_guess[0], p_guess[1], p_guess[2]) # ishift = 0 # if ishift: # print(">>>>>>>> slope zp0[0], zp1[0], diff: ",zp0[0],zp1[1],zp0[0]-zp1[1]) # print(">>>>>>>>>>>>>>>>>>> shift value: ",(zp0-zp1)[1]) # p_guess[3] = (zp0-zp1)[1] # zp1 = func_ellipse(yp0, p_guess[0], p_guess[1], p_guess[2], p_guess[3]) print("p0,q0,theta: ", p0, q0, theta0) fitfunc_ell_heights = lambda p, x: func_ellipse_amparo( x, p[0], p[1], p[2]) errfunc_ell_heights = lambda p, x, y: fitfunc_ell_heights(p, x) - y if ibounded == 1: print("======== Least Squares fitting =======") popt, cov_x, infodic, mesg, ier = leastsq(errfunc_ell_heights, p_guess, args=(y0, z0), full_output=True) else: print("======== Bounded Least Squares fitting =======") # https://github.com/jjhelmus/leastsqbound-scipy from leastsqbound import leastsqbound bounds = [(p0 * 0.998, p0 * 1.002), (q0 * 0.8, q0 * 1.2), (theta0 * 0.98, theta0 * 1.02)] popt, cov_x, infodic, mesg, ier = leastsqbound( errfunc_ell_heights, p_guess, args=(y0, z0), bounds=bounds, full_output=True) print("cov_x:", cov_x) # print("infodic['nfev']:", infodic['nfev']) # print("infodic['fvec']:", infodic['fvec']) # print("infodic['fjac']:", infodic['fjac']) # print("infodic['ipvt']:", infodic['ipvt']) # print("infodic['qtf']:", infodic['qtf']) # print("mesg:", mesg) # print("ier:", ier) print(">>>>> p_guess:", p_guess) #zp1 = func_ellipse_slopes(yp0, p_guess[0], p_guess[1], p_guess[2], 0.0 ) #p_guess[3]) #TODO!! dd = numpy.concatenate((y0, z1), axis=0).reshape(2, -1).transpose() outFile = "tmp_z1.dat" numpy.savetxt(outFile, dd) print("File " + outFile + " written to disk:\n") print(">>>>> popt (p,q,theta): ", popt) z2 = func_ellipse(y0, popt[0], popt[1], popt[2]) #amparo z2 = func_ellipse(y0, 98.0, 81.826e-3, 3.865*1e-3) if ibounded != 0: print('Height error RMS z0-z1: %.3f nm' % (1e9 * (z0 - z1).std())) print('height error RMS z0-z2: %.3f nm' % (1e9 * (z0 - z2).std())) dd = numpy.concatenate((y0, z2), axis=0).reshape(2, -1).transpose() outFile = "tmp_z2.dat" numpy.savetxt(outFile, dd) print("File " + outFile + " written to disk:\n") if fit_method == 4: # ellipse, slopes fit ibounded = 1 #=0 curve_fit (no guess), 1=leastsq, 2=bounded print("======== Fitting slopes =======") if ibounded == 0: print("======== Curve fitting without guess =======") popt, cov_x = curve_fit(func_ellipse_slopes, yp0, zp0, maxfev=10000) else: ishift = 0 #dabam-4 (Amparo) p0 = 98.00 q0 = 0.0775 theta0 = 3.9e-3 # # # # # #dabam-6 (Soleil) p=499.14 mm q= 4500 mm teta = 34.99 mrad # p0 = 499.14e-3 # q0 = 4500e-3 # theta0 = 34.99e-3 # ishift = 1 # # # # # # # # #dabam-19 #design parameter of ellipse: entrance arm: 420000mm; exit arm: 900mm; angle of incidence 3.052mrad # p0 = 420.0 #WRONG INPUTS? # q0 = 0.9 #WRONG INPUTS? # theta0 = 3.052e-3 #WRONG INPUTS? # # yp0 = yp0 - yp0[int(yp0.size/2)] # # # # #dabam-20 #design parameter of ellipse: entrance arm 9000mm; exit arm: 350mm; angle of incidence: 2.5deg # p0 = 9.0 # q0 = 0.35 # theta0 = 2.5*numpy.pi/180 # #TODO: # yp0 = yp0 - yp0[int(yp0.size/2)] # zp0 = -zp0 # # # # #dabam-21 #design parameter of ellipse: entrance arm: 7500mm; exit arm: 2500mm; angle of incidence 0.6deg # p0 = 7.5 # q0 = 2.5 # theta0 = 0.6*numpy.pi/180 # ishift = 1 p_guess = [p0, q0, theta0] zp1 = func_ellipse_slopes(yp0, p_guess[0], p_guess[1], p_guess[2]) if ishift: zp0 = zp0 + (zp1[0] - zp0[0]) print("p0,q0,theta: ", p0, q0, theta0) fitfunc_ell_slopes = lambda p, x: func_ellipse_slopes( x, p[0], p[1], p[2]) errfunc_ell_slopes = lambda p, x, y: fitfunc_ell_slopes(p, x) - y if ibounded == 1: print("======== Least Squares fitting =======") popt, cov_x, infodic, mesg, ier = leastsq(errfunc_ell_slopes, p_guess, args=(yp0, zp0), full_output=True) elif ibounded == 2: print("======== Bounded Least Squares fitting =======") # https://github.com/jjhelmus/leastsqbound-scipy from leastsqbound import leastsqbound bounds = [(p0 * 0.998, p0 * 1.002), (q0 * 0.8, q0 * 1.2), (theta0 * 0.98, theta0 * 1.02)] popt, cov_x, infodic, mesg, ier = leastsqbound( errfunc_ell_slopes, p_guess, args=(yp0, zp0), bounds=bounds, full_output=True) print("cov_x:", cov_x) # print("infodic['nfev']:", infodic['nfev']) # print("infodic['fvec']:", infodic['fvec']) # print("infodic['fjac']:", infodic['fjac']) # print("infodic['ipvt']:", infodic['ipvt']) # print("infodic['qtf']:", infodic['qtf']) # print("mesg:", mesg) # print("ier:", ier) print(">>>>> p_guess:", p_guess) #zp1 = func_ellipse_slopes(yp0, p_guess[0], p_guess[1], p_guess[2]) dd = numpy.concatenate((yp0, zp1), axis=0).reshape(2, -1).transpose() outFile = "tmp_zp1.dat" numpy.savetxt(outFile, dd) print("File " + outFile + " written to disk:\n") print(">>>>> popt (p,q,theta): ", popt) zp2 = func_ellipse_slopes(yp0, popt[0], popt[1], popt[2]) #amparo zp2 = func_ellipse_slopes(yp, 98.0, 82.0424e-3, 3.8754e-3, 0.0) if ibounded != 0: print('Slope error RMS zp0-zp1: %.3f urad' % (1e6 * (zp0 - zp1).std())) print('Slope error RMS zp0-zp2: %.3f urad' % (1e6 * (zp0 - zp2).std())) dd = numpy.concatenate((yp0, zp2), axis=0).reshape(2, -1).transpose() outFile = "tmp_zp2.dat" numpy.savetxt(outFile, dd) print("File " + outFile + " written to disk:\n") if fit_method == 5: # ellipse fitting heights using Xianbo method ibounded = 2 #=0 curve_fit (no guess), 1=leastsq, 2=bounded print("======== Fitting heights =======") if ibounded == 0: print("======== Curve fitting without guess =======") popt, cov_x = curve_fit(func_ellipse_xianbo, y0, z0, maxfev=10000) else: #dabam-4 (Amparo) # p0 = 98.00 # q0 = 0.0775 # theta0 = 3.9e-3 # OFFSET = 0.0 # XC = 0.0 # # # #dabam-6 (Soleil) p=499.14 mm q= 4500 mm teta = 34.99 mrad # p0 = 499.14e-3 # q0 = 4500e-3 # theta0 = 34.99e-3 # OFFSET = 0.0 # XC = 0.0 # # # #dabam-19 #design parameter of ellipse: entrance arm: 420000mm; exit arm: 900mm; angle of incidence 3.052mrad # p0 = 420.0 # q0 = 0.9 # theta0 = 3.052e-3 # OFFSET = 0.0 # XC = 0.0 # # # #dabam-20 #design parameter of ellipse: entrance arm 9000mm; exit arm: 350mm; angle of incidence: 2.5deg p0 = 9.0 q0 = 0.35 theta0 = 2.5 * numpy.pi / 180 OFFSET = 0.0 XC = 75e-3 # #TODO: # zp0 = -zp0 # # # #dabam-21 #design parameter of ellipse: entrance arm: 7500mm; exit arm: 2500mm; angle of incidence 0.6deg # p0 = 7.5 # q0 = 2.5 # theta0 = 0.6*numpy.pi/180 # OFFSET = 0.0 # XC = 0.0 p_guess = [p0, q0, theta0, OFFSET, XC] z1 = func_ellipse_xianbo(yp0, p_guess[0], p_guess[1], p_guess[2], p_guess[3], p_guess[4]) # ishift = 0 # if ishift: # print(">>>>>>>> slope zp0[0], zp1[0], diff: ",zp0[0],zp1[1],zp0[0]-zp1[1]) # print(">>>>>>>>>>>>>>>>>>> shift value: ",(zp0-zp1)[1]) # p_guess[3] = (zp0-zp1)[1] # zp1 = func_ellipse(yp0, p_guess[0], p_guess[1], p_guess[2], p_guess[3]) print("p0,q0,theta,OFFSET,XC: ", p0, q0, theta0, OFFSET, XC) fitfunc_ell_heights = lambda p, x: func_ellipse_xianbo( x, p[0], p[1], p[2], p[3], p[4]) errfunc_ell_heights = lambda p, x, y: fitfunc_ell_heights(p, x) - y if ibounded == 1: print("======== Least Squares fitting =======") popt, cov_x, infodic, mesg, ier = leastsq(errfunc_ell_heights, p_guess, args=(y0, z0), full_output=True) else: print("======== Bounded Least Squares fitting =======") # https://github.com/jjhelmus/leastsqbound-scipy from leastsqbound import leastsqbound bounds = [(p0 * 0.998, p0 * 1.002), (q0 * 0.8, q0 * 1.2), (theta0 * 0.98, theta0 * 1.02), (OFFSET * 0.9, OFFSET * 1.2), (XC * 0.9, XC * 1.2)] popt, cov_x, infodic, mesg, ier = leastsqbound( errfunc_ell_heights, p_guess, args=(y0, z0), bounds=bounds, full_output=True) print("cov_x:", cov_x) # print("infodic['nfev']:", infodic['nfev']) # print("infodic['fvec']:", infodic['fvec']) # print("infodic['fjac']:", infodic['fjac']) # print("infodic['ipvt']:", infodic['ipvt']) # print("infodic['qtf']:", infodic['qtf']) # print("mesg:", mesg) # print("ier:", ier) print(">>>>> p_guess:", p_guess) #zp1 = func_ellipse_slopes(yp0, p_guess[0], p_guess[1], p_guess[2], 0.0 ) #p_guess[3]) #TODO!! dd = numpy.concatenate((y0, z1), axis=0).reshape(2, -1).transpose() outFile = "tmp_z1.dat" numpy.savetxt(outFile, dd) print("File " + outFile + " written to disk:\n") print(">>>>> popt (p,q,theta): ", popt) z2 = func_ellipse_xianbo(y0, popt[0], popt[1], popt[2], popt[3], popt[4]) #amparo z2 = func_ellipse(y0, 98.0, 81.826e-3, 3.865*1e-3) if ibounded != 0: print('Height error RMS z0-z1: %.3f nm' % (1e9 * (z0 - z1).std())) print('height error RMS z0-z2: %.3f nm' % (1e9 * (z0 - z2).std())) dd = numpy.concatenate((y0, z2), axis=0).reshape(2, -1).transpose() outFile = "tmp_z2.dat" numpy.savetxt(outFile, dd) print("File " + outFile + " written to disk:\n") # #plots # do_plots = 1 if do_plots: # #plots # from matplotlib import pylab as plt if fit_method == 4: #slopes f1 = plt.figure(1) ax = plt.gca() ax.get_xaxis().get_major_formatter().set_useOffset(False) ax.get_yaxis().get_major_formatter().set_useOffset(False) plt.plot(yp0 * 1e3, zp0 * 1e6) if ibounded != 0: plt.plot(yp0 * 1e3, zp1 * 1e6) plt.plot(yp0 * 1e3, zp2 * 1e6) plt.title( "slopes data (blue), starting (green) and optimized (red) ellipse" ) plt.xlabel("Y [mm]") plt.ylabel("Zp [urad]") f2 = plt.figure(2) ax = plt.gca() ax.get_xaxis().get_major_formatter().set_useOffset(False) ax.get_yaxis().get_major_formatter().set_useOffset(False) plt.plot(yp0 * 1e3, (zp0 - zp2) * 1e6) plt.title("residual slopes") plt.xlabel("Y [mm]") plt.ylabel("Zp [urad]") elif (fit_method == 3 or fit_method == 5): #heights f1 = plt.figure(1) ax = plt.gca() ax.get_xaxis().get_major_formatter().set_useOffset(False) ax.get_yaxis().get_major_formatter().set_useOffset(False) plt.plot(y0 * 1e3, z0 * 1e6) if ibounded != 0: plt.plot(y0 * 1e3, z1 * 1e6) plt.plot(y0 * 1e3, z2 * 1e6) plt.title( "height data (blue), starting (green) and optimized (red) ellipse" ) plt.xlabel("Y [mm]") plt.ylabel("Zp [um]") f2 = plt.figure(2) ax = plt.gca() ax.get_xaxis().get_major_formatter().set_useOffset(False) ax.get_yaxis().get_major_formatter().set_useOffset(False) plt.plot(y0 * 1e3, (z0 - z2) * 1e9) plt.title("residual heights") plt.xlabel("Y [mm]") plt.ylabel("Z [nm]") plt.show()
def leastsq(self, x, y, parameters=None, sigma=None): logger = logging.getLogger(__name__) # Ensure all values of sigma or non zero by replacing with the minimum nonzero value if sigma is not None and self.useErrorBars: nonzerosigma = sigma[sigma > 0] sigma[sigma == 0] = numpy.min( nonzerosigma) if len(nonzerosigma) > 0 else 1.0 else: sigma = None if parameters is None: parameters = [float(param) for param in self.startParameters] if self.useSmartStartValues: smartParameters = self.smartStartValues(x, y, parameters, self.parameterEnabled) if smartParameters is not None: parameters = [ smartparam if enabled else param for enabled, param, smartparam in zip( self.parameterEnabled, parameters, smartParameters) ] myEnabledBounds = self.enabledBounds() if myEnabledBounds: enabledOnlyParameters, cov_x, infodict, self.mesg, self.ier = leastsqbound( self.residuals, self.enabledStartParameters(parameters, bounded=True), args=(y, x, sigma), epsfcn=self.epsfcn, full_output=True, bounds=myEnabledBounds) else: enabledOnlyParameters, cov_x, infodict, self.mesg, self.ier = leastsq( self.residuals, self.enabledStartParameters(parameters), args=(y, x, sigma), epsfcn=self.epsfcn, full_output=True) self.setEnabledFitParameters(enabledOnlyParameters) self.update(self.parameters) logger.info("chisq {0}".format(sum(infodict["fvec"] * infodict["fvec"]))) # calculate final chi square self.chisq = sum(infodict["fvec"] * infodict["fvec"]) self.dof = max(len(x) - len(parameters), 1) RMSres = Q(sqrt(self.chisq / self.dof)) RMSres.significantDigits = 3 self.results['RMSres'].value = RMSres # chisq, sqrt(chisq/dof) agrees with gnuplot logger.info("success {0} {1}".format(self.ier, self.mesg)) logger.info("Converged with chi squared {0}".format(self.chisq)) logger.info("degrees of freedom, dof {0}".format(self.dof)) logger.info( "RMS of residuals (i.e. sqrt(chisq/dof)) {0}".format(RMSres)) logger.info("Reduced chisq (i.e. variance of residuals) {0}".format( self.chisq / self.dof)) # uncertainties are calculated as per gnuplot, "fixing" the result # for non unit values of the reduced chisq. # values at min match gnuplot enabledParameterNames = self.enabledParameterNames() if cov_x is not None: enabledOnlyParametersConfidence = numpy.sqrt( numpy.diagonal(cov_x)) * sqrt(self.chisq / self.dof) self.setEnabledConfidenceParameters( enabledOnlyParametersConfidence) logger.info("Fitted parameters at minimum, with 68% C.I.:") for i, pmin in enumerate(enabledOnlyParameters): logger.info( "%2i %-10s %12f +/- %10f" % (i, enabledParameterNames[i], pmin, sqrt(max(cov_x[i, i], 0)) * sqrt(self.chisq / self.dof))) logger.info("Correlation matrix") # correlation matrix close to gnuplot messagelist = [" "] for i in range(len(enabledOnlyParameters)): messagelist.append("%-10s" % (enabledParameterNames[i], )) logger.info(" ".join(messagelist)) messagelist = [] for i in range(len(enabledOnlyParameters)): messagelist.append("%10s" % enabledParameterNames[i]) for j in range(i + 1): messagelist.append( "%10f" % (cov_x[i, j] / sqrt(abs(cov_x[i, i] * cov_x[j, j])), )) logger.info(" ".join(messagelist)) #----------------------------------------------- else: self.parametersConfidence = [None] * len(self.parametersConfidence) return self.parameters
def ellipse_fit(entry_number=21, fit_method=1, fit_function='dabam', ibounded=1, do_plots=1): """ :param entry_number: dabam entry number :param fit_method: fit elliptical heights (0), fit elliptical slopes (1) :param fit_function: 'dabam' , 'amparo', 'xianbo' :param ibounded: 0 curve_fit (no guess), 1=leastsq, 2=bounded :param do_plot: 1 display plots :return: """ # #get profiles # import dabam dm = dabam.dabam() dm.inputs["entryNumber"] = entry_number dm.inputs["setDetrending"] = -1 dm.load() # # # p0 = dm.h["ELLIPSE_DESIGN_P"] q0 = dm.h["ELLIPSE_DESIGN_Q"] theta0 = dm.h["ELLIPSE_DESIGN_THETA"] # y axis is horizonta, z axis is vertical y0 = dm.sy z0 = dm.zprof zp0 = dm.sz if fit_method == 0: # ellipse fitting heights hshift = 0.0 #nm vshift = 0.0 # nm #preprocessors if entry_number == 4: z0 -= z0.min() elif entry_number == 6: imin = z0.argmin() z0 -= z0[imin] y0 -= y0[imin] y0 *= -1.0 elif entry_number == 19: pass elif entry_number == 20: hshift = -15e3 elif entry_number == 21: y0 -= y0[y0.size / 2] if fit_function == "amparo": fitfunc_ell_heights = lambda p, x: func_ellipse_heights_amparo( x, p[0], p[1], p[2], p[3], p[4]) print("Using function definition: AMPARO") elif fit_function == "xianbo": fitfunc_ell_heights = lambda p, x: func_ellipse_heights_xianbo( x, p[0], p[1], p[2], p[3], p[4]) print("Using function definition: XIANBO") else: fitfunc_ell_heights = lambda p, x: func_ellipse_heights_dabam( x, p[0], p[1], p[2], p[3], p[4]) print("Using function definition: DABAM") print("======== Fitting heights =======") errfunc_ell_heights = lambda p, x, y: fitfunc_ell_heights(p, x) - y p_guess = [p0, q0, theta0, hshift, vshift] if ibounded == 0: print("======== Curve fitting without guess =======") if fit_function == "amparo": popt, cov_x = curve_fit(func_ellipse_heights_amparo, y0, z0, maxfev=10000) elif fit_function == "xianbo": popt, cov_x = curve_fit(func_ellipse_heights_xianbo, y0, z0, maxfev=10000) else: popt, cov_x = curve_fit(func_ellipse_heights_dabam, y0, z0, maxfev=10000) elif ibounded == 1: print("======== Least Squares fitting =======") popt, cov_x, infodic, mesg, ier = leastsq(errfunc_ell_heights, p_guess, args=(y0, z0), full_output=True) else: print("======== Bounded Least Squares fitting =======") # https://github.com/jjhelmus/leastsqbound-scipy from leastsqbound import leastsqbound bounds = [(p0 * 0.998, p0 * 1.002), (q0 * 0.8, q0 * 1.2), (theta0 * 0.98, theta0 * 1.02), (-0.01, 0.01), (-0.001, 0.001)] popt, cov_x, infodic, mesg, ier = leastsqbound(errfunc_ell_heights, p_guess, args=(y0, z0), full_output=True, bounds=bounds) print(">>>>> p_guess:", p_guess) print(">>>>> popt:", popt) z1 = fitfunc_ell_heights(p_guess, y0) z2 = fitfunc_ell_heights(popt, y0) zp1 = numpy.gradient(z1, y0[1] - y0[0]) zp2 = numpy.gradient(z2, y0[1] - y0[0]) rms_values = (1e9 * (z0 - z1).std(), 1e9 * (z0 - z2).std(), 1e6 * numpy.gradient(z0 - z1, y0[1] - y0[0]).std(), 1e6 * numpy.gradient(z0 - z2, y0[1] - y0[0]).std()) print('Height error RMS z0-z1: %.3f nm' % (1e9 * (z0 - z1).std())) print('Slope error RMS z0-z1: %.3f urad' % (1e6 * numpy.gradient(z0 - z1, y0[1] - y0[0]).std())) print('height error RMS z0-z2: %.3f nm' % (1e9 * (z0 - z2).std())) print('Slope error RMS z0-z2: %.3f urad' % (1e6 * numpy.gradient(z0 - z2, y0[1] - y0[0]).std())) #dump file outFile = "fit.spec" f = open(outFile, 'w') f.write("#F %s\n" % outFile) f.write("\n#S 1 heights profiles\n") f.write("#N 5\n") f.write( "#L coordinate [mm] heights_orig [um] ellipse_guess [um] ellipse_fit [um] heights-fit [nm]\n" ) for i in range(y0.size): f.write("%f %f %f %f %f \n" % (y0[i] * 1e3, z0[i] * 1e6, z1[i] * 1e6, z2[i] * 1e6, (z0[i] - z2[i]) * 1e9)) f.close() if fit_method == 1: # ellipse, slopes fit #preprocessors ellipse fitting slopes if entry_number == 4: pass elif entry_number == 6: pass elif entry_number == 19: pass elif entry_number == 20: pass elif entry_number == 21: pass if fit_function == "amparo": fitfunc_ell_slopes = lambda p, x: func_ellipse_slopes_amparo( x, p[0], p[1], p[2], p[3]) elif fit_function == "dabam": fitfunc_ell_slopes = lambda p, x: func_ellipse_slopes_dabam( x, p[0], p[1], p[2], p[3]) else: print("Not implemented function: ", fit_function) raise NotImplementedError print("======== Fitting slopes =======") errfunc_ell_slopes = lambda p, x, y: fitfunc_ell_slopes(p, x) - y p_guess = [p0, q0, theta0, 0.0] zp1 = fitfunc_ell_slopes(p_guess, y0) if ibounded == 0: print("======== Curve fitting without guess =======") if fit_function == "amparo": popt, cov_x = curve_fit(func_ellipse_slopes_amparo, y0, zp0, maxfev=10000) elif fit_function == "dabam": popt, cov_x = curve_fit(func_ellipse_slopes_dabam, y0, zp0, maxfev=10000) else: print("Not implemented function: ", fit_function) raise NotImplementedError elif ibounded == 1: print("======== Least Squares fitting =======") popt, cov_x, infodic, mesg, ier = leastsq(errfunc_ell_slopes, p_guess, args=(y0, zp0), full_output=True) else: print("======== Bounded Least Squares fitting =======") # https://github.com/jjhelmus/leastsqbound-scipy from leastsqbound import leastsqbound bounds = [(p0 * 0.9, p0 * 1.1), (q0 * 0.9, q0 * 1.1), (theta0 * 0.9, theta0 * 1.1), (-2.0, 2.0)] popt, cov_x, infodic, mesg, ier = leastsqbound(errfunc_ell_slopes, p_guess, args=(y0, zp0), bounds=bounds, full_output=True) print(">>>>> p_guess:", p_guess) print(">>>>> popt (p,q,theta): ", popt) zp2 = fitfunc_ell_slopes(popt, y0) z1 = cdf(y0, zp1) z2 = cdf(y0, zp2) rms_values = (1e9 * (cdf(y0, zp0 - zp1)).std(), 1e9 * (cdf(y0, zp0 - zp2)).std(), 1e6 * (zp0 - zp1).std(), 1e6 * (zp0 - zp2).std()) print('Height error RMS z0-z1: %.3f nm' % (1e9 * (cdf(y0, zp0 - zp1)).std())) print('Slope error RMS zp0-zp1: %.3f urad' % (1e6 * (zp0 - zp1).std())) print('Height error RMS z0-z2: %.3f nm' % (1e9 * (cdf(y0, zp0 - zp2)).std())) print('Slope error RMS zp0-zp2: %.3f urad' % (1e6 * (zp0 - zp2).std())) #dump file outFile = "fit.spec" f = open(outFile, 'w') f.write("#F %s\n" % outFile) f.write("\n#S 1 slopes profiles\n") f.write("#N 5\n") f.write( "#L coordinate [mm] slopes_orig [urad] ellipse_guess [urad] ellipse_fit [urad] slopes-fit [nrad]\n" ) for i in range(y0.size): f.write("%f %f %f %f %f \n" % (y0[i] * 1e3, zp0[i] * 1e6, zp1[i] * 1e6, zp2[i] * 1e6, (zp0[i] - zp2[i]) * 1e9)) f.close() print(">>>>> popt (p,q,theta): ", popt) rms_values = (1e9 * (z0 - z1).std(), 1e9 * (z0 - z2).std(), 1e6 * numpy.gradient(z0 - z1, y0[1] - y0[0]).std(), 1e6 * numpy.gradient(z0 - z2, y0[1] - y0[0]).std()) if ibounded != 0: print('Height error RMS z0-z1: %.3f nm' % (1e9 * (z0 - z1).std())) print('height error RMS z0-z2: %.3f nm' % (1e9 * (z0 - z2).std())) dd = numpy.concatenate((y0, z2), axis=0).reshape(2, -1).transpose() outFile = "tmp_z2.dat" numpy.savetxt(outFile, dd) print("File " + outFile + " written to disk:\n") # #plots # if do_plots: # #plots # from matplotlib import pylab as plt if (fit_method == 0): #heights f1 = plt.figure(1) ax = plt.gca() ax.get_xaxis().get_major_formatter().set_useOffset(False) ax.get_yaxis().get_major_formatter().set_useOffset(False) plt.plot(y0 * 1e3, z0 * 1e6) plt.plot(y0 * 1e3, z1 * 1e6) plt.plot(y0 * 1e3, z2 * 1e6) plt.title( "height data (blue), starting (green) and optimized (red) ellipse" ) plt.xlabel("Y [mm]") plt.ylabel("Zp [um]") f2 = plt.figure(2) ax = plt.gca() ax.get_xaxis().get_major_formatter().set_useOffset(False) ax.get_yaxis().get_major_formatter().set_useOffset(False) plt.plot(y0 * 1e3, (z0 - z2) * 1e9) plt.title("residual heights") plt.xlabel("Y [mm]") plt.ylabel("Z [nm]") elif fit_method == 1: #slopes f1 = plt.figure(1) ax = plt.gca() ax.get_xaxis().get_major_formatter().set_useOffset(False) ax.get_yaxis().get_major_formatter().set_useOffset(False) plt.plot(y0 * 1e3, zp0 * 1e6) if ibounded != 0: plt.plot(y0 * 1e3, zp1 * 1e6) plt.plot(y0 * 1e3, zp2 * 1e6) plt.title( "slopes data (blue), starting (green) and optimized (red) ellipse" ) plt.xlabel("Y [mm]") plt.ylabel("Zp [urad]") f2 = plt.figure(2) ax = plt.gca() ax.get_xaxis().get_major_formatter().set_useOffset(False) ax.get_yaxis().get_major_formatter().set_useOffset(False) plt.plot(y0 * 1e3, (zp0 - zp2) * 1e6) plt.title("residual slopes") plt.xlabel("Y [mm]") plt.ylabel("Zp [urad]") plt.show() return rms_values
def LevMar(func, par, func_args, y, err=None, fixed=None, bounds=None, return_BIC=False, return_AIC=False, verbose=True, fix_noise=False): #,maxiter=10000, maxfun=10000, verbose=True): """ Function wrapper for Levenberg-Marquardt via scipy.optimize.least_sq Similar interface to Optimiser.py to allow for fixed parameters. I have included code from https://github.com/jjhelmus/leastsqbound-scipy/ in order to implement the bound case (leastsqbound), else defaults to least_squares Has a similar syntax to Optimiser, but requires the function to be passed rather than the likelihood function (therefore cannot optimise noise parameters, GPs etc). Added leastsqbound (from https://github.com/jjhelmus/leastsqbound-scipy/, Copyright (c) 2012 Jonathan J. Helmus, see file for full license) that uses parameter transformations to enable bound optimisation. This is only enabled for bound optimisation. The error estimates from LM optimisation are useful to seed MCMC, and also can be used to compute an evidence approximation (via BIC, AIC or Laplace optimisation). Care needs to be taken as to the reliability of the uncertainties compared to an MCMC, and this should generally only be used as an approximation. Parameters ---------- func : function to fit par : parameters of function func_args : arguments to function y : measurements err : uncertainties for each measurement, defaults to array of ones fixed : array of fixed parameters bounds : array of boundaries (min,max) pairs for each parameter, array (N_param x 2) - input None where for no lower/upper boundary. bounds = None uses std leastsq return_BIC : return BIC evidence estimate return_AIC : return AIC evidence estimate fix_noise : if True, don't rescale errorbars according to chi2 Returns ------- bf_par : fitted parameter vector err_par : uncertainty estimate for each parameter rescale : rescale value for errors, equivalent to white noise estimate for err = 1 std of the residuals in this case, or if err provided a rescale to get true noise K_fit : covariance matrix of the fitted parameters (should edit to include non-fitted terms?) edits will be needed to use in laplace optimisation of alpha parameters... logE : evidence approximation from Laplace approximation logE_BIC : evidence approximation from BIC (optional) logE_AIC : evidence approximation from AIC (optional) """ #make variable and fixed par arrays if fixed is None: var_par = np.copy(par) fixed_par = None #otherwise construct the parameter vector from var_par and fixed_par_val else: par = np.array(par) fixed = np.array(fixed) #ensure fixed is a np array #assign parameters to normal param vector fixed_par = par[np.where(fixed == True)] var_par = par[np.where(fixed != True)] #set error vector if not provided if err is None: err = np.ones(y.size) else: err = err * np.ones(y.size) #get the bounds for variable parameters if bounds is None: bounds_var = None else: bounds_var = bounds[np.where(fixed != True)] #perform the optimisation: #if bounds is None: R = leastsq(LM_ErrFunc,var_par,(func,func_args,y,err,fixed,fixed_par),full_output=1) if bounds is None: R = least_squares(LM_ErrFunc, var_par, args=(func, func_args, y, err, fixed, fixed_par), method='trf', verbose=0) fitted_par = R.x H = np.dot(R.jac.T, R.jac) #hessian matrix K_fit = np.linalg.inv(H) #covariance matrix nfev = R.nfev else: R = leastsqbound(LM_ErrFunc, var_par, (func, func_args, y, err, fixed, fixed_par), bounds=bounds_var, full_output=1) fitted_par = R[0] K_fit = R[1] nfev = R[2]['nfev'] #reconstruct the full parameter vector and covariance matrix if fixed is None: bf_par = fitted_par return_err = np.sqrt(np.diag(K_fit)) err_par = np.sqrt(np.diag(K_fit)) K = K_fit else: bf_par = np.copy(par) bf_par[np.where(fixed != True)] = fitted_par err_par = np.zeros(par.size) err_par[np.where(fixed != True)] = np.sqrt(np.diag(K_fit)) K = K_fit #rescale errors and covariance rescale = np.std((y - func(bf_par, *func_args)) / err) if not fix_noise: K_fit *= rescale**2 err_par *= rescale #estimate the white noise from the residuals resid = y - func(bf_par, *func_args) wn = np.std(resid) if verbose: print "-" * 80 print "LM fit parameter estimates: (function evals: {})".format(nfev) print " par = mean +- err" for i in range(bf_par.size): print " p[{}] = {:.8f} +- {:.8f}".format(i, bf_par[i], err_par[i]) print "white noise =", wn #calculate the log evidence for the best fit model if fix_noise: logP_max = LogLikelihood_iid(resid, 1., err) else: logP_max = LogLikelihood_iid(resid, 1., err * rescale) D = np.diag(K_fit).size N_obs = y.size logE_BIC = logP_max - D / 2. * np.log(N_obs) logE_AIC = logP_max - D * N_obs / (N_obs - D - 1.) sign, logdetK = np.linalg.slogdet(2 * np.pi * K_fit) # get log determinant logE = logP_max + 0.5 * logdetK #get evidence approximation based on Gaussian assumption if fixed is None or fixed.sum() == 0: Kn = K else: #expand K to the complete covariance matrix - ie even fixed parameters + white noise ind = np.hstack([(fixed == 0).cumsum()[np.where(fixed == 1)], K.diagonal().size]) #get index to insert zeros Kn = np.insert(np.insert(K, ind, 0, axis=0), ind, 0, axis=1) #insert zeros corresponding to fixed pars if verbose: print "Gaussian Evidence approx:" print " log ML =", logP_max print " log E =", logE print " log E (BIC) =", logE_BIC, "(D = {}, N = {})".format(D, N_obs) print " log E (AIC) =", logE_AIC, "(D = {}, N = {})".format(D, N_obs) print "-" * 80 ret_list = [bf_par, err_par, rescale, Kn, logE] if return_BIC: ret_list.append(logE_BIC) if return_AIC: ret_list.append(logE_AIC) return ret_list
def ellipse_fit(entry_number = 21, fit_method=1, fit_function='dabam', ibounded=1,do_plots=1): """ :param entry_number: dabam entry number :param fit_method: fit elliptical heights (0), fit elliptical slopes (1) :param fit_function: 'dabam' , 'amparo', 'xianbo' :param ibounded: 0 curve_fit (no guess), 1=leastsq, 2=bounded :param do_plot: 1 display plots :return: """ # #get profiles # import dabam dm = dabam.dabam() dm.inputs["entryNumber"] = entry_number dm.inputs["setDetrending"] = -1 dm.load() # # # p0 = dm.h["ELLIPSE_DESIGN_P"] q0 = dm.h["ELLIPSE_DESIGN_Q"] theta0 = dm.h["ELLIPSE_DESIGN_THETA"] # y axis is horizonta, z axis is vertical y0 = dm.sy z0 = dm.zprof zp0 = dm.sz if fit_method == 0: # ellipse fitting heights hshift = 0.0 #nm vshift = 0.0 # nm #preprocessors if entry_number == 4: z0 -= z0.min() elif entry_number == 6: imin = z0.argmin() z0 -= z0[imin] y0 -= y0[imin] y0 *= -1.0 elif entry_number == 19: pass elif entry_number == 20: hshift = -15e3 elif entry_number == 21: y0 -= y0[y0.size/2] if fit_function == "amparo": fitfunc_ell_heights = lambda p, x: func_ellipse_heights_amparo(x, p[0], p[1], p[2], p[3], p[4]) print("Using function definition: AMPARO") elif fit_function == "xianbo": fitfunc_ell_heights = lambda p, x: func_ellipse_heights_xianbo(x, p[0], p[1], p[2], p[3], p[4]) print("Using function definition: XIANBO") else: fitfunc_ell_heights = lambda p, x: func_ellipse_heights_dabam(x, p[0], p[1], p[2], p[3], p[4]) print("Using function definition: DABAM") print("======== Fitting heights =======") errfunc_ell_heights = lambda p, x, y: fitfunc_ell_heights(p, x) - y p_guess = [p0,q0,theta0,hshift,vshift] if ibounded == 0: print("======== Curve fitting without guess =======") if fit_function == "amparo": popt, cov_x = curve_fit(func_ellipse_heights_amparo, y0, z0, maxfev=10000) elif fit_function == "xianbo": popt, cov_x = curve_fit(func_ellipse_heights_xianbo, y0, z0, maxfev=10000) else: popt, cov_x = curve_fit(func_ellipse_heights_dabam, y0, z0, maxfev=10000) elif ibounded == 1: print("======== Least Squares fitting =======") popt, cov_x, infodic, mesg, ier = leastsq(errfunc_ell_heights, p_guess,args=(y0, z0), full_output=True) else: print("======== Bounded Least Squares fitting =======") # https://github.com/jjhelmus/leastsqbound-scipy from leastsqbound import leastsqbound bounds = [ (p0*0.998,p0*1.002) , (q0*0.8,q0*1.2), (theta0*0.98,theta0*1.02), (-0.01,0.01), (-0.001,0.001)] popt, cov_x, infodic, mesg, ier = leastsqbound(errfunc_ell_heights, p_guess, args=(y0,z0), full_output=True, bounds=bounds) print(">>>>> p_guess:", p_guess) print(">>>>> popt:", popt) z1 = fitfunc_ell_heights(p_guess, y0) z2 = fitfunc_ell_heights(popt, y0) zp1 = numpy.gradient(z1,y0[1]-y0[0]) zp2 = numpy.gradient(z2,y0[1]-y0[0]) rms_values = ( 1e9*(z0-z1).std(),1e9*(z0-z2).std(), 1e6*numpy.gradient(z0-z1,y0[1]-y0[0]).std(),1e6*numpy.gradient(z0-z2,y0[1]-y0[0]).std()) print ('Height error RMS z0-z1: %.3f nm'%(1e9*(z0-z1).std())) print ('Slope error RMS z0-z1: %.3f urad'%(1e6*numpy.gradient(z0-z1,y0[1]-y0[0]).std())) print ('height error RMS z0-z2: %.3f nm'%(1e9*(z0-z2).std())) print ('Slope error RMS z0-z2: %.3f urad'%(1e6*numpy.gradient(z0-z2,y0[1]-y0[0]).std())) #dump file outFile = "fit.spec" f = open(outFile,'w') f.write("#F %s\n"%outFile) f.write("\n#S 1 heights profiles\n") f.write("#N 5\n") f.write("#L coordinate [mm] heights_orig [um] ellipse_guess [um] ellipse_fit [um] heights-fit [nm]\n") for i in range(y0.size): f.write("%f %f %f %f %f \n"%(y0[i]*1e3,z0[i]*1e6,z1[i]*1e6,z2[i]*1e6,(z0[i]-z2[i])*1e9)) f.close() if fit_method == 1: # ellipse, slopes fit #preprocessors ellipse fitting slopes if entry_number == 4: pass elif entry_number == 6: pass elif entry_number == 19: pass elif entry_number == 20: pass elif entry_number == 21: pass if fit_function == "amparo": fitfunc_ell_slopes = lambda p, x: func_ellipse_slopes_amparo(x, p[0], p[1], p[2], p[3]) elif fit_function == "dabam": fitfunc_ell_slopes = lambda p, x: func_ellipse_slopes_dabam(x, p[0], p[1], p[2], p[3]) else: print("Not implemented function: ",fit_function) raise NotImplementedError print("======== Fitting slopes =======") errfunc_ell_slopes = lambda p, x, y: fitfunc_ell_slopes(p, x) - y p_guess = [p0,q0,theta0,0.0] zp1 = fitfunc_ell_slopes(p_guess, y0) if ibounded == 0: print("======== Curve fitting without guess =======") if fit_function == "amparo": popt, cov_x = curve_fit(func_ellipse_slopes_amparo, y0, zp0, maxfev=10000) elif fit_function == "dabam": popt, cov_x = curve_fit(func_ellipse_slopes_dabam, y0, zp0, maxfev=10000) else: print("Not implemented function: ",fit_function) raise NotImplementedError elif ibounded == 1: print("======== Least Squares fitting =======") popt, cov_x, infodic, mesg, ier = leastsq(errfunc_ell_slopes, p_guess, args=(y0, zp0), full_output=True) else: print("======== Bounded Least Squares fitting =======") # https://github.com/jjhelmus/leastsqbound-scipy from leastsqbound import leastsqbound bounds = [ (p0*0.9,p0*1.1) , (q0*0.9,q0*1.1), (theta0*0.9,theta0*1.1), (-2.0,2.0)] popt, cov_x, infodic, mesg, ier = leastsqbound(errfunc_ell_slopes, p_guess, args=(y0,zp0), bounds=bounds,full_output=True) print(">>>>> p_guess:", p_guess) print(">>>>> popt (p,q,theta): ",popt) zp2 = fitfunc_ell_slopes(popt, y0) z1 = cdf(y0,zp1) z2 = cdf(y0,zp2) rms_values = (1e9*(cdf(y0,zp0-zp1)).std(),1e9*(cdf(y0,zp0-zp2)).std(), 1e6*(zp0-zp1).std(),1e6*(zp0-zp2).std() ) print ('Height error RMS z0-z1: %.3f nm'%(1e9*(cdf(y0,zp0-zp1)).std())) print ('Slope error RMS zp0-zp1: %.3f urad'%(1e6*(zp0-zp1).std())) print ('Height error RMS z0-z2: %.3f nm'%(1e9*(cdf(y0,zp0-zp2)).std())) print ('Slope error RMS zp0-zp2: %.3f urad'%(1e6*(zp0-zp2).std())) #dump file outFile = "fit.spec" f = open(outFile,'w') f.write("#F %s\n"%outFile) f.write("\n#S 1 slopes profiles\n") f.write("#N 5\n") f.write("#L coordinate [mm] slopes_orig [urad] ellipse_guess [urad] ellipse_fit [urad] slopes-fit [nrad]\n") for i in range(y0.size): f.write("%f %f %f %f %f \n"%(y0[i]*1e3,zp0[i]*1e6,zp1[i]*1e6,zp2[i]*1e6,(zp0[i]-zp2[i])*1e9)) f.close() print(">>>>> popt (p,q,theta): ",popt) rms_values = ( 1e9*(z0-z1).std(),1e9*(z0-z2).std(), 1e6*numpy.gradient(z0-z1,y0[1]-y0[0]).std(),1e6*numpy.gradient(z0-z2,y0[1]-y0[0]).std()) if ibounded != 0: print ('Height error RMS z0-z1: %.3f nm'%(1e9*(z0-z1).std())) print ('height error RMS z0-z2: %.3f nm'%(1e9*(z0-z2).std())) dd=numpy.concatenate( (y0, z2) ,axis=0).reshape(2,-1).transpose() outFile = "tmp_z2.dat" numpy.savetxt(outFile,dd) print ("File "+outFile+" written to disk:\n") # #plots # if do_plots: # #plots # from matplotlib import pylab as plt if (fit_method == 0): #heights f1 = plt.figure(1) ax = plt.gca() ax.get_xaxis().get_major_formatter().set_useOffset(False) ax.get_yaxis().get_major_formatter().set_useOffset(False) plt.plot(y0*1e3,z0*1e6) plt.plot(y0*1e3,z1*1e6) plt.plot(y0*1e3,z2*1e6) plt.title("height data (blue), starting (green) and optimized (red) ellipse") plt.xlabel("Y [mm]") plt.ylabel("Zp [um]") f2 = plt.figure(2) ax = plt.gca() ax.get_xaxis().get_major_formatter().set_useOffset(False) ax.get_yaxis().get_major_formatter().set_useOffset(False) plt.plot(y0*1e3,(z0-z2)*1e9) plt.title("residual heights") plt.xlabel("Y [mm]") plt.ylabel("Z [nm]") elif fit_method == 1: #slopes f1 = plt.figure(1) ax = plt.gca() ax.get_xaxis().get_major_formatter().set_useOffset(False) ax.get_yaxis().get_major_formatter().set_useOffset(False) plt.plot(y0*1e3,zp0*1e6) if ibounded != 0: plt.plot(y0*1e3,zp1*1e6) plt.plot(y0*1e3,zp2*1e6) plt.title("slopes data (blue), starting (green) and optimized (red) ellipse") plt.xlabel("Y [mm]") plt.ylabel("Zp [urad]") f2 = plt.figure(2) ax = plt.gca() ax.get_xaxis().get_major_formatter().set_useOffset(False) ax.get_yaxis().get_major_formatter().set_useOffset(False) plt.plot(y0*1e3,(zp0-zp2)*1e6) plt.title("residual slopes") plt.xlabel("Y [mm]") plt.ylabel("Zp [urad]") plt.show() return rms_values
def LevMar(func,par,func_args,y,err=None,fixed=None,bounds=None,return_BIC=False,return_AIC=False,verbose=True):#,maxiter=10000, maxfun=10000, verbose=True): """ Function wrapper for Levenberg-Marquardt via scipy.optimize.least_sq Similar interface to Optimiser.py to allow for fixed parameters. I have included code from https://github.com/jjhelmus/leastsqbound-scipy/ in order to implement the bound case (leastsqbound), else defaults to least_squares Has a similar syntax to Optimiser, but requires the function to be passed rather than the likelihood function (therefore cannot optimise noise parameters, GPs etc). Added leastsqbound (from https://github.com/jjhelmus/leastsqbound-scipy/, Copyright (c) 2012 Jonathan J. Helmus, see file for full license) that uses parameter transformations to enable bound optimisation. This is only enabled for bound optimisation. The error estimates from LM optimisation are useful to seed MCMC, and also can be used to compute an evidence approximation (via BIC, AIC or Laplace optimisation). Care needs to be taken as to the reliability of the uncertainties compared to an MCMC, and this should generally only be used as an approximation. Parameters ---------- func : function to fit par : parameters of function func_args : arguments to function y : measurements err : uncertainties for each measurement, defaults to array of ones fixed : array of fixed parameters bounds : array of boundaries (min,max) pairs for each parameter, array (N_param x 2) - input None where for no lower/upper boundary. bounds = None uses std leastsq return_BIC : return BIC evidence estimate return_AIC : return AIC evidence estimate Returns ------- bf_par : fitted parameter vector err_par : uncertainty estimate for each parameter rescale : rescale value for errors, equivalent to white noise estimate for err = 1 std of the residuals in this case, or if err provided a rescale to get true noise K_fit : covariance matrix of the fitted parameters (should edit to include non-fitted terms?) edits will be needed to use in laplace optimisation of alpha parameters... logE : evidence approximation from Laplace approximation logE_BIC : evidence approximation from BIC (optional) logE_AIC : evidence approximation from AIC (optional) """ #make variable and fixed par arrays if fixed is None: var_par = np.copy(par) fixed_par = None #otherwise construct the parameter vector from var_par and fixed_par_val else: par = np.array(par) fixed = np.array(fixed) #ensure fixed is a np array #assign parameters to normal param vector fixed_par = par[np.where(fixed==True)] var_par = par[np.where(fixed!=True)] #set error vector if not provided if err is None: err = np.ones(y.size) else: err = err * np.ones(y.size) #get the bounds for variable parameters if bounds is None: bounds_var = None else: bounds_var = bounds[np.where(fixed!=True)] #perform the optimisation: #if bounds is None: R = leastsq(LM_ErrFunc,var_par,(func,func_args,y,err,fixed,fixed_par),full_output=1) if bounds is None: R = least_squares(LM_ErrFunc,var_par,args=(func,func_args,y,err,fixed,fixed_par),method='trf',verbose=0) fitted_par = R.x H = np.dot(R.jac.T,R.jac) #hessian matrix K_fit = np.linalg.inv(H) #covariance matrix nfev = R.nfev else: R = leastsqbound(LM_ErrFunc,var_par,(func,func_args,y,err,fixed,fixed_par),bounds=bounds_var,full_output=1) fitted_par = R[0] K_fit = R[1] nfev = R[2]['nfev'] #reconstruct the full parameter vector and covariance matrix if fixed is None: bf_par = fitted_par return_err = np.sqrt(np.diag(K_fit)) err_par = np.sqrt(np.diag(K_fit)) K = K_fit else: bf_par = np.copy(par) bf_par[np.where(fixed!=True)] = fitted_par err_par = np.zeros(par.size) err_par[np.where(fixed!=True)] = np.sqrt(np.diag(K_fit)) K = K_fit #rescale errors and covariance rescale = np.std((y - func(bf_par,*func_args)) / err) K_fit *= rescale**2 err_par *= rescale #estimate the white noise from the residuals resid = y - func(bf_par,*func_args) wn = np.std(resid) if verbose: print "-"*80 print "LM fit parameter estimates: (function evals: {})".format(nfev) print " par = mean +- err" for i in range(bf_par.size): print " p[{}] = {:.8f} +- {:.8f}".format(i,bf_par[i],err_par[i]) print "white noise =", wn #calculate the log evidence for the best fit model logP_max = LogLikelihood_iid(resid,1.,err*rescale) D = np.diag(K_fit).size N_obs = y.size logE_BIC = logP_max - D/2.*np.log(N_obs) logE_AIC = logP_max - D * N_obs / (N_obs-D-1.) sign,logdetK = np.linalg.slogdet( 2*np.pi*K_fit ) # get log determinant logE = logP_max + 0.5 * logdetK #get evidence approximation based on Gaussian assumption if fixed is None or fixed.sum()==0: Kn = K else: #expand K to the complete covariance matrix - ie even fixed parameters + white noise ind = np.hstack([(fixed==0).cumsum()[np.where(fixed==1)],K.diagonal().size]) #get index to insert zeros Kn = np.insert(np.insert(K,ind,0,axis=0),ind,0,axis=1) #insert zeros corresponding to fixed pars if verbose: print "Gaussian Evidence approx:" print " log ML =", logP_max print " log E =", logE print " log E (BIC) =", logE_BIC, "(D = {}, N = {})".format(D,N_obs) print " log E (AIC) =", logE_AIC, "(D = {}, N = {})".format(D,N_obs) print "-"*80 ret_list = [bf_par,err_par,rescale,Kn,logE] if return_BIC: ret_list.append(logE_BIC) if return_AIC: ret_list.append(logE_AIC) return ret_list
def main(): # # y axis is horizontal # z axis is vertical # # #load height profile # input_file = "tmpHeights.dat" a = numpy.loadtxt(input_file) y0 = a[:,0] z0 = a[:,1] z0 -= z0.min() # #load slopes profile # input_file = "tmpSlopes.dat" a = numpy.loadtxt(input_file) yp0 = a[:,0] zp0 = a[:,1] L = y0[-1]-y0[0] print("Mirror data from file: %s :"%input_file) print(" Mirror length is: %.3f m"%L) N = y0.size print(" Mirror contains %d points"%N) slope_error_rms = zp0.std() print(" Mirror slope error RMS is %.3f urad = %.3f arcsec"%(slope_error_rms*1e6,slope_error_rms*180/numpy.pi*3600)) # #aspheric fit # # fit_method = 0 fit aspherical heights, use curve_fit on heights (NOT WORKING) # fit_method = 1 fit aspherical heights, use leastsq on heights (NOT WORKING) # fit_method = 2 fit aspherical heights, use bounded leastsq on heights (NOT WORKING) # fit_method = 3 fit elliptical heights # fit_method = 4 fit elliptical slopes # fit_method = 5 fit elliptical heights using Xianbo method fit_method = 4 if fit_method == 0: # use curve_fit popt, pcov = curve_fit(func_aspheric, y0, z0) print("popt: ",repr(popt)) print("pcov: ",repr(pcov)) z2 = func_aspheric(y0, popt[0], popt[1]) if fit_method == 1: # use lestsq fitfunc = lambda p, x: func_aspheric(x, p[0], p[1]) #z2 = fitfunc([radius*1.2,0.0],y0) errfunc = lambda p, x, y: fitfunc(p, x) - y #z2 = errfunc([radius*1.2,0.0],y0,z0) #print(errfunc([radius,0.0],y0,z0)) p0 = [radius, 0.0] # initial guess #popt, success = leastsq(errfunc, p0[:], args=(y0, z0)) #print("popt: ",repr(popt)) #print("success: ",repr(success)) popt, cov_x, infodic, mesg, ier = leastsq(errfunc, p0, args=(y0, z0), full_output=True) print("Standard Least Squares fitting results:") print("p0:", p0) print("cov_x:", cov_x) print("infodic['nfev']:", infodic['nfev']) print("infodic['fvec']:", infodic['fvec']) print("infodic['fjac']:", infodic['fjac']) print("infodic['ipvt']:", infodic['ipvt']) print("infodic['qtf']:", infodic['qtf']) print("mesg:", mesg) print("ier:", ier) print(">>>>> popt: ",repr(popt)) print("") z2 = func_aspheric(y0, popt[0], popt[1]) if fit_method == 2: # use lestsq fitfunc = lambda p, x: func_aspheric(x, p[0], p[1]) #z2 = fitfunc([radius*1.2,0.0],y0) errfunc = lambda p, x, y: fitfunc(p, x) - y #z2 = errfunc([radius*1.2,0.0],y0,z0) #print(errfunc([radius,0.0],y0,z0)) p0 = [radius, -0.9999999999] # initial guess # https://github.com/jjhelmus/leastsqbound-scipy from leastsqbound import leastsqbound bounds = [(radius*0.5, radius*1.5), (-1.0, -0.9)] popt, cov_x, infodic, mesg, ier = leastsqbound(errfunc, p0, args=(y0,z0), bounds=bounds,full_output=True) # print out results print("Bounded Least Squares fitting with no bounds results:") print("p0:", p0) print("cov_x:", cov_x) print("infodic['nfev']:", infodic['nfev']) print("infodic['fvec']:", infodic['fvec']) print("infodic['fjac']:", infodic['fjac']) print("infodic['ipvt']:", infodic['ipvt']) print("infodic['qtf']:", infodic['qtf']) print("mesg:", mesg) print("ier:", ier) print(">>>>> popt: ",repr(popt)) print("") z2 = func_aspheric(y0, popt[0], popt[1]) #z2 = func_aspheric(y0, popt[0], -0.99999996025050053) if fit_method == 3: # ellipse fitting heights ibounded = 0 #=0 curve_fit (no guess), 1=leastsq, 2=bounded print("======== Fitting heights =======") if ibounded == 0: print("======== Curve fitting without guess =======") popt, cov_x = curve_fit(func_ellipse, y0, z0, maxfev=10000) else: #dabam-4 (Amparo) # p0 = 98.00 # q0 = 0.0775 # theta0 = 3.9e-3 # # # #dabam-6 (Soleil) p=499.14 mm q= 4500 mm teta = 34.99 mrad p0 = 499.14e-3 q0 = 4500e-3 theta0 = 34.99e-3 # # # #dabam-19 #design parameter of ellipse: entrance arm: 420000mm; exit arm: 900mm; angle of incidence 3.052mrad # p0 = 420.0 # q0 = 0.9 # theta0 = 3.052e-3 # # # #dabam-20 #design parameter of ellipse: entrance arm 9000mm; exit arm: 350mm; angle of incidence: 2.5deg # p0 = 9.0 # q0 = 0.35 # theta0 = 2.5*numpy.pi/180 # #TODO: # zp0 = -zp0 # # # #dabam-21 #design parameter of ellipse: entrance arm: 7500mm; exit arm: 2500mm; angle of incidence 0.6deg # p0 = 7.5 # q0 = 2.5 # theta0 = 0.6*numpy.pi/180 p_guess = [p0,q0,theta0] z1 = func_ellipse_amparo(yp0, p_guess[0], p_guess[1], p_guess[2]) # ishift = 0 # if ishift: # print(">>>>>>>> slope zp0[0], zp1[0], diff: ",zp0[0],zp1[1],zp0[0]-zp1[1]) # print(">>>>>>>>>>>>>>>>>>> shift value: ",(zp0-zp1)[1]) # p_guess[3] = (zp0-zp1)[1] # zp1 = func_ellipse(yp0, p_guess[0], p_guess[1], p_guess[2], p_guess[3]) print("p0,q0,theta: ",p0,q0,theta0) fitfunc_ell_heights = lambda p, x: func_ellipse_amparo(x, p[0], p[1], p[2]) errfunc_ell_heights = lambda p, x, y: fitfunc_ell_heights(p, x) - y if ibounded == 1: print("======== Least Squares fitting =======") popt, cov_x, infodic, mesg, ier = leastsq(errfunc_ell_heights, p_guess, args=(y0, z0), full_output=True) else: print("======== Bounded Least Squares fitting =======") # https://github.com/jjhelmus/leastsqbound-scipy from leastsqbound import leastsqbound bounds = [ (p0*0.998,p0*1.002) , (q0*0.8,q0*1.2), (theta0*0.98,theta0*1.02)] popt, cov_x, infodic, mesg, ier = leastsqbound(errfunc_ell_heights, p_guess, args=(y0,z0), bounds=bounds,full_output=True) print("cov_x:", cov_x) # print("infodic['nfev']:", infodic['nfev']) # print("infodic['fvec']:", infodic['fvec']) # print("infodic['fjac']:", infodic['fjac']) # print("infodic['ipvt']:", infodic['ipvt']) # print("infodic['qtf']:", infodic['qtf']) # print("mesg:", mesg) # print("ier:", ier) print(">>>>> p_guess:", p_guess) #zp1 = func_ellipse_slopes(yp0, p_guess[0], p_guess[1], p_guess[2], 0.0 ) #p_guess[3]) #TODO!! dd=numpy.concatenate( (y0, z1) ,axis=0).reshape(2,-1).transpose() outFile = "tmp_z1.dat" numpy.savetxt(outFile,dd) print ("File "+outFile+" written to disk:\n") print(">>>>> popt (p,q,theta): ",popt) z2 = func_ellipse(y0, popt[0], popt[1], popt[2]) #amparo z2 = func_ellipse(y0, 98.0, 81.826e-3, 3.865*1e-3) if ibounded != 0: print ('Height error RMS z0-z1: %.3f nm'%(1e9*(z0-z1).std())) print ('height error RMS z0-z2: %.3f nm'%(1e9*(z0-z2).std())) dd=numpy.concatenate( (y0, z2) ,axis=0).reshape(2,-1).transpose() outFile = "tmp_z2.dat" numpy.savetxt(outFile,dd) print ("File "+outFile+" written to disk:\n") if fit_method == 4: # ellipse, slopes fit ibounded = 1 #=0 curve_fit (no guess), 1=leastsq, 2=bounded print("======== Fitting slopes =======") if ibounded == 0: print("======== Curve fitting without guess =======") popt, cov_x = curve_fit(func_ellipse_slopes, yp0, zp0, maxfev=10000) else: ishift = 0 #dabam-4 (Amparo) p0 = 98.00 q0 = 0.0775 theta0 = 3.9e-3 # # # # # #dabam-6 (Soleil) p=499.14 mm q= 4500 mm teta = 34.99 mrad # p0 = 499.14e-3 # q0 = 4500e-3 # theta0 = 34.99e-3 # ishift = 1 # # # # # # # # #dabam-19 #design parameter of ellipse: entrance arm: 420000mm; exit arm: 900mm; angle of incidence 3.052mrad # p0 = 420.0 #WRONG INPUTS? # q0 = 0.9 #WRONG INPUTS? # theta0 = 3.052e-3 #WRONG INPUTS? # # yp0 = yp0 - yp0[int(yp0.size/2)] # # # # #dabam-20 #design parameter of ellipse: entrance arm 9000mm; exit arm: 350mm; angle of incidence: 2.5deg # p0 = 9.0 # q0 = 0.35 # theta0 = 2.5*numpy.pi/180 # #TODO: # yp0 = yp0 - yp0[int(yp0.size/2)] # zp0 = -zp0 # # # # #dabam-21 #design parameter of ellipse: entrance arm: 7500mm; exit arm: 2500mm; angle of incidence 0.6deg # p0 = 7.5 # q0 = 2.5 # theta0 = 0.6*numpy.pi/180 # ishift = 1 p_guess = [p0,q0,theta0] zp1 = func_ellipse_slopes(yp0, p_guess[0], p_guess[1], p_guess[2]) if ishift: zp0 = zp0 + (zp1[0]-zp0[0]) print("p0,q0,theta: ",p0,q0,theta0) fitfunc_ell_slopes = lambda p, x: func_ellipse_slopes(x, p[0], p[1], p[2]) errfunc_ell_slopes = lambda p, x, y: fitfunc_ell_slopes(p, x) - y if ibounded == 1: print("======== Least Squares fitting =======") popt, cov_x, infodic, mesg, ier = leastsq(errfunc_ell_slopes, p_guess, args=(yp0, zp0), full_output=True) elif ibounded == 2: print("======== Bounded Least Squares fitting =======") # https://github.com/jjhelmus/leastsqbound-scipy from leastsqbound import leastsqbound bounds = [ (p0*0.998,p0*1.002) , (q0*0.8,q0*1.2), (theta0*0.98,theta0*1.02)] popt, cov_x, infodic, mesg, ier = leastsqbound(errfunc_ell_slopes, p_guess, args=(yp0,zp0), bounds=bounds,full_output=True) print("cov_x:", cov_x) # print("infodic['nfev']:", infodic['nfev']) # print("infodic['fvec']:", infodic['fvec']) # print("infodic['fjac']:", infodic['fjac']) # print("infodic['ipvt']:", infodic['ipvt']) # print("infodic['qtf']:", infodic['qtf']) # print("mesg:", mesg) # print("ier:", ier) print(">>>>> p_guess:", p_guess) #zp1 = func_ellipse_slopes(yp0, p_guess[0], p_guess[1], p_guess[2]) dd=numpy.concatenate( (yp0, zp1) ,axis=0).reshape(2,-1).transpose() outFile = "tmp_zp1.dat" numpy.savetxt(outFile,dd) print ("File "+outFile+" written to disk:\n") print(">>>>> popt (p,q,theta): ",popt) zp2 = func_ellipse_slopes(yp0, popt[0], popt[1], popt[2]) #amparo zp2 = func_ellipse_slopes(yp, 98.0, 82.0424e-3, 3.8754e-3, 0.0) if ibounded != 0: print ('Slope error RMS zp0-zp1: %.3f urad'%(1e6*(zp0-zp1).std())) print ('Slope error RMS zp0-zp2: %.3f urad'%(1e6*(zp0-zp2).std())) dd=numpy.concatenate( (yp0, zp2) ,axis=0).reshape(2,-1).transpose() outFile = "tmp_zp2.dat" numpy.savetxt(outFile,dd) print ("File "+outFile+" written to disk:\n") if fit_method == 5: # ellipse fitting heights using Xianbo method ibounded = 2 #=0 curve_fit (no guess), 1=leastsq, 2=bounded print("======== Fitting heights =======") if ibounded == 0: print("======== Curve fitting without guess =======") popt, cov_x = curve_fit(func_ellipse_xianbo, y0, z0, maxfev=10000) else: #dabam-4 (Amparo) # p0 = 98.00 # q0 = 0.0775 # theta0 = 3.9e-3 # OFFSET = 0.0 # XC = 0.0 # # # #dabam-6 (Soleil) p=499.14 mm q= 4500 mm teta = 34.99 mrad # p0 = 499.14e-3 # q0 = 4500e-3 # theta0 = 34.99e-3 # OFFSET = 0.0 # XC = 0.0 # # # #dabam-19 #design parameter of ellipse: entrance arm: 420000mm; exit arm: 900mm; angle of incidence 3.052mrad # p0 = 420.0 # q0 = 0.9 # theta0 = 3.052e-3 # OFFSET = 0.0 # XC = 0.0 # # # #dabam-20 #design parameter of ellipse: entrance arm 9000mm; exit arm: 350mm; angle of incidence: 2.5deg p0 = 9.0 q0 = 0.35 theta0 = 2.5*numpy.pi/180 OFFSET = 0.0 XC = 75e-3 # #TODO: # zp0 = -zp0 # # # #dabam-21 #design parameter of ellipse: entrance arm: 7500mm; exit arm: 2500mm; angle of incidence 0.6deg # p0 = 7.5 # q0 = 2.5 # theta0 = 0.6*numpy.pi/180 # OFFSET = 0.0 # XC = 0.0 p_guess = [p0,q0,theta0, OFFSET, XC] z1 = func_ellipse_xianbo(yp0, p_guess[0], p_guess[1], p_guess[2], p_guess[3], p_guess[4]) # ishift = 0 # if ishift: # print(">>>>>>>> slope zp0[0], zp1[0], diff: ",zp0[0],zp1[1],zp0[0]-zp1[1]) # print(">>>>>>>>>>>>>>>>>>> shift value: ",(zp0-zp1)[1]) # p_guess[3] = (zp0-zp1)[1] # zp1 = func_ellipse(yp0, p_guess[0], p_guess[1], p_guess[2], p_guess[3]) print("p0,q0,theta,OFFSET,XC: ",p0,q0,theta0,OFFSET,XC) fitfunc_ell_heights = lambda p, x: func_ellipse_xianbo(x, p[0], p[1], p[2], p[3], p[4]) errfunc_ell_heights = lambda p, x, y: fitfunc_ell_heights(p, x) - y if ibounded == 1: print("======== Least Squares fitting =======") popt, cov_x, infodic, mesg, ier = leastsq(errfunc_ell_heights, p_guess, args=(y0, z0), full_output=True) else: print("======== Bounded Least Squares fitting =======") # https://github.com/jjhelmus/leastsqbound-scipy from leastsqbound import leastsqbound bounds = [ (p0*0.998,p0*1.002) , (q0*0.8,q0*1.2), (theta0*0.98,theta0*1.02), (OFFSET*0.9,OFFSET*1.2), (XC*0.9,XC*1.2)] popt, cov_x, infodic, mesg, ier = leastsqbound(errfunc_ell_heights, p_guess, args=(y0,z0), bounds=bounds,full_output=True) print("cov_x:", cov_x) # print("infodic['nfev']:", infodic['nfev']) # print("infodic['fvec']:", infodic['fvec']) # print("infodic['fjac']:", infodic['fjac']) # print("infodic['ipvt']:", infodic['ipvt']) # print("infodic['qtf']:", infodic['qtf']) # print("mesg:", mesg) # print("ier:", ier) print(">>>>> p_guess:", p_guess) #zp1 = func_ellipse_slopes(yp0, p_guess[0], p_guess[1], p_guess[2], 0.0 ) #p_guess[3]) #TODO!! dd=numpy.concatenate( (y0, z1) ,axis=0).reshape(2,-1).transpose() outFile = "tmp_z1.dat" numpy.savetxt(outFile,dd) print ("File "+outFile+" written to disk:\n") print(">>>>> popt (p,q,theta): ",popt) z2 = func_ellipse_xianbo(y0, popt[0], popt[1], popt[2], popt[3], popt[4]) #amparo z2 = func_ellipse(y0, 98.0, 81.826e-3, 3.865*1e-3) if ibounded != 0: print ('Height error RMS z0-z1: %.3f nm'%(1e9*(z0-z1).std())) print ('height error RMS z0-z2: %.3f nm'%(1e9*(z0-z2).std())) dd=numpy.concatenate( (y0, z2) ,axis=0).reshape(2,-1).transpose() outFile = "tmp_z2.dat" numpy.savetxt(outFile,dd) print ("File "+outFile+" written to disk:\n") # #plots # do_plots = 1 if do_plots: # #plots # from matplotlib import pylab as plt if fit_method == 4: #slopes f1 = plt.figure(1) ax = plt.gca() ax.get_xaxis().get_major_formatter().set_useOffset(False) ax.get_yaxis().get_major_formatter().set_useOffset(False) plt.plot(yp0*1e3,zp0*1e6) if ibounded != 0: plt.plot(yp0*1e3,zp1*1e6) plt.plot(yp0*1e3,zp2*1e6) plt.title("slopes data (blue), starting (green) and optimized (red) ellipse") plt.xlabel("Y [mm]") plt.ylabel("Zp [urad]") f2 = plt.figure(2) ax = plt.gca() ax.get_xaxis().get_major_formatter().set_useOffset(False) ax.get_yaxis().get_major_formatter().set_useOffset(False) plt.plot(yp0*1e3,(zp0-zp2)*1e6) plt.title("residual slopes") plt.xlabel("Y [mm]") plt.ylabel("Zp [urad]") elif (fit_method == 3 or fit_method == 5): #heights f1 = plt.figure(1) ax = plt.gca() ax.get_xaxis().get_major_formatter().set_useOffset(False) ax.get_yaxis().get_major_formatter().set_useOffset(False) plt.plot(y0*1e3,z0*1e6) if ibounded != 0: plt.plot(y0*1e3,z1*1e6) plt.plot(y0*1e3,z2*1e6) plt.title("height data (blue), starting (green) and optimized (red) ellipse") plt.xlabel("Y [mm]") plt.ylabel("Zp [um]") f2 = plt.figure(2) ax = plt.gca() ax.get_xaxis().get_major_formatter().set_useOffset(False) ax.get_yaxis().get_major_formatter().set_useOffset(False) plt.plot(y0*1e3,(z0-z2)*1e9) plt.title("residual heights") plt.xlabel("Y [mm]") plt.ylabel("Z [nm]") plt.show()