Flow field around cylinder in Matlab - matlab

I'm pretty new to different plots in Matlab and I'm trying to write a code that will show the flow field around a cylinder in Matlab. I'm at the very start and first of all I want to just make the circle in a rectangular domain (cylinder should not be right in the middle of the field).
So far, I have this set up but I want to know if it's possible to make the cylinder look more circular and less like an oval, especially because the domain is a rectangle and not a square. The points on the circle are correct but I want it to look better. Any tips on this? The code I have at the moment is:
U_i = 20; % Ambient velocity
a = 4; % cylinder radius
c = -a*5; % starting coordinate (x)
b = a*10; % ending coordinate (x)
d = -60; % starting coordinate (y)
e = 60; % ending coordinate (y)
n = a*50; % number of intervals (step size in grid)
[x,y] = meshgrid([c:(b-c)/n:b],[d:(e-d)/n:e]');
for i = 1:length(x)
for k = 1:length(x);
f = sqrt(x(i,k).^2 + y(i,k).^2);
if f < a
x(i,k) = 0;
y(i,k) = 0;
end
end
end
% Definition of polar variables
r = sqrt(x.^2+y.^2);
theta = atan2(y,x);
%% Creation of Streamline function
z = U_i.*r.*(1-a^2./r.^2).*sin(theta);%- G*log(r)/(2*pi);
%% Creation of Figure
m = 100;
s = ones(1,m+1)*a;
t = [0:2*pi/m:2*pi];
%% Streamline plot
contour(x,y,z,50);
hold on
polar(t,s,'-k');
% axis square
title('Stream Lines');
grid off

Related

How do I label lines in a MatLab plot?

What my plot looks like
What the plot should look like
The code is working like it should but im trying to get the labels to show up on each line from (1-8). Just like the picture above.
I have read a bunch of posts and tried to search Matlab but i havent been able to figure it out.
clc;clear;close all;
V_inf = 20; % freestream velocity
R = 1; % cylinder radius
n = 8; % number of panels
d_theta = 2*pi/n; % resolution of angles
alpha = 0; % angle of attack
theta = pi+pi/n:-d_theta:-pi+pi/n; % angles of boundary points of panels
X = R*cos(theta); % X coordinates of boundary points of panels
Y = R*sin(theta); % Y coordinates of boundary points of panels
Phi = zeros(n,1); % angle from Vinf to bottom of panel
beta = zeros(n,1); % angle from Vinf to outward normal of panel
conX = zeros(n,1); % X coordinates of control points
conY = zeros(n,1); % Y coordinates of control points
S = zeros(n,1); % panel length
for i = 1:n
Phi(i) = -alpha + atan2((Y(i+1)-Y(i)),(X(i+1)-X(i)));
beta(i) = Phi(i)+pi/2;
if beta(i)>2*pi, beta(i)=beta(i)-2*pi;
elseif beta(i)<0, beta(i)=beta(i)+2*pi; end
conX(i) = (X(i+1)+X(i))/2;
conY(i) = (Y(i+1)+Y(i))/2;
S(i) = sqrt((X(i+1)-X(i))^2 + (Y(i+1)-Y(i))^2);
end
close all
plot(R*cos(0:0.01:2*pi),R*sin(0:0.01:2*pi),'b', X,Y,'r',conX,conY,'g^');
axis equal; legend('Exact shape','Panel approximation','Control points')
xlabel('x, m'); ylabel('y, m'); title('Fig. 1 Panel layout (n = 8, R = 1m)');
Possibly plotting the labels along the points of a circle using the text() function may suffice. There's some shifting of points and flipping that needs to be done to get the order you wish but otherwise it's just 8 points taken along a circle that is smaller in diameter in comparison to the octagon. An alternative would be using the green triangles as reference instead but that involves more math. As long as your octagon is expected to be symmetrical vertically and horizontally this should work alright.
clc;clear;close all;
V_inf = 20; % freestream velocity
R = 1; % cylinder radius
n = 8; % number of panels
d_theta = 2*pi/n; % resolution of angles
alpha = 0; % angle of attack
theta = pi+pi/n:-d_theta:-pi+pi/n; % angles of boundary points of panels
X = R*cos(theta); % X coordinates of boundary points of panels
Y = R*sin(theta); % Y coordinates of boundary points of panels
Phi = zeros(n,1); % angle from Vinf to bottom of panel
beta = zeros(n,1); % angle from Vinf to outward normal of panel
conX = zeros(n,1); % X coordinates of control points
conY = zeros(n,1); % Y coordinates of control points
S = zeros(n,1); % panel length
for i = 1:n
Phi(i) = -alpha + atan2((Y(i+1)-Y(i)),(X(i+1)-X(i)));
beta(i) = Phi(i)+pi/2;
if beta(i)>2*pi, beta(i)=beta(i)-2*pi;
elseif beta(i)<0, beta(i)=beta(i)+2*pi; end
conX(i) = (X(i+1)+X(i))/2;
conY(i) = (Y(i+1)+Y(i))/2;
S(i) = sqrt((X(i+1)-X(i))^2 + (Y(i+1)-Y(i))^2);
end
close all
plot(R*cos(0:0.01:2*pi),R*sin(0:0.01:2*pi),'b', X,Y,'r',conX,conY,'g^');
axis equal; legend('Exact shape','Panel approximation','Control points')
xlabel('x, m'); ylabel('y, m'); title('Fig. 1 Panel layout (n = 8, R = 1m)');
%*************************************************************************%
%ADDING LABELS BY PLOTTING LABELS ALONG CIRCLE%
%*************************************************************************%
Radius = 0.8;
Number_Of_Data_Points = 9;
theta = linspace(0,2*pi,Number_Of_Data_Points);
X_Circle = Radius*cos(theta);
X_Circle = X_Circle(1:end-1);
Y_Circle = Radius*sin(theta);
Y_Circle = Y_Circle(1:end-1);
X_Circle = flip(circshift(X_Circle,3));
Y_Circle = flip(circshift(Y_Circle,3));
for Point_Index = 1: numel(conX)
X_Displacement = X_Circle(Point_Index);
Y_Displacement = Y_Circle(Point_Index);
text(X_Displacement,Y_Displacement,num2str(Point_Index),'HorizontalAlignment','center','fontsize',20);
end
To Plot on Control Points:
%*************************************************************************%
%ADDING LABELS BY PLOTTING LABELS ALONG CONTROL POINTS%
%*************************************************************************%
for Point_Index = 1: numel(conX)
text(conX(Point_Index),conY(Point_Index),num2str(Point_Index),'HorizontalAlignment','center','fontsize',20);
end

How to speed up runtime of code that searches for data between several arrays within a 'moving' sphere

I am trying to average my CFD data (which is in the form of a scalar N x M x P array; N corresponds to Y, M to x, and P to z) over a subset of time steps. I've tried to simplify the description of my desired averaging process below.
Rotate the grid at each time step by a specified angle (this is because the flow has a coherent structure that rotates and changes shape/size at each time step and I want to overlap them and find a time averaged form of the structure that takes into account the change of shape/size over time)
Drawing a sphere centered on the original unrotated grid
Identifying the grid points from all the rotated grids that lie within the sphere
Identify the indices of the grid points in each rotated grid
Use the indices to find the scalar data at the rotated grid points within the sphere
Take an average of the values within the sphere
Put that new averaged value at the location on the unrotated grid
I have a code that seems to do what I want correctly, but it takes far too long to finish the calculations. I would like to make it run faster, and I am open to changing the code if necessary. Below is version of my code that works with a smaller version of the data.
x = -5:5; % x - position data
y = -2:.5:5; % y - position data
z = -5:5; % z - position data
% my grid is much bigger actually
[X,Y,Z] = meshgrid(x,y,z); % mesh for plotting data
dX = diff(x)'; dX(end+1) = dX(end); % x grid intervals
dY = diff(y)'; dY(end+1) = dY(end); % y grid intervals
dZ = diff(z)'; dZ(end+1) = dZ(end); % z grid intervals
TestPoints = combvec(x,y,z)'; % you need the Matlab Neural Network Toolbox to run this
dXYZ = combvec(dX',dY',dZ')';
% TestPoints is the unrotated grid
M = length(x); % size of grid x - direction
N = length(y); % size of grid y - direction
P = length(z); % size of grid z - direction
D = randi([-10,10],N,M,P,3); % placeholder for data for 3 time steps (I have more than 3, this is a subset)
D2{3,M*N*P} = [];
PosAll{3,2} = [];
[xSph,ySph,zSph] = sphere(50);
c = 0.01; % 1 cm
nu = 8e-6; % 8 cSt
s = 3*c; % span for Aspect Ratio 3
r_g = s/sqrt(3);
U_g = 110*nu/c; % velocity for Reynolds number 110
Omega = U_g/r_g; % angular velocity
T = (2*pi)/Omega; % period
dt = 40*T/1920; % time interval
DeltaRotAngle = ((2*pi)/T)*dt; % angle interval
timesteps = 121:123; % time steps 121, 122, and 123
for ti=timesteps
tj = find(ti==timesteps);
Theta = ti*DeltaRotAngle;
Rotate = [cos(Theta),0,sin(Theta);...
0,1,0;...
-sin(Theta),0,cos(Theta)];
PosAll{tj,1} = (Rotate*TestPoints')';
end
for i=1:M*N*P
aa = TestPoints(i,1);
bb = TestPoints(i,2);
cc = TestPoints(i,3);
rs = 0.8*sqrt(dXYZ(i,1)^2 + dXYZ(i,2)^2 + dXYZ(i,3)^2);
handles.H = figure;
hs = surf(xSph*rs+aa,ySph*rs+bb,zSph*rs+cc);
[Fs,Vs,~] = surf2patch(hs,'triangle');
close(handles.H)
for ti=timesteps
tj = find(timesteps==ti);
f = inpolyhedron(Fs,Vs,PosAll{tj,1},'FlipNormals',false);
TestPointsR_ti = PosAll{tj,1};
PointsInSphere = TestPointsR_ti(f,:);
p1 = [aa,bb,cc];
p2 = [PointsInSphere(:,1),...
PointsInSphere(:,2),...
PointsInSphere(:,3)];
w = 1./sqrt(sum(...
(p2-repmat(p1,size(PointsInSphere,1),1))...
.^2,2));
D_ti = reshape(D(:,:,:,tj),M*N*P,1);
D2{tj,i} = [D_ti(f),w];
end
end
D3{M*N*P,1} = [];
for i=1:M*N*P
D3{i} = vertcat(D2{:,i});
end
D4 = zeros(M*N*P,1);
for i=1:M*N*P
D4(i) = sum(D3{i}(:,1).*D3{i}(:,2))/...
sum(D3{i}(:,2));
end
D_ta = reshape(D4,N,M,P);
I expect to get an N x M x P array where each index is the weighted average of all the points covering all of the time steps at that specific position in the unrotated grid. As you can see this is exactly what I get. The major problem however is the length of time it takes to do so when I use the larger set of my 'real' data. The code above takes only a couple minutes to run, but when M = 120, N = 24, and P = 120, and the number of time steps is 24 this can take much longer. Based on my estimates it would take approximately 25+ days to finish the entire calculation.
Nevermind, I can help you with the math. What you are trying to do here is find things inside a sphere. You have a well-defined sphere so this makes things easy. Just find the distance of all points from the center point. No need to plot or use inpolyhedron. Note line 66 where I modify the points by the center point of the sphere, compute the distance of these points, and compare to the radius of the sphere.
% x = -5:2:5; % x - position data
x = linspace(-5,5,120);
% y = -2:5; % y - position data
y = linspace(-2,5,24);
% z = -5:2:5; % z - position data
z = linspace(-5,5,120);
% my grid is much bigger actually
[X,Y,Z] = meshgrid(x,y,z); % mesh for plotting data
dX = diff(x)'; dX(end+1) = dX(end); % x grid intervals
dY = diff(y)'; dY(end+1) = dY(end); % y grid intervals
dZ = diff(z)'; dZ(end+1) = dZ(end); % z grid intervals
TestPoints = combvec(x,y,z)'; % you need the Matlab Neural Network Toolbox to run this
dXYZ = combvec(dX',dY',dZ')';
% TestPoints is the unrotated grid
M = length(x); % size of grid x - direction
N = length(y); % size of grid y - direction
P = length(z); % size of grid z - direction
D = randi([-10,10],N,M,P,3); % placeholder for data for 3 time steps (I have more than 3, this is a subset)
D2{3,M*N*P} = [];
PosAll{3,2} = [];
[xSph,ySph,zSph] = sphere(50);
c = 0.01; % 1 cm
nu = 8e-6; % 8 cSt
s = 3*c; % span for Aspect Ratio 3
r_g = s/sqrt(3);
U_g = 110*nu/c; % velocity for Reynolds number 110
Omega = U_g/r_g; % angular velocity
T = (2*pi)/Omega; % period
dt = 40*T/1920; % time interval
DeltaRotAngle = ((2*pi)/T)*dt; % angle interval
timesteps = 121:123; % time steps 121, 122, and 123
for ti=timesteps
tj = find(ti==timesteps);
Theta = ti*DeltaRotAngle;
Rotate = [cos(Theta),0,sin(Theta);...
0,1,0;...
-sin(Theta),0,cos(Theta)];
PosAll{tj,1} = (Rotate*TestPoints')';
end
tic
for i=1:M*N*P
aa = TestPoints(i,1);
bb = TestPoints(i,2);
cc = TestPoints(i,3);
rs = 0.8*sqrt(dXYZ(i,1)^2 + dXYZ(i,2)^2 + dXYZ(i,3)^2);
% handles.H = figure;
% hs = surf(xSph*rs+aa,ySph*rs+bb,zSph*rs+cc);
% [Fs,Vs,~] = surf2patch(hs,'triangle');
% close(handles.H)
for ti=timesteps
tj = find(timesteps==ti);
% f = inpolyhedron(Fs,Vs,PosAll{tj,1},'FlipNormals',false);
f = sqrt(sum((PosAll{tj,1}-[aa,bb,cc]).^2,2))<rs;
TestPointsR_ti = PosAll{tj,1};
PointsInSphere = TestPointsR_ti(f,:);
p1 = [aa,bb,cc];
p2 = [PointsInSphere(:,1),...
PointsInSphere(:,2),...
PointsInSphere(:,3)];
w = 1./sqrt(sum(...
(p2-repmat(p1,size(PointsInSphere,1),1))...
.^2,2));
D_ti = reshape(D(:,:,:,tj),M*N*P,1);
D2{tj,i} = [D_ti(f),w];
end
if ~mod(i,10)
toc
end
end
D3{M*N*P,1} = [];
for i=1:M*N*P
D3{i} = vertcat(D2{:,i});
end
D4 = zeros(M*N*P,1);
for i=1:M*N*P
D4(i) = sum(D3{i}(:,1).*D3{i}(:,2))/...
sum(D3{i}(:,2));
end
D_ta = reshape(D4,N,M,P);
In terms of runtime, on my computer, the old code takes 57 hours to run. The new code takes 2 hours. At this point, the main calculation is the distance so I doubt you'll get much better.

Plot quiver polar coordinates

I want to plot the field distribution inside a circular structure with radius a.
What I expect to see are circular arrows that from the centre 0 go toward a in the radial direction like this
but I'm obtaining something far from this result. I wrote this
x_np = besselzero(n, p, 1); %toolbox from mathworks.com for the roots
R = 0.1:1:a; PHI = 0:pi/180:2*pi;
for r = 1:size(R,2)
for phi = 1:size(PHI,2)
u_R(r,phi) = -1/2*((besselj(n-1,x_np*R(1,r)/a)-besselj(n+1,x_np*R(1,r)/a))/a)*cos(n*PHI(1,phi));
u_PHI(r,phi) = n*(besselj(n,x_np*R(1,r)/a)/(x_np*R(1,r)))*sin(PHI(1,phi));
end
end
[X,Y] = meshgrid(R);
quiver(X,Y,u_R,u_PHI)
where u_R is supposed to be the radial component and u_PHI the angular component. Supposing the formulas that I'm writing are correct, do you think there is a problem with for cycles? Plus, since R and PHI are not with the same dimension (in this case R is 1x20 and PHI 1X361) I also get the error
The size of X must match the size of U or the number of columns of U.
that I hope to solve it if I figure out which is the problem with the cycles.
This is the plot that I get
The problem has to do with a difference in co-ordinate systems.
quiver expects inputs in a Cartesian co-ordinate system.
The rest of your code seems to be expressed in a polar co-ordinate system.
Here's a snippet that should do what you want. The initial parameters section is filled in with random values because I don't have besselzero or the other details of your problem.
% Define initial parameters
x_np = 3;
a = 1;
n = 1;
% Set up domain (Cartesian)
x = -a:0.1:a;
y = -a:0.1:a;
[X, Y] = meshgrid(x, y);
% Allocate output
U = zeros(size(X));
V = zeros(size(X));
% Loop over each point in domain
for ii = 1:length(x)
for jj = 1:length(y)
% Compute polar representation
r = norm([X(ii,jj), Y(ii,jj)]);
phi = atan2(Y(ii,jj), X(ii,jj));
% Compute polar unit vectors
rhat = [cos(phi); sin(phi)];
phihat = [-sin(phi); cos(phi)];
% Compute output (in polar co-ordinates)
u_R = -1/2*((besselj(n-1, x_np*r/a)-besselj(n+1, x_np*r/a))/a)*cos(n*phi);
u_PHI = n*(besselj(n, x_np*r/a)/(x_np*r))*sin(phi);
% Transform output to Cartesian co-ordinates
U(ii,jj) = u_R*rhat(1) + u_PHI*phihat(1);
V(ii,jj) = u_R*rhat(2) + u_PHI*phihat(2);
end
end
% Generate quiver plot
quiver(X, Y, U, V);

How calculate the distance of all point inside a square?

I Have an issue to create some geometries inside a phantom with Filed II framework. I did create a circle, but now I have problem to create a square inside the phantom.
It is the following code to produce it in Matlab. The line of code that produce inside, is my issue. For the circle, I did calculate the distance of two points inside the circle and when it is less than the radius of the circle, they are inside the circle. But I have problem for triangle or square.
Phantom.x_size = 50/1000; % Width of phantom [mm]
Phantom.y_size = 10/1000; % Transverse width of phantom [mm]
Phantom.z_size = 60/1000; % Height of phantom [mm]
Phantom.z_start = 30/1000; % Start of phantom surface [mm];
N = Calculate_number_of_scatterers(Phantom);
N = 1000*ceil(N/1000);
% Create the general scatterers
x = (rand (N,1)-0.5)*Phantom.x_size;
y = (rand (N,1)-0.5)*Phantom.y_size;
z = rand (N,1)*Phantom.z_size + Phantom.z_start;
% Generate the amplitudes with a Gaussian distribution
amplitudes = randn(N,1);
%Make the cyst
r = 8/2/1000; %radius of cyst[mm]
xc = 10/1000; %place of the cyst
zc = 40/1000 + Phantom.z_start;
% [in,out] = inpolygon(xc,zc,x,z);
inside = ( ((x-xc).^2 + (z-zc).^2) < r^2); % scatteres inside the cyst
amplitudes = amplitudes .* (1-inside); % amplitude of the scatteres inside the cyst
Phantom.positions = [x y z];
Phantom.amplitudes = amplitudes;
figure;
plot3(Phantom.positions(:,1), Phantom.positions(:,3),Phantom.amplitudes,'.')

Draw circle on surface map Matlab

I have a surface map created from Northing (X), Easting (y), and Elevation (z) data. I would like to draw a circle around a specific point of a specific radius (say 400 m). The circle has to show up on the surface map. Below is my code for creating the surface map. Any help would be greatly appreciated.
% load the map data
x = elevgrid(:,4); % northing
y = elevgrid(:,5); % easting
z = elevgrid(:,3); % elevation
% Put data onto a grid
[qx,qy] = meshgrid(linspace(min(x),max(x)),linspace(min(y),max(y)));
F = TriScatteredInterp(x,y,z);
qz = F(qx,qy);
% plot in matrix form
surf(qx,qy,qz)
EDIT
Here is a link to a text file of sample data - format being longtitude, latitiude, elevation.
You should be able to do this with plot3 quite easily. See code below for a modified version of your posted code.
I'm not sure about how your sample data is represented (to avoid problems in the future, please try to brew your question down to just the bare essentials, with inputs included).
clear;clc
% create data
xy = -2.5 + 5*gallery('uniformdata',[200 2],0);
x = xy(:,1);
y = xy(:,2);
z = x.*exp(-x.^2-y.^2);
% Put data onto a grid
[qx,qy] = meshgrid(linspace(min(x),max(x)),linspace(min(y),max(y)));
F = scatteredInterpolant(x,y,z);
qz = F(qx,qy);
% plot in matrix form
mesh(qx,qy,qz)
% Plot circle
hold on
r = 0.6;
xp = 0.4;
yp = -1.2;
t = linspace(0,2*pi);
Xp = r*sin(t)+xp;
Yp = r*cos(t)+yp;
plot3(Xp,Yp,F(Xp,Yp))
hold off
BR Magnus