def test_ErCi(nu, C, k_f): sim = ecs.Simulation(True) sim.env.setTemperature(T) sim.el.disk(r) red = ecs.Species('red', C, D) ox = ecs.Species('ox', 0.0, D) prod = ecs.Species('prod', 0.0, D) rdx1 = ecs.Redox(ox, red, n, 0.0, 10.0, alpha).enable() sim.sys.addRedox(rdx1) rxn1 = ecs.Reaction(ox, None, prod, None, k_f, 0.0).enable() sim.sys.addReaction(rxn1) sim.exper.setScanPotentials(-0.5, [0.5], -0.5) sim.exper.setScanRate(nu) [potential, current] = sim.run() metrics = sim.metrics() # Savéant (Elements of ...) page 83: i_p_theoretical = 0.496 * F * (np.pi * r * r) * C * np.sqrt(f * nu * D) print(metrics[0], i_p_theoretical) E_p_theoretical = (0.78 - np.log(k_f / nu / f) / 2) / f print(metrics[1], E_p_theoretical) i_p_err = np.abs(2 * (i_p_theoretical - metrics[0]) / (i_p_theoretical + metrics[0])) E_p_diff = np.abs(E_p_theoretical - metrics[1]) / np.abs(potential[0] - potential[1]) assert i_p_err < 0.025 # less than 2.5% error in peak current assert E_p_diff < 1.0 # peak potential within step potential
def test_Er(T, r, nu, n, alpha, C, Dred, Dox): global R, F f = float(n)*F/R/T sim = ecs.Simulation(False) sim.setPotentialSizing(0.2/float(n)) # TODO: this should happen inside the algorithm sim.env.setTemperature(T) sim.el.disk(r) ox = ecs.Species('ox', 0.0, Dox) red = ecs.Species('red', C, Dred) rdx1 = ecs.Redox(ox, red, int(n), 0.0, 10.0, alpha).enable() sim.sys.addRedox(rdx1) sim.exper.setScanPotentials(-0.5, [0.5], -0.5) sim.exper.setScanRate(nu) [potential, current] = sim.run() metrics = sim.metrics() # Bard & Faulkner chapter 6: i_p_theoretical = 0.4463*float(n)*F*(np.pi*r*r)*C*np.sqrt(f*nu*Dred) # Randles-Sevcik equation E_half = np.log(np.sqrt(Dred/Dox)) / f E_p_theoretical = E_half + 1.109 / f i_p_err = np.abs(2*(i_p_theoretical - metrics[0])/(i_p_theoretical + metrics[0])) E_p_diff = np.abs(E_p_theoretical - metrics[1]) / np.abs(potential[0]-potential[1]) assert i_p_err < 0.01 # less than 1% error in peak current assert E_p_diff < 1.0 # peak potential within step potential
def test_ErCr(nu, C, k_f, k_b): sim = ecs.Simulation(True) sim.env.setTemperature(T) sim.el.disk(r) red = ecs.Species('red', C, D) ox = ecs.Species('ox', 0.0, D) prod = ecs.Species('prod', 0.0, D) rdx1 = ecs.Redox(ox, red, n, 0.0, 10.0, alpha).enable() sim.sys.addRedox(rdx1) rxn1 = ecs.Reaction(ox, None, prod, None, k_f, k_b).enable() sim.sys.addReaction(rxn1) sim.exper.setScanPotentials(-1.0, [0.5], -1.0) sim.exper.setScanRate(nu) #sim.setPotentialSizing(0.1) [potential, current] = sim.run() metrics = sim.metrics() # Savéant (Elements of ...) page 85: i_p_theoretical = 0.4463 * F * (np.pi * r * r) * C * np.sqrt( f * nu * D) # Randles-Sevcik equation print(metrics[0], i_p_theoretical) E_p_theoretical = (1.109 - np.log(1 + k_f / k_b)) / f print(metrics[1], E_p_theoretical) i_p_err = np.abs(2 * (i_p_theoretical - metrics[0]) / (i_p_theoretical + metrics[0])) E_p_diff = np.abs(E_p_theoretical - metrics[1]) / np.abs(potential[0] - potential[1]) assert i_p_err < 0.015 # less than 2.5% error in peak current assert E_p_diff < 1.0 # peak potential within 2 step potential
def test_Ei(T, r, nu, alpha, k_e, C, Dred, Dox): global R, F f = (1 - alpha) * F / R / T sim = ecs.Simulation(False) sim.env.setTemperature(T) sim.el.disk(r) ox = ecs.Species('ox', 0.0, Dox) red = ecs.Species('red', C, Dred) rdx1 = ecs.Redox(ox, red, 1, 0.0, k_e, alpha).enable() sim.sys.addRedox(rdx1) sim.exper.setScanPotentials(-0.5, [2.0], -0.5) sim.exper.setScanRate(nu) [potential, current] = sim.run() metrics = sim.metrics() # Bard & Faulkner chapter 6 (section 6.3.2): i_p_theoretical = 0.4958 * F * (np.pi * r * r) * C * np.sqrt(f * nu * Dred) print(metrics[0] * 1.0e6, i_p_theoretical * 1.0e6) E_p_theoretical = (0.780 + np.log(np.sqrt(Dred * nu * f) / k_e)) / f i_p_err = np.abs(2 * (i_p_theoretical - metrics[0]) / (i_p_theoretical + metrics[0])) E_p_diff = np.abs(E_p_theoretical - metrics[1]) / np.abs(potential[0] - potential[1]) assert i_p_err < 0.01 # less than 1% error in peak current assert E_p_diff < 1.0 # peak potential within step potential
def test_CE_KP(nu, C, k_f, k_b): sim = ecs.Simulation(True) sim.env.setTemperature(T) sim.el.disk(r) red = ecs.Species('red', 0.0, D) ox = ecs.Species('ox', 0.0, D) prod = ecs.Species('prod', C, D) rdx1 = ecs.Redox(ox, red, n, 0.0, 10.0, alpha).enable() sim.sys.addRedox(rdx1) rxn1 = ecs.Reaction(prod, None, red, None, k_f, k_b).enable() sim.sys.addReaction(rxn1) sim.exper.setScanPotentials(-0.5, [0.5], -0.5) sim.exper.setScanRate(nu) [potential, current] = sim.run() metrics = sim.metrics() # Savéant (Elements of ...) page 93: i_p_theoretical = F * (np.pi * r * r) * C * np.sqrt(D * k_b) * (k_f / k_b) print(metrics[0], i_p_theoretical) i_p_err = np.abs(2 * (i_p_theoretical - metrics[0]) / (i_p_theoretical + metrics[0])) assert i_p_err < 0.01 # less than 1% error in plateau current
def simulate_Eq(T, r, nu, alpha, k_e, C, Dred, Dox, deltaTheta=0.2): sim = ecs.Simulation(True) sim.env.setTemperature(T) sim.el.disk(r) ox = ecs.Species('ox', 0.0, Dox) red = ecs.Species('red', C, Dred) rdx1 = ecs.Redox(ox, red, 1, 0.0, k_e, 1 - alpha).enable() sim.sys.addRedox(rdx1) sim.exper.setScanPotentials(-0.2, [], 1.0) sim.exper.setScanRate(nu) sim.setPotentialSizing(deltaTheta) [potential, current] = sim.run() return [potential, current, sim.metrics()]
import matplotlib as mpl import matplotlib.pyplot as plt import pyecsim as ecs if __name__ == '__main__': sim = ecs.Simulation(True) # bool verbosity A = ecs.Species('A', 1.0, 1.0e-9) B = ecs.Species('B', 0.0, 1.0e-9) C = ecs.Species('C', 0.0, 1.0e-9) rxn1 = ecs.Reaction(B, None, C, None, 10.0, 0.0).enable() sim.sys.addReaction(rxn1) rdx1 = ecs.Redox(A, B, 1, -0.5, 10.0, 0.5).enable() sim.sys.addRedox(rdx1) sim.el.disk(1.0e-3) sim.exper.setScanPotentials(0.0, [-0.7], 0.0) sim.exper.setScanRate(1.0) k_fs = np.logspace(-5.0, 9.0, num=10) E_pc = [] cmap_conc = mpl.cm.get_cmap('nipy_spectral') plt.figure() for index, k_f in enumerate(list(k_fs)): cval = 1.0 - index / 10