diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml new file mode 100644 index 0000000..09bc9a9 --- /dev/null +++ b/.github/workflows/codecov.yml @@ -0,0 +1,52 @@ +name: codecov + +on: + push: + paths-ignore: + - "*.md" + - "LICENSE" + - "docs/**" + - "images/**" + - ".github/ISSUE_TEMPLATE/**" + + pull_request: + branches: [main] + paths-ignore: + - "*.md" + - "LICENSE" + - "docs/**" + - "images/**" + - ".github/ISSUE_TEMPLATE/**" + +jobs: + tests: + name: Collect and upload coverage + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.14" + + - name: Install ampworks + run: | + python -m pip install --upgrade pip + pip install .[tests] + + - name: Pytest with coverage + run: pytest --cov=ampworks --cov-report=xml tests/ + + - name: Upload to codecov + uses: codecov/codecov-action@v5 + with: + token: ${{ secrets.CODECOV_TOKEN }} + verbose: true + flags: unittests + env_vars: OS,PYTHON + files: ./coverage.xml + name: codecov-umbrella + fail_ci_if_error: false diff --git a/CHANGELOG.md b/CHANGELOG.md index f23b425..7fefd0f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ - Complete overhaul to `plotutils` for shorter, modular use ([#2](https://github.com/NatLabRockies/ampworks/pull/2)) ### Chores +- Enable and configure `codecov` for tracking test coverage and comparing PRs ([#21](https://github.com/NatLabRockies/ampworks/pull/21)) - Organize example datasets by module to improve discovery and scalability ([#20](https://github.com/NatLabRockies/ampworks/pull/20)) - Remove `flake8` and `autopep8` and use `ruff` for linting/formatting instead ([#18](https://github.com/NatLabRockies/ampworks/pull/18)) - Make GitHub hyperlinks reference new org name `NREL` -> `NatLabRockies` ([#17](https://github.com/NatLabRockies/ampworks/pull/17)) diff --git a/README.md b/README.md index fbfb959..d986fde 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ # ampworks -[![ci-tests](https://github.com/NatLabRockies/ampworks/actions/workflows/ci.yml/badge.svg)](https://github.com/NatLabRockies/ampworks/actions/workflows/ci.yml)   -![coverage](https://github.com/NatLabRockies/ampworks/blob/main/images/coverage.svg?raw=true)   -[![license](https://img.shields.io/badge/License-BSD--3--Clause-blue.svg)](https://github.com/NatLabRockies/ampworks/blob/main/LICENSE)   +[![ci](https://github.com/NatLabRockies/ampworks/actions/workflows/ci.yml/badge.svg)](https://github.com/NatLabRockies/ampworks/actions/workflows/ci.yml)   +[![codecov](https://codecov.io/gh/NatLabRockies/ampworks/graph/badge.svg?token=O6PP2KXSEV)](https://codecov.io/gh/NatLabRockies/ampworks)   +[![license](https://img.shields.io/badge/license-BSD--3-blue.svg)](https://github.com/NatLabRockies/ampworks/blob/main/LICENSE)   [![downloads](https://static.pepy.tech/personalized-badge/ampworks?period=total&units=INTERNATIONAL_SYSTEM&left_color=GREY&right_color=GREEN&left_text=downloads)](https://pepy.tech/projects/ampworks)   -[![ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)   +[![pypi](https://img.shields.io/pypi/v/ampworks)](https://pypi.org/project/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 full list of the GUI-based applications by running `ampworks -h` in your terminal after installation. diff --git a/examples/simple_dQdV_example.py b/examples/simple_dQdV_example.py index c37e3e8..4198b2a 100644 --- a/examples/simple_dQdV_example.py +++ b/examples/simple_dQdV_example.py @@ -3,6 +3,7 @@ import ampworks as amp import matplotlib.pyplot as plt + # %% Import the data # ================== # Calculating LAM and LLI by fitting dQdV curves requires low-rate data from @@ -106,6 +107,7 @@ def smooth_data(data, volts_resolution, smoothing_factor, plot=False): fitter = amp.dqdv.DqdvFitter(neg, pos, cell_BOL) fitter.cost_terms = ['voltage', 'dqdv', 'dvdq'] + # %% Grid searches # ================ # Because fitting routines can get stuck in local minima, it can be important @@ -218,23 +220,20 @@ def smooth_data(data, volts_resolution, smoothing_factor, plot=False): print(f"neg voltage limits: {neg_vlims.min():.3f}--{neg_vlims.max():.3f} V") print(f"pos voltage limits: {pos_vlims.min():.3f}--{pos_vlims.max():.3f} V") -# You can also use the fitted stoichiometries to plot the electrode voltage -# curves vs. their own SOC rather than in reference to the full-cell SOC, but -# this requires a small linear transformation (and flipping SOC for the negative -# electrode). You can see how we perform the flip below, by changing the order -# of the linspace for the negative electrode, i.e., using fitres.x[1] for the -# "min" and fitres.x[0] for the "max". We do not have to do this flip for the -# positive electrode because the positive electrode SOC is already in the same -# reference frame as the full cell SOC, just with different limits. +# If you'd prefer to plot the full voltage windows of each electrode, you can +# do that as well, as shown below. Note that when we plot the negative elctrode +# voltage window we use `1.0 - neg_soc` to flip the reference frame back to the +# negative electrode's perspective. This only needs to get done when plotting, +# since the `get_ocv()` method evaluates in the full-cell reference frame so it +# it compatible with the `fitres.x` values without adjustments. -soc = np.linspace(0, 1, 201) -neg_soc = np.linspace(fitres2.x[1], fitres2.x[0], soc.size) -pos_soc = np.linspace(fitres2.x[2], fitres2.x[3], soc.size) +neg_soc = np.linspace(fitres2.x[0], fitres2.x[1], 101) +pos_soc = np.linspace(fitres2.x[2], fitres2.x[3], 101) fig, axs = plt.subplots(1, 2, figsize=[8, 3]) -axs[0].plot(soc, fitter.get_ocv('neg', neg_soc)) -axs[1].plot(soc, fitter.get_ocv('pos', pos_soc)) +axs[0].plot(1.0 - neg_soc, fitter.get_ocv('neg', neg_soc)) +axs[1].plot(pos_soc, fitter.get_ocv('pos', pos_soc)) for ax in axs: ax.set_xlabel('SOC [-]')