Finite difference - wave equation - boundary conditions and setting things up - matlab

I am working on a project that has to do with solving the wave equation in 2D (x, y, t) numericaly using the central difference approximation in MATLAB with the following boundary conditions:
The general assembly formula is:
I understand some of the boundary conditions (BC), like
du/dy=0 at j=m,
,
but I am not sure how to implement these boundary conditions in MATLAB.
A friend has given me these equations:
Here is my try with the MATLAB code,
but I am not able to progress any further:
% The wave function
% Explicit
% Universal boundary conditions for all 3 cases:
% u=0 at t=0
% du/dt=0 at t=0
% Case 1 boundary conditions
% At x=0, u=2sin(2*pi*t/5);
% At y=0, du/dy=0;
% At y=2, du/dy=0;
% At x=5, du/dx=0;
% u=0 and du/dt=0 at t=0;
%-------------------------------------------------------------------------%
% Setting up
clc; clear all; close all;
% length, time, height
L = 5; % [m]
h = 2; % [m]
T = 10; % [s]
% Constants
c_x = 1; % arbitrary
c_y = 1; % arbitrary
dx = 0.1; % <x> increment
dy = 0.1; % <y> increment
dt = 0.1; % time increment
nx = L/dx + 1; % number of <x> samples
ny = h/dy + 1; % number of <y> samples
nt = T/dt + 1; % number of time samples
t(:,1) = linspace(0, T, nt);
theta_x = c_x*(dt^2)/(dx^2);
theta_y = c_y*(dt^2)/(dy^2);
% theta_x = theta_y
theta = theta_x;
%-------------------------------------------------------------------------%
% The matrix
U = zeros(nt, nx, ny);
% Setting up the <U> matrix with the boundary conditions - case 1
U(1, :, :) = 0; % U=0 at t=0
for tt=1:nt % U=2sin(2pi/5*t) at x=0
for jj=1:ny
U(tt, 1, jj)=2*sin(2*pi/5.*t(tt));
end
end
for it=2:t
for ix=2:nx-1
for iy=2:ny-1
% Boundary conditions
% General case (internal):
U1 = -U(it-1, ix, iy);
U2 = 2*(1-2*theta)*u(it, ix, iy);
U3 = theta*U(it, ix-1, iy);
U4 = theta*U(it, ix+1, iy);
U5 = theta*U(it, ix, iy-1);
U6 = theta*U(it, ix, iy+1);
end
end
end

The general assembly formula you have kind of applies to the boundaries as well.
The complication is that when you apply the formula when j = 1 and j = m, you have j = 0 and j = m+1 term that are off of your grid.
To ameliorate this problem, boundary conditions give you a relationship between the points off the grid and on the grid.
As you have indicated, the dudy = 0 condition has given you the relation that u(i,m-1) == u(u,m+1) on the boundary. So you use the general assembly formula and replace all of the m+1 terms with m-1 on the boundary. You'll have a similar relation for the lower boundary as well.

Related

Linear Congruential generator graph

I implemented a simple code for a linear congruential generator
clear all; clc
% Input
m = 59; % module
a = 17; % multiplier
c = 43; % increase
X0 = 27; % seed
n = 100; % sample length
y = [X0 zeros(1,n-1)];
% recursive formula
% X(n+1) = (a*X(n) + c) mod m
for i = 2:n
y(i) = mod(a*y(i-1)+c,m);
end
x = 0:1:n-1;
%for i = 1:n
% plot(x,y);
%end
What I would like to do is a plot where each time the period repeats it draws a vertical line upward as in this graph
I think I have to use the plot function inside a FOR loop and an IF-ELSE to see if the value of the subsequence X(n) is equal to the seed X(0) but I have no idea how to implement it
I think I have to use the plot function inside a FOR loop and an IF-ELSE to see if the value of the subsequence X(n) is equal to the seed X(0) but I have no idea how to implement it

Applying ode15s to solve a spatial discretization using finite difference for multiple variables

I am trying to run the following ode15s with three variables, C1, q1 and phi1. However, I keep on receiving the following warning:
Warning: Failure at t=1.163115e-13. Unable to meet integration
tolerances without reducing the step size below the smallest value
allowed (4.038968e-28) at time t.
The simulation runs correctly if I do not include the dq1_over_dt term in the ode15s solver, so issue is definitely there. If the simulation runs correctly, the result is a Y matrix of 486X360 dimensions.
Any practical advice is welcomed.
%-------------------------------------------------------------------------%
% Chromatography Simulation 1
% By Santiago Taguado
% Chromatogram Simulation
%-------------------------------------------------------------------------%
close all; clear variables; clc;
% Global variables (meaning reported below)
global u Dax N h isopar K eps v Dphi phi_in Cin mod_gradient
%-------------------------------------------------------------------------%
% Chromatography with variable boundaries
%-------------------------------------------------------------------------%
L = 25; % Length (cm)
Q = 2.513; % Flow Rate (mL/min)
D = 0.8; % Diameter of Column (cm)
S = pi()*(D/2)^2; % Column Cross Section (cm2)
eps = 0.7; % Void Fraction
u = Q/S; % superficial velocity (cm/min)
v = u/eps; %intersitial velocity
Dax = 0.039/u; % axial dispersion (cm)
Dphi = 0.039/u; % axial dispersion (cm)
N = 120; % number of grid points (-)
alpha1 = 149421.036; % Parameter 1
alpha2 = -3.054; % Sensibility variable 1
alpha3 = 500; % Parameter 2
alpha4 = 500; % Sensibility variable 2
isopar = [alpha1 alpha2 alpha3 alpha4];
K = 3; % Linear Driving Force
eps = 0.7; % Void Fraction
%-------------------------------------------------------------------------%
% Preprocessing
%-------------------------------------------------------------------------%
h = L/(N-1); % grid spacing (cm)
nt = 3000; % number of time steps
t_load = 8; % loading time,min
t_tot = 49;
dt = t_tot/(nt-1);
%-------------------------------------------------------------------------%
% Solution via ode15s solver for Loading Phase
%-------------------------------------------------------------------------%
C1 = [0; zeros(N-1,1)]; % Initial Conditions
q1 = [0;zeros(N-1,1)];
phi = [0;zeros(N-1,1)];
Y = [C1;q1;phi];
phi_in = 0.02;
Cin = 1.085; % initial concentration (mg/mL)
mod_gradient = 0;
tspan = 0:dt:t_load;
[t, Y] = ode15s(#ODESystem, tspan, Y);
%-------------------------------------------------------------------------%
% ODE system
%-------------------------------------------------------------------------%
function dY = ODESystem(t,Y)
global u Dax N h Dphi v phi_in Cin mod_gradient eps isopar
C1 = Y(1:N);
q1 = Y(N+1:N*2);
phi = Y(N*2+1:N*3);
dC1_over_dt = zeros(N,1);
dq1_over_dt = zeros(N,1);
dphi_over_dt = zeros(N,1);
% Boundary # x=0
dC1_over_dt(1) = (Cin(1) + Dax/u/h*C1(2))/(1+Dax/u/h);
dq1_over_dt(1) = 0;
dphi_over_dt(1) = (phi_in + mod_gradient*t + Dphi/v/h*phi(2))/(1+Dphi/v/h);
% Internal points
for i=2:N-1
% Isotherm Value
H1 = isopar(1)*phi(i)^isopar(2); H1(isinf(H1)) = 0;
q_inf1 = isopar(3)*H1/(1+H1); q_inf1(isnan(q_inf1)) = 0;
denom = 1 + C1(i)*H1/q_inf1; denom(isnan(denom)) = 1;
qstar1 = C1(i)*H1/denom;
dq1_over_dt(i) = eps/(1-eps)*(qstar1 - q1(i));
% Species, 1
dC1_over_dx = (C1(i-1)-C1(i))/(h);
d2C1_over_dx2 = (C1(i+1)-2.*C1(i)+C1(i-1))/h^2;
% Modifier,1
dphi_over_dx = (phi(i-1)-phi(i))/(h);
d2phi_over_dx2 = (phi(i+1)-2.*phi(i)+phi(i-1))/h^2;
dphi_over_dt(i) = u*dphi_over_dx + ...
Dphi*d2phi_over_dx2;
dC1_over_dt(i) = v*dC1_over_dx + Dax*d2C1_over_dx2;
end
% Boundary # x=L
dC1_over_dt(N) = dC1_over_dt(N-1);
dq1_over_dt(N) = dq1_over_dt(N-1);
dphi_over_dt(N) = dphi_over_dt(N-1);
dY = [dC1_over_dt;dq1_over_dt;dphi_over_dt];
end

Axially loaded stepped shaft analysis in MATLAB

I have a stepped shaft as per the attached image. Following information available as an input parameters:
Young's modulus 123e3N/mm^2.
Cross-sectional area 300mm^2 for the length of 400mm
Cross-sectional area 400mm^2 for the length of 250mm
Axial force of 200kN acts axially on the shaft and the location of load is at 200mm from the one end of the shaft on cross-sectional area of 300mm^2
I need help to make do finite element analysis in MATALB.
Please help me in making MATLAB code for this.
%% Clearing workspace
clc
clear
close all
%% Element specifications
ne = 3; % Number of elements
nne = 2; % Number of nodes per element
nn = ne*(nne - 1) + 1; % total number of nodes
ndof = 1; % Number of degress of freedom per node
sg = nn*ndof; % size of global stiffness matrix
se = nne*ndof; % size of elemental stiffness matrix
KG = zeros(sg,sg); % Global stiffness matrix
Ke = zeros(se,se); % Elemental Stiffness MAtrix
Fe = zeros(se,1); % Elemental Force Vector
FG = zeros(sg,1); % Global Force Vector
%% Geometrical parameters
E = 123e3*ones(1,ne); % Young's Modulus in N/mm^2
P = 200e3; % Force in N
F = P;
A = ones(1,ne) ; % Area of cross-section
A(1)=300; % Area of cross-section of 1st element in mm^2
A(2)=300; % Area of cross-section of 2nd element in mm^2
A(3)=400; % Area of cross-section of 3rd element in mm^2
L = ones(1,ne); % Length of elements in mm
L(1)=200; % Length of 1st element in mm
L(2)=200; % Length of 2nd element in mm
L(3)=250; % Length of 3rd element in mm
%% Assembly of Global Stiffness Matrix
for i = 1:ne
Ke = (A(i)*E(i)/L(i))*[1 -1;-1 1]; % Element Stiffness Matrix
for j = 1:se
for k = 1:se
KG(i + j - 1, i + k - 1) = KG(i + j - 1, i + k - 1) + Ke(j,k);
end
end
end
%% Concentrated Load Vector at end
FG(2,1) = F; % Defining location of concentrated load
%% Application of boundary conditions
KGS = KG;
cdof = [1 4]; % specify fixed degree of freedom number
Lcdof = length(cdof);
for a = 1:Lcdof
KGS(cdof(a),:) = 0;
KGS(:,cdof(a)) = 1;
FG(cdof(a),1) = 0;
end
FGL = length(FG);
for b = 1:FGL
if(b > length(FG))
elseif(FG(b)<0)
FG(b) = [];
end
end
%% Solving for displacement
U = linsolve(KGS,FG)
U1=KGS\FG
%% Calculation of Reaction Forces
FR = KG*U1

Looping my algorithm to plot for a different parameter value on the same graph(MATLAB)

I've implemented an algorithm for my physics project which does exactly what I want. The problem that I'm stuck which is not the Physics content itself hence I think it might be somewhat trivial to explain what my code does. I'm mainly stuck with the way MATLAB's plotting works if I was to loop over the same algorithm to produce similar graphs with a slight change of a value of my parameter. Here's my code below:
clear; clc; close all;
% Parameters:
z_nn = 4; % Number of nearest-neighbour in lattice (square = 4).
z_nnn = 4; % Number of next-nearest-neighbours in lattice (square = 4).
Lx = 40; % Number of sites along x-axis.
Ly = 40; % Number of sites along y-axis.
sigma = 1; % Size of a site (defines our units of length).
beta = 1.2; % Inverse temperature beta*epsilon.
mu = -2.53; % Chemical potential mu/epsilon.
mu_2 = -2.67; % Chemical potential mu/epsilon for 2nd line.
J = linspace(1, 11, 11);%J points for the line graph plot
potential = zeros(Ly);
attract = 1.6; %wall attraction constant
k = 1; %wall depth
rho_0 = 0.4; % Initial density.
tol = 1e-12; % Convergence tolerance.
count = 30000; % Upper limit for iterations.
alpha = 0.01; % Mixing parameter.
conv = 1; cnt = 1; % Convergence value and counter.
rho = rho_0*ones(Ly); % Initialise rho to the starting guess(i-th rho_old) in Eq(47)
rho_rhs = zeros(Ly); % Initialise rho_new to zeros.
% Solve equations iteratively:
while conv>=tol && cnt<count
cnt = cnt + 1; % Increment counter.
% Loop over all lattice sites:
for j=1:Ly
%Defining the Lennard-Jones potential
if j<k
potential(j) = 1000000000;
else
potential(j) = -attract*(j-k)^(-3);
end
% Handle the periodic boundaries for x and y:
%left = mod((i-1)-1,Lx) + 1; % i-1, maps 0 to Lx.
%right = mod((i+1)-1,Lx) + 1; % i+1, maps Lx+1 to 1.
if j<k+1 %depth of wall
rho_rhs(j) = 0;
rho(j) = 0;
elseif j<(20+k)
rho_rhs(j) = (1 - rho(j))*exp((beta*((3/2)*rho(j-1) + (3/2)*rho(j+1) + 2*rho(j) + mu) - potential(j)));
else
rho_rhs(j) = rho_rhs(j-1);
end
end
conv = sum(sum((rho - rho_rhs).^2)); % Convergence value is the sum of the differences between new and current solution.
rho = alpha*rho_rhs + (1 - alpha)*rho; % Mix the new and current solutions for next iteration.
end
% disp(['conv = ' num2str(conv_2) ' cnt = ' num2str(cnt)]); % Display final answer.
% figure(2);
% pcolor(rho_2);
figure(1);
plot(J, rho(1:11));
hold on;
% plot(J, rho_2(1,1:11));
hold off;
disp(['conv = ' num2str(conv) ' cnt = ' num2str(cnt)]); % Display final answer.
figure(3);
pcolor(rho);
Running this code should give you a graph like this
Now I want to produce a similar graph but with one of the variable's value changed and plotted on the same graph. My approach that I've tried is below:
clear; clc; close all;
% Parameters:
z_nn = 4; % Number of nearest-neighbour in lattice (square = 4).
z_nnn = 4; % Number of next-nearest-neighbours in lattice (square = 4).
Lx = 40; % Number of sites along x-axis.
Ly = 40; % Number of sites along y-axis.
sigma = 1; % Size of a site (defines our units of length).
beta = 1.2; % Inverse temperature beta*epsilon.
mu = [-2.53,-2.67]; % Chemical potential mu/epsilon.
mu_2 = -2.67; % Chemical potential mu/epsilon for 2nd line.
J = linspace(1, 10, 10);%J points for the line graph plot
potential = zeros(Ly, length(mu));
gamma = zeros(Ly, length(mu));
attract = 1.6; %wall attraction constant
k = 1; %wall depth
rho_0 = 0.4; % Initial density.
tol = 1e-12; % Convergence tolerance.
count = 30000; % Upper limit for iterations.
alpha = 0.01; % Mixing parameter.
conv = 1; cnt = 1; % Convergence value and counter.
rho = rho_0*[Ly,length(mu)]; % Initialise rho to the starting guess(i-th rho_old) in Eq(47)
rho_rhs = zeros(Ly,length(mu)); % Initialise rho_new to zeros.
figure(3);
hold on;
% Solve equations iteratively:
while conv>=tol && cnt<count
cnt = cnt + 1; % Increment counter.
% Loop over all lattice sites:
for j=1:Ly
for i=1:length(mu)
y = 1:Ly;
MU = mu(i).*ones(Ly)
%Defining the Lennard-Jones potential
if j<k
potential(j) = 1000000000;
else
potential(j) = -attract*(j-k).^(-3);
end
% Handle the periodic boundaries for x and y:
%left = mod((i-1)-1,Lx) + 1; % i-1, maps 0 to Lx.
%right = mod((i+1)-1,Lx) + 1; % i+1, maps Lx+1 to 1.
if j<k+1 %depth of wall
rho_rhs(j) = 0;
rho(j) = 0;
elseif j<(20+k)
rho_rhs(j) = (1 - rho(j))*exp((beta*((3/2)*rho(j-1) + (3/2)*rho(j+1) + 2*rho(j) + MU - potential(j)));
else
rho_rhs(j) = rho_rhs(j-1);
end
end
end
conv = sum(sum((rho - rho_rhs).^2)); % Convergence value is the sum of the differences between new and current solution.
rho = alpha*rho_rhs + (1 - alpha)*rho; % Mix the new and current solutions for next iteration.
disp(['conv = ' num2str(conv) ' cnt = ' num2str(cnt)]); % Display final answer.
figure(1);
pcolor(rho);
plot(J, rho(1:10));
end
hold off;
The only variable that I'm changing here is mu. I would like to loop my first code so that I can enter an arbitrary amount of different values of mu and plot them on the same graph. Naturally I had to change all of the lists dimension from (1 to size of Ly) to (#of mu(s) to size of Ly), such that when the first code is being looped, the i-th mu value in that loop is being turned into lists with dimension as long as Ly. So I thought I would do the plotting within the loop and use "hold on" encapsulating the whole loop so that every plot that was generated in each loop won't be erased. But I've been spending hours on trying to figure out the semantics of MATLAB but ultimately I can't figure out what to do. So hopefully I can get some help on this!
hold on only applies to the active figure, it is not a generic property shared among all figures. What is does is changing the value of the current figure NextPlot property, which governs the behavior when adding plots to a figure.
hold on is equivalent to set(gcf,'NextPlot','add');
hold off is equivalent to set(gcf,'NextPlot','replace');
In your code you have:
figure(3); % Makes figure 3 the active figure
hold on; % Sets figure 3 'NextPlot' property to 'add'
% Do some things %
while conv>=tol && cnt<count
% Do many things %
figure(1); % Makes figure 1 the active figure; 'hold on' was not applied to that figure
plot(J, rho(1:10)); % plots rho while erasing the previous plot
end
You should try to add another hold on statement after figure(1)
figure(1);
hold on
plot(J, rho(1:10));

Plotting 2D equation with infinite sum

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.