Skip to content

Commit 4e4e1ab

Browse files
Merge pull request #1118 from pybamm-team/issue-1114-r-average
Issue 1114 r average
2 parents 07d250d + 1270afc commit 4e4e1ab

File tree

9 files changed

+126
-51
lines changed

9 files changed

+126
-51
lines changed

CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
## Features
44

5+
- Added "R-averaged particle concentration" variables` ([#1118](https://github.com/pybamm-team/PyBaMM/pull/1118))
56
- Added support for sensitivity calculations to the casadi solver ([#1109](https://github.com/pybamm-team/PyBaMM/pull/1109))
67
- Added support for index 1 semi-explicit dae equations and sensitivity calculations to JAX BDF solver ([#1107](https://github.com/pybamm-team/PyBaMM/pull/1107))
78
- Allowed keyword arguments to be passed to `Simulation.plot()` ([#1099](https://github.com/pybamm-team/PyBaMM/pull/1099))
@@ -10,6 +11,8 @@
1011

1112
## Bug fixes
1213

14+
- Fixed `r_average` to work with `SecondaryBroadcast` ([#1118](https://github.com/pybamm-team/PyBaMM/pull/1118))
15+
- Fixed finite volume discretisation of spherical integrals ([#1118](https://github.com/pybamm-team/PyBaMM/pull/1118))
1316
- `t_eval` now gets changed to a `linspace` if a list of length 2 is passed ([#1113](https://github.com/pybamm-team/PyBaMM/pull/1113))
1417
- Fixed bug when setting a function with an `InputParameter` ([#1111](https://github.com/pybamm-team/PyBaMM/pull/1111))
1518

examples/notebooks/spatial_methods/finite-volumes.ipynb

+78-41
Large diffs are not rendered by default.

pybamm/expression_tree/broadcasts.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,11 @@ def check_and_set_domains(
184184
self, child, broadcast_type, broadcast_domain, broadcast_auxiliary_domains
185185
):
186186
"See :meth:`Broadcast.check_and_set_domains`"
187-
187+
if child.domain == []:
188+
raise TypeError(
189+
"Cannot take SecondaryBroadcast of an object with empty domain. "
190+
"Use PrimaryBroadcast instead."
191+
)
188192
# Can only do secondary broadcast from particle to electrode or from
189193
# electrode to current collector
190194
if child.domain[0] in [

pybamm/expression_tree/unary_operators.py

+16-4
Original file line numberDiff line numberDiff line change
@@ -1167,13 +1167,25 @@ def r_average(symbol):
11671167
# Can't take average if the symbol evaluates on edges
11681168
if symbol.evaluates_on_edges("primary"):
11691169
raise ValueError("Can't take the r-average of a symbol that evaluates on edges")
1170-
# If symbol doesn't have a particle domain, its r-averaged value is itself
1171-
if symbol.domain not in [["positive particle"], ["negative particle"]]:
1170+
# Otherwise, if symbol doesn't have a particle domain,
1171+
# its r-averaged value is itself
1172+
elif symbol.domain not in [["positive particle"], ["negative particle"]]:
11721173
new_symbol = symbol.new_copy()
11731174
new_symbol.parent = None
11741175
return new_symbol
1175-
# If symbol is a Broadcast, its average value is its child
1176-
elif isinstance(symbol, pybamm.Broadcast):
1176+
# If symbol is a secondary broadcast onto "negative electrode" or
1177+
# "positive electrode", take the r-average of the child then broadcast back
1178+
elif isinstance(symbol, pybamm.SecondaryBroadcast) and symbol.domains[
1179+
"secondary"
1180+
] in [["positive electrode"], ["negative electrode"]]:
1181+
child = symbol.orphans[0]
1182+
child_av = pybamm.r_average(child)
1183+
return pybamm.PrimaryBroadcast(child_av, symbol.domains["secondary"])
1184+
# If symbol is a Broadcast onto a particle domain, its average value is its child
1185+
elif isinstance(symbol, pybamm.PrimaryBroadcast) and symbol.domain in [
1186+
["positive particle"],
1187+
["negative particle"],
1188+
]:
11771189
return symbol.orphans[0]
11781190
else:
11791191
r = pybamm.SpatialVariable("r", symbol.domain)

pybamm/models/submodels/particle/base_particle.py

+7
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,22 @@ def _get_standard_concentration_variables(self, c_s, c_s_xav):
3434
elif self.domain == "Positive":
3535
c_scale = self.param.c_p_max
3636
active_volume = geo_param.a_p_dim * geo_param.R_p / 3
37+
38+
c_s_rav = pybamm.r_average(c_s)
3739
c_s_av = pybamm.r_average(c_s_xav)
3840
c_s_av_vol = active_volume * c_s_av
41+
3942
variables = {
4043
self.domain + " particle concentration": c_s,
4144
self.domain + " particle concentration [mol.m-3]": c_s * c_scale,
4245
"X-averaged " + self.domain.lower() + " particle concentration": c_s_xav,
4346
"X-averaged "
4447
+ self.domain.lower()
4548
+ " particle concentration [mol.m-3]": c_s_xav * c_scale,
49+
"R-averaged " + self.domain.lower() + " particle concentration": c_s_rav,
50+
"R-averaged "
51+
+ self.domain.lower()
52+
+ " particle concentration [mol.m-3]": c_s_rav * c_scale,
4653
self.domain + " particle surface concentration": c_s_surf,
4754
self.domain
4855
+ " particle surface concentration [mol.m-3]": c_scale * c_s_surf,

pybamm/spatial_methods/finite_volume.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ def integral(self, child, discretised_child, integration_dimension):
242242
second_dim_repeats = self._get_auxiliary_domain_repeats(child.domains)
243243
r_numpy = np.kron(np.ones(second_dim_repeats), submesh.nodes)
244244
r = pybamm.Vector(r_numpy)
245-
out = 4 * np.pi ** 2 * integration_vector @ (discretised_child * r)
245+
out = 4 * np.pi * integration_vector @ (discretised_child * r ** 2)
246246
else:
247247
out = integration_vector @ discretised_child
248248

tests/unit/test_expression_tree/test_broadcasts.py

+3
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ def test_secondary_broadcast(self):
5555
{"secondary": ["negative electrode"], "tertiary": ["current collector"]},
5656
)
5757

58+
a = pybamm.Symbol("a")
59+
with self.assertRaisesRegex(TypeError, "empty domain"):
60+
pybamm.SecondaryBroadcast(a, "current collector")
5861
a = pybamm.Symbol("a", domain="negative particle")
5962
with self.assertRaisesRegex(
6063
pybamm.DomainError, "Secondary broadcast from particle"

tests/unit/test_expression_tree/test_unary_operators.py

+9
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,15 @@ def test_r_average(self):
439439
# electrode domains go to current collector when averaged
440440
self.assertEqual(av_a.domain, [])
441441

442+
# r-average of a symbol that is broadcast to x
443+
# takes the average of the child then broadcasts it
444+
a = pybamm.Scalar(1, domain="positive particle")
445+
broad_a = pybamm.SecondaryBroadcast(a, "positive electrode")
446+
average_broad_a = pybamm.r_average(broad_a)
447+
self.assertIsInstance(average_broad_a, pybamm.PrimaryBroadcast)
448+
self.assertEqual(average_broad_a.domain, ["positive electrode"])
449+
self.assertEqual(average_broad_a.children[0].id, pybamm.r_average(a).id)
450+
442451
# r-average of symbol that evaluates on edges raises error
443452
symbol_on_edges = pybamm.PrimaryBroadcastToEdges(1, "domain")
444453
with self.assertRaisesRegex(

tests/unit/test_spatial_methods/test_finite_volume/test_finite_volume.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -725,15 +725,15 @@ def test_definite_integral(self):
725725

726726
constant_y = np.ones_like(mesh["negative particle"].nodes[:, np.newaxis])
727727
np.testing.assert_array_almost_equal(
728-
integral_eqn_disc.evaluate(None, constant_y), 2 * np.pi ** 2
728+
integral_eqn_disc.evaluate(None, constant_y), 4 * np.pi / 3, decimal=4
729729
)
730730
linear_y = mesh["negative particle"].nodes
731731
np.testing.assert_array_almost_equal(
732-
integral_eqn_disc.evaluate(None, linear_y), 4 * np.pi ** 2 / 3, decimal=3
732+
integral_eqn_disc.evaluate(None, linear_y), np.pi, decimal=3
733733
)
734-
one_over_y = 1 / mesh["negative particle"].nodes
734+
one_over_y_squared = 1 / mesh["negative particle"].nodes ** 2
735735
np.testing.assert_array_almost_equal(
736-
integral_eqn_disc.evaluate(None, one_over_y), 4 * np.pi ** 2
736+
integral_eqn_disc.evaluate(None, one_over_y_squared), 4 * np.pi
737737
)
738738

739739
# test failure for secondary dimension column form

0 commit comments

Comments
 (0)