In [1]:
%load_ext autoreload
%autoreload 2
In [24]:
%matplotlib widget
# import seaborn as sbn # can be used for getting nice colormaps and good settings of the matplotlib rc
In [25]:
import holoviews as hv
hv.extension('bokeh')
In [4]:
from cellpy.utils import batch
from cellpy import prms
In [5]:
import os
In [6]:
current_file_path = os.getcwd()
relative_test_data_dir = "../testdata"
test_data_dir = os.path.abspath(os.path.join(current_file_path, relative_test_data_dir))
test_data_dir_raw = os.path.join(test_data_dir, "data")
test_res_file = "20160805_test001_45_cc_01.res"
test_res_file_full = os.path.join(test_data_dir_raw,test_res_file)
test_data_dir_out = os.path.join(test_data_dir, "out")
test_data_dir_cellpy = os.path.join(test_data_dir, "hdf5")
test_cellpy_file = "20160805_test001_45_cc.h5"
test_cellpy_file_tmp = "tmpfile.h5"
test_cellpy_file_full = os.path.join(test_data_dir_cellpy,test_cellpy_file)
test_cellpy_file_tmp_full = os.path.join(test_data_dir_cellpy,test_cellpy_file_tmp)
test_run_name = "20160805_test001_45_cc"
In [ ]:
In [ ]:
In [23]:
import pandas as pd
import matplotlib.pyplot as plt
infoname = '/CellpyData/info'
dataname = '/CellpyData/dfdata'
summaryname = '/CellpyData/dfsummary'
fidname = '/CellpyData/fidtable'
stepname = '/CellpyData/step_table'
v_hdr = "Voltage"
c_hdr = "Charge_Capacity"
d_hdr = "Discharge_Capacity"
i_hdr = "Current"
In [9]:
def _query_dfdata(store, q):
return store.select('/CellpyData/dfdata', q)
In [10]:
def _convert_to_specific(s, mass):
return s*1000000.0 / mass
In [11]:
def _make_selectors(t):
if not t.lower() in [
"galvanostatic_charge", "galvanostatic_discharge",
"cycle", "ocv",
"discharge", "cv_discharge", "charge", "cv_charge", "ocvrlx_up", "ocvrlx_down",
]:
# error-message here
return
selectors = []
if t.lower() == "galvanostatic_charge":
selectors.append("charge")
elif t.lower() == "galvanostatic_discharge":
selectors.append("discharge")
elif t.lower() == "charge":
selectors.extend(["charge", "cv_charge"])
elif t.lower() == "discharge":
selectors.extend(["discharge", "cv_discharge"])
elif t.lower() == "cycle":
selectors.extend(["charge", "discharge"])
elif t.lower() == "ocv":
selectors.extend(["ocvrlx_down", "ocvrlx_up"])
else:
selectors.append(t.lower())
return(selectors)
In [12]:
def _get_step_table(file_name):
step_name = '/CellpyData/step_table'
with pd.HDFStore(file_name) as store:
step_table = store.select(step_name)
return step_table
In [13]:
def _get_info_name(file_name):
info_name = '/CellpyData/info'
with pd.HDFStore(file_name) as store:
info_table = store.select(info_name)
return info_table
In [14]:
def _filter_step_table(selectors, step_table, cycle_numbers):
steps = step_table.type.isin(selectors) & step_table.cycle.isin(cycle_numbers)
return step_table.loc[steps]
In [39]:
def _generate_cycle_data_query(a, headers=None):
"""create cycle query from a step_table DataFrame"""
a = a[["point_first", "point_last"]]
if headers is None:
headers = [
"Step_Time",
"Voltage",
"Charge_Capacity",
"Discharge_Capacity",
"Current",
"Cycle_Index"
]
sections = []
for points in a.iterrows():
p1, p2 = points[-1].values
sections.append(f"(index>={p1} & index<={p2})")
q = " | ".join(sections)
hdr_txts = []
for h in headers:
hdr_txts.append(f"'{h}'")
hdr_txt = ", ".join(hdr_txts)
q += f" & columns = [{hdr_txt}]"
return q
In [16]:
cellpyfile = test_cellpy_file_full
step_table = _get_step_table(cellpyfile)
In [17]:
info_table = _get_info_name(cellpyfile)
In [18]:
mass = float(info_table.mass)
In [19]:
cycle_numbers = [3]
In [40]:
with pd.HDFStore(cellpyfile) as store:
selectors = _make_selectors("cycle")
a = _filter_step_table(selectors, step_table, cycle_numbers=cycle_numbers)
q = _generate_cycle_data_query(a)
c = _query_dfdata(store, q)
c["Charge_Capacity"] = _convert_to_specific(c["Charge_Capacity"], mass)
c["Discharge_Capacity"] = _convert_to_specific(c["Discharge_Capacity"], mass)
In [41]:
c.describe()
Out[41]:
In [42]:
c.head()
Out[42]:
In [26]:
c.plot.scatter(x="Charge_Capacity", y="Voltage", )
Out[26]:
In [27]:
with pd.HDFStore(cellpyfile) as store:
selectors = _make_selectors("galvanostatic_charge")
a = _filter_step_table(selectors, step_table, cycle_numbers=cycle_numbers)
q = _generate_cycle_data_query(a)
gc = _query_dfdata(store, q)
gc["Charge_Capacity"] = _convert_to_specific(gc["Charge_Capacity"], mass)
In [28]:
gc.head()
Out[28]:
In [29]:
def get_charge_cycle(step_table, cycle_number, mass):
headers = [
"Step_Time",
"Voltage",
"Charge_Capacity",
#"Discharge_Capacity",
#"Current"
]
with pd.HDFStore(cellpyfile) as store:
selectors = _make_selectors("galvanostatic_charge")
a = _filter_step_table(selectors, step_table, cycle_numbers=[cycle_number])
q = _generate_cycle_data_query(a)
gc = _query_dfdata(store, q)
gc["Charge_Capacity"] = _convert_to_specific(gc["Charge_Capacity"], mass)
return gc
In [30]:
cycles = list(step_table.cycle.unique())
number_of_cycles = len(cycles)
In [37]:
%%time
charge_cycles = []
for n in cycles[:]:
try:
cycle = get_charge_cycle(step_table, n, mass)
except SyntaxError as e:
print(f"could not extract cycle {n}")
print(e)
charge_cycles.append(cycle)
In [32]:
from cellpy.utils import ica
In [33]:
import matplotlib.style
import matplotlib as mpl
import numpy as np
mpl.style.use('seaborn')
In [34]:
colormap = "viridis"
Accent, Accent_r, Blues, Blues_r, BrBG, BrBG_r, BuGn, BuGn_r, BuPu, BuPu_r, CMRmap, CMRmap_r, Dark2, Dark2_r, GnBu, GnBu_r, Greens, Greens_r, Greys, Greys_r, OrRd, OrRd_r, Oranges, Oranges_r, PRGn, PRGn_r, Paired, Paired_r, Pastel1, Pastel1_r, Pastel2, Pastel2_r, PiYG, PiYG_r, PuBu, PuBuGn, PuBuGn_r, PuBu_r, PuOr, PuOr_r, PuRd, PuRd_r, Purples, Purples_r, RdBu, RdBu_r, RdGy, RdGy_r, RdPu, RdPu_r, RdYlBu, RdYlBu_r, RdYlGn, RdYlGn_r, Reds, Reds_r, Set1, Set1_r, Set2, Set2_r, Set3, Set3_r, Spectral, Spectral_r, Wistia, Wistia_r, YlGn, YlGnBu, YlGnBu_r, YlGn_r, YlOrBr, YlOrBr_r, YlOrRd, YlOrRd_r, afmhot, afmhot_r, autumn, autumn_r, binary, binary_r, bone, bone_r, brg, brg_r, bwr, bwr_r, cividis, cividis_r, cool, cool_r, coolwarm, coolwarm_r, copper, copper_r, cubehelix, cubehelix_r, flag, flag_r, gist_earth, gist_earth_r, gist_gray, gist_gray_r, gist_heat, gist_heat_r, gist_ncar, gist_ncar_r, gist_rainbow, gist_rainbow_r, gist_stern, gist_stern_r, gist_yarg, gist_yarg_r, gnuplot, gnuplot2, gnuplot2_r, gnuplot_r, gray, gray_r, hot, hot_r, hsv, hsv_r, inferno, inferno_r, jet, jet_r, magma, magma_r, nipy_spectral, nipy_spectral_r, ocean, ocean_r, pink, pink_r, plasma, plasma_r, prism, prism_r, rainbow, rainbow_r, seismic, seismic_r, spring, spring_r, summer, summer_r, tab10, tab10_r, tab20, tab20_r, tab20b, tab20b_r, tab20c, tab20c_r, terrain, terrain_r, viridis, viridis_r, winter, winter_r
In [35]:
cmap = plt.cm.get_cmap(colormap)(np.linspace(0, 1, number_of_cycles+10))
In [36]:
fig, (ax1, ax2) = plt.subplots(2,1, sharex=True)
for i, frame in enumerate(charge_cycles):
ax1.plot(frame.Voltage, frame.Charge_Capacity, label=str(i+1), color=cmap[i])
v, dq = ica.dqdv(frame.Voltage, frame.Charge_Capacity)
ax2.plot(v, dq, color=cmap[i])
ax1.legend(ncol=3, loc=4, frameon=True)
ax1.set_ylabel("Charge capacity (mAh/g)")
ax2.set_xlabel("Voltage (V vs Li+/Li)")
Out[36]:
In [ ]:
In [ ]:
In [43]:
def get_charge_cycles1(step_table, cycle_numbers, mass):
headers = [
"Cycle_Index",
"Step_Time",
"Voltage",
"Charge_Capacity",
#"Discharge_Capacity",
#"Current"
]
with pd.HDFStore(cellpyfile) as store:
selectors = _make_selectors("galvanostatic_charge")
a = _filter_step_table(selectors, step_table, cycle_numbers=cycle_numbers)
q = _generate_cycle_data_query(a)
gc = _query_dfdata(store, q)
gc["Charge_Capacity"] = _convert_to_specific(gc["Charge_Capacity"], mass)
return gc
In [60]:
def get_charge_cycles2(step_table, cycle_numbers, mass):
headers = [
"Cycle_Index",
"Step_Time",
"Voltage",
"Charge_Capacity",
#"Discharge_Capacity",
#"Current"
]
gcs = []
with pd.HDFStore(cellpyfile) as store:
for cycle_number in cycle_numbers:
selectors = _make_selectors("galvanostatic_charge")
a = _filter_step_table(selectors, step_table, cycle_numbers=[cycle_number])
q = _generate_cycle_data_query(a)
gc = _query_dfdata(store, q)
gc["Charge_Capacity"] = _convert_to_specific(gc["Charge_Capacity"], mass)
gcs.append(gc)
gcs = pd.concat(gcs)
return gcs
In [61]:
cycs = list(range(1,18))
In [66]:
%%timeit
c1 = get_charge_cycles1(step_table, cycs, mass)
In [67]:
%%timeit
c2 = get_charge_cycles2(step_table, cycs, mass)
In [68]:
c1.columns
Out[68]:
In [87]:
# defining key dimensions
cycles = hv.Dataset(c1, ['Cycle_Index', 'Charge_Capacity'])
In [134]:
dqdv = []
cycle_indexes = c1.Cycle_Index.unique()
for c in cycle_indexes:
frame = c1.loc[c1.Cycle_Index==c]
v, dq = ica.dqdv(frame.Voltage, frame.Charge_Capacity)
df = pd.DataFrame(
dict(
v=v,
dq=dq,
)
)
df["Cycle_Index"] = c
dqdv.append(df)
In [135]:
dqdv_frame = pd.concat(dqdv)
In [136]:
dqdv_frame.head()
Out[136]:
In [138]:
# defining key dimensions
dqdv = hv.Dataset(dqdv_frame, ['Cycle_Index', 'v'])
In [88]:
print(cycles.groupby('Cycle_Index'))
In [92]:
%%opts Curve [width=500]
curves = cycles.to(hv.Curve, 'Charge_Capacity', 'Voltage', groupby='Cycle_Index')
curves
Out[92]:
In [105]:
%%opts Scatter [width=500 height=400,] (alpha=0.1)
%%opts Curve (line_width=5)
%%opts NdOverlay [legend_position='left']
ndoverlay = cycles.to(hv.Scatter, 'Charge_Capacity', 'Voltage', groupby='Cycle_Index').overlay()
curves = cycles.to(hv.Curve, 'Charge_Capacity', 'Voltage', groupby='Cycle_Index')
curves * ndoverlay
Out[105]:
In [146]:
%%opts Curve.all [width=500 height=400,] (alpha=0.3)
%%opts Curve.focus (line_width=5)
%%opts NdOverlay [legend_position='left']
dndoverlay = dqdv.to(hv.Curve, 'v', 'dq', groupby='Cycle_Index', group="all").overlay()
dcurves = dqdv.to(hv.Curve, 'v', 'dq', groupby='Cycle_Index', group="focus")
dcurves * dndoverlay
Out[146]:
In [ ]: