Finite element analysis, 1D - pde

I want the output to be values of C, at all range of i and t in the loops.
When I run it, I get error in sym/subref, L_tilde, idx.
I do not know what it means.
syms C;
alphaX=0.05;
DiffCoef = 5*10^-5
v = 0.1;
L = 10; xZones = 100;
dx = L/xZones;
T = 150;
u = 0.1;
dt= 0.005;
t = 150;
D = DiffCoef + (alphaX * u);
for i = 1:xZones
for t = 1:xZones
(C(i,t+dt) - C(i,t))/dt = -u(C(i+1,t +dt) - C(i,t+dt))/dx + D(C(i+1,t+dt) - 2*(C(i,t+dt) + C(i-1,t+dt)))/(dx)^2
end
end

Assuming this is Matlab code, there are some problems:
1) you cannot assign two outputs so the statement
(C(i,t+dt) - C(i,t))/dt = ...
is illegal. Matlab expressions can only return one output (without using for example "deal"), so in your case you would have to rearrange your expression as maybe
C(i,t+dt) = ...
C(i,t) = ...
Moreover, as this seems it is a time difference formula typically anything f(t+dt) is the unknown (left hand side), and f(t) are the known values as previous time step (right hand side) so that
f(t+dt) = dt*old_rhs - f(t)
In your case you have prescribed _C(i,t_dt)_ which seems very unusual, so please check your equations.

Related

Matlab Array Division

I have been playing with matlab and was trying to calculate absolute relative error using two arrays. However, when I divide the two arrays, my resulting array has the same value throughout the array even though when I calculate the values by hand, they are not all the same. I was wondering why my resulting array shows the same answer for every value in the array.
Here is my code:
function [X] = absrelerror(A, B)
% Calculates absolute relative error for true value A and approximate value B.
A = linspace(sin(-pi/6), sin(pi/6), 50); %True
B = linspace(-pi/6, pi/6, 50); %Approximate
Y = abs((A-B) ./ A); %ARE equation
X = Y * 100; %convert to percent
end
I think you have approached the problem in a wrong way.
Here, the first elements of both A and B are constant. Also, the spacing between two elements of any of the vectors is also constant. Say, they are c and d where c = {A(50) - A(1)}/49 and d = {B(50) - B(1)}/49. Now, the nth value of Y is {A(1)*nc - B(1)*nd}/{A(1)*c} = {A(1)*c - B(1)*c}/A(1) which is constant. So, it's not surprising that MATLAB is giving a constant value in Y.
If I have understood correctly what you are trying to do, then you should do it in the following way:
%A = linspace(sin(-pi/6), sin(pi/6), 50); %True
B = linspace(-pi/6, pi/6, 50); %Approximate
%Y = abs((A-B) ./ A); %ARE equation
%X = Y * 100; %convert to percent
A = sin(B);
X = abs((A-B)./A) * 100;
fprintf('%f ', X)
The output is:
4.719755 4.330958 3.960262 3.607413 3.272170 2.954306 2.653606 2.369868 2.102903 1.852533 1.618593 1.400927 1.199394 1.013862 0.844209 0.690325 0.552111 0.429477 0.322344 0.230643 0.154315 0.093311 0.047592 0.017130 0.001903 0.001903 0.017130 0.047592 0.093311 0.154315 0.230643 0.322344 0.429477 0.552111 0.690325 0.844209 1.013862 1.199394 1.400927 1.618593 1.852533 2.102903 2.369868 2.653606 2.954306 3.272170 3.607413 3.960262 4.330958 4.719755

Removing array components that are outside given limit

In matlab I have calculated an array representing a stress field of an elliptic cross-section. That I have done by
% Input
a = 4; b = 2; M = 5;
K = pi*a^3*b^3/(a^2+b^2);
% Stress function
y = linspace(-a,a);
z = linspace(-b,b);
[Y,Z] = meshgrid(y,z);
X = 2*M/K*(a^4*Z.^2+b^4*Y.^2)^(1/2)/(a^2+b^2);
At the same time I have an ellipsis defined as
t = -pi:0.01:pi;
YEllipsis = a*cos(t);
ZEllipsis = b*sin(t);
I need to remove all components of the array X that lies outside the border of the ellipsis defined above. My aim is to plot the contour of the ellipsis by lines, and plot the stress field (X) with contour lines in the same plot.
Any suggestions on how to do that?
Learn about logical indexing. Here's an article that should get you going.
And here's the code to set all the values of X to zero that lie outside the ellipse. (I assume that's what you mean by "remove all components of the array X that lie outside the border", that is the typical way this is done.)
X(y.^2/a^2 + z.^2/b^2 < 1) = 0;
Or, if you really just want that array, you can do it this way:
XNew = X(y.^2/a^2 + z.^2/b^2 < 1);

How to recursively fill an array with functions?

So I'm trying to write a function to generate Hermite polynomials and it's doing something super crazy ... Why does it generate different elements for h when I start with a different n? So inputting Hpoly(2,1) gives
h = [ 1, 2*y, 4*y^2 - 2]
while for Hpoly(3,1) ,
h = [ 1, 2*y, 4*y^2 - 4, 2*y*(4*y^2 - 4) - 8*y]
( (4y^2 - 2) vs (4y^2 - 4) as a third element here )
also, I can't figure out how to actually evaluate the expression. I tried out = subs(h(np1),y,x) but that did nothing.
code:
function out = Hpoly(n, x)
clc;
syms y
np1 = n + 1;
h = [1, 2*y];
f(np1)
function f(np1)
if numel(h) < np1
f(np1 - 1)
h(np1) = 2*y*h(np1-1) - 2*(n-1)*h(np1-2);
end
end
h
y = x;
out = h(np1);
end
-------------------------- EDIT ----------------------------
So I got around that by using a while loop instead. I wonder why the other way didn't work ... (and still can't figure out how to evaluate the expression other than just plug in x from the very beginning ... I suppose that's not that important, but would still be nice to know...)
Sadly, my code isn't as fast as hermiteH :( I wonder why.
function out = Hpoly(n, x)
h = [1, 2*x];
np1 = n + 1;
while np1 > length(h)
h(end+1) = 2*x*h(end) - 2*(length(h)-1)*h(end-1);
end
out = h(end)
end
Why is your code slower? Recursion is not necessarily of Matlab's fortes so you may have improved it by using a recurrence relation. However, hermiteH is written in C and your loop won't be as fast as it could be because you're using a while instead of for and needlessly reallocating memory instead of preallocating it. hermiteH may even use a lookup table for the first coefficients or it might benefit from vectorization using the explicit expression. I might rewrite your function like this:
function h = Hpoly(n,x)
% n - Increasing sequence of integers starting at zero
% x - Point at which to evaluate polynomial, numeric or symbolic value
mx = max(n);
h = cast(zeros(1,mx),class(x)); % Use zeros(1,mx,'like',x) in newer versions of Matlab
h(1) = 1;
if mx > 0
h(2) = 2*x;
end
for i = 2:length(n)-1
h(i+1) = 2*x*h(i)-2*(i-1)*h(i-1);
end
You can then call it with
syms x;
deg = 3;
h = Hpoly(0:deg,x)
which returns [ 1, 2*x, 4*x^2 - 2, 2*x*(4*x^2 - 2) - 8*x] (use expand on the output if you want). Unfortunately, this won't be much faster if x is symbolic.
If you're only interested in numeric results of the the polynomial evaluated at particular values, then it's best to avoid symbolic math altogether. The function above valued for double precision x will be three to four orders of magnitude faster than for symbolic x. For example:
x = pi;
deg = 3;
h = Hpoly(0:deg,x)
yields
h =
1.0e+02 *
0.010000000000000 0.062831853071796 0.374784176043574 2.103511015993210
Note:
The hermiteH function is R2015a+, but assuming that you still have access to the Symbolic Math toolbox and the Matlab version is R2012b+, you can also try calling MuPAD's orthpoly::hermite. hermiteH used this function under the hood. See here for details on how to call MuPAD functions from Matlab. This function is a bit simpler in that it only returns a single term. Using a for loop:
syms x;
deg = 2;
h = sym(zeros(1,deg+1));
for i = 1:deg+1
h(i) = feval(symengine,'orthpoly::hermite',i-1,x);
end
Alternatively, you can use map to vectorize the above:
deg = 2;
h = feval(symengine,'map',0:deg,'n->orthpoly::hermite(n,x)');
Both return [ 1, 2*x, 4*x^2 - 2].

C program to calculate mathematical correlation function/autocorrelation function

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main ()
{
double g_1, e_1, e_2, e_3, e_4, e_5;
int k;
// double e[k];
e_1 = 3.0;
e_2 = 9.0;
e_3 = 27.0;
e_4 = 81.0;
e_5 = 243.0;
g_1 = ((e_1*e_2 + e_2*e_3 + e_3*e_4 + e_4*e_5)/5) - (((e_1)* + (e_2) + (e_3) +(e_4) + (e_5)/5)*((e_1)* + (e_2) + (e_3) +(e_4) + (e_5)/5));
printf("\n\n this is g(1): %f",g_1);
return (0);
}
I am trying to write a program that calculates the correlation between values. The mathematical function I have is the autocorrelation function or mathematical correlation function which is
g(T) = sum(from t = 1 to m-T) [ (e_t)*(e_(T+t)] - (sum(from t = 1 to m) [e_t/m] )^2
where m is the number of values I have.
Above I have tried to do the simplest version by taking 5 numbers and just plugging them into the formula. But eventually I need to be able to read a file containing any number of values from 100 to 5000 and find the correlation between them. I will worry about reading the file to the entries of an array later but first I would like to know is there a logical way of doing this using arrays?
For example I tried to do the following:
e[1] = 3.0;
e[2] = 9.0;
e[3] = 27.0;
e[4] = 81.0;
e[5] = 243.0;
for(k=1;k<=5;k++)
{
g[k]= ((e[k]*e[k+1] + e[k+1]*e[k+2] + e[k+2]*e[k+3] + e[k+3]*e[k+4])/5) - (((e[k] + e[k+1] + e[k+2] + e[k+3] + e[k+4])/5)*((e[k] + e[k+1] + e[k+2] + e[k+3] + e[k+4])/5))
}
But this would only make sense for k=1, because by the time it gets to k = 5, then k+1 will be 6, k+2 will be 7.. and I don't have these values.. But I'm not sure how exactly to program this.. Can anybody help?
Thank you
This is the formula using MathJax
g(\tau) = \sum_{\tau_{0}=1}^{m-\tau} ((\epsilon_{\tau{_0}} * \epsilon_{\tau+\tau_{0}})/m) - (\sum_{\tau_{0}=1}^m \epsilon_{\tau_{0}}/m)^2
an alternative form of the formula is:
g(\tau) = <\epsilon_{\tau_{0}}\epsilon_{\tau_{0}+\tau}>-<\epsilon_{\tau_{0}}>^2
where means expectation of a.
This is more of a how to read a math expression problem. It seems like in your example, m = 5, so the sums never reference beyond that.
I'm not entirely clear on your equation. Have tried Mathjax, but the formula is still not clear to me, but...
When translating a math expression to code, think of the summation sign (sigma) as equivalent to a for loop!
when writing the code, write (initially) in the most explicit way possible. For this problem code TWO for loops, one after the other, NOT nested. Each for loop does part of the calculation for g(k).
Get this to work for g(1). Then code a third for loop that wraps or surrounds the two loops you just got working. This loop will calculate g(1), g(2), etc. Note. if m is 5 and you only have 5 data points then you can only compute g(1), if m is 6 you can compute g(1) and g(2), etc.
Hope this helps, please post if you more information or questions.
To answer your comment, the following for loop implements a sum or sigma. Note. This is NOT exactly what your code should do, but it does demo using two for loops.
int g1; x = 0; y = 0;
int i;
// compute x = sum(g(i)) + sum(f(i))
// sum i = 0 to 2 [g(i)]
for (i=0; i < 3; i++) {x += g[i];}
// sum i = 0 to 1 [f(i)];
for (i=0; i < 2; i++) {y += f[i];}
g1 = x - y^2;
The C code you are looking for would be in this form:
int tau = 7
int m = 80;
double *e; /* An array filled with m values */
double lhs,rhs,answer;
int tau0;
/* Left Summation */
for(sum=0,tau0=1; tau0 < m-tau; ++tau0)
sum += e[tau0] * e[tau+tau0];
lhs = sum / m;
/* Right Summation */
for(sum=0,tau0=1; tau0 < m; ++tau0)
sum += e[tau0] / m;
rhs = sum * sum;
answer = lhs - rhs;
Hopefully this get you closer to your solution.

How to create an array in Matlab but run a function at the same time?

I'm trying to populate an array with values from a function that I am running. In this function I am changing a variable z2 in increments of 0.01 from 0 to 0.99. At the same time I want to populate an array with those values. I've tried a while loop and a for loop. How to write this with only a for loop?
my code:
Ys = y(2000);
Mp = ((max(y)-Ys)/Ys)*100;
[max, i] = max(y);
tp = t(i);
z = sqrt(((log(Mp))^2)/((pi*pi)+(log(Mp))^2));
%Given Equations
wd = pi/tp;
wn = wd/(sqrt(1-(z*z)));
ts = 4.6/(z*wn);
tr = 1.8/wn;
%for loop for z from 0 to 0.99
for i = 1:100;
for z2 = 0:0.01:0.99
%tr*wn = Fa
Fa(i) = 2.917*z2^2 - 0.4167*z2 + 1;
i = i + 1;
if i >= 100;
break;
end
end
end
find_zeta = interp1(Fa, 1.8);
disp(Fa);
disp(find_zeta);
error I am experiencing: I am getting only 1s in my array.
You can do it without a loop, in a 'vectorized' matlab statement
z2 = 0:0.01:0.99;
Fa = 2.917*z2.^2 - 0.4167.*z2 + 1;
First, compute z2 values that you need. Next, operating on the vector element by element (note .^ syntax) compute Fa. There is a fundamental difference between ^ and .^ operators, and you really want to know the difference. In general, you can add a . to an operator, which means that it will work on individual scalar elements of your array. Read about matrix and array operators here. For example:
A = rand(10);
B = rand(10);
% matrix multiplication
C=A*B;
% element by element multiplication
C=A.*B
The complaint you got only means that what you do is inefficient. Since matlab does not know the size of Fa beforehand, it needs to reallocate the array every time you append to it. You can still use it, it is just inefficient.
Index's in matlab start from 1, not from 0 as they do in other programming languages
The error you are getting is about pre-allocating the array. Add Fa = zeros(1,100); to the start of the script and it will go away.
Fa = zeros(1,100);
i = 1;
for z2 = 0:0.01:0.99
Fa(i) = 2.917*z2^2 - 0.4167*z2 + 1;
i = i +1;
end
The use of 'vectorized' as suggested in another answer is more the way to go though.

Resources