Gauss-Seidel code not converging on solution for 2-D Helmholtz - matlab

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

Related

Exact solution Error in Heat Equation Matlab Code

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

How to plot 2D advection problem when using meshgrid to find value for velocity?

I am currently trying to solve a 2nd order 2D advection equation using the upwind scheme. At first the task is to plot a quiver() plot and then over lay it on top of a contourf(). When using the data for velocity u and v into the upwind scheme I am getting straight line outputs as seen below. However I am using an initial condition of phi0 = cos(x). When checking the values for X,Y,u,v they all have different values at (i,j) locations. I see that my phi0 and phi are staying constant down each column but the output of the advection should be different at different times. I followed my 1D 2nd order code which works perfectly, but cannot seem to get a advected moving graph. Any advice on my setup or if you can point out where I am going wrong with this plot would be a big help!
clear all
clc
%Problem 1
%Part B
%Creating a quiver plot for the 2D vector profile
L=2*pi;%Length Lx=Ly = 2pi
L0=0;
N=31; % Nx=Ny=31
%get a value of dx=dy to know distance between steps
dx=L/N;
dy=L/N
x=L0-dx*2:dx:L+dx*2;
y=L0-dy*2:dy:L+dy*2;
[X,Y]=meshgrid(x,y);
u=cos(X).*sin(Y);
v=-sin(X).*cos(Y);
figure
hold on
%Part B & C using the courtf plot Phi=cos(x)
phi0=cos(X);
contourf(X,Y,phi0)
colormap autumn
colorbar
xlabel('Length from 0 to 2*pi with dx spacing')
ylabel('Length from 0 to 2*pi with dy spacing')
title('Quiver plot on the phi=cos(x) Contour Plot')
quiver(X,Y,u,v)
hold off
figure(2)
plot(x,phi0)
%%
%Writing a code to sovle 2D advection for part D
t=0; %initial time
tmax=10; %Maximum time
dt=0.01; %time step
phi=phi0;
phip1=phi0;
%phi(:)=phi; %Initial Condition
nsteps = tmax/dt
%Add periodic boundary conditions for both x & y direction
for n=1 : nsteps
phi(1,:) = phi(end-2,:);
phi(2,:) = phi(end-3,:);
phi(end,:) = phi(3,:);
phi(end-1,:) = phi(4,:);
%Y ghost cells
phi(:,1) = phi(:,end-2);
phi(:,1) = phi(:,end-3);
phi(:,end) = phi(:,3);
phi(:,end-1) = phi(:,4);
for i=3:N+1
for j=3:N+1
if u > 0 & v>0
phip1(i,j)= phi(i,j) - u(i)*dt/(2*dx) * (3*phi(i,j)-4*phi(i-1,j)+phi(i-2,j))- v(j)*dt/(2*dx) *(3*phi(i,j)-4*phi(i,j-1)+phi(i,j-2))
elseif u <0 & v<0
phip1(i,j)= phi(i,j) - u(i)*dt/(2*dx) * (-3*phi(i,j)+4*phi(i+1,j)-phi(i+2,j))- v(j)*dt/(2*dx) *(-3*phi(i,j)+4*phi(i,j+1)-phi(i,j+2))
elseif u >0 & v <0
phip1(i,j)= phi(i,j) - u(i)*dt/(2*dx) * (3*phi(i,j)-4*phi(i+1,j)+phi(i+2,j))- v(j)*dt/(2*dx) *(-3*phi(i,j)+4*phi(i,j-1)-phi(i,j-2))
elseif u <0 & v >0
phip1(i,j)= phi(i,j) - u(i)*dt/(2*dx) * (-3*phi(i,j)+4*phi(i-1,j)-phi(i-2,j))- v(j)*dt/(2*dx) *(3*phi(i,j)-4*phi(i,j+1)+phi(i,j+2))
end
end
end
t=t+dt;
phi=phip1;
plot(x,phi)
%pause(0.5)
end
The problem I see is that you are plotting phi (which is 2D) against x (which is 1D).
I am not 100% sure on the right section you want to plot but something along the lines of this should work: plot(x,phi0(1,:)). What this does is to plot the first slice of phi in the y direction.
EDIT
To visualize phi0 as function of both X and Y, you can use either surf(X,Y,phi0) or mesh(X,Y,phi0).

How to correctly use ode45 function in MATLAB for differential drive robot?

I am trying to determine the pose (x,y,theta) of a differential drive robot using ode45. The code I have below solves for the x position, but I am having an issue with the initial condition. I set it to 0 since at time 0 the robot is assumed to be at the origin, but I get an error. How do I set the initial condition for ode45 such that I get the expected output?
I tried to make the initial conditions vector of the same length as dxdt by setting initial conditions as a 41x1 zeros matrix, but I didn't understand the output and I don't believe I did it correctly.
% Given conditions for a differential drive robot:
B = 20; % (cm) distance along axle between centers of two wheels
r = 10; % (cm) diameter of both wheels
w_l = 5*sin(3*t); % (rad/s) angular rate of left wheel
w_r = 5*sin(3*t); % (rad/s) angular rate of right wheel
v_l = r*w_l; % (cm/s) velocity of left wheel
v_r = r*w_r; % (cm/s) velocity of right wheel
v = (v_r+v_l)/B; % (cm/s) velocity of robot
theta = 90; % constant orientation of robot since trajectory is straight
% Solve differential equation for x:
dxdt = v*cos(theta); % diff equaition for x
tspan = [0 20]; % time period to integrate over
x0 = 0; % initial condition since robot begins at origin
[t,x] = ode45(#(t,y) dxdt, tspan, x0);
I want to solve the differential equation dxdt for 0 to 20 seconds with an initial condition of 0. I expect the output to give me a vector of time from 0 to 20 and an array of for x. The problem I believe lies with the initial condition. MATLAB gives me an error in the live editor telling me, " #(t,y)dxdt returns a vector of length 69, but the length of initial conditions vector is 1. The vector returned by #(t,y)dxdt and the initial conditions vector must have the same number of elements."
The issue is not the initial condition. You need to define dxdt as a function i.e.
% Define differential equation
function derivative = dxdt(t,y)
% Given conditions for a differential drive robot:
B = 20; % (cm) distance along axle between centers of two wheels
r = 10; % (cm) diameter of both wheels
w_l = 5*sin(3*t); % (rad/s) angular rate of left wheel
w_r = 5*sin(3*t); % (rad/s) angular rate of right wheel
v_l = r*w_l; % (cm/s) velocity of left wheel
v_r = r*w_r; % (cm/s) velocity of right wheel
v = (v_r+v_l)/B; % (cm/s) velocity of robot
theta = 90; % constant orientation of robot since trajectory is straight
derivative = v*cos(theta); % diff equation for x
end
Then when you use ode45 you should tell it to pass the t and y variables as arguments to dxdt like
[t,x] = ode45(#(t,y) dxdt(t,y), tspan, x0);
This should then work. In this case, as dxdt only takes the default arguments, you could also write
[t,x] = ode45(#dxdt, tspan, x0);
The error you got indicates that at some point you made dxdt into a vector of length 69, whilst MATLAB was expecting to get back 1 value for dxdt when it passed one t and one y to your dxdt 'function'. Whenever you get errors like this, I'd recommend putting
clear all
`clearvars` % better than clear all - see am304's comment below
at the top of your script to avoid polluting your workspace with previously defined variables.

How do I plot the solutions and errors obtained through Jacobi Iteration?

I am trying to create a figure showing the solution I obtained through Jacobi iteration along with the true solution, as well as the error of the Jacobi solution.
The figure I'm trying to create should consist of two plots.
I used the subplot command, to split the figure into
an upper and lower axes and I wrote the for loop that calculates the Jacobi iterations and the error. The loop is going to iterate 400 times using x0 as the initial guess. Before this, I calculated the true solution to the system Ax = b.
N = 30;
iter = 400;
A = toeplitz([-2 1 zeros(1, N-2)], [-2 1 zeros(1, N-2)]);
bk = ones(N,1);
for jj = 1:N
bk(jj) = cos(5*jj) + (1/2)*sin(7*jj);
end
x = A\bk;
D = diag(diag(A));
T = A - D;
x0 = zeros(N,1);
error = zeros(iter,1);
M = -D\T;
g = D\bk;
for nn = 1:iter
x0 = M*x0 + g;
error(nn) = norm(x - x0,2);
end
subplot(2,1,1)
plot(x0(1:N,1),'ro');
ylabel('Solution','FontSize',22);
title('Solution by Jacobi Iteration','FontSize',22);
xlim([0 pi]);
ylim([-5 5]);
xticks(0:0.5:3);
yticks(-5:5:5);
subplot(2,1,2)
plot(error(1:N),'ro')
ylabel('Error','FontSize',22);
xlabel('t','FontSize',22);
xlim([0 pi]);
ylim([0 0.1]);
xticks(0:0.5:3);
yticks(0:0.05:0.1);
The upper window should show the true solution in red circles connected by solid lines. The lower window show show the error as red
circles connected by dotted lines. When I ran my code, only 3 red circles appeared in the upper window and nothing was plotted in the lower window. I'm still bad at plotting iterations of a loop. Can someone help me with plotting the solutions and errors I calculated?
The xlim and ylim statements are not representative of the data.
x0 and x have N elements (30 here), and the elements of x and x0 span -2 to 2 in this setup.
error has iter elements (400 here), and the elements of error go from 4 to about 0.01.
For these plots, the element index maps to the horizontal x-axis, and their values to the y-axis. I think this plot setup should give you the result you desire (I probably changed more than actually needed):
subplot(2,1,1);
plot(1:N, x0(1:N,1), 'ro', 1:N, x,'k+');
title('Solution by Jacobi Iteration','FontSize',22);
ylabel('Solution','FontSize',22);
xlim([1, N]);
ylim([-3, 3]);
xticks(1:N);
yticks(-3:0.5:3);
subplot(2,1,2)
semilogy(1:iter, error(1:iter),'ro')
ylabel('Error','FontSize',22);
xlabel('t','FontSize',22);
xlim([1 iter]);
ylim([0 4]);
xticks(0:25:400);

Plotting cantilever and beam plots using Matlab

Problem
I have to plot a beam/cantilever using Matlab. Where my inputs are:
Length of the beam
Position of the loads (input is a vector)
Forces of the load (input is a vector)
Whether is it a cantilever or not. Because I have different equations for calculating the displacement.
My Solution
I have come to an idea on how I can actually plot the cantilever, but I can not formulate it into a code in MATLAB. I have spent hours trying to write something on Matlab but I have gotten nowhere. (I am a novice to Matlab)
My solution is as follow: I have the formula for the displacement from starting position.
I can define a vector using loop for x coordinates until the given beam length. Hence,
x=[0 ... L]
Then I want to define another vector where the difference is calculated (this is where I can't figure out Matlab)
y = [h, h - y(x1), h - y(x2), .... h - y(L)]
where h is the starting height, which I have thought to be defined as (y(x1) - y(L)) + 1, so that the graph then doesn't go into the negative axes. y(x) is the function which will calculate the displacement or fall of the beam.
Once that is done, then I can simply plot(x,y) and that would give me a graph of a shape of deflected beam for the given range from 0 to beam length. I have tested my theory on excel and it works as per the graph is concerned but I can not figure out implementation on Matlab.
My incomplete code
%Firstly we need the inputs
%Length of the beam
l = str2double(input('Insert the length of your beam: ', 's'));
%Now we need a vector for the positions of the load
a = [];
while 1
a(end+1) = input('Input the coordinate for the position of your load: ');
if length(a)>1; break; end
end
%Now we need a vector for the forces of the load
W = [];
while 1
W(end+1) = input('Input the forces of your load: ');
if length(W)>1; break; end
end
%
%
%
%Define the formula
y = ((W * (l - a) * x)/(6*E*I*l)) * (l^2 - x^2 - (l - a)^2);
%Where
E = 200*10^9;
I = 0.001;
%
%
%
%Now we try to plot
%Define a vector with the x values
vectx = [];
for i = 1:l
vectx = [vectx i];
end
%Now I want to calculate displacement for each x value from vectx
vecty = [];
for i=1:l
vecty=[10 - y(x(i)) i];
end
%Now I can plot all the information
plot(vectx, vecty)
hold on
%Now I plot the coordinate of the positions of the load
plot(load)
end
Really need some help/guidance. Would be truly grateful if someone can help me out or give me a hint :)
I have edited the question with further details
There are several things that do not work in your example.
For instance, parameters should be defined BEFORE you use them, so E and I should be defined before the deflection equation. And you should define x.
I do not understand why you put your inputs whithin a while loop, if you stop it at length(a)>1;. You can remove the loop.
You do not need a loop to calculate displacements, you can just use a substraction between vectors, like displacement = 10 - y. However, I do not understand what is H in your example; since your beam is initially at position 0, your displacement is just -y.
Finally, your equation to calculate the deformed shape is wrong; it only accounts for the first part of the beam.
Here, try if this code works:
%Length of the beam
l = input('Insert the length of your beam: ');
%Now we need a vector for the positions of the load
a = input('Input the coordinate for the position of your load: ');
%Now we need a vector for the forces of the load
W = input('Input the forces of your load: ');
%Define the formula
E = 200*10^9;
I = 0.001;
% x Position along the beam
x = linspace(0,l,100);
b = l - a;
% Deflection before the load position
pos = x <= a;
y(pos) = ((W * b .* x(pos))/(6*E*I*l)) .* (l^2 - x(pos).^2 - b^2);
% Cantilever option
% y(pos) = W*x(pos).^2/(6*E*I).*(3*a-x(pos));
% Deflection after the load position
pos = x > a;
y(pos) = ((W * b )/(6*E*I*l)) .* (l/b*(x(pos)-a).^3 + (l^2 - b^2)*x(pos) - x(pos).^3);
% Cantilever option
% y(pos) = W*a^2/(6*E*I).*(3*x(pos)-a);
displacement = 10 - y; % ???
% Plot beam
figure
plot(x , x .* 0 , 'k-')
hold on;
% Plot deflection
plot(x , y , '--')
% Plot load position
% Normalize arrow size as 1/10 of the beam length
quiver(a , 0 , 0 , sign(W) .* max(abs(y))/2)