I'm running a while loop and I am running in to some problems.
I have the following piece of code:
Angle_int = 0.5; % Initial interpolation angle of attack
Clmax2d(1,1:length(Yle_wing)) = 3; % Dummy value
diff = 0; % Dummy value
while sum(diff < 0) > fix(tol*length(Yle_wing))
Angle_int = Angle_int + 0.5; % Interpolation angle increases with 0.5 with every iteration
for j = 1:length(Yle_wing)
CL3d = interp1(Angle,[cl_matrix(1,j) cl_matrix(2,j) cl_matrix(3,j)],Angle_int,'linear');
CL_3DD(:,j) = CL3d;
end
diff = (Clmax2d - CL_3DD); % Difference between Cl2d and Cl3d
Angle_stall = Angle_int;
CL_3D = CL_3DD;
end
For some reason, CL_3D = CL_3DD; and Angle_stall = Angle_int; seem to disappear when the while loop finishes. Hence, I cannot use their converged values ahead of the while loop since these variables are not recognized. I get the following error:
Undefined function or variable "CL_3D".
Hence, does someone knows what I am doing wrong? or any tips would be welcome as well.
Thanks in advance,
cheers
The error message:
Undefined function or variable "CL_3D".
is always because you're trying to use a variable or function that you haven't initialized yet. Often this happens in loops where you want to increment a counter, or compare values etc.
A common error is doing something like this without writing ii = 0 in front of the loop:
while ii < some_num
ii = ii + 1;
some_function();
end
With your dummy variables, you never enter the loop (unless tol < 0, which seems like an odd choice). You probably want to initialize diff = Inf or something like that. However, using diff as a variable name is not a good idea, since it's a builtin function.
You probably try to use CL_3D, when it's not yet initialized (somewhere else in your code, not in the part you posted). MATLAB tells you which line the error appears in, you should try using it!
Maybe initializing it like zeros(size(Clmax2d)); could work (it will definitely remove your error, but it might not give the desired behavior).
PS!
Using i and j as variables are not recommended as they represent the imaginary unit in MATLAB.
Related
I have a Matlab script including a for loop which loos like the following:
for k = 1:10
c = myfun(k,a,b);
result{k} = c;
end
Right now, the problem is that during the for loop, sometimes myfun() may have errors and stop. After fixing the error in myfun(), how can I continue to run with the existing value of variables? The reason is that myfun() will take a very long time to get the result and the previous results are right.
For example, if a error happens when k == 4, then I save all the variables in the current workspace. I set a breakpoint at c = myfun(k,a,b); and restore the saved variables, but I find that in the next loop, k will be 2 instead of 5 as I want. Matlab is not allowed to modify the value of k during the for loop I think. I have tested this for a few times.
How can I continue the for loop with some existing data?
You cannot change your for loop iterator programmatically inside of the loop.
For example:
for ii = 1:3
disp(ii)
ii = 3;
end
Prints:
1
2
3
If you're going to be modifying code based on errors received, dbstop if error is not going to be beneficial because it will not reflect changes in your code until the debugger is exited and your code executed again (unless you execute manually in the debugger). If you're not modifying code you could potentially use a try/except clause to catch fixable issues.
If you're loading data for a later index and then restarting, you can change where your for loop begins, or use a while loop (if appropriate).
For example:
% Load data here
for ii = 3:3
disp(ii)
end
Prints 3.
Where the while interpretation would be:
% Load data here
ii = 3
while ii <= 3
disp(ii)
ii = ii + 1;
end
For the same result.
On solution can be first catch the exception likes the following and pass from them:
bug = [];
for k = 1:10
try
c = myfun(k,a,b);
result{k} = c;
catch
warning('some bug for the following values:');
display([k a b]);
bug = [bug; k a b];
result{k} = NaN;
end
end
Then iterate over bug to compute missing information after debugging. This solution works when your algorithm is not dependent on the previous value of the result (or is not recursive).
total newbie here. I'm having problems looping a function that I've created. I'm having some problems copying the code over but I'll give a general idea of it:
function[X]=Test(A,B,C,D)
other parts of the code
.
.
.
X = linsolve(K,L)
end
where K,L are other matrices I derived from the 4 variables A,B,C,D
The problem is whenever I execute the function Test(1,2,3,4), I can only get one answer out. I'm trying to loop this process for one variable, keep the other 3 variables constant.
For example, I want to get answers for A = 1:10, while B = 2, C = 3, D = 4
I've tried the following method and they did not work:
Function[X] = Test(A,B,C,D)
for A = 1:10
other parts of the code...
X=linsolve(K,L)
end
Whenever I keyed in the command Test(1,2,3,4), it only gave me the output of Test(10,2,3,4)
Then I read somewhere that you have to call the function from somewhere else, so I edited the Test function to be Function[X] = Test(B,C,D) and left A out where it can be assigned in another script eg:
global A
for A = 1:10
Test(A,2,3,4)
end
But this gives an error as well, as Test function requires A to be defined. As such I'm a little lost and can't seem to find any information on how can this be done. Would appreciate all the help I can get.
Cheers guys
I think this is what you're looking for:
A=1:10; B=2; C=3; D=4;
%Do pre-allocation for X according to the dimensions of your output
for iter = 1:length(A)
X(:,:,iter)= Test(A(iter),B,C,D);
end
X
where
function [X]=Test(A,B,C,D)
%other parts of the code
X = linsolve(K,L)
end
Try this:
function X = Test(A,B,C,D)
% allocate output (it is faster than changing the size in every loop)
X = {};
% loop for each position in A
for i = 1:numel(A);
%in the other parts you have to use A(i) instead of just A
... other parts of code
%overwrite the value in X at position i
X{i} = linsolve(K,L);
end
end
and run it with Test(1:10,2,3,4)
To answer what went wrong before:
When you loop with 'for A=1:10' you overwrite the A that was passed to the function (so the function will ignore the A that you passed it) and in each loop you overwrite the X calculated in the previous loop (that is why you can only see the answer for A=10).
The second try should work if you have created a file named Test.m with the function X = (A,B,C,D) as the first code in the file. Although the global assignment is unnecessary. In fact I would strongly recommend you not to use global variables as it gets very messy very fast.
I have piece of code with a while loop. This loop will diverge in certain conditions and thus will yield a infinite loop.
I want to check whether the loop is diverging and break the loop in an elegant and efficient procedure.
A solution to this is to check every output of the loop, save it, and compare it to the previously calculated loop output.
This is the code:
ai = 0;
ai_old = 100;
iteration = 0;
CDeff = 0;
while abs(ai - ai_old)>2*10^-1 % Get induced angle of attack
iteration = iteration +1;
ai_old = ai;
Cleff = (Clp * cosd(ai)^2 + CDeff * sind(ai) )/cosd(ai);
Veff = Vp/cosd(ai);
Re_eff = Reinf * Veff/Vinf * cp/c;
Meff = Mp/cosd(ai);
if iteration ==1
AFdata(:,2) = AFdata(:,2)/cosd(SweepQC);
end
[~,a_eff,CDeff] = obj.ConstantVortex(AFdata,[],Cleff,Meff);
ai = -a_eff + (AOA + Twists(zz))/cosd(SweepQC);
end
Here, ai is calculated with the function obj.ConstantVortex and compared with the previous calculated ai. The while loop is terminated when the difference is small enough.
However, it can occur that the difference between the initial ai and calculated ai is increasing with every iteration.
How can I check this? and break the loop accordingly?
Thank you
A typical solution for this situation is to store more previous values, and monitor the behaviour over time. So instead of ai_old, you would use:
ai = 0;
num_prev = 5; % how many previous results to check
ai_prev = zeros(1,num_prev);
iteration = 0;
while abs(ai - ai_prev(end))>2*10^-1
iteration = iteration+1;
% your loop code goes here
% now update the array of previous values
ai_prev = circshift(ai_prev,[0 -1]);
ai_prev(end) = ai;
if iteration > num_prev && all(sign(diff(ai_prev)))
% the slope of the previous five results is positive, so exit
break
end
end
You can change the number of previous results and use whatever function is appropriate to check for a break condition on the data in ai_prev for your computation. For example you might want to do some averaging on the previous results, or use a different function than diff().
One solution is to keep last differences or min differences and compare the current difference with that. For example you can have variable ai_older and use it. You can add
ai_older = 1000;
before your while loop and then have
ai_older = ai_old;
ai_old = ai;
and change while condition to
while abs(ai - ai_old)>2*10^-1 && abs(ai - ai_old) < abs(ai_old - ai_older)
Now you can avoid divergence. However, I'm not completely aware of your problem and not sure using abs is required or not.
As I previously mentioned, depending to your problem you may want to keep minimum difference till now and compare current one against that.
I have a multi-start fmincon code. One variable needs to be determined: u0. Inside ObjectiveFunc there is a variable, Parameter I need to output when running multi-start, so I am trying to output a parameter that changes inside an objective function. I wrote a simple example below.
How can I output the value of the Parameter inside Func(u0) below when running run(ms,Prob,big start)?
ObjectiveFunc = #(u0) Func(u0);
gs = GlobalSearch; ms = MultiStart(gs); opts = optimoptions(#fmincon);
Prob = createOptimProblem('fmincon','x0',1,'objective',ObjectiveFunc,'options',opts);
u0_ini_range = 0.1:1:20;
[u0_iniGrid] = ndgrid(u0_ini_range);
W = u0_iniGrid(:);
bigstart = CustomStartPointSet(W);
[u0_OptVal Delta_u0] = run(ms,Prob,bigstart);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function Delta_u0 = Func(u0)
Parameter = randn(1);
Delta_u0 = u0+Parameter;
There are a variety of ways to solve this issue. None of them are pretty. The problem is confounded due to the use of MultiStart, which runs multiple instances simultaneously, only one of which returns the global optimum. This means that the last evaluation of your objective function (and it's call to randn) isn't necessarily the relevant one.
Here's one way to accomplish this with persistent variables. First, you objective function need to look something like this (here Delta is your Parameter):
function [z,Delta_u0_Opt]=HBM1_SlipSolution02hbm3Fcn(u0)
persistent Delta idx;
if isempty(idx)
idx = 0; % Initialize persistent index
end
if nargout > 1
% Output Delta history
Delta_u0_Opt = Delta;
z = (u0-Delta).^2;
else
% Normal operation
idx = idx+1;
Delta(idx) = randn; % Save Delta history
z = (u0-Delta(idx)).^2;
end
Then run your setup code as before:
ObjectiveFunc = #(u0)HBM1_SlipSolution02hbm3Fcn(u0);
u0_ini0 = 0;
gs = GlobalSearch;
ms = MultiStart(gs);
opts = optimoptions(#fmincon);
Lowbound = 0.1;
Xst_rig = 1;
Upbound = 20*Xst_rig;
Prob = createOptimProblem('fmincon','x0',u0_ini0,'objective',ObjectiveFunc,...
'lb',Lowbound,'options',opts);
u0_ini_range = 0.1:1:Upbound;
[u0_iniGrid] = ndgrid(u0_ini_range);
W = u0_iniGrid(:);
bigstart = CustomStartPointSet(W);
[u0_OptVal,fval1] = run(ms,Prob,big start);
Then extract your Delta value:
[fval2,Delta_u0_Opt] = HBM1_SlipSolution02hbm3Fcn(u0_OptVal)
Delta_u0_Opt = Delta_u0_Opt(fval1==fval2)
The main problem with this solution is that the entire history of Delta must be retained via constantly appending to a vector. And it requires that the function value of the solution, fval1, uniquely match only one of fval2. The solution could probably be optimized a bit and the last issue resolved by saving more state history and clever use of an output function. I have no idea how or if this would work if you decide to turn on UseParallel. As you can see, this optimization scheme is not at all designed for what you're trying to get it to do.
Finally, are you sure that it's a good idea to use random values in the way that you are for this kind of optimization scheme? At minimum, be sure to specify a seed so results can be replicated. You might consider creating your own global optimization method based on fmincon if you want something more straightforward and efficient.
Say I have a for loop in MATLAB:
scales = 5:5:95;
for scale = scales
do stuff
end
How can I get the iteration number inside a MATLAB for loop as concisely as possible?
In Python for example I would use:
for idx, item in enumerate(scales):
where idx is the iteration number.
I know that in MATLAB (like in any other language) I could create a count variable:
scales = 5:5:95;
scale_count = 0;
for scale = scales
scale_count = scale_count + 1;
do stuff
end
I could otherwise use find:
scales = 5:5:95;
for scale = scales
scale_count = find(scales == scale);
do stuff
end
But I'm curious to know whether there exists a more concise way to do it, e.g. like in the Python example.
Maybe you can use the following:
scales = 5:5:95;
for iter = 1:length(scales)
scale=scales(iter); % "iter" is the iteration number.
do stuff
end
Since for iterates over the columns of whatever you give it, another way of approximating multiple loop variables would be to use an appropriately constructed matrix:
for scale=[5:5:95; 1:19]
% do stuff with scale(1) or scale(2) as appropriate
end
(my personal preference is to loop over the indices as per Parag's answer and just refer to data(index) directly within the loop, without an intermediate. Matlab's syntax isn't very concise at the best of times - you just get used to it)
The MATLAB way is probably doing it with vectors.
For example suppose you want to find in a vector if there is a value that is equal to its position. You would generally do this:
a = [10 20 1 3 5];
found = 0;
for index = 1:length(a)
if a(index) == index
found = 1;
break;
end
end
Instead you can do:
found = any(a == 1:length(a));
In general
for i=1:length(a)
dostuff(a(i), i);
end
can be replaced with:
dostuff(a(i), 1:length(a))
it dostuff can be vectorized or
arrayfun(#dostuff, a, 1:length(a))
otherwise.