Skip to content

Commit 8555a64

Browse files
committed
#704 added convergence tests for all types of extrapolation
1 parent fb794ff commit 8555a64

File tree

3 files changed

+119
-6
lines changed

3 files changed

+119
-6
lines changed

pybamm/spatial_methods/finite_volume.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -590,7 +590,7 @@ def boundary_value_or_flux(self, symbol, discretised_child, bcs=None):
590590
prim_pts = submesh_list[0].npts
591591
sec_pts = len(submesh_list)
592592

593-
if not bcs:
593+
if bcs is None:
594594
bcs = {}
595595

596596
# Create submatrix to compute boundary values or fluxes

pybamm/spatial_methods/spatial_method.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ class SpatialMethod:
1212
operations.
1313
All spatial methods will follow the general form of SpatialMethod in
1414
that they contain a method for broadcasting variables onto a mesh,
15-
a gradient operator, and a diverence operator.
15+
a gradient operator, and a divergence operator.
1616
1717
Parameters
1818
----------

tests/unit/test_spatial_methods/test_finite_volume/test_extrapolation.py

+117-4
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
import unittest
1616

1717

18-
def errors(pts, function, method_options):
18+
def errors(pts, function, method_options, bcs=None):
1919

2020
domain = "test"
2121
x = pybamm.SpatialVariable("x", domain=domain)
@@ -33,6 +33,12 @@ def errors(pts, function, method_options):
3333
left_extrap = pybamm.BoundaryValue(var, "left")
3434
right_extrap = pybamm.BoundaryValue(var, "right")
3535

36+
if bcs:
37+
model = pybamm.BaseBatteryModel()
38+
bc_dict = {var: bcs}
39+
model.boundary_conditions = bc_dict
40+
disc.bcs = disc.process_boundary_conditions(model)
41+
3642
submesh = mesh["test"]
3743
y, l_true, r_true = function(submesh[0].nodes)
3844

@@ -46,13 +52,13 @@ def errors(pts, function, method_options):
4652
return l_error, r_error
4753

4854

49-
def get_errors(function, method_options, pts):
55+
def get_errors(function, method_options, pts, bcs=None):
5056

5157
l_errors = np.zeros(pts.shape)
5258
r_errors = np.zeros(pts.shape)
5359

5460
for i, pt in enumerate(pts):
55-
l_errors[i], r_errors[i] = errors(pt, function, method_options)
61+
l_errors[i], r_errors[i] = errors(pt, function, method_options, bcs)
5662

5763
return l_errors, r_errors
5864

@@ -126,9 +132,116 @@ def x_cubed(x):
126132
np.testing.assert_array_almost_equal(l_quad_rates, 3)
127133
np.testing.assert_array_almost_equal(r_quad_rates, 3, decimal=3)
128134

129-
def test_extrapolation_with_bcs(self):
135+
def test_extrapolation_with_bcs_right_neumann(self):
136+
# simple particle with a flux bc
137+
138+
pts = 10 ** np.arange(1, 6, 1)
139+
dx = 1 / pts
140+
141+
left_val = 1
142+
right_flux = 2
143+
144+
def x_cubed(x):
145+
n = 3
146+
f_x = x ** n
147+
f_l = 0
148+
fp_r = n
149+
y = f_x + (right_flux - fp_r) * x + (left_val - f_l)
150+
151+
true_left = left_val
152+
true_right = 1 + (right_flux - fp_r) + (left_val - f_l)
153+
154+
return y, true_left, true_right
155+
156+
bcs = {"left": (left_val, "Dirichlet"), "right": (right_flux, "Neumann")}
157+
158+
linear = {"extrapolation": {"order": "linear", "use bcs": True}}
159+
quad = {"extrapolation": {"order": "quadratic", "use bcs": True}}
160+
l_errors_lin_no_bc, r_errors_lin_no_bc = get_errors(x_cubed, linear, pts,)
161+
l_errors_quad_no_bc, r_errors_quad_no_bc = get_errors(x_cubed, quad, pts,)
162+
163+
l_errors_lin_with_bc, r_errors_lin_with_bc = get_errors(
164+
x_cubed, linear, pts, bcs
165+
)
166+
l_errors_quad_with_bc, r_errors_quad_with_bc = get_errors(
167+
x_cubed, quad, pts, bcs
168+
)
169+
170+
# test that with bc is better than without
171+
172+
np.testing.assert_array_less(l_errors_lin_with_bc, l_errors_lin_no_bc)
173+
np.testing.assert_array_less(r_errors_lin_with_bc, r_errors_lin_no_bc)
174+
np.testing.assert_array_less(l_errors_quad_with_bc, l_errors_quad_no_bc)
175+
np.testing.assert_array_less(r_errors_quad_with_bc, r_errors_quad_no_bc)
176+
177+
# note that with bcs we now obtain the left Dirichlet condition exactly
178+
179+
r_lin_rates_bc = np.log(
180+
r_errors_lin_with_bc[:-1] / r_errors_lin_with_bc[1:]
181+
) / np.log(dx[:-1] / dx[1:])
182+
r_quad_rates_bc = np.log(
183+
r_errors_quad_with_bc[:-1] / r_errors_quad_with_bc[1:]
184+
) / np.log(dx[:-1] / dx[1:])
185+
186+
# check convergence is about the correct order
187+
np.testing.assert_array_almost_equal(r_lin_rates_bc, 2, decimal=2)
188+
np.testing.assert_array_almost_equal(r_quad_rates_bc, 3, decimal=1)
189+
190+
def test_extrapolation_with_bcs_left_neumann(self):
130191
# simple particle with a flux bc
131192

193+
pts = 10 ** np.arange(1, 5, 1)
194+
dx = 1 / pts
195+
196+
left_flux = 2
197+
right_val = 1
198+
199+
def x_cubed(x):
200+
n = 3
201+
f_x = x ** n
202+
fp_l = 0
203+
f_r = 1
204+
y = f_x + (left_flux - fp_l) * x + (right_val - f_r - left_flux + fp_l)
205+
206+
true_left = right_val - f_r - left_flux + fp_l
207+
true_right = right_val
208+
209+
return y, true_left, true_right
210+
211+
bcs = {"left": (left_flux, "Neumann"), "right": (right_val, "Dirichlet")}
212+
213+
linear = {"extrapolation": {"order": "linear", "use bcs": True}}
214+
quad = {"extrapolation": {"order": "quadratic", "use bcs": True}}
215+
l_errors_lin_no_bc, r_errors_lin_no_bc = get_errors(x_cubed, linear, pts,)
216+
l_errors_quad_no_bc, r_errors_quad_no_bc = get_errors(x_cubed, quad, pts,)
217+
218+
l_errors_lin_with_bc, r_errors_lin_with_bc = get_errors(
219+
x_cubed, linear, pts, bcs
220+
)
221+
l_errors_quad_with_bc, r_errors_quad_with_bc = get_errors(
222+
x_cubed, quad, pts, bcs
223+
)
224+
225+
# test that with bc is better than without
226+
227+
np.testing.assert_array_less(l_errors_lin_with_bc, l_errors_lin_no_bc)
228+
np.testing.assert_array_less(r_errors_lin_with_bc, r_errors_lin_no_bc)
229+
np.testing.assert_array_less(l_errors_quad_with_bc, l_errors_quad_no_bc)
230+
np.testing.assert_array_less(r_errors_quad_with_bc, r_errors_quad_no_bc)
231+
232+
# note that with bcs we now obtain the right Dirichlet condition exactly
233+
234+
l_lin_rates_bc = np.log(
235+
l_errors_lin_with_bc[:-1] / l_errors_lin_with_bc[1:]
236+
) / np.log(dx[:-1] / dx[1:])
237+
l_quad_rates_bc = np.log(
238+
l_errors_quad_with_bc[:-1] / l_errors_quad_with_bc[1:]
239+
) / np.log(dx[:-1] / dx[1:])
240+
241+
# check convergence is about the correct order
242+
np.testing.assert_array_less(2, l_lin_rates_bc)
243+
np.testing.assert_array_almost_equal(l_quad_rates_bc, 3, decimal=1)
244+
132245

133246
if __name__ == "__main__":
134247
print("Add -v for more debug output")

0 commit comments

Comments
 (0)