I have three looped operations O1 O2 O3 each with an IF statement and the operation with the largest flag=[F1 F2 F3] value has a higher priority to run.
How can I switch between operations depending on the value of that flag ? The flag value for each operation varies with time.
For simplicity, operation 1 is going to run first, and by the end of it's loop the flag value will be the lowest, hence operation 2 or 3 should run next. So for this example, at t=0 : F1=5 F2=3 and F3=1.
The over-simplified pseudo code for what im trying to achieve :
while 1
find largest flag value using [v index]=max(flag)
Run operation with highest flag value
..loop back..
end
I am not sure how the value of flag will be compared in between operations, and hence why I hope for someone to shed some light on the issue here.
EDIT
Currently, all operations are written in one matlab file, and each is triggered with an IF statement. The operations run systematically one after the other (depending on which one is written first in matlab). I want to avoid that and trigger them depending on the flag value instead.
If your operations are functions (a little hard to tell from the question), then make a cell array of function handles, there fun1 is the name of one of your actual functions.
handles = {#fun1, #fun2, #fun3}
Then you can just use the index returned from your max term to get the correct function from the array. You can pass any arguments to the function using the following syntax.
handles{index}(args)
Using the style above makes the solution scalable, so you don't need a stack of if statements that require maintenance when the number of operations expands. If the functions are really simple you can always use lambdas (or anonymous functions in Matlab speak).
However, if you have a limited number of simple operations that are not likely to expand, you may choose to use a switch statement in your while loop instead. It conveys your intention better than a stack of if statements.
while 1
[~, index]=max(flag);
switch index
case 1
operation1
flag = [x y z]
case 2
operation2
flag = [x y z]
otherwise
operation3
flag = [x y z]
end
end
Related
I have a constrained nonlinear optimization problem, "A". Inside the computation is an om.Group which I'll call "B" that requires a nonlinear solve. Whether "B" finds a solution or crashes seems to depend on its initial conditions. So far I've found that some of the initial conditions given to "B" are inconsistent with the constraints on "A", and that this seems to be contributing to its propensity for crashing. The constraints on "A" can be computed before "B".
If the objective of "A" could be computed before "B" then I would put "A" in its own group and have it pass its known-good solution to "B". However, the objective of "A" can only be computed as a result of the converged solution of "B". Is there a way to tell OpenMDAO or the optimizer (right now I'm using ScipyOptimizerDriver and the SLSQP method) that when it chooses a new point in design-variable space, it should check that the constraints of "A" hold before proceeding to "B"?
A slightly simpler example (without the complication of an initial guess) might be:
There are two design variables 0 < x1 < 1, 0 < x2 < 1.
There is a constraint that x2 >= x1.
Minimize f(sqrt(x2 - x1), x1) where f crashes if given imaginary inputs. How can I make sure that the driver explores the design space without giving f a bad input?
I have two proposed solutions. The best one is highly problem dependent. You can either raise an AnalysisError or use numerical clipping.
import numpy as np
import openmdao.api as om
class SafeComponent(om.ExplicitComponent):
def setup(self):
self.add_input('x1')
self.add_input('x2')
self.add_output('y')
def compute(self, inputs, outputs):
x1 = inputs['x1']
x2 = inputs['x2']
diff = x1 - x2
######################################################
# option 1: raise an error, which causes the
# optimizer line search to backtrack
######################################################
# if (diff < 0):
# raise om.AnalysisError('invalid inputs: x2 > x1')
######################################################
# option 2: use numerical clipping
######################################################
if (diff < 0):
diff = 0.
outputs['y'] = np.sqrt(diff)
# build the model
prob = om.Problem()
prob.model.add_subsystem('sc', SafeComponent(), promotes=['*'])
prob.setup()
prob['x1'] = 10
prob['x2'] = 20
prob.run_model()
print(prob['y'])
Option 1: raise an AnalysisError
Some optimizers are set up to handle this well. Others are not.
As of V3.7.0, the OpenMDAO wrappers for SLSQP from scipy and pyoptsparse, and the SNOPT/IPOPT wrappers from pyoptsparse all handle AnalysisErrors gracefully.
When the error is raised, the execution stops and the optimizer recognizes a failed case. It backtracks on the linesearch a bit to try and get out of the situation. It will usually try a few steps backwards, but at some point it will give up. So the success of this situation depends a bit on why you ended up in the bad part of the space and how much the gradients are pushing you back into it.
This solution works very well with fully analytic derivatives. The reason is that (most) gradient based optimizers will only ever ask for function evaluations along a line search operation. So that means that, as long as a clean point is found, you're always able to be able to compute derivatives at that point as well.
If you're using finite-differences, you could end a line search right near the error condition, but not violating it (e.g. x1=1, x2=.9999999). Then during the FD step to compute derivatives, you might end up tripping the error condition and raising the error. The optimizer is not going to be able to recover from this condition. Errors during FD steps will effectively kill the whole opt.
So, for this reason I never recommend the AnalysisError approach if you're suing FD.
Option 2: Numerical Clipping
If you optimizer wrapper does not have the ability to handle an AnalysisError, you can try some numerical clipping instead. You can add a filter in your calcs to to keep the values numerically safe. However, you obviously need to use this very carefully. You should at least add an additional constraint that forces the optimizer to keep away from the error condition when converged (e.g. x1 >= x2).
One important note: if you provide analytic derivatives, include the clipping in them!
Sometimes the optimizer just wants to pass through this bad region on its way to the answer. In that case, the simple clipping I show here is probably fine. Other times it wants to ride the constraint (be sure you add that constraint!!!) and then you probably want a more smoothly varying type of clipping. In other words don't use a simple if-condition. Smooth the round corner a bit, and maybe make the value asymptotically approach 0 from a very small value. This way you have a c1 continuous function and the derivatives won't got to exactly 0 for these inputs.
I am working on a project dealing with closed curves. I want to trace out a curve swept out by a coordinate vector moves. Just to get the code down I'm trying to accomplish the goal using a circle. I am able to animate the motion of the vector with the following command
animate(arrow, [[cos(2*Pi*n/1000),sin(2*Pi*n/1000)], shape = arrow,
scaling = constrained], n=0..1000, frames = 100);
Is there a way to trace the circle that is swept out by this curve. Again my goal is to be able to do this for an arbitrary parameterized curve. Any help is greatly appreciated.
Here is a basic but verbose way to do it,
restart;
plots:-animate(plots:-display,
[ 'plots:-arrow([cos(2*Pi*n/1000),
sin(2*Pi*n/1000)],
shape = arrow)',
'plot([cos(2*Pi*nn/1000),
sin(2*Pi*nn/1000),nn=0..n])',
scaling = constrained ],
n=0..1000, frames = 30);
If that seems complicated then perhaps it's good to review Maple's evaluation rules for procedure calls. Maple normally evaluates the arguments before passing them to the procedure.
But sometimes you don't want that evaluation to occur until, say, the procedure can provide a numeric value for a parameter in some argument. That is to say, sometimes you want to avoid premature evaluation of the arguments.
The seq command deals with this by having so-called special-evaluation rules, where the evaluation of the argument is delayed unto the seq index variable takes on it individual values.
The plots:-animate command allows you to deal with it by separating the main command from its arguments (which get passed separately, in a list). That is often adequate, but not when those arguments in the list also contain full calls to plotting commands which would not evaluate ok (ie. without error, up front) until the animating parameter gets its actual values.
That is why I also used single right-quotes to delay the evaluation of the calls to plots:-arrow and plot in the example above. Those evaluations need to wait until the animating parameter n takes on its actual numeric values.
And another, related approach is to create a procedure which accepts the animating parameter value and constructs a whole frame.
F := proc(n)
plots:-display(
plots:-arrow([cos(2*Pi*n/1000),
sin(2*Pi*n/1000)],
shape = arrow),
plot([cos(2*Pi*nn/1000),
sin(2*Pi*nn/1000),
nn=0..n]),
scaling = constrained);
end proc:
This can be handy as it lets you test beforehand.
F(307.2);
(I didn't bother to optimize F, but you could notice that the sin and cos calls happen twice, and instead do them just once inside the procedure and assign to local variables. That might make things easier when you go on to more involved parametric curves.)
Now the calls to plots:-animate can be terse,
plots:-animate(F, [ n ],
n=0..1000, frames = 30);
The above produces the same animation as before.
Here's another way, by constructing a list containing a sequence of all the frames.
Note that, as written, evaluating F at unknown, unassigned name n produces an error.
F(n);
Error, (in plots/arrow) invalid input: plottools:-arrow
expects its 3rd argument, pv, to be of type {Vector, list,
vector, complexcons, realcons}, but received 0.5000000000e-1*
(cos(0.6283185308e-2*n)^2+sin(0.6283185308e-2*n)^2)^(1/2)
The error occurs because n does not have a numeric value.
But the special-evaluation rules of the seq command allow us to proceed anyway, since it delays the evaluation of F(n) until n gets its values.
# note termination with full colon, to suppress output
S := [seq(F(n), n=0..1000, (1000-0)/(30-1))]:
nops(S); # check that we really got 30 frames
30
plots:-display(S, insequence=true);
That last command also displays the same 30-frame animation.
I have an ODE for calculating how acidicity changes. Everything is working just fine, only I would like to change a constant whenever acidicity reaches a critical point. It is supposed to be some kind of irreversible effect I wish to simulate.
My constants are coming from a structure file (c) I load once in the ODE function.
[Time,Results] = ode15s(#(x, c) f1(x, c),[0 c.length],x0,options);
The main problem I have here is not telling Matlab to change the constant but remember if it happened already during the simulation once. so Matlab should take the irreversibly changed constant rather than the one I supply at the beginning.
I would like to write a flag that is saved while the ODE is running and an if condition, "if flag exists, change constant". How to do that?
UPDATE I:
PROBLEM SOLVED
Here a first own solution, it is not polished and requires a structure file approach. Which means, the constants which should suddenly changed upon an event, must be struct files which are handed in the ODE function into the function that should be evaluated (look above for the ODE syntax). The function accepts the inputs like this:
function [OUTPUT] = f1(t, x, c)
% So here, the constants all start with c. followed by the variable name. (because they are structs instead of globals)
%% write a flag when that event happens
if c.someODEevent <= 999 && exist ('flag.txt') == 0
dlmwrite ('flag.txt',1);
end
%% next iteration will either write the flag again or not. more importantly, if it exists, the constant will change because of this.
if exist ('flag.txt') == 2
c.changingconstant = c.changingconstant/2;
end
end
Please look into Horchlers kind answer where you have to take care that such a step may introduce inaccuracies and you have to be careful to check if your code does what it is supposed to do.
To do this accurately, you should use event detection within the ODE solver. I can't give you a specific answer because you've only provided the ode15s call it in your question, but you'll need to write an events function and then specify it via odeset. Something like this:
function acidity_main
% load c data
...
x0 = ...
options = odeset('Events',#events); % add any other options too
% integrate until critical value and stop
[Time1,Results1] = ode15s(#(x,c)f1(x,c),[0 c.length],x0,options);
x0 = Results(end,:); % set new initial conditions
% pass new parameters -it's not clear how you're passing parameters
% if desired, change options to turn off events for faster integration
[Time2,Results2] = ode15s(#(x,c)f1(x,c),[0 c.length],x0,options);
% append outputs, last of 1 is same as first of 2
Time = [Time1;Time2(2:end)];
Results = [Results1;Results2(2:end,:)];
...
function y=f1(x,c)
% your integration function
...
function [value,isterminal,direction] = events(x,c)
value = ... % crossing condition, evaluates to zero at event condition
isterminal = 1; % stop integration when event detected
direction = ... % see documentation
You'll want to use the events to integrate right to the point where the "acidicity reaches a critical point" and stop the integration. Then call ode15s again with the new value and continue the integration. This may seem crude, but it how this sort of thing can be done accurately.
You can see an example of basic event detection here. Type ballode in your command window to see the code for this. You can see a slightly more complex version of this demo in my answer here. Here's an example of using events to accurately change an ODE at specified times (rather than your case of specified state values).
Note: I find it strange that you're passing what you call "constants", c, as the second argument to ode15s. This function has strict input argument requirements: the first is the independent variable (often time), and the second is the array of state variables (same as your initial condition vector). Also if f1 only takes two arguments, #(x,c)f1(x,c) is superfluous – it's sufficient to pass in #f1.
I've got an ODE system working perfectly. But now, I want in each iteration, sort in ascending order the solution vector. I've tried many ways but I could not do it. Does anyone know how to do?
Here is a simplified code:
function dtemp = tanque1(t,temp)
for i=1:N
if i==1
dtemp(i)=(((-k(i)*At*(temp(i)-temp(i+1)))/(y))-(U*As(i)*(temp(i)-Tamb)))/(ro(i)*vol_nodo*cp(i));
end
if i>1 && i<N
dtemp(i)=(((k(i)*At*(temp(i-1)-temp(i)))/(y))-((k(i)*At*(temp(i)-temp(i+1)))/(y))-(U*As(i)*(temp(i)-Tamb)))/(ro(i)*vol_nodo*cp(i));
end
if i==N
dtemp(i)=(((k(i)*At*(temp(i-1)-temp(i)))/(y))-(U*As(i)*(temp(i)-Tamb)))/(ro(i)*vol_nodo*cp(i));
end
end
end
Test Script:
inicial=343.15*ones(200,1);
[t temp]=ode45(#tanque1,0:360:18000,inicial);
It looks like you have three different sets of differential equations depending on the index i of the solution vector. I don't think you mean "sort," but rather a more efficient way to implement what you've already done - basically vectorization. Provided I haven't accidentally made any typos (you should check), the following should do what you need:
function dtemp = tanque1(t,temp)
dtemp(1) = (-k(1)*At*(temp(1)-temp(2))/y-U*As(1)*(temp(1)-Tamb))/(ro(1)*vol_nodo*cp(1));
dtemp(2:N-1) = (k(2:N-1).*(diff(temp(1:N-1))-diff(temp(2:N)))*At/y-U*As(2:N-1).*(temp(2:N-1)-Tamb))./(vol_nodo*ro(2:N-1).*cp(2:N-1));
dtemp(N) = (k(N)*At*(temp(N-1)-temp(N))/y-U*As(N)*(temp(N)-Tamb))/(ro(N)*vol_nodo*cp(N));
You'll still need to define N and the other parameters and ensure that temp is returned as a column vector. You could also try replacing N with the end keyword, which might be faster. The two uses of diff make the code shorter, but, depending on the value of N, they may also speed up the calculation. They could be replaced with temp(1:N-2)-temp(2:N-1) and temp(2:N-1)-temp(3:N). It may be possible to collapse these down to a single vectorized equation, but I'll leave that as an exercise for you to attempt if you like.
Note that I also removed a great many unnecessary parentheses for clarity. As you learn Matlab you'll to get used to the order of operations and figure out when parentheses are needed.
i want fsolve to calculate the output for different uc each time (increasing uc by 0.001 each time). each output from fsolve should be sent to a simulink model seperatly. so i set a loop to do so, but i believe that at the currenty constellation (if it will work)will just calculate 1000 different values? is there a way to send out the values seperately?
if not, how can i create a parameter uc. that goes from 0 to say 1000? i tried uc=0:0.001:1000, but again, the demension doen't seem to fit.
how do i create a function that takes the next element of a vector/matrix each time the function is called?
best regards
The general approach to iterating over an array of values and feeding them one-by-one into a series of evaluations of a function follows this form:
for ix = 0:0.1:10
func(arg1, arg2, ix)
end
See how each call to func includes the current value of ix ? On the first iteration ix==0, on the next ix==0.1 and so forth. You should be able to adapt this to your needs; in your code the loop index (which you call i) is not used inside the loop.
Now some un-asked-for criticism of your code. The lines
x0=[1,1,1];
y=x0(1);
u=x0(2);
yc=x0(3);
options=optimset('Display','off');
do not change as the loop iterations advance; they always return the same values whatever the value of the loop iterator (i in your code) may be. It is pointless including them inside the loop.
Leaving them inside the loop may even be a waste of a lot of time if Matlab decides to calculate them at every iteration. I'm not sure what Matlab does in this case, it may be smart enough to figure out that these values don't change at each iteration, but even if it does it is bad programming practice to write your code this way; lift constant expressions such as these out of loops.
It's not clear from the fragment you've posted why you have defined y, u and yc at all, they're not used anywhere; perhaps they're used in other parts of your program.