Problem plotting 2d numerical solution of wave equation - matlab

I am trying to make an animation of the 2d wave equation in MATLAB (R2020a). So far I believe that the finite difference method is implemented correctly. However; when I try to plot these values using the "surf" command in matlab it does not work.
This is my script so far:
clear
clc
close all
VL = 2;
tMin = 0;
tMax = 30;
xMin = -10;
xMax = 10;
yMin = -10;
yMax = 10;
Nt = 100;
Nx = 100;
Ny = 100;
t = linspace(tMin,tMax,Nt);
x = linspace(xMin,xMax,Nx);
y = linspace(yMin,yMax,Ny);
DeltaT = t(2) - t(1);
DeltaX = x(2) - x(1);
DeltaY = y(2) - y(1);
CFX = ((VL)*(DeltaT/DeltaX))^2;
CFY = ((VL)*(DeltaT/DeltaY))^2;
u = zeros(Nt,Nx,Ny);
[X,Y] = meshgrid(x,y);
u(1,:,:) = Initial(t(1),X,Y);
u(2,:,:) = Initial(t(1),X,Y) + InitialV(t(1),X,Y);
for i=3:Nt
for j=1:Nx
for k=1:Ny
if(j==1 || j==Nx || k==1 || k==Ny)
u(i,j,k) = 0;
else
u(i,j,k) = 2*u(i-1,j,k) - u(i-2,j,k) + (CFX)*(u(i-1,j+1,k) - 2*u(i-1,j,k) + u(i-1,j-1,k)) + (CFY)*(u(i-1,j,k+1) - 2*u(i-1,j,k) + u(i-1,j,k-1));
end
end
end
end
the functions: Initial and initialV are u(0,x,y) and ut(0,x,y) respectively.
I believe this code works for finding the function values for u however when I try to plot the results as follows:
for i=1:Nt
figure
clf
hold on
surf(X,Y,u(i,:,:))
end
I get an error saying Z must be a matrix... In my opinion this seems strange, slicing a 3d array results in a 2d matrix.
How can I make an animation that shows u as a function of x and y?
Thanks in advance! any help is greatly appreciated
P.S. I am new to this page so if I am neglecting certain guidelines when it comes to sharing code please let me know and I will adjust it.

Another way to remove the singleton dimension of your u array would be to use squeeze() as it doesn't need any information on the remaining size of the array.
for i = 1:Nt
figure
clf
hold on
surf(X, Y, squeeze(u(i, :, :)))
end

To force u(i,:,:) to match the 100 by 100 dimensions of X and Y try using the reshape() function.
for i=1:Nt
figure
clf
hold on
surf(X,Y,reshape(u(i,:,:),[100 100]));
end

Related

Negative values obtained in the solution of the 1D advection-dispersion equation using FD method

I am trying to solve the 1D ADE
This is my code so far:
clc; clear; close all
%Input parameters
Ao = 1; %Initial value
L = 0.08; %Column length [m]
nx = 40; %spatial gridpoints
dx = L/nx; %Length step size [m]
T = 20/24; %End time [days]
nt = 100; %temporal gridpoints
dt = T/nt; %Time step size [days]
Vel = dx/dt; %Velocity in each cell [m/day]
alpha = 0.002; %Dispersivity [m]
De = alpha*Vel; % Dispersion coeff. [m2/day]
%Gridblocks
x = 0:dx:L;
t = 0:dt:T;
%Initial and boundary conditions
f = #(x) x; % initial cond.
% boundary conditions
g1 = #(t) Ao;
g2 = #(t) 0;
%Initialization
A = zeros(nx+1, nt+1);
A(:,1) = f(x);
A(1,:) = g1(t);
gamma = dt/(dx^2);
beta = dt/dx;
% Implementation of the explicit method
for j= 1:nt-1 % Time Loop
for i= 2:nx-1 % Space Loop
A(i,j+1) = (A(i-1,j))*(Vel*beta + De*gamma)...
+ A(i,j)*(1-2*De*gamma-Vel*beta) + A(i+1,j)*(De*gamma);
end
% Insert boundary conditions for i = 1 and i = N
A(2,j+1) = A(1,j)*(Vel*beta + De*gamma) + A(2,j)*(1-2*De*gamma-Vel*beta) + A(3,j)*(De*gamma);
A(nx,j+1) = A(nx-1,j)*(Vel*beta + 2*De*gamma) + A(nx,j)*(1-2*De*gamma-Vel*beta)+ (2*De*gamma*dx*g2(t));
end
figure
plot(t, A(end,:), 'r*', 'MarkerSize', 2)
title('A Vs time profile (Using FDM)')
xlabel('t'),ylabel('A')
Now, I have been able to solve the problem using MATLAB’s pdepe function (see plot), but I am trying to compare the result with the finite difference method (implemented in the code above). I am however getting negative values of the dependent variable, but I am not sure what exactly I could be doing wrong. I therefore will really appreciate if anyone can help me out here. Many thanks in anticipation.
PS: I can post the code I used for the pdepe if anyone would like to see it.

Simulating a ship sailing in water wave in Matlab

I have a project in which I have to simulate a ship which is sailing in a water wave. I have decided to do it in by 3D surface plot. I have created water waves but I'm having trouble making the ship which should sit right at the centre of the plot. Following is my water wave simulation code:
clc; clear all ;
x_l = -20;
x_r = 20;
y_l = -20;
y_r = 20;
ds = 0.5;
A = 1;
k = 1;
dt = 0.05;
w = 1;
x = [x_l:ds:x_r];
y = [y_l:ds:y_r];
[X,Y] = meshgrid(x,y);
for i = 1:100
Z = A*sin(k*Y+(w*i/2));
CO(:,:,1) = 0.3*ones((y_r-y_l)/ds + 1) + 0.3*cos(k*Y+(w*i/2));
CO(:,:,2) = 0.3*ones((y_r-y_l)/ds + 1) + 0.3*cos(k*Y+(w*i/2));
CO(:,:,3) = 0.7*ones((y_r-y_l)/ds + 1) + 0.3*cos(k*Y+(w*i/2));
surf(X,Y,Z,CO);
hold on;
shading interp;
xlim([x_l x_r]);
ylim([y_l y_r]);
zlim([y_l y_r]);
Zc = sqrt(X.^2+Y.^2);
surf(X,Y,Zc);
shading interp;
hold off;
drawnow;
pause(dt);
end
Please guide me in the right direction if I'm doing this in the wrong way.
I just made a simple model of a sailing boat that is made up of quads. This allows us to use the surf function to draw it too. This should just serve as a starting point to see how you could do it. But keep in mind that this is probably not the best way of doing it. As a comment already mentioned, MATLAB is really not the best software for this, Blender is probably a way better option, but still we can make a nice little ship.
The first step is creating the fixed model in a local coordinate system. The NaNs are just to separate the different components of the ship, because otherwise we would have additional quads connecting e.g. the hull to the sails that would look out of place. (If it is unclear, just replace them with some arbitrary coordinates to see what is happening.)
Then to give it some movement, we have to incorporate the temporal component. I just added a slight rocking motion in the y-z plane as well as a little bouncing in the z-direction to give it the look of a ship moving through waves. I made sure to use the same frequency w/2 as you already used for the waves. This is important to make the boat to apper to rock with the waves.
clc; clear all ;
x_l = -20;
x_r = 20;
y_l = -20;
y_r = 20;
ds = 0.5;
A = 1;
k = 1;
dt = 0.05;
w = 1;
x = [x_l:ds:x_r];
y = [y_l:ds:y_r];
[X,Y] = meshgrid(x,y);
%sailboat
U = 0.7*[0,-1,-1,1,1,0;...%hull
0,0,0,0,0,0; NaN(1,6);...
0,0,NaN,0,0,NaN; %sails
0,-1,NaN,0,0,NaN];
V = 0.7*[3,1,-3,-3,1,3;%hull
1,1,-2,-2,1,1; NaN(1,6);...
3,0,NaN,0,-3,NaN; %sails
3,-1,NaN,0,-3,NaN];
W = 0.7*[1,1,1,1,1,1;%hull
0,0,0,0,0,0; NaN(1,6);...
2,6,NaN,7,2,NaN; %sails
2,2,NaN,2,2,NaN];
H = ones(2,6);
S = ones(3,3);
C = cat(3,[H*0.4;S*1,S*1],[H*0.2;S*0.6,S*0],[H*0;S*0.8,S*0]);
for i = 1:100
clf;
hold on;
Z = A*sin(k*Y+(w*i/2));
CO(:,:,1) = 0.3*ones((y_r-y_l)/ds + 1) + 0.3*cos(k*Y+(w*i/2));
CO(:,:,2) = 0.3*ones((y_r-y_l)/ds + 1) + 0.3*cos(k*Y+(w*i/2));
CO(:,:,3) = 0.7*ones((y_r-y_l)/ds + 1) + 0.3*cos(k*Y+(w*i/2));
surf(X,Y,Z,CO);
xlabel('x'); ylabel('y');
% rocking the boat
angle = 0.5*cos(w*i/2); %control rocking
Vs = V*cos(angle) - W*sin(angle);
Ws = V*sin(angle) + W*cos(angle) + 0.4 + 0.8*cos(w*(i - 0.5 * 2*pi)/2);%control amplitude
surf(U,Vs,Ws,C);
camproj('perspective');
xlim([x_l x_r]);
ylim([y_l y_r]);
zlim([y_l y_r]);
Zc = sqrt(X.^2+Y.^2);
%surf(X,Y,Zc);
%view([-100,20])
az = interp1([1,100],[-30, -120],i);
el = interp1([1,100],[1,30],i);
view([az,el]);
axis([-20,20,-20,20,-20,20]*0.5);
shading interp;
hold off;
drawnow;
pause(dt);
end
EDIT: The key to creating these "models" is knowign how surf works: Given some matrices X,Y,Z, each 2x2 submatrix of these matrices define the vertices of a quadrilateral. So the idea is decomposing our models into quadrilaterals (and adding NaN in this matrix where we do not want any quadrilaterals in between). Check out following snippet that shows just the hull and the quadrilaterals involved. The displayed numbers show the index of the coordinates of the corresponding points in the coordinate matrices U,V,W. I added a small number e that pulls the seams apart so that you can actually see the quadrilaterals. Set it to 0 to see the original shape:
e = 0.2; %small shift to visualize seams
%sailboat
U = 0.7*[0-e,-1-e,-1-e,1+e,1+e,0+e;...%hull
0-e,0-e,0-e,0+e,0+e,0+e];
V = 0.7*[3+e,1,-3,-3,1,3+e;%hull
1+e,1,-2,-2,1,1+e];
W = 0.7*[1,1,1,1,1,1;%hull
0,0,0,0,0,0];
surf(U,V,W);
axis equal
view([161,30])
hold on
for i=1:2
for j=1:6
text(U(i,j),V(i,j),W(i,j),[num2str(i),',',num2str(j)]); %plot indices of points
end
end
xlabel('U')
ylabel('V')
zlabel('W')
title('i,j refers to the point with coordinates (U(i,j),V(i,j),W(i,j))')
hold off

How to use surf to plot sphere function in matlab

I'm trying to plot sphere function below, But I'm getting wrong result
Here is the code I'm using
x1 = [-10:1:10];
x2 = [-10:1:10];
y = zeros(1,21);
for i = 1:21
y(i) = sphere([x1(i) x2(i)]);
end
Y = meshgrid(y);
surf(x1,x2,Y);
colormap hsv;
sphere.m
function [y] = sphere(x)
d = length(x);
sum = 0;
for i = 1:d
sum = sum + x(i)^2;
end
y = sum;
end
For the sake of completness your code is not working because you are only evaluating your function on the pairs (x,x) for some x \in [-10,10] so you don't cover the whole domain. It would work with this:
x1 = [-10:1:10];
x2 = [-10:1:10];
y = zeros(1,21);
for i = 1:21
for j=1:21
Y(i,j) = sphere([x1(i) x2(j)]);
end
end
surf(x1,x2,Y);
colormap hsv;
or way faster (because you should always avoid unnecessary loops for computation time reasons):
x1 = meshgrid([-10:1:10]);
x2 = x1';
Y = x1.^2+x2.^2;
surf(x1,x2,Y)
sphere(10)
It is a MatLab built in function.
Please enjoy responsibly.
If you need to see the source code use: edit sphere or help sphere when your sphere function is not on the path.

Why is my matlab plot not evolving using finite difference method?

I am trying to use a finite difference method to solve the heat equation for a given function u0. I want to evolve it in time using plots to see each frame change but when I run it all I see is the same frame over and over. I am aware of the error at the ends due to me not giving "u" a first or last index which will cause more overall error in the solution. I am not very good at matlab so I am not sure if I am writing my nested piece correctly.
% set up domain in time and space
t_step = .1;
tspan = [0 :t_step:1000];
L = 10; %length of domain
n = 64;
dx = 2*pi/(n-1); %spacing
x = 0:dx:2*pi;
x = x'; %make x vertical vector
% initial conditions for the function
u0 = sin(2*pi*x/L)+0*cos(3*2*pi*x/L) + 0.2*(cos(5*2*pi*x/L))+0*randn(size(x));
plot(x,u0);title('initial condition');pause;
t = 0;
for m = 1:tspan(end)
u = u0;
t = t + t_step;
for j= 2:n-1
u(j,m) = u0(j-1) - 2*u0(j) + u0(j+1)/dx^2; %u(1) and n left out
end
plot(x,u(:,m))
pause(0.01);
end

3D filled line plot

I have a matrix for contact positions and these positions are linear, therefore I can easily plot the contact positions within MATLAB and come out with the x amount of lines. At the moment I am plotting within a 2D graph.
for j= 1:5
for k= 1:20
Yijk(j,:,k)=x*tan_helix+one_array*(k-P)*Pb/P+one_array*(j-(L+1)/2)*Pb;
end
end
x_axis = linspace(0,b*1000, N+1);
figure;
for j=1:zPairs;
hold on
plot(x_axis,Yijk(j,:,k))
hold off
end
The above is only a small section of a large coding so all variables and parameters are stated else where.
Below is the graph this simply creates with a 2D graph:
What I wish to do is plot the correspoding contact to each of these positions, contact only occurs at positions > 0 and therefore will only occur along the lines plotted above. Therefore the plot will need to be in a 3D format and I am assuming that the lines will be plotted initially, then the contact_force and then a fill command as such - but I may be wrong.
What I am aiming to create is something similar to:
If any one has any guidance or tips it will be greatly appreciated as I am getting nowhere.
Please note the contact_force is also a matrix of the same dimensions as the contact positions.
for j = 1:zPairs
Xx = linspace(0,b*1000,N+1);
Yy = Yijk(j,:,1);
n = length(Xx);
Zz = contact_force(j,:,1);
Xp = zeros(2*n,1);
Yp = zeros(2*n,1);
Xp(1:N+1) = Xx;
Xp(N+2:2*(N+1)) = Xx(N+1:-1:1);
Yp(1:N+1) = Yy;
Yp(N+2:2*(N+1)) = Yy(N+1:-1:1);
Zp(1:N+1) = 0;
Zp(N+2:2*(N+1)) = Zz(N+1:-1:1);
figure(12);
hold on
patch(Xp,Yp,Zp,'c');
title('Zone of Contact');
hold off
end
The above code works great, but only creates one graph as it is for (j,:,1). I would like to change this so as that it is for (j,:,k) and k number of graphs are created. How would I set up this for loop ?
I wrote a little MATLAB code to test it out. This program creates a polygon on top of a 2D line. fill3 or patch functions are what you are looking for.
a = 2;
b = 1;
X = 0:10;
Y = a*X + b;
n = length(X);
Z = rand(n,1)*2+1;
Xp = zeros(2*n,1);
Yp = zeros(2*n,1);
Xp(1:n) = X;
Xp(n+1:2*n) = X(n:-1:1);
Yp(1:n) = Y;
Yp(n+1:2*n) = Y(n:-1:1);
Zp(1:n) = 0;
Zp(n+1:2*n) = Z(n:-1:1);
fill3(Xp,Yp,Zp,'c');