# coding: utf-8
# # Golem Workshop Kiten 2018 - Data Processing
#
# This is a notebook for data processing of the Golem operation domain scan.
# In[1]:
get_ipython().magic('matplotlib inline')
# At first, load some basic libraries.
import numpy as np
from urllib.request import urlopen
import shutil
import os
from matplotlib import pyplot as plt
from scipy.interpolate import interp1d
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
# Plot settings, can be changed to globally influence the appearance
plt.rc('text', usetex=True)
plt.rc('font', family='sans-serif')
plt.rc('font', size=22) # controls default text sizes
plt.rc('axes', titlesize=22) # fontsize of the axes title
plt.rc('axes', labelsize=20) # fontsize of the x and y labels
plt.rc('xtick', labelsize=20) # fontsize of the tick labels
plt.rc('ytick', labelsize=20) # fontsize of the tick labels
plt.rc('legend', fontsize=22) # legend fontsize
plt.rc('figure', titlesize=22) # fontsize of the figure title
# ## Golem Database Access
#
# Thanks to Golem staff for the golem_data function.
#
# This should not be changed :).
# In[2]:
def golem_data(shot, diagn):
"""
Simple interface for GOLEM database
Use:
obj = golem_data(10011, 'loop_voltage')
plot(obj.tvec, obj.data)
d - object containing all availible informations
d.tvec - time vector Nx1
d.data - data matrix NxM
Example:
from golem_data import golem_data
from matplotlib.pyplot import *
obj1 = golem_data(10689 , 'electron_temperature')
obj2 = golem_data(10689 , 'spectrometr:temperature')
plot(obj1.tvec,obj1.data, label=obj1.labels) %
errorbar(obj2.tvec, obj2.data, xerr=obj2.tvec_err, yerr=[obj2.data_err[:,0], obj2.data_err[:,1]], label=obj2.labels )
xlabel(obj2.ax_labels[0])
ylabel(obj2.ax_labels[1])
legend([obj1.name, obj2.name])
axis([obj1.plasma_start, obj1.plasma_end, 0, None])
title(obj1.info)
show()
"""
remote_file = "http://golem.fjfi.cvut.cz/utils/data/"+str(shot)+"/"+diagn+'.npz'
gfile = np.DataSource().open(remote_file, mode='rb') # remote file
try:
d = dict(np.load(gfile, encoding='bytes', fix_imports=True))
except IOError:
raise IOError('Missing diagnostic ' + str(diagn) + ' in shot ' + str(shot))
if not 'tvec' in d and 't_start' in d:
d['tvec'] = np.linspace( d.pop('t_start'), d.pop('t_end'), len(d['data']) )
try:
if 'scale' in d:
d['data'] = np.double(d['data']) * d.pop('scale') # rescale data
except:
pass
return Data( **d )
class Data(object):
""" Simple data handling object"""
def __init__(self, **kwargs):
self.__dict__.update(kwargs)
def __repr__(self):
return "Data object, keys:\n" + str(self.__dict__.keys())
def __getitem__(self, key):
return getattr(self, key)
# ## Some Useful Scripts
#
# ### Validate
# Excludes bad shots from a shot list.
# In[3]:
def Validate(shot_list, bad_shots):
valid = [];
for shot_no in shot_list:
try:
if not(shot_no in bad_shots):
b_v = golem_data(shot_no, 'breakdown_voltage').data
valid.append(shot_no)
except Exception:
pass
return valid;
# ### GetValAtTime
#
# Takes a diagnostic obtained by `golem_data` and interpolates its value for a specific time in the shot.
#
# Calling with `plot_progress = True` will show the interpolation on the graph.
# In[4]:
def GetValAtTime(diag, time, plot_progress = False):
f = interp1d(diag.tvec, diag.data)
# change to true if you want to see the plots
if plot_progress:
fig = plt.figure()
plt.plot(diag.tvec, diag.data, linewidth=2)
t = np.linspace(min(diag.tvec), max(diag.tvec), 50)
plt.plot(t, f(t), linewidth=1)
plt.plot([time, time], [min(diag.data), max(diag.data)], '--')
plt.plot(time, f(time), 'o')
plt.xlabel('$t$ [s]')
plt.ylabel('$B_\mathrm{t}$ [T]')
plt.grid(True, axis='both')
plt.show()
plt.close()
return f(time)
# ### Load
#
# Loads all specified diagnostics for a specified shot number.
#
# Any newly requested diagnostics should be added here.
#
# **To use the diagnostic in the scan, one point should be selected (e.g. by interpolation for a specific time).** Toroidal field is now treated like this.
# In[5]:
# Diagnostics should be added here (according to the sample fro)
def Load(shot_no):
data_dict = {
'shot_no': shot_no,
'pressure_request': golem_data(shot_no, 'pressure_request').data,
'pressure': golem_data(shot_no, 'pressure').data,
'ucd': golem_data(shot_no, 'ucd').data,
'electron_temperature': golem_data(shot_no, 'electron_temperature_max').data,
'breakdown_voltage': golem_data(shot_no, 'breakdown_voltage').data,
'toroidal_field': GetValAtTime(golem_data(shot_no, 'toroidal_field'),
golem_data(shot_no, 'plasma_start').data)
}
return data_dict
# ### GetScan1, GetScan2
#
# Sorts the data for further processing. Poorly written, should be somewhat more refined (to allow for arbitrary N-dimensional scans).
# In[6]:
def GetScan1(data_list, scan_var, diag_var):
d_l = sorted(data_list, key=lambda d: d[scan_var])
return {
'x': [d[scan_var] for d in d_l],
'val': [d[diag_var] for d in d_l],
}
def GetScan2(data_list, scan_var, diag_var):
d_l = sorted(data_list, key=lambda d: (d[scan_var[0]], d[scan_var[1]]))
return {
'x': [d[scan_var[0]] for d in d_l],
'y': [d[scan_var[1]] for d in d_l],
'val': [d[diag_var] for d in d_l],
}
# ### ScanPlot2D
#
# Plots a 2D scan (scaled colormap).
# In[7]:
def ScanPlot2D(golem_scan, scan_id, scan_description):
fig = plt.figure(figsize=(8, 6), dpi=80)
plt.tricontourf(golem_scan[scan_id]['x'], golem_scan[scan_id]['y'],
golem_scan[scan_id]['val'])
plt.plot(golem_scan[scan_id]['x'], golem_scan[scan_id]['y'], 'ko', ms=3)
plt.xlabel('$p$ [mPa]')
plt.ylabel('$U_\mathrm{CD}$ [V]')
c = plt.colorbar()
c.set_label(scan_description)
return fig
# ### ScanPlotLines
#
# Plots a 2D scan as a series of lines grouped by one of scan variables (can be selected by setting `group_by` to either `x` or `y`.
# In[8]:
def ScanPlotLines(golem_scan, group_by, scan_id, scan_description):
fig = plt.figure(figsize=(8, 6), dpi=80)
x_axis = 'x' if group_by == 'y' else 'y';
x_label = '$p$ [mPa]' if x_axis == 'x' else '$U_\mathrm{CD}$ [V]'
lines_label = 'mPa' if x_axis == 'y' else 'V'
unique = set(golem_scan[scan_id][group_by])
unique = sorted(list(unique))
for u_v in unique:
data_x = []
data_y = []
for i in range(len(golem_scan[scan_id][x_axis])):
if golem_scan[scan_id][group_by][i] == u_v:
data_x.append(golem_scan[scan_id][x_axis][i])
data_y.append(golem_scan[scan_id]['val'][i])
plt.plot(data_x, data_y, 'o--', label = '{0} {1}'.format(u_v, lines_label))
plt.legend(bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0.)
plt.xlabel(x_label)
plt.ylabel(scan_description)
plt.grid()
return fig
# ## Data Load
#
# Let's load the data from selected shots.
# In[9]:
# Kiten scan
shot_list = range(27454, 27491, 1)
bad_shots = [27481, 27482, 27483]
# Second scan (Prague 28/06)
shot_list = [27617, 27618, 27619, 27620, 27621, 27622, 27623, 27624, 27625, 27626, 27627, 27628, 27629, 27630,
27633, 27634, 27635, 27636, 27637, 27638, 27639, 27640, 27641, 27642, 27643, 27644, 27645, 27646,
27647, 27648, 27649, 27650, 27651, 27652, 27653, 27654, 27655, 27656, 27657, 27658, 27659, 27660,
27661, 27662, 27663, 27664, 27665, 27666, 27667, 27668, 27669, 27670, 27671, 27672, 27673, 27674]
bad_shots = []
# Do the loading
valid_shots = Validate(shot_list, bad_shots)
data_list = [Load(s_no) for s_no in valid_shots]
# ## Data Processing
#
# Three scans variables (`['breakdown_voltage', 'electron_temperature', 'toroidal_field']`) are selected and a scans in `pressure` and `ucd` (current drive voltage) are generated.
#
# A second scan set is generated for requested pressure instead of real pressure.
# In[10]:
scan_vars = ['breakdown_voltage', 'electron_temperature', 'toroidal_field']
# the main scan
golem_scan = {};
for s_id in scan_vars:
golem_scan[s_id] = GetScan2(data_list, ['pressure', 'ucd'], s_id)
# the auxiliary scan
golem_scan_request = {};
for s_id in scan_vars:
golem_scan_request[s_id] = GetScan2(data_list, ['pressure_request', 'ucd'], s_id)
# ### Breakdown voltage
# We should see some minima on the Paschen curves.
# In[11]:
fig = ScanPlotLines(golem_scan, 'y', 'breakdown_voltage', '$U_\mathrm{b}$ [V]');
fig.savefig("grouped-p-U_bd.pdf", bbox_inches="tight");
fig.savefig("grouped-p-U_bd.png", bbox_inches="tight");
# ### 2D plots
#
# * Breakdown voltage
# * Electron temperature
# * Toroidal field at the beginning of the discharge (plasma)
# In[12]:
fig = ScanPlot2D(golem_scan, 'breakdown_voltage', '$U_\mathrm{b}$ [V]');
fig.savefig("scan2d-p-U_cd-U_bd.pdf", bbox_inches="tight");
fig.savefig("scan2d-p-U_cd-U_bd.png", bbox_inches="tight");
# In[13]:
fig = ScanPlot2D(golem_scan, 'electron_temperature', '$T_\mathrm{e}$ [eV]');
fig.savefig("scan2d-p-U_cd-T_e.pdf", bbox_inches="tight");
fig.savefig("scan2d-p-U_cd-T_e.png", bbox_inches="tight");
# In[14]:
fig = ScanPlot2D(golem_scan, 'toroidal_field', '$B_\mathrm{t}$ [T]');
fig.savefig("scan2d-p-U_cd-B_t.pdf", bbox_inches="tight");
fig.savefig("scan2d-p-U_cd-B_t.png", bbox_inches="tight");
# ### Toroidal field
#
# Grouped by the requested pressure.
# In[15]:
fig = ScanPlotLines(golem_scan_request, 'x', 'toroidal_field', '$B_\mathrm{t}$ [T]');
fig.savefig("grouped-p-B_t.pdf", bbox_inches="tight");
fig.savefig("grouped-p-B_t.png", bbox_inches="tight");
# In[ ]: