%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% LICENSE %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% This file is part of mitx_mathematics_programming_examples. %
% %
% mitx_mathematics_programming_examples is free software: you can %
% redistribute it and/or modify it under the terms of the GNU General Public %
% License as published by the Free Software Foundation, either version 3 of %
% the License, or (at your option) any later version. %
% %
% mitx_mathematics_programming_examples is distributed in the hope that it %
% will be useful, but WITHOUT ANY WARRANTY; without even the implied %
% warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the %
% GNU General Public License for more details. %
% %
% You should have received a copy of the GNU General Public License %
% along with mitx_mathematics_programming_examples. If not, see %
% <https://www.gnu.org/licenses/>. %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Purpose: %
% Numerical solver for the heat equation applied to baking a cake. %
% Notes: %
% This is an adaptation of the original MATLAB code written by the MITx %
% team some years ago. I have re-written everything so that it works on %
% GNU Octave, so users need not rely on MATLAB. %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Author: Ryan Maguire %
% Date: Nevember 4, 2024. %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Solve heat equation using forward time, centered space scheme.
close all;
clearvars;
% Parameters for the spatial grid.
length_of_cake = 0.1;
number_of_steps = 20;
% Time step used in the numerical solver.
dt = 0.06;
% Time parameter for the simulation.
max_time = 60.0;
% Create an array for the time axis.
time = 0.0:dt:max_time;
% And create an array for the spacial component.
x = linspace(0.0, length_of_cake, number_of_steps);
% Displacement. This is the length of the cake divided by the number of steps.
dx = x(2) - x(1);
% Pre-compute the scale factors to save on redundant calculations.
dx_sq = dx*dx;
two_dx_sq = 2.0 * dx_sq;
% Initial condition.
initial_conditions = @(x) 20 * ones(1, 20);
% Parameters for the time and spatial components of the for-loops below.
number_of_time_steps = length(time);
number_of_spatial_steps = number_of_steps - 1;
% Set the initial conditions for the cake.
u = initial_conditions(x);
u(1) = 200;
u(end) = u(end - 1);
% Conductivity.
k = @(u) ((0.19 - 0.31)*0.5) * erf(u-100) + (0.31 - 0.19)*0.5 + 0.19;
% Capacity.
c = @(u) ((2200.0 - 2800.0)*0.5) * erf(u-100) + (2800.0 - 2200.0)*0.52 + 2200.0;
% Loop through both the time and spatial compents and numerically solve.
for i = 1:number_of_time_steps
% Impose left boundary condition.
u(i + 1, 1) = 200;
for j = 2:number_of_spatial_steps
% Find solution at next time step.
denom = two_dx_sq * c(u(i, j));
factor = dt / denom;
% Centered spatial component, numerical solver. We have, for the
% heat equation, the following setup:
% u_xx = u_t
% Applying an Euler-like numerical solver, we get:
% u(i+1, j) = dt u_xx(i, j)
% We numerically compute u_xx using the centered difference calculation.
% We need u(i, j), u(i, j-1), and u(i, j+1) for this. Compute.
u_j_plus_1 = u(i, j + 1);
u_j = u(i, j);
u_j_minus_1 = u(i, j - 1);
% Compute the sums from the centered difference scheme.
right_sum = u_j_plus_1 + u_j;
left_sum = u_j_minus_1 + u_j;
right = k(right_sum) * u_j_plus_1;
left = k(left_sum) * u_j_minus_1;
center = (k(u_j_plus_1) + 2.0 * k(u_j) + k(u_j_minus_1)) * u_j;
% Numerically calculate the next step.
u(i + 1, j) = u(i, j) + factor * (right + left - center);
end
% Impose right boundary condition.
u(i + 1, end) = u(i + 1, end - 1);
% Create the animation
% First time through the main loop, create the plot
% Subsequent times, update YData and title
if i == 1
% Plot solution.
p = plot(x, u(i, :), 'linewidth', 2);
xlabel('$x$', 'interpreter', 'latex')
ylabel('$u$', 'interpreter', 'latex')
ylim([20, 200]);
else
% Update the plot.
set(p, 'YData', u(i, :));
end
title(['t = ', num2str(time(i), '%.3f')], 'interpreter', 'latex')
drawnow
end