Documente Academic
Documente Profesional
Documente Cultură
Pengfei Du
ut 2u x, y, t 0, lx 0, l y 0, t f
(1)
(2)
2
2
where n is time step index, x / y and t are spatial and time step length. This
uijn 1 uijn
uijn 1 uijn
t
(3)
or
uijn1 Fox x2uijn1 Foy y2uijn1 uijn Fox x2uijn Foy y2uijn
where Fox
t
2 x
,Foy
t
2 y
(3)
If you are satisfied with an unconditionally stable scheme and dose not care
about the efficiency, Crank-Nicolson is one of the choices. The following will
1 Fo 1 Fo u
2
x x
n 1
ij
2
y
(4)
This equation is then solved in splitting or fractional step methods. There are many
ways to accomplish the splitting. Peaceman-Rachford scheme is shown below
1 Fo u
1+ Foy y2 uijn
(5a)
1 Fo u
1+ Fox x2 uijn1/2
(5b)
n 1/2
ij
2
x
2
y
n 1
ij
It is clear that, instead of going directly from step n to n+1, we first get an
intermediate solution at (n+1/2) then to (n+1). To write down equation (5a) and
(5b) in a form that more suitable for programming, we need the following notations
(for now, neglect the boundary condition, we will fill in the boundary
conditions later.)
Ax
Fo 1 2 Fo
Fox
x
x
Fox
1 2 Fox Fox
Ay
Fo 1 2 Fo
Fo y
y
y
Fo y
1 2 Fo y Fo y
nxnx
nxnx
Ax
Fo 1 2 Fo
Fox
x
x
Fox
1 2 Fox
Fox
Ay
Fo 1 2 Fo
Fo y
y
y
Fo y
1 2 Fo y
nyny
nyny
Fo y
where nx is grid point number along x-direction and ny is the grid point number
along y-direction. With these notations, now we have
(6)
Ay u;nj1 Ax u;nj1/2
uijn uijn1
2
(7)
For Dirichlet boundary condition, lets say at i=1, u1; B y, t , equation (7) yields
u1nj1/2
u1nj u1nj1
2
Fo y y2 u1nj u1nj1
B1nj B1nj1
2
Foy
n
1( j 1)
If B is constant, equation (8) is simply u1;n1/2 B1; , where ; denotes all possible
column numbers. An example code with such boundary conditions is attached to the
end of this write-up.
Neumann boundary is more complicated. Assume we have a Neumann
boundary at x=0 given by u y x,0, t g x,0, t where g(x,0,t) is a known function.
For those who are content with first order approximation, the discretization is given
by
(9)
(10)
Foy
to get
u;0n 1 Foy
or
n 1
;0
2 Foy
u;1n 1 u;0n 1
y
(12)
If we have Neumann boundary conditions at i=0 or i=nx, we can switch the order of
(5a) and (5b), because there is no reason we should do the sweep along x or y in any
particular order. In this way, we can always have Neumann boundary at the n+1
time step.
2. Compact ADI scheme
High order finite difference schemes fall into two categories: explicit and
compact schemes. The explicit schemes approximate the derivatives by using large
stencils, while the compact schemes using smaller stencils with solving additional
linear systems. Here we only need the first and second order derivatives using the
sixth order accuracy formulas:
fi 1 fi 1
f f
b i 2 i 2
2h
4h
(13)
2
1
2 ; a 4 1 , and
3
3
fi 1 2 fi fi 1
f 2 fi fi 2
b i2
2
h
4h2
(14)
4
1
1 ; a 10 1 .
3
3
Now, lets come back to the ADI scheme with the following splitting:
uxx ij
n 1/2
u yy
ij
uxx ij
n 1/2
uxx ij
(15)
n 1
(16)
where uijn 1/2 is a intermediate approximation and uijn 1 is the final solution. We can
substitute the second order derivatives with sixth-order compact formulas
uxx ; j A1Bu; j
n 1/2
t
t 2 n
1
A
B
u
Ix
u, j u;nj
2
2 y ;j
2 x
2 x
(17)
n 1
t
t 2 n
1
C
D
u
Iy
ui ; uin, 1/2
2
2 x i;
2 y
2 y
(18)
where ui ; , u; j are the solution vectors at i-th row and j-th column, respectively.
ui 1 2ui ui 1
u j 1 2u j u j 1
4 x
and
u j 2 2u j u j 2
4 y
4
1
2
1 and b 1 10 with . In more compact form, this is
3
3
11
Au '' Bu
where
ui 2 2ui ui 2
(19)
...
...
Nx Nx
...
B
2
...
Nx Nx
a
b
a
b
and
and
where
for x-direction and
for
2
2
2
2
4 x
4 y
x
y
y-direction sweep.
But in both A and B matrices, I did not show the boundary conditions. You
may refer to some papers on compact schemes. The result is presented below
without derivation. At first and second boundary layer:
f1'' f 2'' c1 f1 c2 f 2 c3 f3 c4 f 4 c5 f5 c6 f 6 c7 f 7 h 2
c1 2077 /157, c2 2943 /100, c3 573 / 44, c4 167 / 99,
(20)
(21)
f N'' 1 f N'' c1 f N c2 f N 1 c3 f N 2 c4 f N 3 c5 f N 4 c6 f N 5 c7 f N 6 h2
(22)
Source code for ADI using Peaceman-Rachford scheme. The code is pretty much selfexplained.
//===========================================================================
// Name
: ADI.cpp
// Author : Pengfei Du, Mechanical Engineering, Univ. of Iowa.
// Website : http://pengfeidu.net/
// Description : Transient heat conduction problem solved using ADI scheme.
//
Initial inside temperature is 150;
//
All boundaries are Dirichlet boundaries kept at 50.
//
Calculation domain: x=[0:1] y=[0:1].
// NOTE: This is only a demonstration of Peaceman-Rachford scheme. It is
//
INEFFICIENT. To directly compile this short program, you need
//
TNT and JAMA libraries; otherwise, take this as a pseudo-code.
//===========================================================================
#include <iostream>
#include <fstream>
#include "tnt.h"
#include "jama_lu.h"
#include <iomanip>
using namespace TNT;
using namespace std;
using namespace JAMA;
int main()
{
ofstream result;
int i,j,Nx,Ny;
double fox,foy,dt,Time,dx,dy,Lx,Ly,alpha;
Nx=11,Ny=12; //node numbers along length and width;
//set Nx Ny to be different on purpose; You should think
//about this carefully to make sure you understand ADI scheme.
dt=0.01; //time step;
Time=0.2; //end of time evolving;
Lx=1.,Ly=1.; //domain length and width;
dx=Lx/(Nx-1),dy=Ly/(Ny-1);
alpha=.2; //thermal diffusivity;
fox=alpha*dt/2./dx/dx,foy=alpha*dt/2./dy/dy;
Array2D< double > Ax_m(Nx,Nx),Ay_m(Ny,Ny),Ax_p(Ny,Ny),Ay_p(Nx,Nx),u(Nx,Ny),
ulast(Nx,Ny),ulastT(Ny,Nx),uT(Ny,Nx);
result.open("result.txt");
for(i=0;i<Nx;i++)
{
for(j=0;j<Ny;j++)
{
u[i][j]=150.; //initial temperature;
ulast[i][j]=150.; //storage of intermediate temperature results;
if(i==0||i==Nx-1||j==0|j==Ny-1){
u[i][j]=50.; //set the temperature on the boundaries;
ulast[i][j]=50.;
}
}
}
for(i=0;i<Ny;i++)
{
for(j=0;j<Ny;j++)
{
Ay_m[i][j]=0.;
Ax_p[i][j]=0.;
}
}
for(i=0;i<Nx;i++)
{
for(j=0;j<Nx;j++)
{
Ax_m[i][j]=0.;
Ay_p[i][j]=0.;
}
}
for(i=1;i<Nx-1;i++)
{
Ax_m[i][i]=1+2*fox;
Ax_m[i][i-1]=-fox;
Ax_m[i][i+1]=-fox;
}
//left and right boundary, constant temperature = 50;
Ax_m[0][0]=1;
Ax_m[Nx-1][Nx-1]=1;
for(i=1;i<Ny-1;i++)
{
Ax_p[i][i]=1-2*fox;
Ax_p[i][i-1]=fox;
Ax_p[i][i+1]=fox;
}
Ax_p[0][0]=1;
Ax_p[Ny-1][Ny-1]=1;
for(i=1;i<Ny-1;i++)
{
Ay_m[i][i]=1+2*foy;
Ay_m[i][i-1]=-foy;
Ay_m[i][i+1]=-foy;
}
//top and bottom boundary, constant temperature = 50;
Ay_m[0][0]=1;
Ay_m[Ny-1][Ny-1]=1;
for(i=1;i<Nx-1;i++)
{
Ay_p[i][i]=1-2*fox;
Ay_p[i][i-1]=fox;
Ay_p[i][i+1]=fox;
}
Ay_p[0][0]=1;
Ay_p[Nx-1][Nx-1]=1;
LU<double> matAx_m(Ax_m);
LU<double> matAy_m(Ay_m);
LU<double> matAx_p(Ax_p);
LU<double> matAy_p(Ay_p);
for (float clock=0;clock<Time;clock=clock+dt){
u=matAx_m.solve(matmult(Ay_p,ulast));
for(j=0;j<Ny;j++){
for(i=0;i<Nx;i++){
uT[j][i]=u[i][j];
}
}
ulastT=matAy_m.solve(matmult(Ax_p,uT));
for(j=0;j<Ny;j++){
for(i=0;i<Nx;i++){
ulast[i][j]=ulastT[j][i];
}
}
result<<"#"<<clock/dt<<endl;
for(j=0;j<Ny;j++){
for(i=0;i<Nx;i++){
result<<setw(7)<<i*dx<<" "<<j*dy<<" "<<ulast[i][j]<<endl;
}
result<<endl;
}
result<<endl;
result<<endl;
}
result.close();
cout<<"Calculation done!";
return 0;
}