Boundary value problems exercise solutions#
Solutions to the exercises on boundary value problems.
Solution to Exercise 5.1
(a) \(p(t) = -\dfrac{4}{t}\), \(q(t) = \dfrac{2}{t^2}\) and \(r(t) = \dfrac{2\ln(t)}{t^3}\) are all continuous and \(q(t) > 0\) for \(t \in [1, 2]\) so this boundary value problem has a unique solution.
(b) \(p(t) = -(t + 1)\), \(q(t) = \cos(t)\) and \(r(t) = e^t\) are all continuous for \(t\in[0,2]\) but \(q(t) < 0\) for \(t \in (\pi/2, 2]\) so this boundary value problem does not have a unique solution.
(c) \(p(t) = 0\), \(q(t) = t^3 + 5\) and \(r(t) = \sin(t)\) are all continuous and \(q(t) > 0\) for \(t\in[0,1]\) so this boundary value problem has a unique solution.
(d) \(p(t) = 0\), \(q(t) = 5e^t\) and \(r(t) = e^t\sin(3t)\) are all continuous and \(q(t) > 0\) for \(t\in[0,1]\) so this boundary value problem has a unique solution.
Solution to Exercise 5.2
Rewriting the ODE as a system of two first-order ODEs
Solving using the Euler method and \(y'(0)=1\)
Solving using \(y'(0)=-1\)
Solution to Exercise 5.3
Calculate the improved guess value
Solving using the Euler method with \(y'(0) = 0.36\)
The solutions to this boundary value problem using the Euler method with the shooting method are tabulated below.
\(t\) |
\(y_1\) |
\(y_2\) |
---|---|---|
0.0 |
1.000000 |
0.360000 |
0.4 |
1.144000 |
0.360000 |
0.8 |
1.288000 |
0.680000 |
1.2 |
1.560000 |
1.320000 |
1.6 |
2.088000 |
2.280000 |
2.0 |
3.000000 |
3.560000 |
Solution to Exercise 5.4
which can be written as the matrix equation
Since \(h=0.4\) then \(\vec{t} = (0, 0.4, 0.8, 1.2, 1.6, 2)\) and
Performing the forward sweep of the Thomas algorithm
Performing the back substitution step
The solutions to this boundary value problem using the finite-difference method are tabulated below.
\(t\) |
\(y\) |
---|---|
0.00 |
0.0000 |
0.40 |
0.8880 |
0.80 |
0.9040 |
1.20 |
0.1760 |
1.60 |
1.8320 |
2.00 |
3.0000 |
Solution to Exercise 5.5
The finite-difference method gives significantly more accurate solutions than the Euler method. This is because the finite-difference used a second-order approximation whereas the Euler method is only first-order. We would expect a more accurate method such as the RK4 method to give similar solutions to the finite-difference method.
Code
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['text.usetex'] = True # allows use of LaTeX in labels
# Define Euler method
def euler(f, tspan, y0, h):
# Initialise t and y arrays
t = np.empty(100000)
y = np.empty((100000,len(y0)))
t[0] = tspan[0]
y[0,:] = y0
# Loop through steps
n = 0
while t[n] < tspan[1]:
# Ensure t does not exceed tspan[1]
h = min(h, tspan[1] - t[n])
# Calculate Euler method
y[n+1,:] = y[n,:] + h * f(t[n], y[n,:])
t[n+1] = t[n] + h
n += 1
return t[:n+1], y[:n+1,:]
# Define shooting method
def shooting_method(solver, f, tspan, bvals, h, tol=1e-6):
s, sprev, gprev = 1, 2, 1
for _ in range(10):
t, y = solver(f, tspan, [bvals[0], s], h)
g = bvals[1] - y[-1,0]
s, sprev, gprev = s - g * (s - sprev) / (g - gprev), s, g
if abs(s - sprev) < tol:
break
return t, y
# Define tri-diagonal solver
def tridiagonal_solver(a, b, c, d):
n = len(b)
for i in range(1, n):
w = a[i] / b[i-1]
b[i] -= w * c[i-1]
d[i] -= w * d[i-1]
x = np.zeros(n)
x[-1] = d[-1] / b[-1]
for i in range(n - 2, -1, -1):
x[i] = (d[i] - c[i] * x[i+1]) / b[i]
return x
# Define ODE functions
def f(t, y):
return np.array([y[1], 2 * t])
def exact(t):
return 1 / 3 * t ** 3 - 1 / 3 * t + 1
# Define BVP parameters
tspan = [0, 2] # boundaries of the t domain
bvals = [1, 3] # boundary values
h = 0.4 # step length
svals = [1, -1]
# Solve BVP using the shooting method
t, y_euler = shooting_method(euler, f, tspan, bvals, h)
# Solve BVP using the finite-difference method
n = int((tspan[1] - tspan[0]) / h) + 1
t = np.arange(n) * h
a, b, c, d = [np.zeros(n) for _ in range(4)]
b[::n-1] = 1
d[::n-1] = bvals
for i in range(1, n - 1):
a[i] = 1
b[i] = -2
c[i] = 1
d[i] = 2 * h ** 2 * t[i]
y_fdm = tridiagonal_solver(a, b, c, d)
# Calculate exact solution
t_exact = np.linspace(tspan[0], tspan[1], 200)
y_exact = exact(t_exact)
# Plot solutions
fig, ax = plt.subplots(figsize=(8, 6))
plt.plot(t_exact, y_exact, "k", label="Exact")
plt.plot(t, y_euler[:,0], "bo-", label="Euler method")
plt.plot(t, y_fdm, "ro-", label="Finite-difference method")
plt.xlabel("$t$", fontsize=14)
plt.ylabel("$y$", fontsize=14)
plt.legend()
plt.show()
% Define ODE
f = @(t, y) [y(2), 2 * t];
% Define exact solution
exact = @(t) 1 / 3 * t .^ 3 - 1 / 3 * t + 1;
% Define BVP
tspan = [0, 2];
bvals = [1, 3];
h = 0.4;
% Solve BVP using the shooting method
[t, y_euler] = shooting_method(@euler, f, tspan, bvals, h, 1e-4);
% Solve BVP using finite-difference method
n = floor((tspan(2) - tspan(1)) / h) + 1;
t = (0 : n - 1) * h;
a = zeros(n, 1);
b = zeros(n, 1);
c = zeros(n, 1);
d = zeros(n, 1);
b([1, end]) = 1;
d([1, end]) = bvals;
for i = 2 : n - 1
a(i) = 1;
b(i) = -2;
c(i) = 1;
d(i) = 2 * h ^ 2 * t(i);
end
y_fdm = tridiagonal_solver(a, b, c, d);
% Calculate exact solution
t_exact = linspace(tspan(1), tspan(2), 200);
y_exact = exact(t_exact);
% Plot solutions
plot(t_exact, y_exact, "k", LineWidth=2)
hold on
plot(t, y_euler(:, 1), "b-o", LineWidth=2, MarkerFaceColor="b")
plot(t, y_fdm, "r-o", LineWidth=2, MarkerFaceColor="r")
hold off
axis padded
xlabel("$t$", FontSize=14, Interpreter="latex")
ylabel("$y$", FontSize=14, Interpreter="latex")
legend("Exact", "Euler method", "Finite-difference method", Location="northwest")
%% ----------------------------------------------------------------------------
function [t, y] = euler(f, tspan, y0, h)
nsteps = floor((tspan(2) - tspan(1)) / h);
neq = length(y0);
t = (0 : nsteps) * h;
y = zeros(nsteps + 1, neq);
y(1, :) = y0;
for n = 1 : nsteps
y(n+1, :) = y(n, :) + h * f(t(n), y(n, :));
end
end
%% ----------------------------------------------------------------------------
function [t, y] = shooting_method(solver, f, tspan, bvals, h, tol)
s = 1;
so = 2;
go = 1;
for i = 1 : 10
[t, y] = solver(f, tspan, [bvals(1), s], h);
g = bvals(2) - y(end,1);
temp = s;
s = s - g * (s - so) / (g - go);
so = temp;
go = g;
if abs(s - so) < tol
break
end
end
end
%% ----------------------------------------------------------------------------
function x = tridiagonal_solver(a, b, c, d)
n = length(b);
for i = 2 : n
w = a(i) / b(i-1);
b(i) = b(i) - w * c(i-1);
d(i) = d(i) - w * d(i-1);
end
x = zeros(n, 1);
x(n) = d(n) / b(n);
for i = n - 1 : -1 : 1
x(i) = (d(i) - c(i) * x(i+1)) / b(i);
end
end