Skip to content

Commit

Permalink
Fix for readthedocs undoc-members
Browse files Browse the repository at this point in the history
  • Loading branch information
c-randall committed Nov 13, 2024
1 parent 3d0cc13 commit 83d59cf
Show file tree
Hide file tree
Showing 7 changed files with 80 additions and 76 deletions.
16 changes: 8 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,33 +30,33 @@ This package is a wrapper for the well-known Thevenin equivalent circuit model.
</p>

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
```math
$$
\begin{align}
&\frac{d\rm SOC}{dt} = \frac{-I}{3600 Q_{\rm max}}, \\
&\frac{dV_j}{dt} = -\frac{V_j}{R_jC_j} + \frac{I}{C_j},
\end{align}
```
$$
where $I$ is the load current (A), $Q_{\rm max}$ is the maximum nominal 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 physics-based models, e.g., the single particle model or pseudo-2D model. While 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
```math
$$
\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), $Q_{\rm gen}$ is the heat generation (W), and $Q_{\rm conv}$ is the convective heat loss (W). Heat generation and convection are defined by
```math
$$
\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<sup>2</sup>/K), $A$ is heat loss area (m<sup>2</sup>), and $T_{\infty}$ is the air/room temperature (K). $V_{\rm OCV}$ is the open circuit voltage (V) and is a function of SOC.

The overall cell voltage is
```math
$$
\begin{equation}
V_{\rm cell} = V_{\rm OCV}({\rm SOC}) - \sum_j V_j - IR_0,
\end{equation}
```
$$
where $R_0$ is 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
Expand Down
2 changes: 1 addition & 1 deletion docs/jupyter_execute/user_guide/basic_tutorial.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@
"output_type": "stream",
"text": [
"CycleSolution(\n",
" solvetime=0.007 s,\n",
" solvetime=0.008 s,\n",
" success=[True, True],\n",
" status=[2, 1],\n",
" nfev=[257, 69],\n",
Expand Down
3 changes: 1 addition & 2 deletions docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,10 +119,9 @@
autoapi_python_class_content = 'both'
autoapi_options = [
'members',
'imported-members',
'inherited-members',
'undoc-members',
'show-module-summary',
'imported-members',
]


Expand Down
Binary file modified images/example_circuit.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 4 additions & 4 deletions images/logos.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
32 changes: 16 additions & 16 deletions src/thevenin/_experiment.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ def __init__(self, **kwargs) -> None:
Parameters
----------
kwargs : dict, optional
IDASolver keyword arguments that will span all steps.
**kwargs : dict, optional
IDASolver keyword arguments that span all steps.
See also
--------
Expand Down Expand Up @@ -105,24 +105,24 @@ def add_step(self, mode: str, value: float | Callable, tspan: tuple,
Parameters
----------
mode : str
Control mode, from {'current_A', 'voltage_V', 'power_W'}.
Control mode, {'current_A', 'current_C', 'voltage_V', 'power_W'}.
value : float | Callable
Value of boundary contion in the appropriate units.
Value of boundary contion mode, in the appropriate units.
tspan : tuple | 1D np.array
Relative times for recording solution [s]. Providing a tuple as
(t_max: float, Nt: int) or (t_max: float, dt: float) constructs
tspan using ``np.linspace`` or ``np.arange``, respectively. See
the notes for more information. Given an array simply uses the
values supplied as the evaluation times. Arrays must be monotonic
increasing and start with zero.
tspan using ``np.linspace`` or ``np.arange``, respectively. Given
an array uses the values supplied as the evaluation times. Arrays
must be monotonically increasing and start with zero. See the notes
for more information.
limits : tuple[str, float], optional
Stopping criteria for the new step, must be entered in sequential
name/value pairs. Allowable names are {'soc', 'temperature_K',
'current_A', 'voltage_V', 'power_W', 'capacity_Ah', 'time_s',
'time_min', 'time_h'}. Values for each limit should immediately
follow a corresponding name and be the appropriate units. All of
the time limits represent the total experiment time. The default
is None.
'current_A', 'current_C', 'voltage_V', 'power_W', 'capacity_Ah',
'time_s', 'time_min', 'time_h'}. Values for each limit should
immediately follow a corresponding name and match its units. Time
limits are in reference to total experiment time. The default is
None.
**kwargs : dict, optional
IDASolver keyword arguments specific to the new step only.
Expand Down Expand Up @@ -158,11 +158,11 @@ def add_step(self, mode: str, value: float | Callable, tspan: tuple,
Notes
-----
For time-dependent loads, use a Callable for 'value' with a function
signature like def load(t: float) -> float, where t is the step's
signature like ``def load(t: float) -> float``, where 't' is the step's
relative time, in seconds.
The solution times array is constructed depending on the 'tspan'
input types:
Solution times are constructed and saved depending on the 'tspan' input
types that were supplied:
* Given (float, int):
``tspan = np.linspace(0., tspan[0], tspan[1])``
Expand Down
95 changes: 50 additions & 45 deletions src/thevenin/_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ def __init__(self, params: dict | str = 'params.yaml'):
params : dict | str
Mapping of model parameter names to their values. Can be either
a dict or absolute/relateive file path to a yaml file (str). The
keys/value pair descriptions are given below. The default uses a
.yaml file. Use the templates() function to view this file.
keys/value pair descriptions are given below. The default uses an
internal yaml file.
============= ========================== ================
Key Value *type*, units
Expand Down Expand Up @@ -70,10 +70,9 @@ def __init__(self, params: dict | str = 'params.yaml'):
Notes
-----
The 'ocv' property needs a signature like ``f(soc: float) -> float``,
where 'soc' is the time-dependent state of charged solved for within
the model. All R0, Rj, and Cj properties should have signatures like
``f(soc: float, T_cell: float) -> float``, where 'T_cell' is the cell
temperature in K determined in the model.
where 'soc' is the state of charge. All R0, Rj, and Cj properties need
signatures like ``f(soc: float, T_cell: float) -> float``. 'T_cell' is
the cell temperature in K.
Rj and Cj are not real property names. These are used generally in the
documentation. If ``num_RC_pairs=1`` then in addition to R0, you should
Expand Down Expand Up @@ -155,32 +154,36 @@ def pre(self, initial_state: bool | Solution = True) -> None:
Parameters
----------
initial_state : bool | Solution
Controls how the model state is initialized. If boolean it will set
the state to a rested state at 'soc0' when True (default) or will
bypass the state initialization update when False. Given a Solution
object, the internal state will be set to the final state of the
solution. See notes for more information.
Control how the model state is initialized. If True (default), the
state is set to a rested condition at 'soc0'. If False, the state
is left untouched and only the parameters and pointers are updated.
Given a Solution instance, the state is set to the final state of
the solution. See notes for more information.
Returns
-------
None.
Warning
-------
This method runs the first time during the class initialization. It
generally does not have to be run again unless you modify any model
attributes. You should manually re-run the pre-processor if you change
any properties after initialization. Forgetting to manually re-run the
pre-processor may cause inconsistencies between the updated properties
and the model's pointers, state, etc.
This method runs during the class initialization. It generally does not
have to be run again unless you modify model properties or attributes.
You should manually re-run the pre-processor if you change properties
after initialization. Forgetting to re-run the pre-processor can cause
inconsistencies between the updated properties and the pointers, state,
etc. If you are updating properties, but want the model's internal state
to not be reset back to a rested condition, use the ``initial_state``
option.
Notes
-----
Using ``initial_state=False`` will raise an error if you are changing
the size of your circuit (e.g., changing from one to two RC pairs).
The same logic applies when initializing based on a Solution instance.
In other words, a 1RC-pair model cannot be initialized given a solution
from a 2RC-pair circuit.
the size of your circuit (e.g., updating from one to two RC pairs).
Without re-initializing, the model's state vector would be a different
size than the circuit it is trying to solve. For this same reason, when
initializing based on a Solution instance, the solution must also be
the same size as the current model. In other words, a 1RC-pair model
cannot be initialized given a solution from a 2RC-pair circuit.
"""

Expand Down Expand Up @@ -389,16 +392,18 @@ def run_step(self, exp: Experiment, stepidx: int) -> StepSolution:
Returns
-------
:class:`~thevenin.StepSolution`
Solution to the experiment step.
Solution to the experimental step.
Warning
-------
The model's internal state is changed at the end of each experiment
The model's internal state is changed at the end of each experimental
step. Consequently, you should not run steps out of order. You should
always start with ``stepidx = 0`` and then progress to the subsequent
steps afterward. Run ``pre()`` after your last step to reset the state
back to a rested state at 'soc0'. Otherwise the internal state will
match the final state from the last step that was run.
back to a rested condition at 'soc0', if needed. Alternatively, you
can continue running experiments back-to-back without a pre-processing
in between if you want the following experiment to pick up from the
same state that the last experiment ended.
See also
--------
Expand All @@ -407,11 +412,11 @@ def run_step(self, exp: Experiment, stepidx: int) -> StepSolution:
Notes
-----
Using the ``run()`` method will automatically run all steps in an
experiment and will stitch the solutions together for you. You should
only run step by step if you are trying to fine tune solver options, or
if you have a complex protocol and you can't set an experimental step
until interpreting a previous step.
Using the ``run()`` loops through all steps in an experiment and then
stitches their solutions together. Most of the time, this is more
convenient. However, advantages for running step-by-step is that it
makes it easier to fine tune solver options, and allows for analyses
or control decisions in the middle of an experiment.
"""

Expand Down Expand Up @@ -449,17 +454,17 @@ def run_step(self, exp: Experiment, stepidx: int) -> StepSolution:
def run(self, exp: Experiment, reset_state: bool = True,
t_shift: float = 1e-3) -> CycleSolution:
"""
Run an experiment.
Run a full experiment.
Parameters
----------
exp : Experiment
An experiment instance.
reset_state : bool
If True (default), the internal state of the model will be reset
back to a rested condition at 'soc0' at the end of the experiment.
When False the state does not reset instead matches the final state
of the last experimental step.
back to a rested condition at 'soc0' at the end of all steps. When
False, the state does not reset. Instead it will update to match
the final state of the last experimental step.
t_shift : float
Time (in seconds) to shift step solutions by when stitching them
together. If zero the end time of each step overlaps the starting
Expand All @@ -468,14 +473,17 @@ def run(self, exp: Experiment, reset_state: bool = True,
Returns
-------
:class:`~thevenin.CycleSolution`
A stitched solution will all experimental steps.
A stitched solution with all experimental steps.
Warning
-------
The default behavior resets the model's internal state back to a rested
condition at 'soc0' by calling the ``pre()`` method. You can bypass this
by using ``reset_state=False``, which will keep the state at the end of
the final experimental step.
condition at 'soc0' by calling the ``pre()`` method at the end of all
steps. This means that if you run a second experiment afterward, it
will not start where the previous one left off. Instead, it will start
from the original rested condition that the model initialized with. You
can bypass this by using ``reset_state=False``, which keeps the state
at the end of the final experimental step.
See also
--------
Expand Down Expand Up @@ -534,10 +542,7 @@ class _RootFunction:

def __init__(self, limits: tuple[str, float]) -> None:
"""
This class is a generalize root function callable. All possible root
functions only have one event that can be triggered. Therefore, the
'size' property is always unity, and is passed to the IDASolver as
the 'nr_rootfns' argument.
This class is a generalized root function callable.
Parameters
----------
Expand Down Expand Up @@ -592,7 +597,7 @@ def _setup_rootfn(limits: tuple[str, float], kwargs: dict) -> None:
The IDASolver requires two keyword arguments to be set when using root
functions. The first is 'rootfn' which requires a Callable. The second
is 'nr_rootfns' with allocates memory to an array that stores the root
is 'num_events' with allocates memory to an array that stores the root
function values.
Parameters
Expand All @@ -601,8 +606,8 @@ def _setup_rootfn(limits: tuple[str, float], kwargs: dict) -> None:
A tuple of root function criteria arranged as ordered pairs of limit
names and values, e.g., ('time_h', 10., 'voltage_V', 4.2).
kwargs : dict
The IDASolver keyword argumnents dictionary. Both the 'rootfn' and
'nr_rootfns' keyword arguments must be added to 'kwargs'.
The IDASolver keyword argumnents dictionary. Both the 'eventsfn' and
'num_events' keyword arguments must be added to 'kwargs'.
Returns
-------
Expand Down

0 comments on commit 83d59cf

Please sign in to comment.