ampworks#

Summary

ampworks is a collection of tools designed to visualize and process experimental battery data. It provides routines for degradation mode analysis, parameter extraction from common protocols (e.g., GITT, ICI, etc.), and more. These routines provide key properties for life and physics-based models (e.g., SPM and P2D). Graphical user interfaces (GUIs) are available for some of the analyses. See a list of the GUI-based applications by running ampworks -h in your terminal after installation.

Note: ampworks is in early development. The API may change as it matures.

Accessing the Documentation

Documentation is accessible via Python’s help() function which prints docstrings from a package, module, function, class, etc. You can also access the documentation by visiting the website, hosted on Read the Docs. The website includes search functionality and more detailed examples.

Submodules#

Classes#

CycleLabel

Readable label for cycles.

Dataset

General dataset.

HeaderAliases

Header alias definitions.

LabelSet

A set of step, cycle, and section labels.

SectionLabel

Readable label for sections.

StepLabel

Readable label for a single step.

Functions#

apply_labels(data, labels)

Apply labels to a dataset.

read_csv(filepath[, aliases, extra_columns])

Read a csv file.

read_excel(filepath[, sheet_name, stack_sheets, ...])

Read an Excel file.

read_table(filepath[, aliases, extra_columns])

Read a tab-delimited file.

standardize_headers(data[, aliases, extra_columns])

Map source columns to ampworks standards.

Package Contents#

class ampworks.CycleLabel(label, *, steps=None, cycles=None)[source]#

Readable label for cycles.

Parameters:
  • label (str) – The label to apply for the cycle.

  • steps (Sequence[int] or None, optional) – The step numbers that define the cycle. Defaults to None. Must be provided if cycles is not.

  • cycles (Sequence[int] or None, optional) – The cycle numbers that define the cycle. Defaults to None. Must be provided if steps is not.

Raises:
  • TypeError – If the label is not a string or if steps or cycles is not a sequence of integers.

  • ValueError – If both steps and cycles are None, or if both are not None.

Notes

Either steps or cycles must be provided, but not both. If steps is provided, the label will be applied to all cycles that contain those steps. Otherwise, if cycles is provided, the label will be applied to those cycles.

Examples

The following demonstrates how to create cycle labels for a dataset. The inputs must be a string label and either a sequence of step numbers or a sequence of cycle numbers. Each label can only be defined using either steps or cycles, not both. However, when applying the labels, there are no restrictions on mixing cycle labels defined using both methods. Also, you can use a range object to define your sequence if more convenient, so there is no need to explicitly list all step or cycle numbers.

>>> from ampworks import CycleLabel
>>> cycle1 = CycleLabel('HPPC', steps=range(1, 9))
>>> cycle2 = CycleLabel('Aging Cycle', cycles=[1, 2, 3, 4, 5])
class ampworks.Dataset(data=None, index=None, columns=None, dtype=None, copy=None)[source]#

General dataset.

downsample(*, n=None, frac=None, resolution=None, inplace=False, ignore_index=False, keep_last=False)[source]#

Downsample the dataset by eliminating rows given:

  • number of rows

  • fraction of rows

  • resolution of a specified column

Parameters:
  • n (int, optional) – Number of evenly spaced rows to keep, by default None.

  • frac (float, optional) – Fraction (in (0, 1]) of evenly spaced rows to keep, by default None.

  • resolution (tuple[str, float], optional) – Column (str) and resolution (float) to use for downsampling based on the absolute difference between adjacent values. By default None.

  • inplace (bool, optional) – Modify in place if True. If False (default), return a new Dataset.

  • ignore_index (bool, optional) – If True, reset the indices. Default is False.

  • keep_last (bool, optional) – If True, always keep the last row. Default is False.

Returns:

data (Dataset or None) – The downsampled Dataset if ‘inplace’ is False. Otherwise, None.

Raises:

ValueError – If more than one of n, frac, resolution is specified, or if they are all None. Also, if n is not positive or frac is not in (0, 1].

Examples

The following demonstrates three ways to downsample a dataset. Note that only the resolution option requires a column to operate on.

import ampworks as amp

data = amp.datasets.load_datasets('dqdv/cell1_rough')

# keep 100 evenly spaced rows
sample1 = data.downsample(n=100)

# keep 50% of the data, dropping evenly spaced rows
sample2 = data.downsample(frac=0.5)

# ensure adjacent voltage readings are at least 1 mV apart
sample3 = data.downsample(resolution=('Volts', 1e-3))
enforce_monotonic(column, increasing=True, strict=False, inplace=False, ignore_index=False)[source]#

Enforce monotonicity in a column by dropping rows that break the trend.

Parameters:
  • column (str) – Column name to enforce monotonicity on.

  • increasing (bool, optional) – If True (default), enforce increasing monotonicity. Otherwise, apply decreasing monotonicity.

  • strict (bool, optional) – If True, enforce strict monotonicity (no equal adjacent values). The default is False, which allows equal adjacent values.

  • inplace (bool, optional) – Modify in place if True. If False (default), return a new Dataset.

  • ignore_index (bool, optional) – If True, reset the indices. Default is False.

Returns:

data (Dataset or None) – The modified Dataset if ‘inplace’ is False. Otherwise, None.

interactive_bokeh(x, y, *, tips=None, figsize=(800, 450), kind='line', save=None)[source]#

Create an interactive bokeh figure with hover tips. Optionally save as a standalone HTML file, viewable without installing Python/ampworks.

Parameters:
  • x (str) – Column name for the variable to plot on the x-axis.

  • y (str) – Column name for the variable to plot on the y-axis.

  • tips (list[str] or None, optional) – List of column names to display as hover tips, by default None.

  • figsize (tuple[int | None, int | None], optional) – Figure size (width, height) in pixels, by default (800, 450). Set either or both dimensions to None to allow them to stretch.

  • kind ({'line', 'scatter', 'both'}, optional) – Type of plot to create. ‘line’ (default) for a line plot, ‘scatter’ for a scatter plot, or ‘both’ to show both a line and markers.

  • save (str, optional) – File path to save the plot as an HTML file, by default None.

See also

interactive_plotly

Interactive plots using plotly. Typically has lower performance for large (>250k) datasets, but is compatible with dash apps.

Notes

The responsive height size option is limited in notebook environments since output cells do not have adjustable heights. In these cases, the height is set to a default minimum value.

Examples

The following creates an interactive plot of an HPPC discharge dataset. Note that the x, y, and tips values must be existing columns; however, you can compute or add new columns before plotting, if needed, as shown by adding an ‘Hours’ column in the second figure below. Also, hovertips must be passed as a list, even if only one column is requested.

import ampworks as amp

data = amp.datasets.load_datasets('hppc/hppc_discharge')
data.interactive_bokeh('Seconds', 'Volts', tips=['Step'])

# Add new column to plot time in hours instead of seconds
data['Hours'] = data['Seconds'] / 3600
data.interactive_bokeh('Hours', 'Volts', tips=['Step', 'Amps'])
interactive_plotly(x, y, *, tips=None, figsize=(800, 450), kind='line', save=None)[source]#

Create an interactive plotly figure with hover tips. Optionally save as a standalone HTML file, viewable without installing Python/ampworks.

Parameters:
  • x (str) – Column name for the variable to plot on the x-axis.

  • y (str) – Column name for the variable to plot on the y-axis.

  • tips (list[str] or None, optional) – List of column names to display as hover tips, by default None.

  • figsize (tuple[int | None, int | None], optional) – Figure size (width, height) in pixels, by default (800, 450). Set either or both dimensions to None to allow them to stretch.

  • kind ({'line', 'scatter', 'both'}, optional) – Kind of plot to draw. ‘line’ (default) for a line plot, ‘scatter’ for a scatter plot, or ‘both’ to show both a line and markers.

  • save (str, optional) – File path to save the plot as an HTML file, by default None.

See also

interactive_bokeh

Interactive plots using bokeh. Typically has higher performance for large (>250k) datasets and better support for notebook exports.

Notes

The responsive height size option is limited in notebook environments since output cells do not have adjustable heights. In these cases, the height is set to a default minimum value.

Examples

The following creates an interactive plot of an HPPC discharge dataset. Note that the x, y, and tips values must be existing columns; however, you can compute or add new columns before plotting, if needed, as shown by adding an ‘Hours’ column in the second figure below. Also, hovertips must be passed as a list, even if only one column is requested.

import ampworks as amp

data = amp.datasets.load_datasets('hppc/hppc_discharge')
data.interactive_plotly('Seconds', 'Volts', tips=['Step'])

# Add new column to plot time in hours instead of seconds
data['Hours'] = data['Seconds'] / 3600
data.interactive_plotly('Hours', 'Volts', tips=['Step', 'Amps'])
zero_below(column, threshold, inplace=False)[source]#

Set values in ‘column’ below ‘threshold’ to zero.

Parameters:
  • column (str) – Column name to apply thresholding.

  • threshold (float) – Values whose absolute value is below this threshold are set to zero. Note that values equal to the threshold are not zeroed.

  • inplace (bool, optional) – Modify in place if True. If False (default), return a new Dataset.

Returns:

data (Dataset or None) – The modified Dataset if ‘inplace’ is False. Otherwise, None.

Examples

Small non-zero values that can be attributed to noise can interfere with some analysis methods. For example, automatic pulse detection identifies pulses based on transitions from zero to non-zero current. This example filters out currents below 1% of the mean non-rest current, though the thresholds should be tailored to your specific use case and data.

import ampworks as amp

# zero out currents below a threshold from non-rest data
data = amp.datasets.load_datasets('hppc/hppc_discharge')
threshold = data.loc[data['State'] != 'R', 'Amps'].mean()*1e-2

data_zeroed = data.zero_below(column='Amps', threshold=threshold)
zero_time(inplace=False)[source]#

Shifts the Seconds column by subtracting the first row’s value to set a new zero reference.

Parameters:

inplace (bool, optional) – Modify in place if True. If False (default), return a new Dataset.

Returns:

data (Dataset | None) – The modified Dataset if ‘inplace’ is False. Otherwise, None.

Notes

This method does not sort by time, nor does it use the minimum time when subtracting. It simply shifts the time values so that the first row has a time of zero, regardless of the actual order of time values. Consider sorting by time first, if needed, using data.sort_values('Seconds').

class ampworks.HeaderAliases(*, Seconds=None, Amps=None, Volts=None, Cycle=None, Step=None, State=None, Ah=None, Wh=None, DateTime=None)[source]#

Header alias definitions.

A container that allows users to specify custom header aliases for their data. These are used to automatically find and standardize columns when loading data. ampworks uses default aliases for any headers that are not provided here.

Parameters:
  • Seconds (str or list[str] or None, optional) – Aliases for the standardized Seconds column.

  • Amps (str or list[str] or None, optional) – Aliases for the standardized Amps column.

  • Volts (str or list[str] or None, optional) – Aliases for the standardized Volts column.

  • Cycle (str or list[str] or None, optional) – Aliases for the standardized Cycle column.

  • Step (str or list[str] or None, optional) – Aliases for the standardized Step column.

  • State (str or list[str] or None, optional) – Aliases for the standardized State column.

  • Ah (str or list[str] or None, optional) – Aliases for the standardized Ah column.

  • Wh (str or list[str] or None, optional) – Aliases for the standardized Wh column.

  • DateTime (str or list[str] or None, optional) – Aliases for the standardized DateTime column.

Examples

The following example shows how to use HeaderAliases to specify custom aliases. Any inputs that are skipped will use a list of defaults. Note that you can provide a single alias or many for each standard header. Be aware that all parameters must be provided as keywords to avoid improper ordering.

>>> import ampworks as amp
>>> aliases = amp.HeaderAliases(
...     Seconds='elapsed_s',
...     Amps=['current_amps', 'current_a'],
... )
items()[source]#

Iterate over (std_header, aliases) pairs.

keys()[source]#

Return standardized header names supported by the alias set.

class ampworks.LabelSet(*, step_labels=None, cycle_labels=None, section_labels=None)[source]#

A set of step, cycle, and section labels.

Parameters:
  • step_labels (Sequence[StepLabel] or None, optional) – The step labels for a given dataset. Defaults to None.

  • cycle_labels (Sequence[CycleLabel] or None, optional) – The cycle labels for a given dataset. Defaults to None.

  • section_labels (Sequence[SectionLabel] or None, optional) – The section labels for a given dataset. Defaults to None.

Raises:

TypeError – If any of the label inputs are not sequences of the appropriate label type, e.g. if step_labels is not a sequence of StepLabel.

class ampworks.SectionLabel(label, *, steps=None, cycles=None)[source]#

Readable label for sections.

Parameters:
  • label (str) – The label to apply for the section.

  • steps (Sequence[int] or None, optional) – The step numbers that define the section. Defaults to None. Must be provided if cycles is not.

  • cycles (Sequence[int] or None, optional) – The cycle numbers that define the section. Defaults to None. Must be provided if steps is not.

Raises:
  • TypeError – If the label is not a string or if steps or cycles is not a sequence of integers.

  • ValueError – If both steps and cycles are None, or if both are not None.

Notes

Either steps or cycles must be provided, but not both. If steps is provided, the label will be applied to all cycles that contain those steps. Otherwise, if cycles is provided, the label will be applied to those cycles.

Examples

The following demonstrates how to create section labels for a dataset. A section label is intended to be one level of abstraction higher than a cycle label.

The inputs must be a string label and either a sequence of step numbers or a sequence of cycle numbers. Each label can only be defined using either steps or cycles, not both. However, when applying the labels, there are no restrictions on mixing section labels defined using both methods. Also, you can use a range object to define your sequence if more convenient, so there is no need to list all step or cycle numbers.

>>> from ampworks import SectionLabel
>>> section1 = SectionLabel('RPT1', cycles=[1, 2, 3])
>>> section2 = SectionLabel('RPT2', cycles=range(100, 104))
class ampworks.StepLabel(label, step)[source]#

Readable label for a single step.

Parameters:
  • label (str) – The label to apply for the step, defined by the ‘step’ argument.

  • step (int) – The step number to which the label will be applied.

Raises:

TypeError – If label is not a string or if step is not an integer.

Examples

The following demonstrates how to create step labels for a dataset. The inputs must be a string label and an integer step number. The label can be as simple or descriptive as desired.

>>> from ampworks import StepLabel
>>> step1 = StepLabel('Initial Rest', 1)
>>> step2 = StepLabel('1C CC Charge until 4.2V', 2)
>>> step3 = StepLabel('CV Charge at 4.2V', 3)
>>> step4 = StepLabel('Final Rest', 4)
ampworks.apply_labels(data, labels)[source]#

Apply labels to a dataset.

Parameters:
  • data (Dataset) – The dataset to which labels will be applied.

  • labels (LabelSet) – The set of step, cycle, and section labels to apply.

Returns:

labeled (Dataset) – A new dataset with the applied labels.

Raises:
  • TypeError – If data is not a Dataset or if labels is not a LabelSet.

  • ValueError – If data does not contain the required ‘Cycle’ and ‘Step’ columns.

See also

Dataset.interactive_plotly

Interactively inspect the labeled dataset with plotly hover tips.

Dataset.interactive_bokeh

Same using bokeh; better suited for large datasets.

Notes

Any cycles or steps that are not labeled will have a label of 'None' in the resulting CycleLabel and StepLabel columns. Also, if a step is given in more than one cycle, the last cycle label will be applied. Similarly, if a step is given more than one step label, only the last step label will be applied to that step.

Examples

The following demonstrates how to apply labels to an HPPC dataset from the ampworks.datasets module. First, we create the labels and them apply them to the dataset. The final line of code plots the resulting dataset with some hover hints so the applied labels can be viewed and checked for accuracy.

import ampworks as amp

# Load in an example dataset
data = amp.datasets.load_datasets('hppc/hppc_discharge')

# Create the labels
labels = amp.LabelSet(
    step_labels=[
        amp.StepLabel('Initial Rest', 1),
        amp.StepLabel('C/3 Discharge', 2),
        amp.StepLabel('Equilibrium Rest', 3),
        amp.StepLabel('1C Discharge Pulse', 4),
        amp.StepLabel('40s Rest', 5),
        amp.StepLabel('0.75C Charge Pulse', 6),
        amp.StepLabel('40s Rest', 7),
        amp.StepLabel('Final Rest', 8),
    ],
    cycle_labels=[
        amp.CycleLabel('HPPC', steps=range(1, 9)),
    ],
)

# Apply the labels
labeled = amp.apply_labels(all_data, labels)

# Add an hours column and plot with the labels as hover tips
labeled['Hours'] = labeled['Seconds'] / 3600

labeled.interactive_plotly(
    x='Hours', y='Volts', tips=['StepLabel', 'CycleLabel'],
)
ampworks.read_csv(filepath, aliases=None, extra_columns=None)[source]#

Read a csv file.

Custom reading function for comma-separated values (CSV) files. Scans the file to identify expected headers (see Notes for specifics). This routine is not specific to any particular cycler. Instead, it uses default internal or user-defined aliases to find and standardize the headers, columns, and data types.

Parameters:
  • filepath (PathLike) – Path to the file, including extension.

  • aliases (HeaderAliases or None, optional) – Column alias mapping for the header standardization. If None (default), a set of internal default aliases is used.

  • extra_columns (dict[str, type or None] or None, optional) – Additional columns to include in the standardized dataset. Include both the exact source column names and their corresponding data types in a dictionary. Use value None to keep pandas-inferred dtype. The type is also compatible with pandas dtypes, e.g., 'string', 'Int64', etc.

Returns:

data (Dataset) – Standardized battery dataset.

Warning

UserWarning

If extra_columns are not found in the source data or conflict with any of the standardized headers. Also, if no valid headers are found and an empty dataset is returned.

See also

HeaderAliases

Custom column mapping for standardization.

Notes

By default, only aliases of Seconds, Amps, Volts, Cycle, Step, State, Ah, Wh, and DateTime are included. If you’d like to ensure that additional data columns are included, use the extra_columns parameter.

Examples

The following example shows how to read in data from a .csv file using a few of the available options.

import ampworks as amp

# read in the file using all default options
data = amp.read_csv('data.csv')

# specify custom aliases for a couple column headers
aliases = amp.HeaderAliases(Seconds='Time_s', Amps='Current_A')
data = amp.read_csv('data.csv', aliases=aliases)

# include extra columns for temperature and notes
extra_cols = {'Temperature': float, 'Notes': None}
data = amp.read_csv('data.csv', extra_columns=extra_cols)
ampworks.read_excel(filepath, sheet_name=None, stack_sheets=False, aliases=None, extra_columns=None)[source]#

Read an Excel file.

Custom reading function for Excel files. Scans all (or some) of the sheets to identify expected headers (see Notes for specifics). This routine is not specific to any particular cycler. Instead, it uses internal or user-defined aliases to find and standardize the headers, columns, and data types.

Parameters:
  • filepath (PathLike) – Path to the file, including extension.

  • sheet_name (str or int or Sequence[str or int] or None, optional) – Name or index of the sheet(s) to read. For integers, use natural indices from 1 to the number of sheets. None (default) will scan for the first sheet with valid headers. Use 'all' to read all sheets.

  • stack_sheets (bool, optional) – If True, concatenate all parsed sheets into one dataset.

  • aliases (HeaderAliases or None, optional) – Column alias mapping for the header standardization. If None (default), a set of internal default aliases is used.

  • extra_columns (dict[str, type or None] or None, optional) – Extra source columns to preserve using exact source names as keys. The values define cast type. Use None to keep inferred dtype. Both Python types and pandas dtypes are accepted, e.g., 'string', 'Int64', etc.

Returns:

data (Dataset or dict[str or int, Dataset]) – Standardized dataset output. A dictionary is returned if multiple sheets are read and stack_sheets is False.

Raises:

ValueError – If the parameter (or any of the elements in) sheet_name are invalid names or indices.

Warning

UserWarning

If extra_columns are not found in the source data or conflict with any of the standardized headers. Also, if no valid headers are found and an empty dataset is returned.

See also

HeaderAliases

Custom column mapping for standardization.

Notes

By default, only aliases of Seconds, Amps, Volts, Cycle, Step, State, Ah, Wh, and DateTime are included. If you’d like to ensure that additional data columns are included, use the extra_columns parameter.

Examples

The following example shows how to read in data from an Excel file using a few of the available options. Note that the examples demonstrate different extensions that are both types of Excel files.

import ampworks as amp

# read in the file using all default options
data = amp.read_excel('data.xls')

# specify custom aliases for a couple column headers
aliases = amp.HeaderAliases(Seconds='Time_s', Amps='Current_A')
data = amp.read_excel('data.xls', aliases=aliases)

# include extra columns for temperature and notes
extra_cols = {'Temperature': float, 'Notes': None}
data = amp.read_excel('data.xls', extra_columns=extra_cols)

# specify the second sheet and a sheet named 'last'
data = amp.read_excel('data.xlsx', sheet_name=[2, 'last'])

# read in all sheets and concatenate the results
data = amp.read_excel('data.xlsx', sheet_name='all', stack_sheets=True)
ampworks.read_table(filepath, aliases=None, extra_columns=None)[source]#

Read a tab-delimited file.

Custom reading function for tab-delimited files. Scans the file to identify expected headers (see Notes for specifics). This routine is not specific to any particular cycler. Instead, it uses internal or user-defined aliases to find and standardize the headers, columns, and data types.

Parameters:
  • filepath (PathLike) – Path to the file, including extension.

  • aliases (HeaderAliases or None, optional) – Column alias mapping for the header standardization. If None (default), a set of internal default aliases is used.

  • extra_columns (dict[str, type or None] or None, optional) – Extra source columns to preserve using exact source names as keys. The values define cast type. Use None to keep inferred dtype. Both Python types and pandas dtypes are accepted, e.g., 'string', 'Int64', etc.

Returns:

data (Dataset) – Standardized battery dataset.

Warning

UserWarning

If extra_columns are not found in the source data or conflict with any of the standardized headers. Also, if no valid headers are found and an empty dataset is returned.

See also

HeaderAliases

Custom column mapping for standardization.

Notes

By default, only aliases of Seconds, Amps, Volts, Cycle, Step, State, Ah, Wh, and DateTime are included. If you’d like to ensure that additional data columns are included, use the extra_columns parameter.

Examples

The following example shows how to read in data from a .txt file using a few of the available options.

import ampworks as amp

# read in the file using all default options
data = amp.read_table('data.txt')

# specify custom aliases for a couple column headers
aliases = amp.HeaderAliases(Seconds='Time_s', Amps='Current_A')
data = amp.read_table('data.txt', aliases=aliases)

# include extra columns for temperature and notes
extra_cols = {'Temperature': float, 'Notes': None}
data = amp.read_table('data.txt', extra_columns=extra_cols)
ampworks.standardize_headers(data, aliases=None, extra_columns=None)[source]#

Map source columns to ampworks standards.

Parameters:
  • data (pandas.DataFrame) – Source data frame with raw cycler headers.

  • aliases (HeaderAliases or None, optional) – Alias mapping used to identify standardized columns. If None, defaults are used.

  • extra_columns (dict[str, type or None] or None, optional) – Extra source columns to keep in output using exact source names as keys. Values define cast type. Use None to keep inferred dtype.

Returns:

data (Dataset) – Standardized dataset.

Warning

UserWarning

Raised when standardized aliases are missing, requested extra columns are not found, or requested extra columns conflict with standardized output columns.