Skip to content

Commit 7800bbc

Browse files
Merge pull request pybamm-team#2552 from pybamm-team/issue-2551-electrolyte
Issue 2551 electrolyte
2 parents 1f25a1a + 4d13032 commit 7800bbc

File tree

9 files changed

+88
-45
lines changed

9 files changed

+88
-45
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
## Bug fixes
1111

12+
- Fixed electrolyte conservation when options {"surface form": "algebraic"} are used
1213
- Fixed "constant concentration" electrolyte model so that "porosity times concentration" is conserved when porosity changes ([#2529](https://github.com/pybamm-team/PyBaMM/pull/2529))
1314
- Fix installation on `Google Colab` (`pybtex` and `Colab` issue) ([#2526](https://github.com/pybamm-team/PyBaMM/pull/2526))
1415

pybamm/expression_tree/unary_operators.py

+8
Original file line numberDiff line numberDiff line change
@@ -1252,6 +1252,14 @@ def boundary_value(symbol, side):
12521252
return BoundaryValue(symbol, side)
12531253

12541254

1255+
def boundary_gradient(symbol, side):
1256+
# Gradient of a broadcast is zero
1257+
if isinstance(symbol, pybamm.Broadcast):
1258+
return 0 * symbol.reduce_one_dimension()
1259+
else:
1260+
return BoundaryGradient(symbol, side)
1261+
1262+
12551263
def sign(symbol):
12561264
"""Returns a :class:`Sign` object."""
12571265
if isinstance(symbol, pybamm.Broadcast):

pybamm/models/submodels/electrolyte_conductivity/surface_potential_form/full_surface_form_conductivity.py

+41-31
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ def get_coupled_variables(self, variables):
6060
+ i_boundary_cc / sigma_eff
6161
)
6262
variables[f"{Domain} electrolyte current density"] = i_e
63+
variables[
64+
f"Divergence of {self.domain} electrolyte current density"
65+
] = pybamm.div(i_e)
6366

6467
phi_s = variables[f"{Domain} electrode potential"]
6568
phi_e = phi_s - delta_phi
@@ -91,8 +94,8 @@ def get_coupled_variables(self, variables):
9194

9295
# Update boundary conditions (for indefinite integral)
9396
self.boundary_conditions[c_e_s] = {
94-
"left": (pybamm.BoundaryGradient(c_e_s, "left"), "Neumann"),
95-
"right": (pybamm.BoundaryGradient(c_e_s, "right"), "Neumann"),
97+
"left": (pybamm.boundary_gradient(c_e_s, "left"), "Neumann"),
98+
"right": (pybamm.boundary_gradient(c_e_s, "right"), "Neumann"),
9699
}
97100

98101
variables[f"{Domain} electrolyte potential"] = phi_e
@@ -111,6 +114,34 @@ def get_coupled_variables(self, variables):
111114
variables.update(self._get_standard_current_variables(i_e))
112115
variables.update(self._get_electrolyte_overpotentials(variables))
113116

117+
# save boundary conditons as variables
118+
if self.domain == "negative":
119+
grad_c_e = pybamm.boundary_gradient(c_e, "right")
120+
grad_left = -i_boundary_cc * pybamm.boundary_value(1 / sigma_eff, "left")
121+
grad_right = (
122+
(i_boundary_cc / pybamm.boundary_value(conductivity, "right"))
123+
- pybamm.boundary_value(param.chiRT_over_Fc(c_e, T), "right") * grad_c_e
124+
- i_boundary_cc * pybamm.boundary_value(1 / sigma_eff, "right")
125+
)
126+
127+
elif self.domain == "positive":
128+
T = variables["Positive electrode temperature"]
129+
grad_c_e = pybamm.boundary_gradient(c_e, "left")
130+
grad_left = (
131+
(i_boundary_cc / pybamm.boundary_value(conductivity, "left"))
132+
- pybamm.boundary_value(param.chiRT_over_Fc(c_e, T), "left") * grad_c_e
133+
- i_boundary_cc * pybamm.boundary_value(1 / sigma_eff, "left")
134+
)
135+
grad_right = -i_boundary_cc * pybamm.boundary_value(1 / sigma_eff, "right")
136+
137+
if self.domain in ["negative", "positive"]:
138+
variables.update(
139+
{
140+
f"{self.domain} grad(delta_phi) left": grad_left,
141+
f"{self.domain} grad(delta_phi) right": grad_right,
142+
f"{self.domain} grad(c_e) internal": grad_c_e,
143+
}
144+
)
114145
return variables
115146

116147
def _get_conductivities(self, variables):
@@ -146,41 +177,20 @@ def set_boundary_conditions(self, variables):
146177
if self.domain == "separator":
147178
return
148179

149-
param = self.param
150-
151-
conductivity, sigma_eff = self._get_conductivities(variables)
152-
i_boundary_cc = variables["Current collector current density"]
153180
c_e = variables[f"{Domain} electrolyte concentration"]
154181
delta_phi = variables[f"{Domain} electrode surface potential difference"]
155182

156-
if self.domain == "negative":
157-
T = variables["Negative electrode temperature"]
158-
c_e_flux = pybamm.BoundaryGradient(c_e, "right")
159-
flux_left = -i_boundary_cc * pybamm.BoundaryValue(1 / sigma_eff, "left")
160-
flux_right = (
161-
(i_boundary_cc / pybamm.BoundaryValue(conductivity, "right"))
162-
- pybamm.BoundaryValue(param.chiRT_over_Fc(c_e, T), "right") * c_e_flux
163-
- i_boundary_cc * pybamm.BoundaryValue(1 / sigma_eff, "right")
164-
)
183+
grad_left = variables[f"{self.domain} grad(delta_phi) left"]
184+
grad_right = variables[f"{self.domain} grad(delta_phi) right"]
185+
grad_c_e = variables[f"{self.domain} grad(c_e) internal"]
165186

166-
lbc = (flux_left, "Neumann")
167-
rbc = (flux_right, "Neumann")
187+
lbc = (grad_left, "Neumann")
188+
rbc = (grad_right, "Neumann")
189+
if self.domain == "negative":
168190
lbc_c_e = (pybamm.Scalar(0), "Neumann")
169-
rbc_c_e = (c_e_flux, "Neumann")
170-
191+
rbc_c_e = (grad_c_e, "Neumann")
171192
elif self.domain == "positive":
172-
T = variables["Positive electrode temperature"]
173-
c_e_flux = pybamm.BoundaryGradient(c_e, "left")
174-
flux_left = (
175-
(i_boundary_cc / pybamm.BoundaryValue(conductivity, "left"))
176-
- pybamm.BoundaryValue(param.chiRT_over_Fc(c_e, T), "left") * c_e_flux
177-
- i_boundary_cc * pybamm.BoundaryValue(1 / sigma_eff, "left")
178-
)
179-
flux_right = -i_boundary_cc * pybamm.BoundaryValue(1 / sigma_eff, "right")
180-
181-
lbc = (flux_left, "Neumann")
182-
rbc = (flux_right, "Neumann")
183-
lbc_c_e = (c_e_flux, "Neumann")
193+
lbc_c_e = (grad_c_e, "Neumann")
184194
rbc_c_e = (pybamm.Scalar(0), "Neumann")
185195

186196
# TODO: check why we still need the boundary conditions for c_e, once we have

pybamm/models/submodels/electrolyte_diffusion/full_diffusion.py

+13-2
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,13 @@ def get_coupled_variables(self, variables):
7676
N_e = N_e_diffusion + N_e_migration + N_e_convection
7777

7878
variables.update(self._get_standard_flux_variables(N_e))
79+
variables.update(
80+
{
81+
"Electrolyte diffusion flux": N_e_diffusion,
82+
"Electrolyte migration flux": N_e_migration,
83+
"Electrolyte convection flux": N_e_convection,
84+
}
85+
)
7986

8087
return variables
8188

@@ -85,12 +92,16 @@ def set_rhs(self, variables):
8592

8693
eps_c_e = variables["Porosity times concentration"]
8794
c_e = variables["Electrolyte concentration"]
88-
N_e = variables["Electrolyte flux"]
95+
T = variables["Cell temperature"]
96+
N_e_diffusion = variables["Electrolyte diffusion flux"]
97+
N_e_convection = variables["Electrolyte convection flux"]
98+
N_e = N_e_diffusion + N_e_convection
8999
div_Vbox = variables["Transverse volume-averaged acceleration"]
90100

91101
sum_s_j = variables["Sum of electrolyte reaction source terms"]
102+
sum_a_j = variables["Sum of volumetric interfacial current densities"]
92103
sum_s_j.print_name = "a"
93-
source_terms = sum_s_j / self.param.gamma_e
104+
source_terms = (sum_s_j - param.t_plus(c_e, T) * sum_a_j) / self.param.gamma_e
94105

95106
self.rhs = {
96107
eps_c_e: -pybamm.div(N_e) / param.C_e + source_terms - c_e * div_Vbox

pybamm/models/submodels/interface/kinetics/diffusion_limited.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ def _get_diffusion_limited_current_density(self, variables):
8484
N_ox_neg_sep_interface = (
8585
-pybamm.boundary_value(tor_s, "left")
8686
* param.curlyD_ox
87-
* pybamm.BoundaryGradient(c_ox_s, "left")
87+
* pybamm.boundary_gradient(c_ox_s, "left")
8888
)
8989
N_ox_neg_sep_interface.domains = {"primary": "current collector"}
9090

pybamm/models/submodels/thermal/pouch_cell/pouch_cell_2D_current_collectors.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,8 @@ def set_boundary_conditions(self, variables):
115115
/ self.param.delta
116116
)
117117

118-
T_av_n = pybamm.BoundaryValue(T_av, "negative tab")
119-
T_av_p = pybamm.BoundaryValue(T_av, "positive tab")
118+
T_av_n = pybamm.boundary_value(T_av, "negative tab")
119+
T_av_p = pybamm.boundary_value(T_av, "positive tab")
120120

121121
self.boundary_conditions = {
122122
T_av: {

pybamm/spatial_methods/finite_volume.py

+5-7
Original file line numberDiff line numberDiff line change
@@ -615,8 +615,6 @@ def add_ghost_nodes(self, symbol, discretised_symbol, bcs):
615615
n = submesh.npts
616616
second_dim_repeats = self._get_auxiliary_domain_repeats(symbol.domains)
617617

618-
bcs_vector = pybamm.Vector([]) # starts empty
619-
620618
lbc_value, lbc_type = bcs["left"]
621619
rbc_value, rbc_type = bcs["right"]
622620

@@ -748,23 +746,23 @@ def add_neumann_values(self, symbol, discretised_gradient, bcs, domain):
748746
n_bcs += 1
749747

750748
# Add any values from Neumann boundary conditions to the bcs vector
751-
if lbc_type == "Neumann":
749+
if lbc_type == "Neumann" and lbc_value != 0:
752750
lbc_sub_matrix = coo_matrix(([1], ([0], [0])), shape=(n + n_bcs, 1))
753751
lbc_matrix = csr_matrix(kron(eye(second_dim_repeats), lbc_sub_matrix))
754752
if lbc_value.evaluates_to_number():
755753
left_bc = lbc_value * pybamm.Vector(np.ones(second_dim_repeats))
756754
else:
757755
left_bc = lbc_value
758756
lbc_vector = pybamm.Matrix(lbc_matrix) @ left_bc
759-
elif lbc_type == "Dirichlet":
757+
elif lbc_type == "Dirichlet" or (lbc_type == "Neumann" and lbc_value == 0):
760758
lbc_vector = pybamm.Vector(np.zeros((n + n_bcs) * second_dim_repeats))
761759
else:
762760
raise ValueError(
763761
"boundary condition must be Dirichlet or Neumann, not '{}'".format(
764-
lbc_type
762+
rbc_type
765763
)
766764
)
767-
if rbc_type == "Neumann":
765+
if rbc_type == "Neumann" and rbc_value != 0:
768766
rbc_sub_matrix = coo_matrix(
769767
([1], ([n + n_bcs - 1], [0])), shape=(n + n_bcs, 1)
770768
)
@@ -774,7 +772,7 @@ def add_neumann_values(self, symbol, discretised_gradient, bcs, domain):
774772
else:
775773
right_bc = rbc_value
776774
rbc_vector = pybamm.Matrix(rbc_matrix) @ right_bc
777-
elif rbc_type == "Dirichlet":
775+
elif rbc_type == "Dirichlet" or (rbc_type == "Neumann" and rbc_value == 0):
778776
rbc_vector = pybamm.Vector(np.zeros((n + n_bcs) * second_dim_repeats))
779777
else:
780778
raise ValueError(

tests/integration/test_models/standard_output_tests.py

+8-2
Original file line numberDiff line numberDiff line change
@@ -508,7 +508,10 @@ def test_conservation(self):
508508
diff = (
509509
self.c_e_tot(self.solution.t[1:]) - self.c_e_tot(self.solution.t[:-1])
510510
) / self.c_e_tot(self.solution.t[:-1])
511-
np.testing.assert_array_almost_equal(diff, 0)
511+
if self.model.options["surface form"] == "differential":
512+
np.testing.assert_array_almost_equal(diff, 0, decimal=9)
513+
else:
514+
np.testing.assert_array_almost_equal(diff, 0, decimal=14)
512515

513516
def test_concentration_profile(self):
514517
"""Test continuity of the concentration profile. Test average concentration is
@@ -560,11 +563,14 @@ def test_splitting(self):
560563

561564
def test_all(self):
562565
self.test_concentration_limit()
563-
self.test_conservation()
564566
self.test_concentration_profile()
565567
self.test_fluxes()
566568
self.test_splitting()
567569

570+
if isinstance(self.model, pybamm.lithium_ion.BaseModel):
571+
# electrolyte is not conserved in lead-acid models
572+
self.test_conservation()
573+
568574

569575
class PotentialTests(BaseOutputTest):
570576
def __init__(self, model, param, disc, solution, operating_condition):

tests/unit/test_expression_tree/test_unary_operators.py

+9
Original file line numberDiff line numberDiff line change
@@ -577,6 +577,15 @@ def test_boundary_value(self):
577577
):
578578
pybamm.boundary_value(symbol_on_edges, "right")
579579

580+
def test_boundary_gradient(self):
581+
var = pybamm.Variable("var", domain=["negative electrode"])
582+
grad = pybamm.boundary_gradient(var, "right")
583+
self.assertIsInstance(grad, pybamm.BoundaryGradient)
584+
585+
zero = pybamm.PrimaryBroadcast(0, ["negative electrode"])
586+
grad = pybamm.boundary_gradient(zero, "right")
587+
self.assertEqual(grad, 0)
588+
580589
def test_unary_simplifications(self):
581590
a = pybamm.Scalar(0)
582591
b = pybamm.Scalar(1)

0 commit comments

Comments
 (0)