예제 #1
0
def test_colvariables():
    result_a = col_variables('ARBIN')
    assert result_a == ('Cycle_Index', 'Data_Point', 'Voltage(V)',
                        'Current(A)', 'Discharge_Capacity(Ah)',
                        'Charge_Capacity(Ah)', 'Step_Index')
    result_b = col_variables('MACCOR')
    assert result_b == ('Cycle_Index', 'Rec', 'Voltage(V)', 'Current(A)',
                        'Cap(Ah)', 'Cap(Ah)', 'Md')
    try:
        result_x = col_variables('not a real datatype')
    except (AssertionError):
        pass
    else:
        raise Exception('Valid datatype not being checked')
예제 #2
0
def generate_model(df_clean, filename, peak_thresh, database):
    """Wrapper for the get_model_dfs function. Takes those results
    and adds them to the database with three new tables
    with the suffices: '-ModPoints', 'ModParams',
    and '-descriptors'."""
    datatype = df_clean['datatype'].iloc[0]
    (cycle_ind_col, data_point_col, volt_col, curr_col, dis_cap_col,
     char_cap_col, charge_or_discharge) = col_variables(datatype)
    chargeloc_dict = {}
    param_df = pd.DataFrame(columns=[
        'Cycle', 'Model_Parameters_charge', 'Model_Parameters_discharge'
    ])
    if len(df_clean[cycle_ind_col].unique()) > 1:
        length_list = [
            len(df_clean[df_clean[cycle_ind_col] == cyc])
            for cyc in df_clean[cycle_ind_col].unique() if cyc != 1
        ]
        lenmax = max(length_list)
    else:
        length_list = 1
        lenmax = len(df_clean)

    mod_pointsdf = pd.DataFrame()
    cycles_no_models = []
    for cyc in df_clean[cycle_ind_col].unique():
        try:
            new_df_mody, model_c_vals, model_d_vals, \
                peak_heights_c, peak_heights_d = get_model_dfs(
                    df_clean, datatype, cyc, lenmax, peak_thresh)
            mod_pointsdf = mod_pointsdf.append(new_df_mody)
            param_df = param_df.append(
                {
                    'Cycle': cyc,
                    'Model_Parameters_charge': str(model_c_vals),
                    'Model_Parameters_discharge': str(model_d_vals),
                    'charge_peak_heights': str(peak_heights_c),
                    'discharge_peak_heights': str(peak_heights_d)
                },
                ignore_index=True)
        except Exception as e:
            cycles_no_models.append(cyc)
    # want this outside of for loop to update the db with the complete df of
    # new params
    update_database_newtable(mod_pointsdf,
                             filename.split('.')[0] + '-ModPoints', database)
    # this will replace the data table in there if it exists already
    update_database_newtable(param_df,
                             filename.split('.')[0] + 'ModParams', database)
    # the below also updates the database with the new descriptors after
    # evaluating the spit out dictionary and putting those parameters
    # into a nicely formatted datatable.
    param_dicts_to_df(filename.split('.')[0] + 'ModParams', database)
    if len(cycles_no_models) > 0:
        return 'That model has been added to the database.' \
            + 'No model was generated for Cycle(s) ' + str(cycles_no_models)
    return 'That model has been added to the database'
예제 #3
0
def update_slider_max(filename):
    if filename is None:
        filename = 'ExampleData'
        database_sel = init_db
    else:
        filename = filename
        database_sel = database
    data, raw_data = pop_with_db(filename, database_sel)
    datatype = data['datatype'].iloc[0]
    (cycle_ind_col, data_point_col, volt_col, curr_col, dis_cap_col,
     char_cap_col, charge_or_discharge) = col_variables(datatype)
    return data['Cycle_Index'].max()
예제 #4
0
def peak_finder(df_run, cd, windowlength, polyorder, datatype, lenmax,
                peak_thresh):
    """Determines the index of each peak in a dQdV curve
    V_series = Pandas series of voltage data
    dQdV_series = Pandas series of differential capacity data
    cd = either 'c' for charge and 'd' for discharge.

    Output:
    i = list of indexes for each found peak"""
    (cycle_ind_col, data_point_col, volt_col, curr_col, dis_cap_col,
     char_cap_col, charge_or_discharge) = col_variables(datatype)
    V_series = df_run[volt_col]
    # this makes the peak finding smoothing independent of any smoothing that
    # has already occured.
    dQdV_series = df_run['Smoothed_dQ/dV']
    sigx, sigy = cd_dataframe(V_series, dQdV_series, cd)
    # the below is to make sure the window length ends up an odd number - even
    # though we are basing it on the length of the df
    wl = lenmax / 20
    wlint = int(round(wl))
    if wlint % 2 == 0:
        windowlength_new = wlint + 1
    else:
        windowlength_new = wlint
    if len(sigy) > windowlength_new and windowlength_new > polyorder:
        # has to be larger than 69 so that windowlength > 3 - necessary for sav
        # golay function
        sigy_smooth = scipy.signal.savgol_filter(sigy, windowlength_new,
                                                 polyorder)
    else:
        sigy_smooth = sigy
    peak_thresh_ft = float(peak_thresh)
    i = peakutils.indexes(sigy_smooth,
                          thres=peak_thresh_ft,
                          min_dist=lenmax / 50)
    if i is not None and len(i) > 0:
        sigx_volts = list(sigx[i])
        peak_heights = list(sigy[i])
    else:
        sigx_volts = []
        peak_heights = []
    return i, sigx_volts, peak_heights
def pop_with_db(filename, database):
    """Returns dataframes that can be used to populate the app graphs.
    Finds the already existing file in the database and returns
    the cleaned version (as a dataframe) and the raw version
    (also as a dataframe)."""
    cleanset_name = get_filename_pref(filename) + 'CleanSet'
    rawset_name = get_filename_pref(filename) + 'Raw'
    if if_file_exists_in_db(database, filename):
        # then the file exists in the database and we can just read it
        df_clean = get_file_from_database(cleanset_name, database)
        df_raw = get_file_from_database(rawset_name, database)
        datatype = df_clean['datatype'].iloc[0]
        (cycle_ind_col, data_point_col, volt_col, curr_col, dis_cap_col,
         char_cap_col, charge_or_discharge) = col_variables(datatype)

    else:
        df_clean = None
        df_raw = None
        peakloc_dict = {}

    return df_clean, df_raw
예제 #6
0
def get_model_dfs(df_clean, datatype, cyc, lenmax, peak_thresh):
    """This is the wrapper for the model generation and fitting for the cycles.
    Returns dictionaries for the charge cycle model parameters and discharge
    cycle model parameters. These will each have at the least base gaussian
    parameter values, with the keys: 'base_amplitude', 'base_center',
    'base_fwhm', 'base_height', and 'base_sigma'. The other keys are
    dependent on whether any peaks were found in the cycle.
    """
    (cycle_ind_col, data_point_col, volt_col, curr_col, dis_cap_col,
     char_cap_col, charge_or_discharge) = col_variables(datatype)
    clean_charge, clean_discharge = sep_char_dis(
        df_clean[df_clean[cycle_ind_col] == cyc], datatype)
    windowlength = 9
    polyorder = 3

    i_charge, volts_i_ch, peak_heights_c = peak_finder(clean_charge, 'c',
                                                       windowlength, polyorder,
                                                       datatype, lenmax,
                                                       peak_thresh)

    V_series_c = clean_charge[volt_col]
    dQdV_series_c = clean_charge['Smoothed_dQ/dV']
    par_c, mod_c, indices_c = model_gen(V_series_c, dQdV_series_c, 'c',
                                        i_charge, cyc, peak_thresh)
    model_c = model_eval(V_series_c, dQdV_series_c, 'c', par_c, mod_c)
    if model_c is not None:
        mod_y_c = mod_c.eval(params=model_c.params, x=V_series_c)
        myseries_c = pd.Series(mod_y_c)
        myseries_c = myseries_c.rename('Model')
        model_c_vals = model_c.values
        new_df_mody_c = pd.concat([
            myseries_c, V_series_c, dQdV_series_c, clean_charge[cycle_ind_col]
        ],
                                  axis=1)
    else:
        mod_y_c = None
        new_df_mody_c = None
        model_c_vals = None
    # now the discharge:
    i_discharge, volts_i_dc, peak_heights_d = peak_finder(
        clean_discharge, 'd', windowlength, polyorder, datatype, lenmax,
        peak_thresh)
    V_series_d = clean_discharge[volt_col]
    dQdV_series_d = clean_discharge['Smoothed_dQ/dV']
    par_d, mod_d, indices_d = model_gen(V_series_d, dQdV_series_d, 'd',
                                        i_discharge, cyc, peak_thresh)
    model_d = model_eval(V_series_d, dQdV_series_d, 'd', par_d, mod_d)
    if model_d is not None:
        mod_y_d = mod_d.eval(params=model_d.params, x=V_series_d)
        myseries_d = pd.Series(mod_y_d)
        myseries_d = myseries_d.rename('Model')
        new_df_mody_d = pd.concat([
            -myseries_d, V_series_d, dQdV_series_d,
            clean_discharge[cycle_ind_col]
        ],
                                  axis=1)
        model_d_vals = model_d.values
    else:
        mod_y_d = None
        new_df_mody_d = None
        model_d_vals = None

    if new_df_mody_c is not None or new_df_mody_d is not None:
        new_df_mody = pd.concat([new_df_mody_c, new_df_mody_d], axis=0)
    else:
        new_df_mody = None

    return new_df_mody, model_c_vals, model_d_vals,\
        peak_heights_c, peak_heights_d
예제 #7
0
def update_figure2(filename, peak_thresh, n_clicks, show_gauss, desc_to_plot,
                   cd_to_plot, peaknum_to_plot):
    """ This is  a function to evaluate the model on a sample plot before updating the database"""
    if filename is None:
        filename = 'ExampleData'
        database_sel = init_db
    else:
        database_sel = database
    data, raw_data = pop_with_db(filename, database_sel)
    datatype = data['datatype'].iloc[0]
    (cycle_ind_col, data_point_col, volt_col, curr_col, dis_cap_col,
     char_cap_col, charge_or_discharge) = col_variables(datatype)
    selected_step = round(data[cycle_ind_col].max() / 2) + 1
    # select a cycle in the middle of the set
    dff_data = data[data[cycle_ind_col] == selected_step]
    if len(data[cycle_ind_col].unique()) > 1:
        lenmax = max([
            len(data[data[cycle_ind_col] == cyc])
            for cyc in data[cycle_ind_col].unique() if cyc != 1
        ])
    else:
        lenmax = len(data)
    dff_raw = raw_data[raw_data[cycle_ind_col] == selected_step]
    peak_vals_df = get_file_from_database(
        filename.split('.')[0] + '-descriptors', database_sel)

    fig = plotly.subplots.make_subplots(
        rows=1,
        cols=2,
        subplot_titles=('Descriptors',
                        'Example Data for Model Tuning (Cycle ' +
                        str(int(selected_step)) + ')'),
        shared_xaxes=True)
    marker = {'color': ['#0074D9']}
    if peak_vals_df is not None:
        if n_clicks is not None:
            # if the user has hit the update-model-button - remake model
            new_df_mody, model_c_vals, model_d_vals, peak_heights_c, peak_heights_d = get_model_dfs(
                dff_data, datatype, selected_step, lenmax, peak_thresh)
            dff_mod = new_df_mody
            c_sigma = model_c_vals['base_sigma']
            c_center = model_c_vals['base_center']
            c_amplitude = model_c_vals['base_amplitude']
            c_fwhm = model_c_vals['base_fwhm']
            c_height = model_c_vals['base_height']

            d_sigma = model_d_vals['base_sigma']
            d_center = model_d_vals['base_center']
            d_amplitude = model_d_vals['base_amplitude']
            d_fwhm = model_d_vals['base_fwhm']
            d_height = model_d_vals['base_height']
        else:
            # if user hasn't pushed the button, populate with original model
            # from database
            modset_name = filename.split('.')[0] + '-ModPoints'
            df_model = get_file_from_database(modset_name, database_sel)
            dff_mod = df_model[df_model[cycle_ind_col] == selected_step]

            filtpeakvals = peak_vals_df[peak_vals_df['c_cycle_number'] ==
                                        selected_step]
            filtpeakvals = filtpeakvals.reset_index(drop=True)
            # grab values for the underlying gaussian in the charge:
            try:
                c_sigma = filtpeakvals['c_gauss_sigma'].iloc[0]
                c_center = filtpeakvals['c_gauss_center'].iloc[0]
                c_amplitude = filtpeakvals['c_gauss_amplitude'].iloc[0]
                c_fwhm = filtpeakvals['c_gauss_fwhm'].iloc[0]
                c_height = filtpeakvals['c_gauss_height'].iloc[0]
            except BaseException:
                # there may not be a model
                pass
            # grab values for the underlying discharge gaussian:
            try:
                d_sigma = filtpeakvals['d_gauss_sigma'].iloc[0]
                d_center = filtpeakvals['d_gauss_center'].iloc[0]
                d_amplitude = filtpeakvals['d_gauss_amplitude'].iloc[0]
                d_fwhm = filtpeakvals['d_gauss_fwhm'].iloc[0]
                d_height = filtpeakvals['d_gauss_height'].iloc[0]
            except BaseException:
                pass

        fig.append_trace(
            {
                'x': dff_data[volt_col],
                'y': dff_data['Smoothed_dQ/dV'],
                'type': 'scatter',
                'marker': marker,
                'name': 'Smoothed Data'
            }, 1, 2)
        if len(peaknum_to_plot) > 0:
            for value in peaknum_to_plot:
                try:
                    fig.append_trace(
                        {
                            'x':
                            peak_vals_df['c_cycle_number'],
                            'y':
                            peak_vals_df[str(''.join(desc_to_plot)) +
                                         str(''.join(cd_to_plot)) + value],
                            'type':
                            'scatter',
                            'marker':
                            marker,
                            'name':
                            value
                        }, 1, 1)
                except KeyError as e:
                    None
        fig.append_trace(
            {
                'x': dff_mod[volt_col],
                'y': dff_mod['Model'],
                'type': 'scatter',
                'name': 'Model of One Cycle'
            }, 1, 2)
        # add if checkbox is selected to show polynomial baseline
        if 'show' in show_gauss:
            try:
                fig.append_trace(
                    {
                        'x':
                        dff_mod[volt_col],
                        'y': ((c_amplitude /
                               (c_sigma * ((2 * 3.14159)**0.5))) * np.exp(
                                   (-(dff_mod[volt_col] - c_center)**2) /
                                   (2 * c_sigma**2))),
                        'type':
                        'scatter',
                        'name':
                        'Charge Gaussian Baseline'  # plot the poly
                    },
                    1,
                    2)
            except BaseException:
                pass
            # add the plot of the discharge guassian:
            try:
                fig.append_trace(
                    {
                        'x':
                        dff_mod[volt_col],
                        'y':
                        -((d_amplitude /
                           (d_sigma * ((2 * 3.14159)**0.5))) * np.exp(
                               (-(dff_mod[volt_col] - d_center)**2) /
                               (2 * d_sigma**2))),
                        'type':
                        'scatter',
                        'name':
                        'Discharge Gaussian Baseline'  # plot the poly
                    },
                    1,
                    2)
            except BaseException:
                pass

    fig['layout']['showlegend'] = True
    fig['layout']['xaxis1'].update(title='Cycle Number')
    fig['layout']['xaxis2'].update(title='Voltage (V)')
    fig['layout']['yaxis1'].update(title='Descriptor Value')
    fig['layout']['yaxis2'].update(title='dQ/dV',
                                   range=[
                                       dff_data['Smoothed_dQ/dV'].min(),
                                       dff_data['Smoothed_dQ/dV'].max()
                                   ])
    fig['layout']['height'] = 600
    fig['layout']['margin'] = {'l': 40, 'r': 10, 't': 60, 'b': 200}
    return fig
예제 #8
0
def update_figure1(selected_step, filename, showmodel):
    fig = plotly.subplots.make_subplots(rows=1,
                                        cols=2,
                                        subplot_titles=('Raw Cycle',
                                                        'Smoothed Cycle'),
                                        shared_xaxes=True)
    marker = {'color': ['#0074D9']}
    if filename is None or filename == 'options':
        filename = 'ExampleData'
        database_sel = init_db
    else:
        database_sel = database
    data, raw_data = pop_with_db(filename, database_sel)
    datatype = data['datatype'].iloc[0]
    (cycle_ind_col, data_point_col, volt_col, curr_col, dis_cap_col,
     char_cap_col, charge_or_discharge) = col_variables(datatype)
    modset_name = filename.split('.')[0] + '-ModPoints'
    df_model = get_file_from_database(modset_name, database_sel)
    if df_model is not None:
        filt_mod = df_model[df_model[cycle_ind_col] == selected_step]

    if data is not None:
        filtered_data = data[data[cycle_ind_col] == selected_step]
    if raw_data is not None:
        raw_filtered_data = raw_data[raw_data[cycle_ind_col] == selected_step]

    for i in filtered_data[cycle_ind_col].unique():
        if data is not None:
            dff = filtered_data[filtered_data[cycle_ind_col] == i]
        if raw_data is not None:
            dff_raw = raw_filtered_data[raw_filtered_data[cycle_ind_col] == i]
        if df_model is not None:
            dff_mod = filt_mod[filt_mod[cycle_ind_col] == i]

        if data is not None:
            fig.append_trace(
                {
                    'x': dff[volt_col],
                    'y': dff['Smoothed_dQ/dV'],
                    'type': 'scatter',
                    'marker': marker,
                    'name': 'Smoothed Data'
                }, 1, 2)
        if raw_data is not None:
            fig.append_trace(
                {
                    'x': dff_raw[volt_col],
                    'y': dff_raw['dQ/dV'],
                    'type': 'scatter',
                    'marker': marker,
                    'name': 'Raw Data'
                }, 1, 1)
        if df_model is not None and showmodel == 'showmodel':
            fig.append_trace(
                {
                    'x': dff_mod[volt_col],
                    'y': dff_mod['Model'],
                    'type': 'scatter',
                    'name': 'Model'
                }, 1, 2)

        fig['layout']['showlegend'] = False
        fig['layout']['xaxis1'].update(title='Voltage (V)')
        fig['layout']['xaxis2'].update(title='Voltage (V)')
        fig['layout']['yaxis1'].update(title='dQ/dV')
        fig['layout']['yaxis2'].update(title='dQ/dV')
        fig['layout']['height'] = 600
        fig['layout']['margin'] = {'l': 40, 'r': 10, 't': 60, 'b': 200}
    return fig