Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .coveragerc
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@ skip_empty = true
exclude_also =
raise NotImplementedError

; don't complain abput abstract methods, they aren't run:
@(abc\.)?abstractmethod
; don't complain about abstract methods, they aren't run:
@(abc\.)?abstractmethod
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
CVsim
--------

`cvsim` is a Python package for cyclic voltammogram (CV) simulation via a semi-analytical method developed by Oldham and Myland<sup>1</sup>. It is valid for CV experiments performed on disk macroelectrodes, and uses a semiintegration algorithm. In the limit of infinitely small potential steps, this algorithm is an exact solution.
`cvsim` is a Python package for cyclic voltammogram (CV) simulation via a semi-analytical method developed by Oldham and Myland<sup>1</sup>. It is valid for CV experiments performed on disk macroelectrodes, and uses a semi-integration algorithm. In the limit of infinitely small potential steps, this algorithm is an exact solution.
Due to the precision of standard potentiostats, simulations that use a potential step of 1-5 mV typically provide a reasonable accuracy-computing time trade-off, where accuracy sanity checks (e.g. Randles-Sevcik relationship for E<sub>r</sub> and E<sub>q</sub> mechanisms) have been performed.


Expand Down Expand Up @@ -31,7 +31,7 @@ git clone git@github.com:ericfell/CVsim.git

## Package Structure

- `mechanisms.py`: Specifies one-/two-electron process mechanism to be simulated.
- `mechanisms.py`: Specifies one-/two-electron process mechanisms to be simulated.
- `fit_curve.py`: Performs fitting of experimental CV data according to a desired mechanism.


Expand Down
85 changes: 0 additions & 85 deletions cv_fitting.py

This file was deleted.

2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ build-backend = "hatchling.build"

[project]
name = "cvsim"
version = "0.0.1"
version = "1.0.0"
authors = [
{ name="Eric Fell", email="efell@g.harvard.edu" },
{ name="Jeremy Fell", email="jfell@sfu.ca"},
Expand Down
44 changes: 22 additions & 22 deletions src/cvsim/fit_curve.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ def __init__(
thetas = [round((i - delta_theta)) for i in [start_potential_mv, switch_potential_mv]]
forward_scan = np.arange(thetas[0], thetas[1], step=delta_theta * -1)
reverse_scan = np.append(forward_scan[-2::-1], start_potential_mv)
self.voltage_to_fit = np.concatenate([forward_scan, reverse_scan]) / 1000
self.voltage = np.concatenate([forward_scan, reverse_scan]) / 1000

# Contains only variables with a user-specified fixed value.
# These params are shared by all CVsim mechanisms
Expand All @@ -121,8 +121,8 @@ def __init__(
# These params are shared by all CVsim mechanisms
self.default_vars = {
'reduction_potential': [
round((self.voltage_to_fit[np.argmax(self.current_to_fit)]
+ self.voltage_to_fit[np.argmin(self.current_to_fit)]) / 2, 3),
round((self.voltage[np.argmax(self.current_to_fit)]
+ self.voltage[np.argmin(self.current_to_fit)]) / 2, 3),
min(self.start_potential, self.switch_potential),
max(self.start_potential, self.switch_potential),
],
Expand Down Expand Up @@ -236,14 +236,14 @@ def fit_function(
# fit raw data but exclude first data point, as semi-analytical method skips time=0
fit_results = curve_fit(
f=fit_function,
xdata=self.voltage_to_fit,
xdata=self.voltage,
ydata=self.current_to_fit[1:],
p0=initial_guesses,
bounds=[lower_bounds, upper_bounds],
)

popt, pcov = list(fit_results)
current_fit = fit_function(self.voltage_to_fit, *popt)
current_fit = fit_function(self.voltage, *popt)
sigma = np.sqrt(np.diag(pcov)) # one standard deviation of the parameters

final_fit = {}
Expand All @@ -253,13 +253,13 @@ def fit_function(

# Semi-analytical method does not compute the first point (i.e. time=0)
# so the starting voltage data point with a zero current is reinserted
self.voltage_to_fit = np.insert(self.voltage_to_fit, 0, self.start_potential)
self.voltage = np.insert(self.voltage, 0, self.start_potential)
current_fit = np.insert(current_fit, 0, 0)
return self.voltage_to_fit, current_fit, final_fit
return self.voltage, current_fit, final_fit


class FitE_rev(FitMechanism):
"""Scheme for fitting a CV for a reversible (Nernstian) one electron transfer mechanism."""
"""Scheme for fitting a CV for a reversible (Nernstian) one-electron transfer mechanism."""

def _scheme(self, get_var: Callable[[str], float]) -> CyclicVoltammetryScheme:
return E_rev(
Expand All @@ -282,7 +282,7 @@ def fit(
diffusion_product: _ParamGuess = None,
) -> tuple[np.ndarray, np.ndarray, dict]:
"""
Fits the CV for a reversible (Nernstian) one electron transfer mechanism.
Fits the CV for a reversible (Nernstian) one-electron transfer mechanism.
If a parameter is given, it must be a: float for initial guess of parameter; tuple[float, float] for
(lower bound, upper bound) of the initial guess; or tuple[float, float, float] for
(initial guess, lower bound, upper bound).
Expand All @@ -301,7 +301,7 @@ def fit(

Returns
-------
voltage_to_fit : np.ndarray
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

all of these were named properly already, see the _fit( function that returns this

voltage : np.ndarray
Array of potential (V) values of the CV fit.
current_fit : np.ndarray
Array of current (A) values of the CV fit.
Expand All @@ -319,7 +319,7 @@ def fit(

class FitE_q(FitMechanism):
"""
Scheme for fitting a CV for a quasi-reversible one electron transfer mechanism.
Scheme for fitting a CV for a quasi-reversible one-electron transfer mechanism.

Parameters
----------
Expand Down Expand Up @@ -426,7 +426,7 @@ def fit(
k0: _ParamGuess = None,
) -> tuple[np.ndarray, np.ndarray, dict]:
"""
Fits the CV for a quasi-reversible one electron transfer mechanism.
Fits the CV for a quasi-reversible one-electron transfer mechanism.
If a parameter is given, it must be a: float for initial guess of parameter; tuple[float, float] for
(lower bound, upper bound) of the initial guess; or tuple[float, float, float] for
(initial guess, lower bound, upper bound).
Expand All @@ -451,7 +451,7 @@ def fit(

Returns
-------
voltage_to_fit : np.ndarray
voltage : np.ndarray
Array of potential (V) values of the CV fit.
current_fit : np.ndarray
Array of current (A) values of the CV fit.
Expand All @@ -470,7 +470,7 @@ def fit(

class FitE_qC(FitMechanism):
"""
Scheme for fitting a CV for a quasi-reversible one electron transfer, followed by
Scheme for fitting a CV for a quasi-reversible one-electron transfer, followed by
a reversible first order homogeneous chemical transformation mechanism.

Parameters
Expand Down Expand Up @@ -598,7 +598,7 @@ def fit(
k_backward: _ParamGuess = None,
) -> tuple[np.ndarray, np.ndarray, dict]:
"""
Fits the CV for a quasi-reversible one electron transfer, followed by a reversible first
Fits the CV for a quasi-reversible one-electron transfer, followed by a reversible first
order homogeneous chemical transformation mechanism.
If a parameter is given, it must be a: float for initial guess of parameter; tuple[float, float] for
(lower bound, upper bound) of the initial guess; or tuple[float, float, float] for
Expand Down Expand Up @@ -630,7 +630,7 @@ def fit(

Returns
-------
voltage_to_fit : np.ndarray
voltage : np.ndarray
Array of potential (V) values of the CV fit.
current_fit : np.ndarray
Array of current (A) values of the CV fit.
Expand Down Expand Up @@ -756,8 +756,8 @@ def __init__(
# default [initial guess, lower bound, upper bound]
self.default_vars |= {
'reduction_potential2': [
round((self.voltage_to_fit[np.argmax(self.current_to_fit)]
+ self.voltage_to_fit[np.argmin(self.current_to_fit)]) / 2, 3),
round((self.voltage[np.argmax(self.current_to_fit)]
+ self.voltage[np.argmin(self.current_to_fit)]) / 2, 3),
min(self.start_potential, self.switch_potential),
max(self.start_potential, self.switch_potential),
],
Expand Down Expand Up @@ -838,7 +838,7 @@ def fit(

Returns
-------
voltage_to_fit : np.ndarray
voltage : np.ndarray
Array of potential (V) values of the CV fit.
current_fit : np.ndarray
Array of current (A) values of the CV fit.
Expand Down Expand Up @@ -990,8 +990,8 @@ def __init__(
# default [initial guess, lower bound, upper bound]
self.default_vars |= {
'reduction_potential2': [
round((self.voltage_to_fit[np.argmax(self.current_to_fit)]
+ self.voltage_to_fit[np.argmin(self.current_to_fit)]) / 2, 3),
round((self.voltage[np.argmax(self.current_to_fit)]
+ self.voltage[np.argmin(self.current_to_fit)]) / 2, 3),
min(self.start_potential, self.switch_potential),
max(self.start_potential, self.switch_potential),
],
Expand Down Expand Up @@ -1090,7 +1090,7 @@ def fit(

Returns
-------
voltage_to_fit : np.ndarray
voltage : np.ndarray
Array of potential (V) values of the CV fit.
current_fit : np.ndarray
Array of current (A) values of the CV fit.
Expand Down
18 changes: 9 additions & 9 deletions src/cvsim/mechanisms.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ def _voltage_profile_setup(self, reduction_potential2: float | None = None) -> t
@abstractmethod
def simulate(self) -> tuple[np.ndarray, np.ndarray]:
"""
Simulates current-potential profile for desired mechanism
Simulates current-potential profile for desired mechanism.

Returns
-------
Expand All @@ -176,14 +176,14 @@ def simulate(self) -> tuple[np.ndarray, np.ndarray]:

class E_rev(CyclicVoltammetryScheme):
"""
Provides a current-potential profile for a reversible (Nernstian) one electron transfer mechanism.
Provides a current-potential profile for a reversible (Nernstian) one-electron transfer mechanism.
This is equation (7:7) from [1].

"""

def simulate(self) -> tuple[np.ndarray, np.ndarray]:
"""
Simulates the CV for a reversible one electron transfer mechanism.
Simulates the CV for a reversible one-electron transfer mechanism.

Returns
-------
Expand All @@ -208,7 +208,7 @@ def simulate(self) -> tuple[np.ndarray, np.ndarray]:

class E_q(CyclicVoltammetryScheme):
"""
Provides a current-potential profile for a quasi-reversible one electron transfer mechanism.
Provides a current-potential profile for a quasi-reversible one-electron transfer mechanism.
This is equation (8:3) from [1].

Parameters
Expand Down Expand Up @@ -278,7 +278,7 @@ def __init__(

def simulate(self) -> tuple[np.ndarray, np.ndarray]:
"""
Simulates the CV for a quasi-reversible one electron transfer mechanism.
Simulates the CV for a quasi-reversible one-electron transfer mechanism.

Returns
-------
Expand Down Expand Up @@ -307,7 +307,7 @@ def simulate(self) -> tuple[np.ndarray, np.ndarray]:

class E_qC(CyclicVoltammetryScheme):
"""
Provides a current-potential profile for a quasi-reversible one electron transfer, followed by a reversible first
Provides a current-potential profile for a quasi-reversible one-electron transfer, followed by a reversible first
order homogeneous chemical transformation mechanism.
This is equation (10:4) from [1].

Expand Down Expand Up @@ -388,7 +388,7 @@ def __init__(

def simulate(self) -> tuple[np.ndarray, np.ndarray]:
"""
Simulates the CV for a quasi-reversible one electron transfer followed by a reversible first order homogeneous
Simulates the CV for a quasi-reversible one-electron transfer followed by a reversible first order homogeneous
chemical transformation mechanism.

Returns
Expand Down Expand Up @@ -580,7 +580,7 @@ def simulate(self) -> tuple[np.ndarray, np.ndarray]:
class SquareScheme(CyclicVoltammetryScheme):
"""
Provides a current-potential profile for two quasi-reversible, one-electron transfers of homogeneously
interconverting reactants (square scheme).
interconverting reactants (Square Scheme).
This is equations (14:14 and 14:15) from [1].

Parameters
Expand Down Expand Up @@ -685,7 +685,7 @@ def __init__(
def simulate(self) -> tuple[np.ndarray, np.ndarray]:
"""
Simulates the CV for two quasi-reversible, one-electron transfers of homogeneously interconverting
reactants (square scheme).
reactants (Square Scheme).

Returns
-------
Expand Down