好的,我们来推导热传导方程的一维显式有限差分格式,并将其写成矩阵向量的形式。在这个过程中,我们会看到如何离散化方程,如何形成变换矩阵,并分析其稳定性。后面有一个国外的教授写的MATLAB代码(链接我就不找了,找到朋友可以把链接发在留言区),不需要修改就可以在北太天元直接运行。

热传导方程的一维显式有限差分格式
热传导方程为:
其中 ( u(x, t) ) 是温度分布函数,( \alpha ) 是热传导系数。
将空间域划分为等距网格,网格点为 ( x_j = j\Delta x ),( j = 0, 1, \ldots, N ),其中 ( \Delta x = L/N ) 是空间步长,( L ) 是空间域的长度。时间也进行离散化,时间点为 ( t_n = n\Delta t ),( n = 0, 1, 2, \ldots ),其中 ( \Delta t ) 是时间步长。
应用向前差分于时间导数,应用中心差分于空间二阶导数,得到:
其中 ( u_j^n = u(x_j, t_n) )。整理上式,得到:
这是热传导方程的一维显式有限差分格式。
将上式写成矩阵向量的形式。定义向量 表示 ( t = t_n ) 时刻的温度分布(注意这里我们忽略了边界点 ( u_0^n ) 和 ( u_N^n ),它们通常由边界条件给出)。
变换矩阵 是一个
的三对角矩阵,其非零元素为:
其中 。注意这里
,并且我们假设了零边界条件,不需要对这个矩阵做额外的修改。
于是,显式有限差分格式可以写成:
为了分析这个差分格式的稳定性,我们需要考察变换矩阵 ( \mathbf{A} ) 的特征值。由于 ( \mathbf{A} ) 是对称正定的(在适当的边界条件下),它的特征值都是实数。为了保证格式的稳定性,我们需要所有特征值的绝对值都不大于1。这通常通过对 ( r ) 施加限制来实现,即Courant-Friedrichs-Lewy(CFL)条件:
当满足CFL条件时,显式有限差分格式是稳定的。如果 ( r ) 超过了这个限制,解可能会变得不稳定并出现振荡。
对于隐式的差分格式,我们同样从热传导方程出发,但这次我们将时间导数用向后差分来近似,而空间导数依然使用中心差分。这样的格式是无条件稳定的,但每个时间步都需要解一个线性方程组。
隐式格式的离散化方程为:
整理得到:
进一步整理为:
定义向量 和
。注意,这里同样使用了零边界条件。
变换矩阵 是一个
的三对角矩阵,其非零元素为:
其中 。与显式格式不同,隐式格式在每个时间步都需要解如下线性方程组:
由于 是对称正定的,这个线性方程组有唯一解,并且可以使用诸如共轭梯度法或预处理的Krylov子空间方法等高效算法来求解。
隐式有限差分格式是无条件稳定的,意味着无论 ( r ) 的值如何,格式都是稳定的。这是因为隐式格式在每个时间步都求解了一个线性方程组,从而确保了数值解的稳定性。然而,由于需要解线性方程组,隐式格式的计算成本通常比显式格式高。
在数学中,向量值函数是从一个实数或实数的子集映射到一个向量空间的函数。在热传导的情境中,我们可以将温度分布看作是定义在空间网格点集合上的向量值函数。对于每个固定的时间 ( t ),函数 可以看作是一个向量值函数,其输出是一个包含所有空间网格点上温度值的向量。
对于热传导方程,当我们离散化空间并使用有限差分方法时,我们在每个时间步得到一个温度分布的向量。这个向量包含了所有离散空间点上的温度近似值。随着时间的推进,这些向量形成了一个序列,每个向量对应一个时间步的温度分布。
在离散化的热传导方程中,我们可以将时间看作是自变量,而温度分布向量看作是因变量。对于隐式差分格式,我们需要求解一个线性方程组来找到下一个时间步的温度分布向量。这个线性方程组中的矩阵可以看作是对拉普拉斯算子的离散化,它作用于温度分布向量。
向量值函数的理论涉及到向量微积分和线性代数的概念。在热传导方程的离散化过程中,我们使用了这些概念来将连续的偏微分方程转化为离散的线性方程组。分析这些线性方程组的解的性质(如稳定性、收敛性等)涉及到矩阵分析和数值线性代数的知识。
总的来说,向量值函数的概念在热传导方程的离散化和求解过程中扮演了重要角色。通过将连续的温度分布函数离散化为一系列的温度分布向量,我们能够使用数值方法来近似求解热传导问题。
% calcolo soluzione heat eq 1D con FTCS e BTCS
%
% heatFTCS_BTCS Solve 1D heat equation with both FTCS and BTCS schemes
%
% Input: nt = number of steps.;
% nx = number of mesh points in x direction.
% alpha = diffusivity. Default: alpha = 1
% L = length of the domain. Default: L = pi;
% tmax = maximum time for the simulation. Default: tmax = 2
% errPlots = flag (1 or 0) to control whether plots of the solution
% and the error at the last time step are created.
% Default: errPlots = 1 (make the plots)
%
% Output: err = L2 norm of error evaluated at the spatial nodes on last time step
% x = location of finite difference nodes
% t = values of time at which solution is obtained (time nodes)
% U = matrix of solutions: U(:,j) is U(x) at t = t(j)
clear, clc, close all
s = 0.4;
nx = 41;
alpha = 1.;
L = pi;
tmax = 2.0;
errPlots=1;
nomefile = ['sqm',num2str(nx),'.txt'];
%
% --- Compute mesh spacing and time step
dx = L/(nx-1);
dt = s*dx^2/alpha;
nt = ceil(tmax/dt);
r = alpha*dt/dx^2; r2 = 1 - 2*r;
fprintf('\ndx = %12.6f dt = %12.6f nt = %4.0i \n',dx,dt,nt);
%fprintf('\nnt*dt = %12.6f \n',nt*dt);
% --- Create arrays to save data for export
x = linspace(0,L,nx)';
%t = linspace(0,tmax,nt);
t = (0:dt:tmax);
U_ftcs = zeros(nx,nt);
err_ftcs = zeros(1,nt);
U_btcs = zeros(nx,nt);
err_btcs = zeros(1,nt);
ue = zeros(nx,nt);
txtfile = fopen(nomefile,'w');
% --- Set IC and BC
U_ftcs(:,1) = sin(pi*x/L); % implies u0 = 0; uL = 0;
u0 = 0; uL = 0; % needed to apply BC inside time step loop
U_btcs(:,1) = sin(pi*x/L); % implies u0 = 0; uL = 0;
fprintf(txtfile,'#t(m),err_ftcs(m),err_btcs(m)\n');
% --- Coefficients of the tridiagonal system
a = (-alpha/dx^2)*ones(nx,1); % subdiagonal a: coefficients of phi(i-1)
c = a; % superdiagonal c: coefficients of phi(i+1)
b = (1/dt)*ones(nx,1) - 2*a; % diagonal b: coefficients of phi(i)
b(1) = 1; c(1) = 0; % Fix coefficients of boundary nodes
b(end) = 1; a(end) = 0;
[e,f] = tridiagLU(a,b,c); % Get LU factorization of coefficient matrix
% --- Loop over time steps
for m=2:nt
for i=2:nx-1
U_ftcs(i,m) = r*U_ftcs(i-1,m-1) + r2*U_ftcs(i,m-1) + r*U_ftcs(i+1,m-1);
end
ue(:,m) = sin(x)*exp(-t(m)*alpha);
err_ftcs(m) = norm(U_ftcs(:,m)-ue(:,m));
%fprintf('\nNorm of error = %12.3e at t = %8.3f\n',err_ftcs(m),t(m));
d = U_btcs(:,m-1)/dt; % update right hand side
d(1) = u0; d(end) = uL; % overwrite BC values
U_btcs(:,m) = tridiagLUsolve(d,a,e,f,U_btcs(:,m-1)); % solve the system
err_btcs(m) = norm(U_btcs(:,m)-ue(:,m));
fprintf('\nerrorNorm = %12.3e %12.3e at t = %8.3f \n',err_ftcs(m),err_btcs(m),t(m));
fprintf(txtfile,'%8.3f %12.3e %12.3e \n',t(m),err_ftcs(m),err_btcs(m));
end
fclose(txtfile);
for i=1:nx
%fprintf('\nsol = %12.3e %12.3e \n',U_ftcs(:,1),U_btcs(:,1));
fprintf(' %12.8f %12.8f %12.8f \n', U_ftcs(i,nt), U_btcs(i,nt),ue(i,nt));
end
% --- Plot error in solution at the last time step
if ~errPlots, return; end
%fprintf('\nNorm of error FTCS = %12.3e BTCS = %12.3e at t = %8.3f\n',err_ftcs(nt),err_btcs(nt),t(nt));
%fprintf('\tdt, dx, nt = %12.5e %12.3e %8.0f\n',dt,dx,nt);
%fprintf('\ttmax, dt, tmax/dt = %12.5e %12.3e %12.6e \n',tmax,dt,tmax/dt);
%return
figure; plot(x,U_ftcs(:,nt),'o--',x,ue(:,nt),'-',x,U_btcs(:,nt),'x--'); xlabel('x'); ylabel('u');
legend('FTCS','Exact','BTCS');
%figure; plot(x,U_ftcs(:,nt)-ue(:,m),'o--'); xlabel('x'); ylabel('u - u_e');
%%legend('err','time');
figure; plot(t,err_ftcs,'o--',t,err_btcs,'x--'); xlabel('t'); ylabel('sqm');
legend('FTCS','BTCS');
function [e,f] = tridiagLU(a,b,c)
% tridiagLU Obtain the LU factorization of a tridiagonal matrix
%
% Synopsis: [e,f] = tridiag(a,b,c)
%
% Input: a,b,c = vectors defining the tridiagonal matrix. a is the
% subdiagonal, b is the main diagonal, and c is the superdiagonal
%
% Output: e,f = vectors defining the L and U factors of the tridiagonal matrix
n = length(a);
e = zeros(n,1); f = e;
e(1) = b(1);
f(1) = c(1)/b(1);
for i=2:n
e(i) = b(i) - a(i)*f(i-1);
f(i) = c(i)/e(i);
end
end
function v = tridiagLUsolve(d,a,e,f,v)
% tridiagLUsolve Solve (LU)*v = d where L and U are LU factors of a tridiagonal
% matrix
%
% Synopsis: v = tridiagLUsolve(d,e,f)
% v = tridiagLUsolve(d,e,f,v)
%
% Input: d = right hand side vector of the system of equatoins
% e,f = vectors defining the L and U factors of the tridiagonal matrix.
% e and f are obtained with the tridiagLU function
% v = solution vector. If v is supplied, the elements of v are over-
% written (thereby saving the memory allocation step). If v is not
% supplied, it is created. v is used as a scratch vector in the
% forward solve.
%
% Output: v = solution vector
n = length(d);
if nargin<5, v = zeros(n,1); end
% --- Forward substitution to solve L*w = d
v(1) = d(1)/e(1);
for i=2:n
v(i) = (d(i) - a(i)*v(i-1))/e(i);
end
% --- Backward substitution to solve U*v = w
for i=n-1:-1:1
v(i) = v(i) - f(i)*v(i+1);
end
end