示例#1
0
def column_check(infile, col_name, verbose=False):
    """
    Given a cleaned Novonix data file,
    check if the col_name column exists.

    Parameters
    -----------
    infile : string
        Name of the input Novonix file

    col_name : string
        Name of the column

    verbose : boolean
        True to print information out.

    Returns
    -------
    column_exists : boolean
        True when the column name has been found in the header

    Examples
    ---------
    >>> import preparenovonix.novonix_variables as nv
    >>> import preparenovonix.novonix_add as prep
    >>> prep.column_check('example_data/example_data_prep.csv',nv.col_step)
    True
    """

    icol = icolumn(infile, col_name)
    if icol > -1:
        if verbose:
            print("The file already has the column {}".format(col_name))
        return True
    else:
        return False
示例#2
0
def plot_vct(before_file, first_loop=0, plot_type="pdf", plot_show=False):
    """
    Given two Novonix data files, pre and post-processing
    with preparenovonix, plot toghether their 
    Voltage, Capacity, Step Number and Loop number versus time

    Parameters
    -----------
    before_file : string
        Name of the pre-processed file

    first_loop : int
        Value for the Loop Number to start showing data

    plot_type : string
        'pdf', 'png', 'jpg' for the format of the saved file

    plot_show : boolean
        True to show the plot.

    Notes
    -----
    This code returns a plot.

    Examples
    ---------
    >>> from preparenovonix.compare import plot_vct
    >>> plot_vct('example_data/example_data.csv','example_data/example_data_prep.csv',first_loop=0,plot_type='pdf',plot_show=True)
    """

    after_file = after_file_name(before_file)
    dirname, fname = os.path.split(os.path.abspath(after_file))
    figname = os.path.join(dirname, "compare_vct." + plot_type)

    # Value of the loop to start the plot from
    val = first_loop

    ### Read the voltage, step number and loop number from
    # the processed file

    a_t = read_column(after_file, nv.col_t, outtype="float")
    a_v = read_column(after_file, nv.col_v, outtype="float")
    a_c = read_column(after_file, nv.col_c, outtype="float")
    a_s = read_column(after_file, nv.col_step, outtype="int")
    a_l = read_column(after_file, nv.loop_col, outtype="int")
    a_p = read_column(after_file, nv.line_col, outtype="int")

    # Find the column positions in the file
    icol_t = icolumn(after_file, nv.col_t)
    icol_v = icolumn(after_file, nv.col_v)
    icol_c = icolumn(after_file, nv.col_c)
    icol_step = icolumn(after_file, nv.col_step)

    ### Read the voltage and step number from the original file
    # Since there are failed tests, these need to be jumped
    data = "[Data]"
    ntests = 0  # Count the number of failed tests
    with open(before_file, "r") as ff:
        for line in ff:
            if line.strip():  # Jump empty lines
                if data in line:
                    # Count failed tests for each start of file
                    ntests += 1
                    idata = 0

    vv = []
    ss = []
    tt = []
    cc = []
    with open(before_file, "r") as ff:
        for line in ff:
            if line.strip():  # Jump empty lines
                if data in line:
                    # Count failed tests for each start of file
                    idata += 1
                    if idata == ntests:
                        # Read the header
                        ff.readline()
                        break
        for line in ff:
            tt.append(line.split(",")[icol_t])
            vv.append(line.split(",")[icol_v])
            cc.append(line.split(",")[icol_c])
            ss.append(line.split(",")[icol_step])

    b_t = np.asarray(tt, dtype=np.float64)
    b_v = np.asarray(vv, dtype=np.float64)
    b_c = np.asarray(cc, dtype=np.float64)
    b_s = np.asarray(ss, dtype=int)

    # Plot
    cols = ["navy", "salmon", "cornflowerblue", "darkred"]
    plt.figure(figsize=(8.0, 11.0))
    gs = gridspec.GridSpec(4, 1)
    gs.update(wspace=0.0, hspace=0.0)
    fs = 15

    # Plot only when the loop starts to be biggeer than val
    ind = np.where(a_l > val)
    if np.shape(ind)[1] < 1:
        print("WARNING compare.plot_vct: not enough data to be plotted")
        return

    astart = ind[0][0]
    first_a_t = a_t[astart]
    ind = np.where(b_t >= first_a_t)
    bstart = ind[0][0]

    # Loop number
    axl = plt.subplot(gs[3, :])
    axl.set_xlabel(nv.col_t, fontsize=fs)
    axl.set_ylabel(nv.loop_col, fontsize=fs, color=cols[0])

    axl.plot(a_t[astart::], a_l[astart::], cols[0], linewidth=2.5, label="Loop number")

    axp = axl.twinx()
    axp.set_ylabel("Protocol line", fontsize=fs, color=cols[2])
    axp.plot(
        a_t[astart::], a_p[astart::], cols[2], linewidth=2.5, label="Protocol line"
    )

    # Steps
    axs = plt.subplot(gs[2, :], sharex=axl)
    plt.setp(axs.get_xticklabels(), visible=False)
    axs.set_ylabel(nv.col_step, fontsize=fs)

    axs.plot(a_t[astart::], a_s[astart::], cols[0], linewidth=2.5, label="After")
    axs.plot(b_t[bstart::], b_s[bstart::], cols[1], linestyle="--", label="Before")

    # Voltage and capacity vs. time
    axv = plt.subplot(gs[:-2, :], sharex=axl)
    plt.setp(axv.get_xticklabels(), visible=False)
    axv.set_ylabel(nv.col_v, fontsize=fs)

    axv.plot(
        a_t[astart::], a_v[astart::], cols[0], linewidth=2.5, label="Potential after"
    )
    axv.plot(
        b_t[bstart::], b_v[bstart::], cols[1], linestyle="--", label="Potential before"
    )

    leg = axv.legend(loc=2, fontsize=fs - 2)
    ii = 0
    for text in leg.get_texts():
        text.set_color(cols[ii])
        ii += 1
    leg.draw_frame(False)

    axc = axv.twinx()
    axc.set_ylabel(nv.col_c, fontsize=fs)
    axc.plot(
        a_t[astart::], a_c[astart::], cols[2], linewidth=2.5, label="Capacity after"
    )
    axc.plot(
        b_t[bstart::], b_c[bstart::], cols[3], linestyle="--", label="Capacity before"
    )

    leg = axc.legend(loc=4, fontsize=fs - 2)
    ii = 2
    for text in leg.get_texts():
        text.set_color(cols[ii])
        ii += 1
    leg.draw_frame(False)

    plt.savefig(figname)

    if plot_show:
        plt.show()

    print("Plot: {}".format(figname))
示例#3
0
def novonix_add_state(infile, verbose=False):
    """
    Given a cleaned Novonix data file, it adds a 'State' column,
    which mimimcs Basytec format with:

    0 = Start of a measurement type (charge/discharge, etc)
    1 = Regular data point (measuring, no mode change)
    2 = End of cycle (last point of the measurement)

    This values are determined by the change in the 'Step Number' from Novonix
    and the 'Step time', which goes to 0 with each new 'Step'.

    Parameters
    -----------
    infile : string
        Name of the input Novonix file

    verbose : boolean
        Yes : print out some informative statements

    Notes
    -----
    This code returns a Novonix file with an extra 'State' column.

    Examples
    ---------
    >>> import preparenovonix.novonix_add as prep
    >>> prep.novonix_add_state('example_data/example_data_prep.csv',verbose=True)
    The file example_data/example_data_prep.csv already has a State column
    """

    # Check if the State column already exists
    col_exists = column_check(infile, nv.state_col, verbose=verbose)
    if col_exists:
        return

    # Find the Step Number column
    icol = icolumn(infile, nv.col_step)
    icolt = icolumn(infile, nv.col_tstep)

    # Read the input file
    header = []
    fw = "fw"
    with open(infile, "r") as ff:
        # Read until the line with [Data]
        for line in ff:
            header.append(line)
            fw = line.rsplit()
            if fw[0] == "[Data]":
                break

        # Read the column names and add the 'State' one
        line = ff.readline()
        new_head = str(line.rstrip()) + ", " + nv.state_col + " \n"
        header.append(new_head)

        # Create a temporary file with the new header
        tmp_file = "tmp.csv"
        ihead = 0
        with open(tmp_file, "w") as tf:
            for item in header:
                tf.write(str(item))
                ihead += 1

        # The State column
        state = []
        data = []
        last_step = -99  # Create a starting last state value
        last_t = 99.0  # Create a starting step time value
        steps = []
        # Read the data adding values to the state
        for il, line in enumerate(ff):
            data.append(line)
            step = line.split(",")[icol]
            steps.append(step)
            stime = float(line.split(",")[icolt])
            if step == last_step and stime > last_t:
                state.append(1)
            else:
                state.append(0)

                # Change the previous value
                if len(state) > 1:
                    if state[-2] == 0:
                        if last_t < nv.eps:
                            # Single measurement
                            state[-2] = -1
                        else:
                            # Jump lines affected by software bug and
                            # 2 single measurements in a row
                            # (this can happen when current overshoots)
                            state[-2] = -99
                            if verbose:
                                # Line count starts with 1, thus (il+1)
                                print(
                                    "WARNING line=",
                                    str(il + ihead),
                                    ", last step time=" + str(last_t),
                                    ": Measurement to be nv.ignored",
                                )
                            if state[-3] == -1:
                                # Avoid 2 single measurements in a row
                                state[-3] = -99
                                if verbose:
                                    print(
                                        "WARNING Measurement to be nv.ignored: line=",
                                        str(il - 1 + ihead),
                                        ", last step time=" + str(last_t),
                                    )

                    elif state[-2] == 1:
                        state[-2] = 2
                    else:
                        sys.exit("STOP function novonix_add_state \n" +
                                 "REASON unexpected state \n" + "      " +
                                 str(infile) + " \n")
            last_step = step
            last_t = stime
        state[-1] = 2

        # Check the new column
        check_pass = state_check(state)
        if not check_pass:
            sys.exit("STOP novonix_add.novonix_add_state \n" + str(infile) +
                     " \n")

        # Write the new data to the temporary file
        with open(tmp_file, "a") as tf:
            ii = 0
            for idata in data:
                if state[ii] > -99:
                    new_line = str(idata.rstrip()) + "," + str(
                        state[ii]) + "\n"
                    tf.write(new_line)
                ii += 1

        # Replace the input file by the tmp_file,
        # which should be bigger.
        replace_file(tmp_file, infile, newbigger=True)

        if verbose:
            print("{} contains now a State column".format(infile))
    return
示例#4
0
def test_icolumn():
    assert prep.icolumn(exfile_prep, nv.col_step) > -1
    assert prep.icolumn(exfile_prep, nv.col_tstep) > -1
    assert prep.icolumn(exfile_prep, "Random name") == -1
示例#5
0
def cleannovonix(infile):
    """
    Given a Novonix file remove blank lines, correct the header,
    remove failed tests if needed.

    Parameters
    -----------
    infile : string
        Name of the input Novonix file

    Notes
    -----
    This code returns a cleaned Novonix file

    Examples
    ---------
    >>> from preparenovonix.novonix_clean import cleannovonix
    >>> cleannovonix('example_data/example_data.csv')
    """

    # Count the number of tests
    ntests = count_tests(infile)

    # Find the capacity colum
    icapacity = icolumn(infile, nv.col_c)
    # Find the run time column
    iruntime = icolumn(infile, nv.col_t)

    # Deal with the capacity of the failed tests
    last_capacity = capacity_failed_tests(icapacity, ntests, infile)

    # Start reading the last test
    # Remove blank lines if present in the header
    itest = 0
    header = []
    with open(infile, "r") as ff:
        for line in ff:
            if line.strip():
                if summary in line:
                    itest += 1
                    if itest == ntests:
                        header.append(summary + " \n")
                        break

        # Read until the line with [Data]
        for line in ff:
            if line.strip():
                char1 = line.strip()[0]
                if char1 == "[":
                    cleanhead = line.split("]")
                    header.append(cleanhead[0] + "] \n")
                    if cleanhead[0] == "[Data":
                        break
                else:
                    header.append(line)

        # From the data header, read the column names
        for line in ff:
            if line.strip():
                break

        # Check that the number of data columns matches the header
        line_data1 = ff.readline()
        data = line_data1.split(",")
        header_data_columns(line, data, header)

        # Create a temporary file without blanck lines
        # and new header if needed
        tmp_file = "tmp.csv"
        with open(tmp_file, "w") as tf:
            for item in header:
                tf.write(str(item))

        # Append the data jumping any line with time going backwards
        with open(tmp_file, "a") as tf:
            # Write the first data row
            if ntests > 1:
                # Modify the Capacity column in case of failed tests
                new_capacity = float(data[icapacity]) + float(last_capacity)
                data[icapacity] = str(new_capacity)

                new_line = data[0]
                for col in data[1:]:
                    new_line = new_line + "," + col
                tf.write(new_line)
            else:
                tf.write(line_data1)

            # Write the rest of the data
            last_t = -1.0
            for line in ff:
                columns = line.split(",")
                if float(columns[iruntime]) < last_t:
                    continue
                last_t = float(columns[iruntime])

                if ntests > 1:
                    # Modify the Capacity column in case of failed tests
                    new_capacity = float(
                        columns[icapacity]) + float(last_capacity)
                    columns[icapacity] = str(new_capacity)

                    new_line = columns[0]
                    for col in columns[1:]:
                        new_line = new_line + "," + col
                    tf.write(new_line)
                else:
                    tf.write(line)

        # Replace the input file with the new one
        replace_file(tmp_file, infile, newbigger=False)
    return