Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
c-randall committed Jul 2, 2024
0 parents commit fdf1a5f
Show file tree
Hide file tree
Showing 49 changed files with 6,051 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .github/linters/.codespellrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[codespell]
skip = .git,docs,reports,images,__pycache__
85 changes: 85 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
name: build-and-test

on:
push:
branches: [main]
paths-ignore:
- '*.md'
- 'README*'
- 'LICENSE'
- 'docs/*'
- 'images/*'

pull_request:
branches: [main]
paths-ignore:
- '*.md'
- 'README*'
- 'LICENSE'
- 'docs/*'
- 'images/*'

jobs:
lint:
name: (Lint ${{ matrix.python-version }}, ${{ matrix.os }})

runs-on: ${{ matrix.os }}

strategy:
fail-fast: false
matrix:
os: ['ubuntu-latest']
python-version: ['3.10']

defaults:
run:
shell: bash -l {0}

steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Spell check
run: |
pip install codespell
codespell --config .github/linters/.codespellrc
tests:
name: (Test ${{ matrix.python-version }}, ${{ matrix.os }})

runs-on: ${{ matrix.os }}

strategy:
fail-fast: false
matrix:
os: ['ubuntu-latest', 'macos-latest', 'windows-latest']
python-version: ['3.8', '3.9', '3.10', '3.11']

defaults:
run:
shell: bash -l {0}

steps:
- uses: actions/checkout@v4
- uses: conda-incubator/setup-miniconda@v3
with:
python-version: ${{ matrix.python-version }}
miniconda-version: 'latest'
use-only-tar-bz2: true
auto-update-conda: true
auto-activate-base: true
- name: Make environment
run: |
conda create -n rovi
conda activate rovi
- name: Conda dependencies
run: conda install -c conda-forge scikits.odes
- name: Pip dependencies
run: pip install .
- name: List packages
run: conda list
- name: Pytest
run: |
pip install pytest
pytest
165 changes: 165 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
# Local developer tools
dev.bat

# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
reports/
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
junit.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# PyBuilder
.pybuilder/
target/

# Jupyter Notebook
.ipynb_checkpoints

# IPython
profile_default/
ipython_config.py

# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version

# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock

# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock

# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
#pdm.lock
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
# in version control.
# https://pdm.fming.dev/#use-with-ide
.pdm.toml

# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/

# Celery stuff
celerybeat-schedule
celerybeat.pid

# SageMath parsed files
*.sage.py

# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

# Spyder project settings
.spyderproject
.spyproject

# VSCode
.vscode

# Rope project settings
.ropeproject

# mkdocs documentation
/site

# mypy
.mypy_cache/
.dmypy.json
dmypy.json

# Pyre type checker
.pyre/

# pytype static type analyzer
.pytype/

# Cython debug symbols
cython_debug/

# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
99 changes: 99 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
<picture>
<source media="(prefers-color-scheme: dark)" srcset="./images/dark.svg"
style="width: 75%; min-width: 250px; max-width: 500px;"/>
<img alt="thevenin logo" src="./images/light.svg"
style="width: 75%; min-width: 250px; max-width: 500px;"/>
</picture>

</br>

[![CI][ci-b]][ci-l] ![tests][test-b] ![coverage][cov-b] [![pep8][pep-b]][pep-l]

[ci-b]: https://github.com/c-randall/thevenin/actions/workflows/ci.yaml/badge.svg
[ci-l]: https://github.com/c-randall/thevenin/actions/workflows/ci.yaml

[test-b]: ./images/tests.svg
[cov-b]: ./images/coverage.svg

[pep-b]: https://img.shields.io/badge/code%20style-pep8-orange.svg
[pep-l]: https://www.python.org/dev/peps/pep-0008

## Summary
This package is a wrapper for the well-known Thevenin equivalent circuit model. The model is comprised of a single series reistor followed by any number of parallel RC pairs. Figure 1 below illustrates a circuit with 2 RC paris; however, the model can be run with as few as zero, and as many as $N$.

<figure style="text-align: center">
<img alt="2RC Thevenin circuit." src="./images/thevenin_circuit.png" style="width: 75%; min-width: 250px; max-width: 500px;"/>
<figcaption>Figure 1: 2RC Thevenin circuit.</figcaption>
</figure>

This system is governed by the evolution of the state of charge (soc, $-$), RC overpotentials ($V_j$, V), cell voltage ($V_{\rm cell}$, V), and temperature ($T_{\rm cell}$, K). soc and $V_j$ evolve in time as
$$
\begin{align}
&\frac{d\rm soc}{dt} = \frac{-I}{3600Q}, \\
&\frac{dV_j}{dt} = -\frac{V_j}{R_jC_j} + \frac{I}{C_j},
\end{align}
$$
where $I$ is the load current (A), $Q$ is the cell capacity (Ah), and $R_j$ and $C_j$ are the resistance (Ohm) and capacitance (F) of each RC pair $j$. Note that the sign convention for $I$ is chosen such that positive $I$ discharges the battery (reduces soc) and negative $I$ charges the battery (increases soc). This convention is consistent with common higher-fidelty models, e.g., the single particle model or pseudo-2D model. While it's not explicitly included in the equations above, $R_j$ and $C_j$ are functions of soc and $T_{\rm cell}$. The temperature increases while the cell is active according to
$$
\begin{equation}
mC_p\frac{dT_{\rm cell}}{dt} = \dot{Q}_{\rm gen} + \dot{Q}_{\rm conv},
\end{equation}
$$
where $m$ is mass (kg), $C_p$ is specific heat capacity (J/kg/K), $\dot{Q}_{\rm gen}$ is the heat generation (W), and $\dot{Q}_{\rm conv}$ is the convective heat loss (W). Heat generation and convection are defined by
$$
\begin{align}
&\dot{Q}_{\rm gen} = I \times (V_{\rm ocv}({\rm soc}) - V_{\rm cell}), \\
&\dot{Q}_{\rm conv} = hA(T_{\infty} - T_{\rm cell}),
\end{align}
$$
where $h$ is the convecitive heat transfer coefficient (W/m$^2$/K), $A$ is heat loss area (m$^2$), and $T_{\infty}$ is the air/room temperature (K). $V_{\rm ocv}$ is the open circuit voltage (V) and is a function of soc.

Finally, the overall cell voltage is
$$
\begin{equation}
V_{\rm cell} = V_{\rm ocv}({\rm soc}) - \sum_j V_j - IR_0,
\end{equation}
$$
where $R_0$ the lone series resistance (Ohm), as shown in Figure 1. Just like the other resistive elements, $R_0$ is a function of soc and $T_{\rm cell}$.

## Installation
We recommend using [Anaconda](https://anaconda.com) to install this package due to the [scikits.odes](https://scikits-odes.readthedocs.io) dependency, which is installed separately using ``conda install`` to avoid having to download and install C++ and Fortran compilers.

After cloning the repository, or downloading the files, use your terminal (MacOS/Linux) or Anaconda Prompt (Windows) to navigate into the folder with the `pyproject.toml` file. Once in the correct folder, execute the following commands:

```cmd
conda create -n rovi python=3.10 scikits.odes -c conda-forge
conda activate rovi
pip install .
```

The first command will create a new Python environment named `rovi`. The environment will be set up using Python 3.10 and will install the `scikits.odes` dependency from the `conda-forge` channel. You can change the environment name as desired and specify any Python version >= 3.8 and < 3.12. Although the package supports multiple Python versions, development and testing is primarily done using 3.10. Therefore, if you have issues with another version, you should revert to using 3.10.

Before running the `pip install` command, which installs `thevenin`, you should activate your new `rovi` environment using the second command. If you plan to make changes to your local package, use the `-e` flag, and add the optional developer dependencies during the `pip install` step.

```cmd
pip install -e .[dev]
```

## Getting Started
The API is organized around three main classes that allow you to construct the model, define an experiment, and interact with the solution. A basic example for a constant-current discharge is given below. To see the documentation for any of the classes or their methods, use Python's built in `help()` function.

```python
import thevenin

model = thevenin.Model()

exp = thevenin.Experiment()
exp.add_step('current_A', 15., (3600., 1.), limit=('voltage_V', 3.))

sol = model.run(experiment)
sol.plot('capacity_Ah', 'voltage_V')
```

## Contributions
Contributions are welcomed and encouraged. If you choose to contribute, please note that this package mostly follows the [PEP8 style guide](https://www.python.org/dev/peps/pep-0008) style guide. However, we allow adding extra spaces around parentheses and brackets, and under- or over-indenting multi-line expressions when it improves readability or avoids the 80-character line limit.

Be aware that it is the authors' preference to not adopt the more opinionated [black formatting style](https://black.readthedocs.io/en/stable/the_black_code_style/current_style.html) formatting style. Please avoid autoformatting any files in this style if you plan to contribute.

## Acknowledgements
This work was authored by the National Renewable Energy Laboratory (NREL), operated by Alliance for Sustainable Energy, LLC, for the U.S. Department of Energy (DOE). The views expressed in the repository do not necessarily represent the views of the DOE or the U.S. Government.
20 changes: 20 additions & 0 deletions docs/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Minimal makefile for Sphinx documentation
#

# You can set these variables from the command line, and also
# from the environment for the first two.
SPHINXOPTS ?=
SPHINXBUILD ?= sphinx-build
SOURCEDIR = source
BUILDDIR = build

# Put it first so that "make" without argument is like "make help".
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

.PHONY: help Makefile

# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit fdf1a5f

Please sign in to comment.