def multifit(x=None, y=None, epsil=None, wid=None, ang=0, mix=None, opti='lbf', yerr=None, smooth=None, dierep=0, ifit=None, nfit_lays=0, lims=None): '''fitting thickness of multiple layers / mixing ratios in dierep: fitting complete dielectric function uses tabulated values of dielec. function (given in epsil) additional parameters to fit can produce polynomial shift of diel. fun (layer adjusted is specified by global "mod_layer" parameter) ADDed: smoothing option to reduce sensitivity to fast variations floating_norm global parameter (in the case of smoothing) global setting non_uniform: accounts for spread of widths over illuminated area (large diaphragm) ''' global idix, fit #if ang>0: print 'incidence at %.1f deg '%ang if opti == 'tnc': from scipy.optimize import tnc as optimod mizer = optimod.fmin_tnc else: from scipy.optimize import lbfgsb as optimod mizer = optimod.fmin_l_bfgs_b from numpy import array, all, conj, sqrt, ones if wid[0] == 0: #no assumptions about initial parameters from spectra import fitting out = fitting(x, y) wid[0] = per_conv[0] / ( (out[0][3] - per_conv[1]) * sqrt(epsil[0].real.mean())) #wid[0]=per_conv/(out[3]*sqrt(epsil[0].real.mean())) print('estimated principal layer width %f' % wid[0]) if yerr != None and all(yerr.real > 0): weight = 1 / yerr.real if all(yerr.imag > 0): weight += 1j / yerr.imag if ifit == None: #no fit functions entered r, sh, psi = plate(x, epsil, wid, ang=ang, rep=-1) from numpy import convolve, polyfit, polyval if smooth != None: y = convolve(y, smooth)[len(smooth):-len(smooth)] print('data shape %i' % y.shape) def fit(spars, rep=0): global idix #print spars slate = convolve( abs( friter([t.copy() for t in r], [sh[i] * spars[i] for i in range(len(sh))], psi))**2, smooth)[len(smooth):-len(smooth)] #slate=convolve(plate(x,epsil,list(spars),meth=0,ang=ang,rep=dierep),smooth)[len(smooth):-len(smooth)] if floating_norm > 0: idix = polyfit(slate, y, floating_norm) dif = y - polyval(idix, slate) else: dif = y - slate if yerr != None: dif *= weight if rep == 1: return dif return sum((dif * conj(dif)).real) else: def fit(spars, rep=0): global idix #print spars rlays = [t.copy() for t in r] shlays = [ sh[i] * spars[i] for i in range(min(len(sh), len(spars))) ] if len(spars) < len(sh): shlays.extend(sh[len(spars):]) elif len(spars) > len(sh): prof = polyval(spars[:len(sh) - 1:-1], x) rlays[mod_layer] *= prof shlays[mod_layer] *= prof if non_uniform: dif = y - wid_spread( rlays, shlays, psi, [1 - abs(non_uniform), 1 + abs(non_uniform)], wind=non_uniform_layer, ang=ang, rep=-2) if floating_norm >= 0: slate = abs(friter(rlays, shlays, psi))**2 if floating_norm == 0: from extra import rob_polyfit a, c = rob_polyfit(slate, y, wei=-1) if c > 0.6: # minimal correlation to do renormalization idix = rob_polyfit(slate, y, wei=2) dif = y - polyval(idix, slate) else: dif = y - slate else: idix = polyfit(slate, y, floating_norm) dif = y - polyval(idix, slate) else: dif = y - abs(friter(rlays, shlays, psi))**2 #dif=y-plate(x,epsil,list(spars),meth=0,ang=ang,rep=dierep) if yerr != None: dif *= weight if rep == 1: return dif return sum((dif * conj(dif)).real) if dierep == -2: return fit else: fit = ifit if nfit_lays == 0: nfit_lays = len(wid) if lims: out = mizer(fit, ones(nfit_lays), None, args=(), approx_grad=True, bounds=array(lims)) else: out = mizer(fit, ones(nfit_lays), None, args=(), approx_grad=True) return out, wid
def multifit(x=None,y=None,epsil=None,wid=None,ang=0,mix=None,opti='lbf',yerr=None,smooth=None,dierep=0,ifit=None,nfit_lays=0,lims=None): '''fitting thickness of multiple layers / mixing ratios in dierep: fitting complete dielectric function uses tabulated values of dielec. function (given in epsil) additional parameters to fit can produce polynomial shift of diel. fun (layer adjusted is specified by global "mod_layer" parameter) ADDed: smoothing option to reduce sensitivity to fast variations floating_norm global parameter (in the case of smoothing) global setting non_uniform: accounts for spread of widths over illuminated area (large diaphragm) ''' global idix,fit #if ang>0: print 'incidence at %.1f deg '%ang if opti=='tnc': from scipy.optimize import tnc as optimod mizer=optimod.fmin_tnc else: from scipy.optimize import lbfgsb as optimod mizer=optimod.fmin_l_bfgs_b from numpy import array,all,conj,sqrt,ones if wid[0]==0: #no assumptions about initial parameters from spectra import fitting out=fitting(x,y) wid[0]=per_conv[0]/((out[0][3]-per_conv[1])*sqrt(epsil[0].real.mean())) #wid[0]=per_conv/(out[3]*sqrt(epsil[0].real.mean())) print('estimated principal layer width %f'%wid[0]) if yerr!=None and all(yerr.real>0): weight=1/yerr.real if all(yerr.imag>0): weight+=1j/yerr.imag if ifit==None: #no fit functions entered r,sh,psi=plate(x,epsil,wid,ang=ang,rep=-1) from numpy import convolve,polyfit,polyval if smooth!=None: y=convolve(y,smooth)[len(smooth):-len(smooth)] print('data shape %i'%y.shape) def fit(spars,rep=0): global idix #print spars slate=convolve(abs(friter([t.copy() for t in r],[sh[i]*spars[i] for i in range(len(sh))],psi))**2,smooth)[len(smooth):-len(smooth)] #slate=convolve(plate(x,epsil,list(spars),meth=0,ang=ang,rep=dierep),smooth)[len(smooth):-len(smooth)] if floating_norm>0: idix=polyfit(slate,y,floating_norm) dif=y-polyval(idix,slate) else: dif=y-slate if yerr!=None: dif*=weight if rep==1: return dif return sum((dif*conj(dif)).real) else: def fit(spars,rep=0): global idix #print spars rlays=[t.copy() for t in r] shlays=[sh[i]*spars[i] for i in range(min(len(sh),len(spars)))] if len(spars)<len(sh): shlays.extend(sh[len(spars):]) elif len(spars)>len(sh): prof=polyval(spars[:len(sh)-1:-1],x) rlays[mod_layer]*=prof shlays[mod_layer]*=prof if non_uniform: dif=y-wid_spread(rlays,shlays,psi,[1-abs(non_uniform),1+abs(non_uniform)],wind=non_uniform_layer,ang=ang,rep=-2) if floating_norm>=0: slate=abs(friter(rlays,shlays,psi))**2 if floating_norm==0: from extra import rob_polyfit a,c=rob_polyfit(slate,y,wei=-1) if c>0.6: # minimal correlation to do renormalization idix=rob_polyfit(slate,y,wei=2) dif=y-polyval(idix,slate) else: dif=y-slate else: idix=polyfit(slate,y,floating_norm) dif=y-polyval(idix,slate) else: dif=y-abs(friter(rlays,shlays,psi))**2 #dif=y-plate(x,epsil,list(spars),meth=0,ang=ang,rep=dierep) if yerr!=None: dif*=weight if rep==1: return dif return sum((dif*conj(dif)).real) if dierep==-2: return fit else: fit=ifit if nfit_lays==0:nfit_lays=len(wid) if lims: out=mizer(fit,ones(nfit_lays),None,args=(),approx_grad=True,bounds=array(lims)) else: out=mizer(fit,ones(nfit_lays),None,args=(),approx_grad=True) return out,wid
def dofit(x, y, pars, lims=[[1e-2, 1e6], [1, 4000.], [0.001, 100.]], yerr=None, einf=1., drude=None, rep=1, opti='lbf', fix=None, args=()): '''fitting reflectivity/transmissivity with N-resonator model pars is a 2-d array (ampl,freq,absorb) errors not yet implemented fitting method either TNC, light BFGS or Cobyla ('tnc/lbf/cob') ''' global gang, fit extrapars = {} if opti == 'tnc': from scipy.optimize import tnc as optimod mizer = optimod.fmin_tnc extrapars = {'messages': 0} else: from scipy.optimize import lbfgsb as optimod mizer = optimod.fmin_l_bfgs_b from numpy import array if fit == None: #no fit functions entered dierep = -1 if len(y.shape) == 2 and y.shape[1] == 2: y = y[:, 0] + 1j * y[:, 1] if yerr != None: weight = 1 / yerr[:, 0] + 1j / yerr[:, 1] print("fitting complex numbers: ellipsometry") #dierep= elif str(y.dtype)[:7] == 'complex': dierep = 0 # calculating in complex plane if yerr != None: weight = 1 / yerr.real + 1j / yerr.imag print("fitting complex numbers") else: if yerr != None: weight = 1 / yerr if drude != None: def fit(spars): ospars = array(spars[3:]).reshape((len(spars) - 3) // 3, 3) #oscilator parameters dif = y.copy() if dierep == 0: dif -= dielect(x, spars[0], ospars, drude=spars[1:3]) else: dif -= rdielect(x, spars[0], ospars, drude=spars[1:3], ang=gang) if yerr != None: dif *= weight return sum(abs(dif)**2) #dif*conj(dif)) else: def fit(spars): ospars = array(spars[1:]).reshape((len(spars) - 1) // 3, 3) dif = y.copy() if dierep == 0: dif -= dielect(x, spars[0], ospars) else: dif -= rdielect(x, spars[0], ospars, ang=gang) if yerr != None: dif *= weight return sum(abs(dif)**2) #sum(dif*conj(dif)) if rep == -3: return fit #def fit(spars,args): # return sum((args[1]-dielect(args[0],spars[0],array(spars[1:]).reshape((len(spars)-1)//3,3)))**2) if type(pars) == list: pars = array(pars) if len(pars.shape) == 2: pars = pars.reshape(pars.shape + (1, )) if einf == None: ipars = [1.] else: ipars = type(einf) == list and einf[:1] or [einf] if drude != None: ipars += list(drude) ipars += list(pars[:, :, 0].flat) if rep == -2: return ipars if lims != None: if len(lims) == len(ipars): blims = lims else: blims = [elims] if drude != None: blims += [[0.1, 100], [0.1, 100.]] if len(lims) == len(ipars) - 1: blims += lims elif len(lims) == 3: print('setting limits') for i in range(len(pars)): for j in range(3): if lims[j][0] < 0: blims.append([pars[i, j, 0] + a for a in lims[j]]) else: blims.append(lims[j]) #if type(lims[0]==list) if rep == -1: return blims blims = array(blims) else: blims = None if opti == 'cob': from scipy.optimize import fmin_cobyla as mizer par_con = [ lambda p: (p[i] - blims[i][0]) * (blims[i][1] - p[i]) for i in range(len(blims)) ] out = mizer(fit, array(ipars), par_con, args=args) else: out = mizer(fit, array(ipars), None, args=args, approx_grad=True, bounds=blims, **extrapars) return out
def dofit(x,y,pars,lims=[[1e-2,1e6],[1,4000.],[0.001,100.]],yerr=None,einf=1.,drude=None,rep=1,opti='lbf',fix=None,args=()): '''fitting reflectivity/transmissivity with N-resonator model pars is a 2-d array (ampl,freq,absorb) errors not yet implemented fitting method either TNC, light BFGS or Cobyla ('tnc/lbf/cob') ''' global gang,fit extrapars={} if opti=='tnc': from scipy.optimize import tnc as optimod mizer=optimod.fmin_tnc extrapars={'messages':0} else: from scipy.optimize import lbfgsb as optimod mizer=optimod.fmin_l_bfgs_b from numpy import array if fit==None: #no fit functions entered dierep=-1 if len(y.shape)==2 and y.shape[1]==2: y=y[:,0]+1j*y[:,1] if yerr!=None: weight=1/yerr[:,0]+1j/yerr[:,1] print("fitting complex numbers: ellipsometry") #dierep= elif str(y.dtype)[:7]=='complex': dierep=0 # calculating in complex plane if yerr!=None: weight=1/yerr.real+1j/yerr.imag print("fitting complex numbers") else: if yerr!=None: weight=1/yerr if drude!=None: def fit(spars): ospars=array(spars[3:]).reshape((len(spars)-3)//3,3) #oscilator parameters dif=y.copy() if dierep==0: dif-=dielect(x,spars[0],ospars,drude=spars[1:3]) else: dif-=rdielect(x,spars[0],ospars,drude=spars[1:3],ang=gang) if yerr!=None: dif*=weight return sum(abs(dif)**2)#dif*conj(dif)) else: def fit(spars): ospars=array(spars[1:]).reshape((len(spars)-1)//3,3) dif=y.copy() if dierep==0: dif-=dielect(x,spars[0],ospars) else: dif-=rdielect(x,spars[0],ospars,ang=gang) if yerr!=None: dif*=weight return sum(abs(dif)**2)#sum(dif*conj(dif)) if rep==-3: return fit #def fit(spars,args): # return sum((args[1]-dielect(args[0],spars[0],array(spars[1:]).reshape((len(spars)-1)//3,3)))**2) if type(pars)==list: pars=array(pars) if len(pars.shape)==2: pars=pars.reshape(pars.shape+(1,)) if einf==None: ipars=[1.] else: ipars=type(einf)==list and einf[:1] or [einf] if drude!=None: ipars+=list(drude) ipars+=list(pars[:,:,0].flat) if rep==-2: return ipars if lims!=None: if len(lims)==len(ipars): blims=lims else: blims=[elims] if drude!=None: blims+=[[0.1,100],[0.1,100.]] if len(lims)==len(ipars)-1: blims+=lims elif len(lims)==3: print('setting limits') for i in range(len(pars)): for j in range(3): if lims[j][0]<0: blims.append([pars[i,j,0]+a for a in lims[j]]) else: blims.append(lims[j]) #if type(lims[0]==list) if rep==-1: return blims blims=array(blims) else: blims=None if opti=='cob': from scipy.optimize import fmin_cobyla as mizer par_con=[lambda p:(p[i]-blims[i][0])*(blims[i][1]-p[i]) for i in range(len(blims))] out=mizer(fit,array(ipars),par_con,args=args) else: out=mizer(fit,array(ipars),None,args=args,approx_grad=True,bounds=blims,**extrapars) return out