problem in the for - loop
Show older comments
Here is the problem
Ive got a FEM code
function main1
clc
n = 100;
x0 = ones(3*n,1);
sol = fsolve(@(x)fun(x,n),x0);
norm(fun(sol,n))
x = ((1:n)-1)/(n-1);
plot(x,sol(1:n))
end
function res = fun(z,n)
eta=1.0;
beta = 1.0;
x = ((1:n)-1)/(n-1);
dx = 1/(n-1);
y1 = z(1:n);
y2 = z(n+1:2*n);
y3 = z(2*n+1:3*n);
for i=1:length(y1)
Y1=y1(i);
end
for i=1:length(y2)
Y2=y2(i);
end
res_y1 = zeros(n,1);
res_y2 = zeros(n,1);
res_y3 = zeros(n,1);
res_y1(1) = y1(1)-10.0;
for i=2:n-1
res_y1(i) = (y1(i+1)-2*y1(i)+y1(i-1))/dx^2 + (y1(i+1)-y1(i-1))/(2*dx) + exp(-5/Y2);
end
res_y1(n) = y1(n);
res_y2(1) = y2(1);
for i = 2:n-1
res_y2(i) = (y2(i+1)-2*y2(i)+y2(i-1))/dx^2 - y1(i).^2;
end
res_y2(n) = y2(n)-eta;
res_y3(1) = y3(1);
for i=2:n-1
res_y3(i) = (y3(i+1)-2*y3(i)+y3(i-1))/dx^2 - Y2;
end
res_y3(n) = y3(n)-1.0;
res = [res_y1;res_y2;res_y3];
end
It seems that using
res_y1(i) = (y1(i+1)-2*y1(i)+y1(i-1))/dx^2 + (y1(i+1)-y1(i-1))/(2*dx) + exp(-5/Y2);
and
res_y1(i) = (y1(i+1)-2*y1(i)+y1(i-1))/dx^2 + (y1(i+1)-y1(i-1))/(2*dx) + exp(-5/y2(i));
must be eqiuvalent, but NO. The results differ
Accepted Answer
More Answers (1)
Cris LaPierre
on 20 Jan 2021
Why would you expect them to be the same?
When you get around to calculation res_y1(i), Y2 has the value of y2(length(y1)). If you substitute that in, you'll see the last part fo the equation is very different
exp(-5/y2(length(y1)));
%vs
exp(-5/y2(i));
The first uses the same value of Y2 for every loop, while the second uses a different element of y2 for each loop.
26 Comments
Cris LaPierre
on 20 Jan 2021
The underlying problem appears to still be the same. In one case, Y2 is always the same value for every loop while in the other, y2(i) will be a different value in every loop.
Gleb
on 21 Jan 2021
Cris LaPierre
on 21 Jan 2021
You can absolutely use a function inside a for loop. You can't define an in-file function in the loop, but that's a different issue.
I guess it's all in how you define your anonymous function. If you define your anonymous function in a variable, you can use it as a function elsewhere in your code.
% define an anonymous function
sqr = @(x) x.^2;
% use the anonymous function
a = sqr(5)
Gleb
on 25 Jan 2021
Cris LaPierre
on 25 Jan 2021
No, I don't think I would code it like this. Of course, you have left out a lot of the details, so it's hard to say for certain. Generally, I wouldn't define the anonymous function inside a for loop.
Also, you are not following the syntax shared in the example. You should indicate a variable used in the equation right after the @, then use that variable in the function. When you call the function, that is when you use your actual indexed variable.
So based on your example, I think it would look like this (untested).
res_Y1(1) = Y1(1)-Y0;
A=@(myY1, myY2) (yY1+myY); % some expressions
B=@(myY1, myY2) (yY1.*myY);
Q=@(myY1, myY2) A(myY1, myY2)+B(myY1, myY2);
for i = 2:n-1
res_Y1(i) =(Y1(i+1)-2*Y1(i)+Y1(i-1))/dx^2-Q(Y1(i), Y2(i))
end
res_Y1(n) =( Y1(n)-Y1(n-1))/dx;
% loop 2
res_Y2(1) = Y2(1)-Y20;
for i = 2:n-1
res_Y2(i) =(Y2(i+1)-2*Y2(i)+Y2(i-1))/dx^2+Q(Y1(i), Y2(i))
end
...
Gleb
on 25 Jan 2021
Cris LaPierre
on 25 Jan 2021
The variable myY1 is a variable that only exists in the anonymous function. When you call A, that is when you pass in the actual value.
Also note that here you have only defined functions. Be sure to also use them to perform an actual calculation.
if Y1(i)<1000
% define your function
A=@(myY1, myY2) (myY1+myY2^2); % some expressions
% use your function
res(i) = A(Y1(i),Y2(i));
else
% define your function
A=@(myY1, myY2) (2*myY1+3*myY2^2)
% use your function
res(i) = A(Y1(i),Y2(i));
end
Gleb
on 25 Jan 2021
Cris LaPierre
on 25 Jan 2021
For that matter, Y1(i) is never defined in the code you shared. This is the problem with trying to simplify your example. If you want an answer that is guaranteed to work, you need to share your actual code.
Cris LaPierre
on 25 Jan 2021
Edited: Cris LaPierre
on 26 Jan 2021
I see a few things.
- First, your if statement uses T_g_(i), but i has not been defined.
- You are defining a new function, c_NO2. However, you try to use it as a variable.
- c_NO2 calls Pn5 with 5 inputs, but you defined it as having 6.
I suggest reviewing the link I shared about function basics. In particular, how to call a function. There are several anonymous functions created in the code that are not called properly.
- tau (no input provided in Pn5)
- Pn2 (has 3 inputs, but you call it with 2)
- Pn5 (has 6 inputs, but you call it with 5)
- Ar (has 3 inputs, but you call it with 2)
- ro_gf (has 3 inputs, but you often use it without any inputs
One more thing to figure out is what is T_g. You use it in your if statements conditional, but have never defined it. It is a variable used in some of your anonymous functions, but it only exists within the function's scope.
After fixing these issues, I think my approach to what you have in line 156 would use logical indexing instead. This allows me to compute a value for all values that meet the condition at once, rather than having to loop through each value.
c_NO2(T_g_<1200)=Pn5(16.108,75.89,-54.3874,14.30777,0.239423,T_g_(T_g_<1200))/M_NO2;
c_NO2(T_g_>=1200)=Pn5(56.82541,0.738053,-0.144721, 0.009777,-5.459911,T_g_(T_g_>=1200))/M_NO2;
Notice that c_NO2 is a variable that captures the result of the calculation performed by the function Pn5.
Gleb
on 25 Jan 2021
Cris LaPierre
on 26 Jan 2021
cc is a variable that got incorrectly set up as an anonymous function. I think it should be
cc=c_cTf.*Y_cTf+ c_B(T_g_).*Y_B;
but you need to confirm that.
Gleb
on 26 Jan 2021
Cris LaPierre
on 26 Jan 2021
Edited: Cris LaPierre
on 26 Jan 2021
Not when I run it.
Check the dimensions of your variables to identify the differences. Then go back to where each of these variables were created to find any errors.
Gleb
on 26 Jan 2021
Cris LaPierre
on 26 Jan 2021
Maybe a new error, but same issue. I think c_gf should not be an anonymous function. I think you are actually trying to create a vector of values.
Cris LaPierre
on 26 Jan 2021
Edited: Cris LaPierre
on 26 Jan 2021
Perhaps a better way to approach this is start with the first anonymous functions your create (lines 135-148).
dHm=cfm;
tau =@(T_g)(T_g/1000);
%_
Pn2=@(k0,k1, T_g)(k0+k1*tau(T_g));
Pn5=@(k0,k1,k2,k3,k4,T_g)(k0+k1*tau(T_g)+k2*tau(T_g).^2+k3*tau(T_g).^3+k4./tau(T_g).^2);
Ar=@(k,E, T_g)(k*exp(-E./(R*T_g)));
M_HMXprod=M_NO2*Y_NO2_f+M_NO*Y_NO_f+M_N2O*Y_N2O_f+M_H2O*Y_H2O_f+M_CO*Y_CO_f+M_CH2O*Y_CH2O_f;
Mg=@(T_g, Y_HMXprod, Y_gHMX)(M_HMXprod*Y_HMXprod+M_HMX*Y_gHMX+M_Tf*Y_gTf + M_BF3*Y_BF3 + M_CF2*Y_CF2 +M_C*Y_C);
% плотности________________________________________________________________
rog=@(T_g, Y_HMXprod, Y_gHMX)(Mg(T_g, Y_HMXprod, Y_gHMX).*P./(R.*T_g));
roc = ro_cTf*Y_cTf + ro_B*Y_B ;
ro_gf=@(T_g, Y_HMXprod, Y_gHMX)((1-fg)*roc+fg*rog(T_g, Y_HMXprod, Y_gHMX));
We've already talked about tau, Pn2 and Pn5. They should remain anonymous functions. Take a hard look at the rest. Which do you think should be vectors of values instead of anonymous functions?
A good criteria to consider is if you ever create the inputs used when you call the function, or if you call the function multiple times with different input values.
Cris LaPierre
on 26 Jan 2021
Edited: Cris LaPierre
on 26 Jan 2021
Let's focus on the ones in the code I shared for now.
As for the for loops at the bottom, you don't need them. I would use indexing.
ind = 2:n-1;
res_T_g_(1) = T_g_(1)-T_fout;
res_T_g_(ind) = (Pe_gm./Pe_g(ind)).*(T_g_(ind+1)-2*T_g_(ind)+T_g_(ind-1))/dx^2 + 0*(1./Pe_dk(ind)).*(c_gf(ind)/cfm).*ro_gf(ind).*((T_g_(ind+1)-T_g_(ind-1))/(2*dx)).*Y_gHMX_(ind).*(Y_gHMX_(ind+1)-Y_gHMX_(ind-1))/(2*dx) - ...
(Pe_gm)^0.5 .* (c_gf(ind)/cfm).*(T_g_(ind+1)-T_g_(ind))/(2*dx) - Q_react_g(ind);
I couldn't help but notice that a large section of your calculation of res_T_g_ is multiplied by 0. Since this doesn't contribute anything to the calculation, you could simply the code by removing it.
res_T_g_(ind) = (Pe_gm./Pe_g(ind)).*(T_g_(ind+1)-2*T_g_(ind)+T_g_(ind-1))/dx^2 - ...
(Pe_gm)^0.5 .* (c_gf(ind)/cfm).*(T_g_(ind+1)-T_g_(ind))/(2*dx) - Q_react_g(ind);
Gleb
on 26 Jan 2021
Cris LaPierre
on 26 Jan 2021
Edited: Cris LaPierre
on 26 Jan 2021
I've shown you how to remove all the for loops, so I think you only need 4 anonymous functions in your code.
tau =@(T_g)(T_g/1000);
%_
Pn2=@(k0,k1, T_g)(k0+k1*tau(T_g));
Pn5=@(k0,k1,k2,k3,k4, T_g)(k0+k1*tau(T_g)+k2*tau(T_g).^2+k3*tau(T_g).^3+k4./tau(T_g).^2);
Ar=@(k,E)(k*exp(-E./(R*T_g_)));
See if you can rewrite your code to remove all other anonymous functions.
Cris LaPierre
on 26 Jan 2021
is there some advantage over traditional for loop?
Loops = slower code. In MATLAB, you can often avoid them by taking advantage of elementwise operators.
Well... There are 3 equations, and 3 loops, isnt it?
I've got to leave something for you to do. You can use the example I shared to see how to remove the loops from the remaining 2 equations.
Categories
Find more on Linear Least Squares in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!

