#!/usr/bin/env python # -*- coding: utf-8 -*- """ Estimate electron temperature and ion concentration based on their the spectral lines intensity. Ions intensity is descrimed by a very simple model with minimal number of parameters: Expectations: 1) that line intesity is proportional to impurity density and fnction of the temperature 2) ratio of lines of the different ionization states of the impuritie as function of the temperature is polynome of order k (k = 1 now) 3) shape of f(T_e) of the first ionozation stage is gaussian with width a and center T0 (for k = 1 => all other are also gaussians) 4) this model can not exactly estimate the temperature, only something which is monotonous function of the T_E => caibration from the spitzer resistivity was necassary. 5) it is expected that during the shot is impurity density as constant as possible. Advantages: simple model => robust most of the spectra are explained very well even by this simple model Disadvantages: OI and NI can be observed in low temperatures a deviation from model, f(T) if this ions don't have a gaussian shape, it radiates strongyl alte low temperatures and the the radiation is alomost constant over large range of temperatures. In helium shots is probably a different physic or a week he lines mess estimate of the NI density. NI radiation is significantly underestimated. Autor :Tomas Odstrcil Date 12.12.2012 """ import matplotlib matplotlib.rcParams['backend'] = 'Agg' from numpy import * import matplotlib.pyplot as plt from numpy.linalg import norm from scipy.linalg import inv,pinv,cholesky,solve_triangular from scipy.stats.stats import pearsonr,hmean from scipy.sparse import block_diag from numpy.matlib import repmat from time import time from pygolem_lite.modules import save_adv,load_adv from pygolem_lite import saveconst import numexpr as ne from scipy.optimize import fmin_bfgs ion_names = ['HI','OI','OII', 'OIII', 'HeI', 'CII', 'CIII', 'NI','NII', 'NIII','M1', 'MIV' ] element_names = ['H','O','He','C','N','M1','MIV'] n_ions = len(ion_names) n_elemets = len(element_names) k = 2 #polynome order ions_index = [[0], [1,2,3], [4], [5,6], [7,8,9], [10],[11]] single_ion = [0,2,5,6] multi_ion = [1,3,4] M1 = matrix([1,]) #H 0 M2 = matrix([[1,-1,0],[0,1,-1],[1,0,-1],[1,0,0]]) #O 1 M3 = matrix([1,]) #He 2 M4 = matrix([[1,-1],[-1,1],[1,0]]) #C 3 M5 = matrix([[1,-1,0],[0,1,-1],[1,0,-1],[0,1,0]]) #N 4 M6 = matrix([1,]) #M1 5 M7 = matrix([1,]) #MIV 6 M = block_diag((M1,M2,M3,M4,M5,M6,M7)) M = M.todense() bound_inter_i = [1,2,3,5,6,7,8,9] bound_inter_j = [1,2,3,6,7,9,10,11] bound_inter = zeros(15, dtype = 'bool') bound_inter[bound_inter_j] = True M_limited = (M[:,bound_inter_i])[bound_inter_j,:] iM = array(linalg.pinv(M)) def CalibrateTemperature(T,Terr): #basend on coeffitients from CompareSpitzerResistivity.py nl_coeff = loadtxt('model_constants/nonlin_tranform_coeff.txt') a = nl_coeff[0] b = nl_coeff[1] c = nl_coeff[2] d = nl_coeff[3] def T2T_eV(T): T = copy(T) ind = where(T <=c*0.95) T[ind] = c*0.95+c*0.05*(1-exp((T[ind]-c*0.05))) ind = where(T>2.9) T_ = (tan((-T-c)/d)-b)/a T_[ind] = exp(-T[ind]+2.9)*(tan((-2.9-c)/d)-b)/a return T_ T_ = T2T_eV(T) Terr_u = T2T_eV(T-Terr)-T_ Terr_d = -T2T_eV(T+Terr)+T_ return T_,Terr_u,Terr_d def EstimateT(p,pE,coeff): pE = pE#+0.1 #because than can be too low values, nonstatistical errors n = size(p,0) m = size(p,1) I = ones(n) cutM = array(M[bound_inter_j,:]) R = dot(cutM,log(p+1e-4).T) m = size(R,1) Re = sqrt(dot(cutM**2,((pE/(p+1e-5))**2).T)) R-= outer(coeff[:,0], I) B = coeff[:,1] B = tile(B,(m,1)).T T = average(R/B, axis = 0, weights=(B/Re)**2) T = sum(B*R/Re**2, axis = 0)/sum((B/Re)**2,axis = 0) B *= T[newaxis,:] chi2 = norm((R-B)/Re)**2/(size(R)-size(T)) print 'chi2 temp:',chi2 return T def plotTprofiles(T0, a, density,N, T,B, coeff,p,pE,i): density_model = ones((100,n_elemets)) T_model = linspace(-3,3,100) N_model = vstack((ones(100),T_model)).T c2 = CalcIntensity(T_model,density_model,N_model,T0,a,B,coeff,ions_index[i])/e I = CalcIntensity(T,density,N,T0,a,B,coeff,ions_index[i]) Resid = (p[:,ions_index[i]]-I)/pE[:,ions_index[i]] ax = plt.subplot(1,1,1) r_tot,_ = pearsonr(ravel(p[:,ions_index[i]]), ravel(I)) #max_Resid je aby se zabránilo přetečení chi2 = norm(Resid)**2/(size(Resid)) max_Resid = double(amax(abs(Resid))) Resid/= max_Resid Resid **= 2 chi2_robust = max_Resid*sum(Resid/sqrt((1/max_Resid)**2 + Resid))/(size(Resid)) colour = ['b', 'r','k', 'y'] for k in range(len(ions_index[i])): x = -T y = squeeze(p[:,(ions_index[i])[k]]/exp(density[:,i])) y_err = squeeze(pE[:,(ions_index[i])[k]]/exp(density[:,i])) noisy = y_err > y*2 errorbar(x[~noisy],y[~noisy],y_err[~noisy], fmt=colour[k]+'.',capsize = 0,linewidth = 0.1,markersize = 0.5) plt.plot(-T_model, c2[:,k], colour[k],label = ion_names[(ions_index[i])[k]]) plt.xlabel('f(T) [-]') plt.ylabel('intensity [a.u.]') leg = plt.legend(loc='upper left', fancybox=True) leg.get_frame().set_alpha(0.7) plt.title(element_names[i]) ax.text(-1.9,1,'$\\chi^2$ = %2.1f \n$\\chi^2$ robust = %2.1f \n$r$ = %1.2f' % (chi2,chi2_robust,r_tot),horizontalalignment='left',verticalalignment='bottom') plt.ylim(0,1.5) plt.xlim(-2,1) #plt.show() plt.savefig('grafy_advance/_'+element_names[i]+' '+name+'.png') fig.clf() from scipy.spatial.distance import cdist iM = copy(iM.T) def CalcIntensity(T,density,N,T0,a,B,coeff,index): density[density>100] = 100 n = size(density,0) F = empty((n,15), dtype= 'double') F[:,bound_inter] = dot(N,coeff.T) T = repmat(T, n_elemets,1).T T -= T0 T *= T T *= a T -= B T += density F[:,~bound_inter] = T I = exp(dot(F,iM[:,index])-1) return I def EstimateDensity(p,pE,T,T0,a,B,coeff): n = size(p,0) #pE = pE+0.1 #because than can be too low values, nonstatistical errors N = vstack([T**j for j in range(k)]).T density = zeros((n,n_elemets)) I = CalcIntensity(T,density,N,T0,a,B,coeff,slice(0,12)) I[I<1e-3] = 1e-3 r = log(p/I+1e-3) re = pE/(p+1e-3) for i,ind in enumerate(ions_index): density[:,i] = average(r[:,ind], axis = 1, weights=1/re[:,ind]) I = CalcIntensity(T,density,N,T0,a,B,coeff,slice(0,12)) chi2 = norm((p-I)/pE)**2/(size(p)-size(density)) #for i in range(n_ions): #plotTprofiles(T0, a, density,N, T, B,coeff,p,pE,i) #import IPython #IPython.embed() print 'chi2 dens:',chi2 return density def CalcDensTemp(): C = loadtxt('model_constants/C.txt') #temperature polynome coeffitients A = loadtxt('model_constants/A.txt') #temperature profile gaussian widths T0= loadtxt('model_constants/T0.txt')#temperature profile gaussian center B = loadtxt('model_constants/B.txt') #temperature profile gaussian height #try: tvec,proj_dict = load_adv('./data/projection') p = proj_dict pE = proj_dict.data_err #p = load('./data/projection.npy') #pE = load('./data/projectionError.npy') #tvec= load('./data/tvec.npy') #except: #print 'Projection was not found' #return #print p.shape, type(p), p.ndim #exit() s = sum(p[:,bound_inter_i],axis = 1) > 0.01 #remove dark and very weak spectra shots_part = linspace(0,1,size(p,0), endpoint = False) p = p[s,:] pE = pE[s,:] tvec = tvec[s] shots_part = shots_part[s] n = size(p,0) if n == 0: return dp = zeros((n+1,n_ions)) dp[1:-1,:] = abs(diff(p, axis = 0)) dp_ = zeros_like(pE) for i in range(n_ions): x = arange(n)+0.5 xp = arange(n+1) dp_[:,i] = interp(x,xp, dp[:,i]) pE += 0.1*dp_ #error due to fast changes during integration pE[pE <= 1e-3] = 1e-3 #due to non-physically small errors n_infty = sum(pE == infty) def f_optim(x): #t = time() T = x[:n]# temperature density = reshape(x[-n*n_elemets:],(n,n_elemets)) #logarithm dems N = vstack([T**j for j in range(k)]).T #t = time() I = CalcIntensity(T,density,N,T0,A,B,C,slice(0,12)) #print time()-t size(pE) doF = (size(p)-size(x)-n_infty) Resid = ne.evaluate('((p-I)/(pE+1e-5))**2') chi2 = ne.evaluate('sum(Resid/sqrt(1 + Resid))')/doF b = norm(T[T > 4]) b += norm(T[T < -3]) d = diff(density,1, axis = 0) #BUG je to OK? d[0,:]/=2 #allow a bigger changes at the start and end of the discharge where is the model not valid d[-1,:]/=2 d = norm(d)/len(d)#+norm(exp(density[:,0]))+norm(exp(density[:,-1])) Td = diff(T,2) Td[Td > 0] = 0 Td = norm(Td) spars = norm(ravel(exp(density))) #suppress extremly high densities #print time()-t #print chi2 +spars*.1+lam*d*.6+Td/10+b return chi2 +spars*.1+lam*d*.6+Td/10+b #make a LSQ based estimates temp0 = EstimateT(p,pE,C) dens0 = EstimateDensity(p,pE,temp0,T0,A,B,C) #print dens0[:,element_names=='O'], temp0 #dens0[:,array(element_names)=='O'] x0 = hstack((temp0, ravel(dens0))) #import IPython #IPython.embed() lam = 10 print 'fmin_bfgs' y= fmin_bfgs(f_optim, x0, gtol=1e-1,maxiter=1e6,disp=False) #print y #exit() #print 'fmin_bfgs finish' T = y[:n]# temperature #print T N = vstack([T**j for j in range(k)]).T density = reshape(y[-n*n_elemets:],(n,n_elemets)) #logarithm density I = CalcIntensity(T,density,N,T0,A,B,C,range(12)) #estimate statistical errors: def RetrofitFunction(x): Temp = x[:n]# temperature Dens = reshape(x[n:],(n,n_elemets))#logarithm density I = CalcIntensity(Temp,Dens,N,T0,A,B,C,range(12)) return ravel(I) def CalcJacobi(x0,fun): n2 = size(p) dx = 1e-6 J = zeros((len(x0),n2), dtype = 'float32') for i in range(len(x0)): xl,xr = copy(x0),copy(x0) xl[i]-= dx xr[i]+= dx J[i,:] = (fun(xl)-fun(xr))/(2*dx) return J J = CalcJacobi(y,RetrofitFunction) chi2 = array([1,3,3,3,1,3,3,13,13,13,10,1]) #BUG must by set by hand correctedPE = copy(pE) correctedPE *= sqrt(chi2) err = ravel(correctedPE) J/= err JJ= dot(J,J.T) JJ.flat[::size(J,0)+1]+= 1e-3 #regularization of the sometimes singular matrix L = cholesky(JJ, lower=False,overwrite_a=True) #vytvoří to asi dolní trojúhelníkovu matici rozkladu #invert L I = identity(L.shape[0]) iL= solve_triangular(L,I , trans=0, lower=True, overwrite_b=True) iL = absolute(iL, out = iL) iL **= 2 err = sqrt(sum(iL, 0)) energy_constants=load('./data/energy_constants.npy') p_calib = p*energy_constants P_total = sum(p_calib,1) temp_err = err[:n] dens_err = reshape(err[n:],(n,n_elemets)) T_calib,T_calib_err_u,T_calib_err_d = CalibrateTemperature(T,temp_err) ind = argsort(P_total)[-2:] max_dens = average(density[ind,:],axis=0, weights=dens_err[ind,:]) max_dens = exp(max_dens) for d,name in zip(max_dens, element_names): print 'ion %2s concentration = %1.2f'%(name,d) saveconst('./HistoricalAnalysis/'+name,d) flt_temp = average(T_calib[ind],weights=1/T_calib_err_d[ind]**2) print 'flattop temperatute %1.1f'%flt_temp saveconst('./HistoricalAnalysis/temperature',flt_temp) chi2 = zeros(n_elemets) for i in range(n_elemets): I = CalcIntensity(T,density,N,T0,A,B,C,ions_index[i]) Resid = (p[:,ions_index[i]]-I)/pE[:,ions_index[i]] max_Resid = double(amax(abs(Resid))) Resid/= max_Resid Resid **= 2 chi2[i] = max_Resid*sum(Resid/sqrt((1/max_Resid)**2 + Resid))/(size(Resid)-n+1) save_adv('./data/density', tvec,density,data_err=dens_err, tvec_err=1e-3) save_adv('./data/temperature', tvec,T_calib, data_err=[T_calib_err_d,T_calib_err_u], tvec_err=1e-3) save_adv('./data/TempDensChi2', arange(n_elemets),chi2) #Plot basic plot try: shots = load('shots.npy') shot_index = where(abs(floor(shots)- shot_number) < 0.5)[0] except: pass fig = plt.figure(num=None, figsize=(8, 7), dpi=80, facecolor='w', edgecolor='k') ax = fig.add_subplot(311) I = CalcIntensity(T,density,N,T0,A,B,C,range(12)) plt.errorbar(arange(size(p)), ravel(p.T), yerr=ravel(pE.T)) plt.plot(ravel(I.T)) chi2doF = norm((p-I)/pE)**2/size(p-size(y)) ax.set_title('Spectral data retrofit') T_est = EstimateT(p,pE,C) d_est = EstimateDensity(p,pE,T_est,T0,A,B,C) I = CalcIntensity(T_est ,d_est,N,T0,A,B,C,range(12)) plt.plot(ravel(I.T), 'r:') ax.axis('tight') ax.set_ylabel('intensity') ax.set_ylim(0,amax(p)*1.2) ax.text(2/2,amax(p)*0.5,'$\chi^2$/doF = %.2f'%chi2doF,horizontalalignment='left',verticalalignment='bottom') for i,name in enumerate(ion_names): ax.text(i*n+1,amax(p)*1.05,name,horizontalalignment='left',verticalalignment='bottom') ax = fig.add_subplot(312) plt.errorbar(tvec*1e3, -T, temp_err,markersize = 0.5) plt.plot(tvec*1e3, -(T_est[:n]),':') try: temperature_full = load('temperature.npy') plt.plot(shots[shot_index]-shot_number, -temperature_full[shot_index], '--') except: pass ax.set_ylim(-4,3) ax.set_ylabel('pseudo temperature') ax = fig.add_subplot(313) plt.semilogy( tvec*1e3,exp(density)) try: density_full = load('density.npy') density_full+= B[:,newaxis] plt.semilogy(shots[shot_index]-shot_number,exp(density_full[:,shot_index].T), '--') except: pass #ax.axis('tight') ax.set_ylim(1e-3,10) ax.set_ylabel('Density') ax.set_xlabel('t [ms]') fig.savefig('./graphs/proj_retrofit.png') fig.clf() return def plotDensTemp(): tvec,density = load_adv('./data/density') dens_err = density.data_err tvec,T = load_adv('./data/temperature') temp_err = T.data_err temp_err = [temp_err[:,0] ,temp_err[:,1]] _,chi2doF = load_adv('./data/TempDensChi2') class MyFormatter(plt.ScalarFormatter): def __call__(self, x, pos=None): if pos==0: return '' else: return plt.ScalarFormatter.__call__(self, x, pos) fig = plt.figure(num=None, figsize=(10, 10), dpi=80, facecolor='w', edgecolor='k') plt.subplots_adjust(hspace=0, wspace = 0) for i in range(0,n_elemets): ax = fig.add_subplot(n_elemets,1,i+1) if i == 0: ax.set_title('Relative ions concentration') ax.xaxis.set_major_formatter( plt.NullFormatter() ) ax.yaxis.set_major_formatter( MyFormatter() ) y = exp(density[:,i]) y_err_up = expm1( dens_err[:,i])*y y_err_down = -expm1(-dens_err[:,i])*y y_med = average(y, weights=abs(y_err_up)) y_err_med = (hmean(abs(y-y_med)+1e-3)+hmean(abs(y_err_up)))/2 plt.errorbar(tvec*1e3,y,yerr=[y_err_down,y_err_up],markersize = 0.5, label = element_names[i]) ax.yaxis.grid(True) ax.text(.05,.2,'$\\chi^2/doF = %2.1f$ \n $n = %1.2f\pm%1.1g$'% (chi2doF[i],y_med,y_err_med),horizontalalignment='left',verticalalignment='bottom',transform=ax.transAxes) ax.set_ylim(0,max(0.1,amax(y))*1.5) leg = plt.legend(loc='upper left', fancybox=True) leg.get_frame().set_alpha(0.5) ax.xaxis.set_major_formatter( plt.ScalarFormatter() ) ax.set_xlabel('t [ms]') fig.savefig('./graphs/density.png',bbox_inches='tight') fig.clf() fig = plt.figure(num=None, figsize=(10, 3), dpi=80, facecolor='w', edgecolor='k') ax = fig.add_subplot(111) ax.set_title('Estimated temperature') plt.errorbar(tvec*1e3, T, yerr=temp_err,markersize = 0.5) ax.set_ylabel('$T_e$ [eV]') ax.set_xlabel('t [ms]') ax.set_ylim(0,80) ax.yaxis.grid(True) fig.savefig('./graphs/temperature.png',bbox_inches='tight') plt.close() try: fig = plt.figure(num=None, figsize=(10, 3), dpi=80, facecolor='w', edgecolor='k') ax = fig.add_subplot(111) data = load('./electronTemperatures/'+str(shot_number)+'/electron_temperature.npz') temp = data['data']*data['scale'] tvec_spitz= linspace(data['t_start'], data['t_end'], len(temp)) try: plasma_start = loadtxt('./electronTemperatures/'+str(shot_number)+'/PlasmaStart') plasma_end = loadtxt('./electronTemperatures/'+str(shot_number)+'/PlasmaEnd') except: pass #plasma_start = amin(tvec[isfinite(temp)]) #plasma_end = amax(tvec[isfinite(temp)]) if shot_number > 9300: temp*= 2 else: tvec_spitz/= 1e3 plasma_start-= 0.5 plasma_start/= 1000 plasma_end/=1000 ax.set_title('Spitzer temperature') plt.plot(tvec_spitz*1e3, temp) ax.set_ylabel('$T_e$ [eV]') ax.set_xlabel('t [ms]') ax.set_ylim(0,80) ax.set_xlim(plasma_start*1000,plasma_end*1000) fig.savefig('./graphs/temperature'+str(shot_number)+'_spitz.png',bbox_inches='tight') plt.close() print 'Te plotted' except: print 'no electron temperature' pass