I wrote this code to solve one-dimensional heat transfer with dufort frankel method and want to compare with exact solution.
But exact solution gives an error. And when i run the code before the exact solution it is correct.
clc
clear
close all
%Declaration point..........................................................
nx=25; %number of point in the x direction
Ta=100; %temperatur (centigrade)
T=zeros(nx,1)+Ta; %initialization of temperator
T_in =0; %inlet temperature
T_out=0; %output temperature
Alpha=0.01; %coefficient (m^2/s)
L=1; %length (m)
x=linspace(0,L,nx); %x grid
dx=L/nx-1; %grid spacing
T(1)= T_in; %BC
T(nx)= T_out; %BC
dt=0.01; %time step from stability for DF
d=Alpha*dt/dx^2; %diffusion number
maxtime=10; %maximum time
nT=maxtime/dt; %time spacing
N=10; %number of series for exact computartion
%Time loop..................................................................
T0=T;
T1=T;
for n=1:nT
display(['Time step:',num2str(n),'time',num2str(n*dT)]);
T= DF(nx,T0,T1,d);
T0=T1;
T1=T;
end
%Exact solution............................................................
Ta = zeros(nx, nt);
for i=1:nx
for j = 1:nt
T(i,j) = sin(pi*x(i))*exp(-pi^2*t(j);
end
end
figure()
contourf(Ta,200,'linecolor','non')
%Error function............................................................
function [Err] = Error[T_exact,T,x];
Err=sqrt(sum(((T(2:end-1)-T_exact(2:end-1))./T_exact(2:end-1)).^2)/(N-2));
end
Related
I have written a Matlab code to construct a Cubic Runout Spline, with a figure to display my data. But how can i show a data which is not in my data group ex.f(2010) in my figure. I have an idea. I can show t is valid after 2000, which t=2010, but I have no idea to start it.
clear; clc;
t= [1850, 1875, 1900, 1925, 1950, 1975, 2000];
y= [285.2, 288.6, 295.7, 305.3, 311.3, 331.36, 369.64];
N= length(t); %number of points I want
n=N-1 ; % number of subintervals
h=(t(N)-t(1))/n; %step size
A=[1,1,1,0],B=[2,0,0,0,2],C=[0,1,1,1];
Trid=diag(4*ones(1,n-1))+diag(A,-1)+diag(B)+diag(C,1);
for i=1:n-1
f(i)= 6/h^2*(y(i+2)-2*y(i+1)+y(i));
end
f=f';
w=inv(Trid)*f;%since sigma 1 and sigma n+1 are both 0, we need to add 0 in the beginning and also in the end of then matrix
sigma=[0;w;0];%it is a nx1 matrix, be careful.
for i=1:n
d(i)=y(i);
b(i)=sigma(i)/2;
a(i)=(sigma(i+1)-sigma(i))/(6*h);
c(i)=(y(i+1)-y(i))/h-h/6*(2*sigma(i)+sigma(i+1));
end
r= 25; %subsubintervals for t ex. between 1850 and 1875, here i seperate it into 1 years per slot
hh=h/r; %step size of subsubintervals
x=t(1):hh:t(N);
for i=1:n
for j=r*(i-1)+1:r*i
s(j)=a(i)*(x(j)-t(i))^3+b(i)*(x(j)-t(i))^2+c(i)*(x(j)-t(i))+d(i);
end
end
s(r*n+1)=y(N);
plot(t,y,'o')
hold on
plot(x,s,'-x')
hold off
What you are asking is extrapolation. You did the interpolation, which is good. For the extrapolation, just continue the last segment's cubic equation.
s(r*n+1)=y(N);
s_orig_len = length(s); %% new
plot(t,y,'o')
hold on
plot(x,s,'-x')
% hold off %%% there is more to plot!
% %% All new lines below
i_last = 6;
i_next = 7;
t = [t 2026];
x_extrapolation = x(end):t(end);
x = [x x_extrapolation];
for j = r*(i_next-1)+1:r*i_next + 3
s(j)=a(i_last)*(x(j)-t(i_last))^3+b(i_last)*(x(j)-t(i_last))^2+c(i_last)*(x(j)-t(i_last))+d(i_last);
end
plot(x_extrapolation, s(s_orig_len+1:end), '-b', 'LineWidth',2)
hold off;
I hope this helps.
I am unable to get converging values using a Gauss-Seidel algorithm for my specific 2-D Helmholtz equation:
Here is the code:
%Final Project Helmhotz 2-D:
%d^2u/dx^2+d^2u/dy^2+Lambda*u=F(x,y)
%Over domain of ax < x < bx and ay < y < by
%Using Gauss-Seidel
clc
clear;
%Given variables
lamda1=0.5; %Given
ax=0; %Given
ay=0; %Given
Pi=4*atan(1); %Given
bx=2*Pi; %Given
by=2*Pi; %Given
v=0; %Given (du/dy #y=by = 0)
%Initial Problem Setup
Nx=20; %Initial number of points in x
Ny=Nx; %Initial number of points in y
Lx=bx; %Length of x
Ly=by; %Length of y
deltax=Lx/(Nx+1); %Step size in x
deltay=Ly/(Ny+1); %Step size in y
%Constants
fbay = (by-ay)*(by-ay)*cos(Pi*ay/by);
gbay = ay*(by-ay)*(by-ay);
cons1 = bx-ax;
dy2=deltay*deltay;
dx2=deltax*deltax;
dx2dy2=deltax*deltax*deltay*deltay;
denominator=2*deltay*deltay+2*deltax*deltax;
denoma=denominator-dx2dy2*lamda1;
x=0:deltax:2*pi;
y=0:deltay:2*pi;
%Solution Matrix
U1 = zeros(Nx+2,Ny+2); % Create solution matix with initial guess of ZERO
%Boundary Conditions
for j = 1:Ny+2 %u(x=ax,y)=fb(y) boundary condition
U1(1,j)=(by-deltay*(j-1))*(by-deltay*(j-1))*cos(Pi*deltay*(j-1)/by);
end
for j=1:Ny+2 %u(x=bx,y)=gb(y) boundary condition
U1(Nx+2,j)=(deltay*(j-1))*(by-deltay*(j-1))*(by-deltay*(j-1));
end
for i=1:Nx+2 %u(x,y=ay) boundary conditoin
U1(i,1)=fbay+(deltax*(i-1)-ax)/cons1*(gbay-fbay);
end
%Part 1 Using Gauss Siedel
F1=zeros(Nx+2,Ny+2);
for i=1:Nx+2
for j=1:Ny+2
F1(i,j)=cos(Pi/2*(2*(deltax*(i-1)-ax)/(bx-ax)+1))*sin(Pi*(deltay*(j-1)-ay)/(by-ay));
end
end
for z=1:100
for i=2:Nx+1
for j=2:Ny+1
%%%%% Different Equations for U if wanted %%%%%%%%%%%%%%%%%%%%
%U1(i,j)=(deltax*deltax*F1(i,j)-(U1(i-1,j)+U1(i+1,j)+U1(i,j-1)+U1(i,j+1)))/(-4+deltax*deltax*lamda1);
%U1a(i,j)=(Cons4*F1(i,j)-dy2*U1(i+1,j)-dy2*U1(i-1,j)-dx2*U1(i,j+1)-dx2*U1(i,j-1))/(Cons5a);
U1(i,j)=((U1(i-1,j)+U1(i+1,j)+U1(i,j-1)+U1(i,j+1))-deltax*deltax*F1(i,j))/(4-deltax*deltax*lamda1);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%U1(i,j)=(dy2*U1(i-1,j)+dy2*U1(i+1,j)+dx2*U1(i,j-1)+dx2*U1(i,j+1))/(denoma)-(dx2dy2*F1(i,j))/(denoma);
end
%%%%%%%%%%%% Different Neumann Conditions if wanted %%%%%%%%%%%%%%
%U1(i,Ny+2)=(deltax*deltax*F1(i,Ny+2)-(U1(i-1,Ny+2)+U1(i+1,Ny+2)+U1(i,Ny+1)+(U1(i,Ny+1)-2*deltax*v)))/(-4+deltax*deltax*lamda1);
%U1a(i,Ny+2)=(Cons4*F1(i,Ny+2)-dy2*U1(i+1,Ny+2)-dy2*U1(i-1,Ny+2)-dx2*U1(i,Ny+1)-dx2*U1(i,Ny+1))/(Cons5a);
U1(i,Ny+2)=((U1(i-1,Ny+2)+U1(i+1,Ny+2)+U1(i,Ny+1)+U1(i,Ny+1))-deltax*deltax*F1(i,Ny+2))/(4-deltax*deltax*lamda1);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%U1(i,Ny+2)=((dy2)*U1(i-1,Ny+2)+(dy2)*U1(i+1,Ny+2)+(dx2)*U1(i,Ny+1)+(dx2)*U1(i,Ny+1))/(denoma)-(dx2dy2*F1(i,Ny+2))/(denoma);
end
end
figure()
surf(x,y,U1);
Whenever I run this code for more than 100 iterations, the values start to diverge from the boundary conditions. I'm not sure why and neither is my professor.
I have also posted pictures of my given problem, boundary conditions, and another image that shows my discretization.
Shows my discretization
Shows my given problem and boundary conditions
I'm trying to plot the following equation (let's call it "Equation 1"):
This is the code I'm testing:
clear all;
xl=0; xr=1; % x domain [xl,xr]
J = 10; % J: number of division for x
dx = (xr-xl) / J; % dx: mesh size
tf = 0.1; % final simulation time
Nt = 60; % Nt: number of time steps
dt = tf/Nt/4;
x = xl : dx : xr; % generate the grid point
u_ex = zeros(J+1,Nt);
for n = 1:Nt
t = n*dt; % current time
for j=1:J+1
xj = xl + (j-1)*dx;
suma = zeros(100 , 1);
for k= 1:100
suma(k) = 4/(((2*k-1)^2) *pi*pi);
suma(k) = suma(k) * exp(-((2*k-1)^2) *pi*pi*t) * cos(2*k-1)*pi*xj;
end
m = sum(suma);
u_ex(j, n)= 0.5 - m;
end
end
tt = dt : dt : Nt*dt;
figure(1)
surf(x,tt, u_ex'); % 3-D surface plot
xlabel('x')
ylabel('t')
zlabel('u')
The problem is that all I get is a flat surface:
Equation 1 is suppossed to be the solution of the following parabolic partial differential equation with boundary values:
And after getting the numerical solution, it should look like this:
This plot gets the right values at the boundaries x = 0 and x = 1. The plot of Equation 1 doesn't have those values at the boundaries.
My complete .m code (that plots both the numerical solution and Equation 1) is:
clear all; % clear all variables in memory
xl=0; xr=1; % x domain [xl,xr]
J = 10; % J: number of division for x
dx = (xr-xl) / J; % dx: mesh size
tf = 0.1; % final simulation time
Nt = 60; % Nt: number of time steps
dt = tf/Nt/4;
mu = dt/(dx)^2;
if mu > 0.5 % make sure dt satisy stability condition
error('mu should < 0.5!')
end
% Evaluate the initial conditions
x = xl : dx : xr; % generate the grid point
% store the solution at all grid points for all time steps
u = zeros(J+1,Nt);
u_ex = zeros(J+1,Nt);
% Find the approximate solution at each time step
for n = 1:Nt
t = n*dt; % current time
% boundary condition at left side
gl = 0;
% boundary condition at right side
gr = 0;
for j=2:J
if n==1 % first time step
u(j,n) = j;
else % interior nodes
u(j,n)=u(j,n-1) + mu*(u(j+1,n-1) - 2*u(j,n-1) + u(j-1,n-1));
end
end
u(1,n) = gl; % the left-end point
u(J+1,n) = gr; % the right-end point
% calculate the analytic solution
for j=1:J+1
xj = xl + (j-1)*dx;
suma = zeros(100 , 1);
for k= 1:100
suma(k) = 4/(((2*k-1)^2) *pi*pi);
suma(k) = suma(k) * exp(-((2*k-1)^2) *pi*pi*t) * cos(2*k-1)*pi*xj;
end
m = sum(suma);
u_ex(j, n)= 0.5 - m;
end
end
% Plot the results
tt = dt : dt : Nt*dt;
figure(1)
colormap(gray); % draw gray figure
surf(x,tt, u'); % 3-D surface plot
xlabel('x')
ylabel('t')
zlabel('u')
title('Numerical solution of 1-D parabolic equation')
figure(2)
surf(x,tt, u_ex'); % 3-D surface plot
xlabel('x')
ylabel('t')
zlabel('u')
title('Analytic solution of 1-D parabolic equation')
maxerr=max(max(abs(u-u_ex))),
The code is taken from the book "Computational Partial Differential Equations Using MATLAB" by Yi-Tung Chen, Jichun Li, chapter 2, exercise 3.
In short: I'm not asking about the differential equation or the boundary problem, I want to know is: Why am I getting a flat surface when plotting Equation 1? Am I missing a parenthesis?
I do not want to use the symsum function because it never stop the script execution and I want to learn how to plot Equation 1 with no using symsum.
I've tested this code with Matlab R2008b and Octave 4.2.1. I got the same results (even with sums of 1000, 10000 and 50000 terms in the for loop with the k variable).
Edit!
Thanks, Steve!
I was missing a couple of parenthesis near the cosine, the right code is:
clear all; % clear all variables in memory
xl=0; xr=1; % x domain [xl,xr]
J = 10; % J: number of division for x
dx = (xr-xl) / J; % dx: mesh size
tf = 0.1; % final simulation time
Nt = 60; % Nt: number of time steps
dt = tf/Nt/4;
mu = dt/(dx)^2;
if mu > 0.5 % make sure dt satisy stability condition
error('mu should < 0.5!')
end
% Evaluate the initial conditions
x = xl : dx : xr; % generate the grid point
% store the solution at all grid points for all time steps
u = zeros(J+1,Nt);
u_ex = zeros(J+1,Nt);
% Find the approximate solution at each time step
for n = 1:Nt
t = n*dt; % current time
% boundary condition at left side
gl = 0;
% boundary condition at right side
gr = 0;
for j=2:J
if n==1 % first time step
u(j,n) = j;
else % interior nodes
u(j,n)=u(j,n-1) + mu*(u(j+1,n-1) - 2*u(j,n-1) + u(j-1,n-1));
end
end
u(1,n) = gl; % the left-end point
u(J+1,n) = gr; % the right-end point
% calculate the analytic solution
for j=1:J+1
xj = xl + (j-1)*dx;
suma = zeros(1000 , 1);
for k= 1:1000
suma(k) = 4/(((2*k-1)^2) *pi*pi);
suma(k) *= exp(-((2*k-1)^2) *pi*pi*t) * cos((2*k-1)*pi*xj);
end
m = sum(suma);
u_ex(j, n)= 0.5 - m;
end
end
% Plot the results
tt = dt : dt : Nt*dt;
figure(1)
colormap(gray); % draw gray figure
surf(x,tt, u'); % 3-D surface plot
xlabel('x')
ylabel('t')
zlabel('u')
title('Numerical solution of 1-D parabolic equation')
figure(2)
surf(x,tt, u_ex'); % 3-D surface plot
xlabel('x')
ylabel('t')
zlabel('u')
title('Analytic solution of 1-D parabolic equation')
Now my Equation 1 looks much better:
Also Steve was right when pointing out that my numerical solution may be wrong. I didn't notice that the boundary values are for the derivatives of my function, not the actual values of the function. I'll ask my teacher about this.
Edit2!
Ok, I got it. To calculate the derivatives at the boundaries you have to use hint 2.21 in the same book:
% hint 2.21 given by the book
% it is better to calculate the boundary values after calculating the inner points inside the for j = 1:m loop because you will need them:
u(1, n) = u(2, n) - dx * gl; % the left-end point
u(J+1,n) = u(J, n) + dx * gr; % the right-end point
Now my numerical solution looks like my analytic solution :D
Matlab R2008b can't recognize the *= operator that Octave does. I'm not tested this operator in other versions of Matlab because I'm too poor.
Yvon: I think the analytical solution formula comes from the real part of a Fourier expansion, but authors don't tell how they got it.
I am solving stochastic differential equation in matlab.
For example:
consider the stochastic differential equation
dx=k A(x,t)dt+ B(x,t)dW(t)
where k is constants, A and B are functions, and dW(t) is Wiener process.
I plot the solution for all t in [0,20]. We know that dW(t) is randomly generated. My question is: I want to know the value of A(x,t), B(x,t), dW(t) for a particular value of t and for particular sub-interval, say [3,6]. What command in Matlab I can use?
Here is the code I used based on a paper by D.Higham:
clear all
close all
t0 = 0; % start time of simulation
tend = 20; % end time
m=2^9; %number of steps in each Brownian path
deltat= tend/m; % time increment for each Brownian path
D=0.1; %diffsuion
R=4;
dt = R*deltat;
dW=sqrt( deltat)*randn(2,m);
theta0=pi*rand(1);
phi0=2*pi*rand(1);
P_initial=[ theta0; phi0];
L = m/ R;
pem=zeros(2,L);
EM_rescale=zeros(2,L);
ptemp=P_initial;
for j=1:L
Winc = sum(dW(:,[ R*(j-1)+1: R*j]),2);
theta=ptemp(1);% updating theta
phi=ptemp(2); % updating phi
%psi=ptemp(3); % updating psi
A=[ D.*cot(theta);...
0];% updating the drift
B=[sqrt(D) 0 ;...
0 sqrt(D)./sin(theta) ]; %% updating the diffusion function
ptemp=ptemp+ dt*A+B*Winc;
pem(1,j)=ptemp(1);%store theta
pem(2,j)=ptemp(2);%store phi
EM_rescale(1,j)=mod(pem(1,j),pi); % re-scale theta
EM_rescale(2,j)=mod(pem(2,j),2*pi); % re-scale phi
end
plot([0:dt:tend],[P_initial,EM_rescale],'--*')
Suppose I want to know all parameters (including random: Brownian) at each specific time point or for any time interval. How to do that?
I'm doing my best to understand your question here, but it's still a bit unclear to me.
Change the loop to:
for ii=1:L
Winc = sum(dW(:,[ R*(ii-1)+1: R*ii]),2);
theta=ptemp(1);% updating theta
phi=ptemp(2); % updating phi
A{ii}=[ D.*cot(theta);...
0];% updating the drift
B{ii}=[sqrt(D) 0 ;...
0 sqrt(D)./sin(theta) ]; %% updating the diffusion function
ptemp = ptemp + dt*A{ii}+B{ii}*Winc;
pem(:,ii) = ptemp;
EM_rescale(1,ii) = mod(pem(1,ii),pi); % re-scale theta
EM_rescale(2,ii) = mod(pem(2,ii),2*pi); % re-scale phi
end
Now, you can get the values of A and B this way:
t = 3;
t_num = round(m/tend*t);
A{t_num}
B{t_num}
ans =
0.0690031455719538
0
ans =
0.316227766016838 0
0 0.38420611784333
I have a 1D heat diffusion code in Matlab which I was using on a timescale of 10s of years and I am now trying to use the same code to work on a scale of millions of years. Obviously if I keep my timestep the same this will take ages to calculate but if I increase my timestep I encounter numerical stability issues.
My questions are:
How should I approach this problem? What affects the maximum stable timestep? And how do I calculate this?
Many thanks,
Alex
close all
clear all
dx = 4; % discretization step in m
dt = 0.0000001; % timestep in Myrs
h=1000; % height of box in m
nx=h/dx+1;
model_lenth=1; %length of model in Myrs
nt=ceil(model_lenth/dt)+1; % number of tsteps to reach end of model
kappa = 1e-6; % thermal diffusivity
x=0:dx:0+h; % finite difference mesh
T=38+0.05.*x; % initial T=Tm everywhere ...
time=zeros(1,nt);
t=0;
Tnew = zeros(1,nx);
%Lower sill
sill_1_thickness=18;
Sill_1_top_position=590;
Sill_1_top=ceil(Sill_1_top_position/dx);
Sill_1_bottom=ceil((Sill_1_top_position+sill_1_thickness)/dx);
%Upper sill
sill_2_thickness=10;
Sill_2_top_position=260;
Sill_2_top=ceil(Sill_2_top_position/dx);
Sill_2_bottom=ceil((Sill_2_top_position+sill_2_thickness)/dx);
%Temperature of dolerite intrusions
Tm=1300;
T(Sill_1_top:Sill_1_bottom)=Tm; %Apply temperature to intrusion 1
% unit conversion to SI:
secinmyr=24*3600*365*1000000; % dt in sec
dt=dt*secinmyr;
%Plot initial conditions
figure(1), clf
f1 = figure(1); %Make full screen
set(f1,'Units', 'Normalized', 'OuterPosition', [0 0 1 1]);
plot (T,x,'LineWidth',2)
xlabel('T [^oC]')
ylabel('x[m]')
axis([0 1310 0 1000])
title(' Initial Conditions')
set(gca,'YDir','reverse');
%Main calculation
for it=1:nt
%Apply temperature to upper intrusion
if it==10;
T(Sill_2_top:Sill_2_bottom)=Tm;
end
for i = 2:nx-1
Tnew(i) = T(i) + kappa*dt*(T(i+1) - 2*T(i) + T(i-1))/dx/dx;
end
Tnew(1) = T(1);
Tnew(nx) = T(nx);
time(it) = t;
T = Tnew; %Set old Temp to = new temp for next loop
tmyears=(t/secinmyr);
%Plot a figure which updates in the loop of temperature against depth
figure(2), clf
plot (T,x,'LineWidth',2)
xlabel('T [^oC]')
ylabel('x[m]')
title([' Temperature against Depth after ',num2str(tmyears),' Myrs'])
axis([0 1300 0 1000])
set(gca,'YDir','reverse');%Reverse y axis
%Make full screen
f2 = figure(2);
set(f2,'Units', 'Normalized', 'OuterPosition', [0 0 1 1]);
drawnow
t=t+dt;
end
The stability condition for an explicit scheme like FTCS is governed by $r = K dt/dx^2 < 1/2$ or $dt < dx^2/(2K)$ where K is your coefficient of diffusion. This is required in order to make the sign of the 4th order derivative leading truncation error term be negative.
If you do not want to be limited by timestep I suggest using an implicit scheme (albeit at a higher of computational cost than an explicit scheme). This can be achieved simply by using backward Euler for the diffusion term instead of forward Euler. Another option is Crank-Nicholson which is also implicit.
#Isopycnal Oscillation is totally correct in that the maximum stable step is limited in an explicit scheme. Just for reference this is usually referred to as the discrete Fourier number or just Fourier number and can be looked up for different boundary conditions.
also the following may help you for the derivation of the Implicit or Crank-Nicholson scheme and mentions stability Finite-Difference Approximations
to the Heat Equation by Gerald W. Recktenwald.
Sorry I don't have the rep yet to add comments