Axially loaded stepped shaft analysis in MATLAB - 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

Related

Directional artifacts in MATLAB randn arrays?

I'm generating 3d fractal noise in MATLAB using a variety of methods. It's working relatively well, but I'm having an issue where I see vertical striping artifacts in my noise. This happens regardless of what data type or resolution I use.
Edit: I figured it out. The solution is posted as an answer below. Thanks everyone for your thoughts and guidance!
expo = 2^6;
dims = [expo,expo,expo];
beta = -4.5;
render = randnd(beta, dims); % Create volumetric fractal
render = render - min(render); % Set floor to zero
render = render ./ max(render); % Set ceiling to one
%render = imbinarize(render); % BW Threshold option
render = render .* 255; % For greyscale
slicer = 1; % Turn on image slicer/saver
i = 0; % Page counter
format = '.png';
imagename = '___testDump/slice';
imshow(render(:,:,1),[0 255]); %Single test image
if slicer == 1
for c = 1:length(render)
i = i+1;
pagenumber = num2str(i);
filename = [imagename, pagenumber, format];
imwrite(uint8(render(:,:,i)),filename)
end
end
function X = randnd(beta,varargin)
seed = 999;
rng(seed); % Set seed
%% X = randnd(beta,varargin)
% Based on similar functions by Jon Yearsley and Hristo Zhivomirov
% Written by Marcin Konowalczyk
% Timmel Group # Oxford University
%% Parse the input
narginchk(0,Inf); nargoutchk(0,1);
if nargin < 2 || isempty(beta); beta = 0; end % Default to white noise
assert(isnumeric(beta) && isequal(size(beta),[1 1]),'''beta'' must be a number');
assert(-6 <= beta && beta <= 6,'''beta'' out of range'); % Put on reasonable bounds
%% Generate N-dimensional white noise with 'randn'
X = randn(varargin{:});
if isempty(X); return; end; % Usually happens when size vector contains zeros
% Squeeze prevents an error if X has more than one leading singleton dimension
% This is a slight deviation from the pure functionality of 'randn'
X = squeeze(X);
% Return if white noise is requested
if beta == 0; return; end;
%% Generate corresponding N-dimensional matrix of multipliers
N = size(X);
% Create matrix of multipliers (M) of X in the frequency domain
M = [];
for j = 1:length(N)
n = N(j);
if (rem(n,2)~=0) % if n is odd
% Nyquist frequency bin does not show up in odd-numbered fft
k = ifftshift(-(n-1)/2:(n-1)/2);
else
k = ifftshift(-n/2:n/2-1);
end
% Spectral multipliers
m = (k.^2)';
if isempty(M);
M = m;
else
% Create the permutation vector
M_perm = circshift(1:length(size(M))+1,[0 1]);
% Permute a singleton dimension to the beginning of M
M = permute(M,M_perm);
% Add m along the first dimension of M
M = bsxfun(#plus,M,m);
end
end
% Reverse M to match X (since new dimensions were being added form the left)
M = permute(M,length(size(M)):-1:1);
assert(isequal(size(M),size(X)),'Bad programming error'); % This should never occur
% Shape the amplitude multipliers by beta/4 which corresponds to shaping the power by beta
M = M.^(beta/4);
% Set the DC component to zero
M(1,1) = 0;
%% Multiply X by M in frequency domain
Xstd = std(X(:));
Xmean = mean(X(:));
X = real(ifftn(fftn(X).*M));
% Force zero mean unity standard deviation
X = X - mean(X(:));
X = X./std(X(:));
% Restore the standard deviation and mean from before the spectral shaping.
% This ensures the random sample from randn is truly random. After all, if
% the mean was always exactly zero it would not be all that random.
X = X + Xmean;
X = X.*Xstd;
end
Here is my solution:
My "min/max" code (lines 6 and 7) was bad. I wanted to divide all values in the matrix by the single largest value in the matrix so that all values would be between 0 and 1. Because I used max() improperly, I was stepping through the max value of each column and using that as my divisor; thus the vertical stripes.
In the end this is what my code looks like. X is the 3 dimensional matrix:
minVal = min(X,[],'all'); % Get the lowest value in the entire matrix
X = X - minVal; % Set min value to zero
maxVal = max(X,[],'all'); % Get the highest value in the entire matrix
X = X ./ maxVal; % Set max value to one

Buffon's needle in MATLAB

I am currently working on a project for my Chemical Engineering class called Buffon's needle. The purpose of this project is to use MATLAB to get an estimate for pi and then to make a "cartoon" which will show the needles on a 10x10 graph with lines every 1 unit apart, with needles crossing the line being one color, and needles not crossing being another. I have found the pi estimate and i have created the graph, but my lines are not the one unit in length like they should be, instead the needles are all different lengths. if anyone could help me with this problem it would be much appreciated. my two scripts are below
clear all;
close all;
clc;
format compact
% Script to illustrate the estimation of pi value by using Buffon's needle
% experiment
% set number of separate experiments
nExperiments = 1000;
% set number of separate trials
nTrials = 3;
% total number of dropped needles is directly based on number of trials and
% number of experiments
ndropped=nTrials.*nExperiments;
% spacing between the parallel lines
spacing = 1;
% length of the needle
L = spacing;
% the lower bound of x coordinate.
a = 10;
totalhits = 0;
for i = 1:nTrials
% keeps track of the number of hits
hits = 0;
% keeps track of the number of times the needle doesn't hit the
% any of the lines
nothits = 0;
for j = 1:nExperiments
[outcome,endpoints,angle] = needle_drop(spacing,L);
if outcome
hits = hits + 1;
endpointsHitList(:,:,hits) = endpoints;
else
nothits = nothits + 1;
endpointsNotHitList(:,:,nothits) = endpoints;
end
angleList(j) = angle;
end
scatter(1:nExperiments,angleList);
xlabel('Experiments');
ylabel('Angles');
piestimate(i) = (2*L/spacing)/(hits/nExperiments);
end
fprintf('The average value of pi is %f plus or minus %f after %d trials of %d experiments with %d total number of dropped needle.\n',mean(piestimate),std(piestimate),nTrials,nExperiments,ndropped);
figure
hold on
% plot the vertical separations
for i = 0:spacing:a
p1 = plot([i,i],[0 11],'k','LineWidth',2);
end
% plot the needles that hit the vertical separation
for i = 1:hits
p2 = plot(endpointsHitList(:,1,i),endpointsHitList(1,:,i),['-','b']);
end
% plot the needles that don't hit the vertical separation
for i = 1:nothits
p3 = plot(endpointsNotHitList(:,1,i),endpointsNotHitList(1,:,i),['-','r']);
end
axis([-2,12 -2 12]);
legend([p1 p2 p3],'Vertical Separations','Hits','Not Hits')
title('Buffon Needle Experiment');
xlabel('x-axis');
ylabel('y-axis');
figure
histogram(piestimate)
title('Histogram of pi estimate');
This below is my function needle_drop:
function [outcome,endpoints,theta] = needle_drop(spacing,L)
% spacing = spacing between the parallel lines spacing
% L = length of the needle
% spacing = 1;
% % In the special case where the length of the needle is equal to the grid spacing
% % between the parallel lines
% L = spacing;
% a is the lower bound of x coordinate. b is the upper bound.
% the needle position will be randomly between 0 and 10.
a = 0;
b = 10;
% generate random number r1 in [0,1]
r1 = rand;
% sample a value of the angle uniformly distributed over the interval
% from zero to ninety degrees
theta = (pi/2)*r1;
% the projection of half the length of the needle horizontally: S
S = (L/2)*cos(theta);
% Another random number r2 is generated
% this corresponds to x,y coordinate
r2 = a + (b-a).*rand(1,2);
% we need to take care of the offset.
% if the x coordinate is between 0 and d then offset is 0 if xcord is
% between d and 2d then offset is d and likewise for other values.
offset = floor(r2(1));
% The sampled position T of the center of the needle is next compared to the
% sampled projection of half the length of the needle
if r2(1)-S <=0+offset || r2(1)+S >=spacing+offset
outcome = 1;
else
outcome = 0;
end
% the projection of half the length of the needle vertically: V
V = L/2*sin(theta);
endpoints = [r2(1)-S,r2(2)+V;r2(1)+S,r2(2)-V];
You made an indexing mistake. Your function returns endpoints:
endpoints = [ r2(1)-S, r2(2)+V; ...
r2(1)+S, r2(2)-V ];
Simplified,
endpoints = [ start_x, start_y; ...
end_x, end_y ];
These are collected in a 3D matrix, which you then plot:
p2 = plot( endpointsHitList(:,1,i), endpointsHitList(1,:,i), ['-','b'] );
% ^ x-coordinates ^ y-coordinates
Thus, here you are plotting a line with x-coordinates [start_x,end_x], and y-coordinates [start_x,start_y]! This latter should have been [start_y,end_y].
This should have been:
p2 = plot( endpointsHitList(:,1,i), endpointsHitList(:,2,i), ['-','b'] );
% ^^^ get second column
The same mistake happens when plotting endpointsNotHitList.

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));

Multiplying a vector times the inverse of a matrix in Matlab

I have a problem multiplying a vector times the inverse of a matrix in Matlab. The code I am using is the following:
% Final Time
T = 0.1;
% Number of grid cells
N=20;
%N=40;
L=20;
% Delta x
dx=1/N
% define cell centers
%x = 0+dx*0.5:dx:1-0.5*dx;
x = linspace(-L/2, L/2, N)';
%define number of time steps
NTime = 100; %NB! Stability conditions-dersom NTime var 50 ville en fått helt feil svar pga lambda>0,5
%NTime = 30;
%NTime = 10;
%NTime = 20;
%NTime = 4*21;
%NTime = 4*19;
% Time step dt
dt = T/NTime
% Define a vector that is useful for handling teh different cells
J = 1:N; % number the cells of the domain
J1 = 2:N-1; % the interior cells
J2 = 1:N-1; % numbering of the cell interfaces
%define vector for initial data
u0 = zeros(1,N);
L = x<0.5;
u0(L) = 0;
u0(~L) = 1;
plot(x,u0,'-r')
grid on
hold on
% define vector for solution
u = zeros(1,N);
u_old = zeros(1,N);
% useful quantity for the discrete scheme
r = dt/dx^2
mu = dt/dx;
% calculate the numerical solution u by going through a loop of NTime number
% of time steps
A=zeros(N,N);
alpha(1)=A(1,1);
d(1)=alpha(1);
b(1)=0;
c(1)=b(1);
gamma(1,2)=A(1,2);
% initial state
u_old = u0;
pause
for j = 2:NTime
A(j,j)=1+2*r;
A(j,j-1)=-(1/dx^2);
A(j,j+1)=-(1/dx^2);
u=u_old./A;
% plotting
plot(x,u,'-')
xlabel('X')
ylabel('P(X)')
hold on
grid on
% update "u_old" before you move forward to the next time level
u_old = u;
pause
end
hold off
The error message I get is:
Matrix dimensions must agree.
Error in Implicit_new (line 72)
u=u_old./A;
My question is therefore how it is possible to perform u=u_old*[A^(-1)] in Matlab?
David
As knedlsepp said, v./A is the elementwise division, which is not what you wanted. You can use either
v/A provided that v is a row vector and its length is equal to the number of columns in A. The result is a row vector.
A\v provided that v is a column vector and its length is equal to the number of rows in A
The results differ only in shape: v/A is the transpose of A'\v'

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

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.