Clean methodology for running a function for a large set of input parameters (in Matlab) - matlab

I have a differential equation that's a function of around 30 constants. The differential equation is a system of (N^2+1) equations (where N is typically 4). Solving this system produces N^2+1 functions.
Often I want to see how the solution of the differential equation functionally depends on constants. For example, I might want to plot the maximum value of one of the output functions and see how that maximum changes for each solution of the differential equation as I linearly increase one of the input constants.
Is there a particularly clean method of doing this?
Right now I turn my differential-equation-solving script into a large function that returns an array of output functions. (Some of the inputs are vectors & matrices). For example:
for i = 1:N
[OutputArray1(i, :), OutputArray2(i, :), OutputArray3(i, :), OutputArray4(i, :), OutputArray5(i, :)] = DE_Simulation(Parameter1Array(i));
end
Here I loop through the function. The function solves a differential equation, and then returns the set of solution functions for that input parameter, and then each is appended as a row to a matrix.
There are a few issues I have with my method:
If I want to see the solution to the differential equation for a different parameter, I have to redefine the function so that it is an input of one of the thirty other parameters. For the sake of code readability, I cannot see myself explicitly writing all of the input parameters as individual inputs. (Although I've read that structures might be helpful here, but I'm not sure how that would be implemented.)
I typically get lost in parameter space and often have to update the same parameter across multiple scripts. I have a script that runs the differential-equation-solving function, and I have a second script that plots the set of simulated data. (And I will save the local variables to a file so that I can load them explicitly for plotting, but I often get lost figuring out which file is associated with what set of parameters). The remaining parameters that are not in the input of the function are inside the function itself. I've tried making the parameters global, but doing so drastically slows down the speed of my code. Additionally, some of the inputs are arrays I would like to plot and see before running the solver. (Some of the inputs are time-dependent boundary conditions, and I often want to see what they look like first.)
I'm trying to figure out a good method for me to keep track of everything. I'm trying to come up with a smart method of saving generated figures with a file tag that displays all the parameters associated with that figure. I can save such a file as a notepad file with a generic tagging-number that's listed in the title of the figure, but I feel like this is an awkward system. It's particularly awkward because it's not easy to see what's different about a long list of 30+ parameters.
Overall, I feel as though what I'm doing is fairly simple, yet I feel as though I don't have a good coding methodology and consequently end up wasting a lot of time saving almost-identical functions and scripts to solve fairly simple tasks.

It seems like what you really want here is something that deals with N-D arrays instead of splitting up the outputs.
If all of the OutputArray_ variables have the same number of rows, then the line
for i = 1:N
[OutputArray1(i, :), OutputArray2(i, :), OutputArray3(i, :), OutputArray4(i, :), OutputArray5(i, :)] = DE_Simulation(Parameter1Array(i));
end
seems to suggest that what you really want your function to return is an M x K array (where in this case, K = 5), and you want to pack that output into an M x K x N array. That is, it seems like you'd want to refactor your DE_Simulation to give you something like
for i = 1:N
OutputArray(:,:,i) = DE_Simulation(Parameter1Array(i));
end
If they aren't the same size, then a struct or a table is probably the best way to go, as you could assign to one element of the struct array per loop iteration or one row of the table per loop iteration (the table approach would assume that the size of the variables doesn't change from iteration to iteration).
If, for some reason, you really need to have these as separate outputs (and perhaps later as separate inputs), then what you probably want is a cell array. In that case you'd be able to deal with the variable number of inputs doing something like
for i = 1:N
[OutputArray{i, 1:K}] = DE_Simulation(Parameter1Array(i));
end
I hesitate to even write that, though, because this almost certainly seems like the wrong data structure for what you're trying to do.

Related

how to 'zero' all variables at each loop iteration

I have written a script describing a dynamic biological process in matlab; the input to which is a year of daily temperature values.The model runs for a year on this daily timestep carrying out different calculations required for the process.
I have thirty years of temperature data (matrix of size 365*30) and I intend to write a 'for loop' at the start of the script in order to use each year of daily data consecutively. I have about 5 variables that are the output from the script, which I intend to output to a txt/csv file at each iteration. My problem is that there are approximately 80 variables within the model and I would like to zero them all at each iteration of the outermost loop (the temperature input). I would like to do this in an efficient manner rather than having to individually zero all the variables. Does anyone know how to do this?
I have been looking at using the 'who' function to list all the variables and I'm thinking that it could be used somehow to zero everything. I have tried letting x = who; which seems to produce a list of all the variables in inverted commas. But obviously; trying to let x = 0 after that just redefines x. I was also thinking of just using 'clear all' but I think this would really slow the model down as it would be 'starting from scratch' redefining all the variable at each loop?
Any help would be appreciated.
First of all, if you have 80 variables you are probably doing something strange. Consider to combine them into vectors or arrays for example.
That being said, there are two situations I can think about:
You already initialize all your variables somewhere
In this case the solution is simple: move the initialization to the start of your outer loop.
You don't initialize anything (bad practice, especially if you are concerned about performance)
In this case you should put a function inside your loop, that only returns your output variables and not all these loose intermediate variables.
Perhaps a combination of these two methods can also apply, but really I would recommend not to use 80 different variables! And initialize any variable that you need to use.
A compact syntax to initialize scalars would be:
[a, b,c] = deal(0);

Vectorising 3d array

I am trying to vectorise a for loop. I have a set of coordinates listed in a [68x200] matrix called plt2, and I have another set of coordinates listed in a [400x1] matrix called trans1. I want to create a three dimensional array called dist1, where in dist1(:,:,1) I have all of the values of plt2 with the first value of trans1 subtracted, all the way through to the end of trans1. I have a for loop like this which works but is very slow:
for i=1:source_points;
dist1(:,:,i)=plt2-trans1(i,1);
end
Thanks for any help.
If I understood correctly, this can be easily solved with bsxfun:
dist1 = bsxfun(#minus, plt2, shiftdim(trans1,-2));
Or, if speed is important, use this equivalent version (thanks to #chappjc), which seems to be much faster:
dist1 = bsxfun(#minus, plt2, reshape(trans1,1,1,[]));
In general, bsxfun is a very useful function for cases like this. Its behaviour can be summarized as follows: for any singleton dimension of any of its two input arrays, it applies an "implicit" for loop to the other array along the same dimension. See the doc for further details.
Vectorizing is a good first optimization, and is usually much easier than going all in writing your own compiled mex-function (in c).
However, the golden middle-way for power users is Matlab Coder (this also applies to slightly harder problems than the one posted, where vectorization is more or less impossible). First, create a small m-file function around the slow code, in your case:
function dist1 = do_some_stuff(source_points,dist1,plt2,trans1)
for i=1:source_points;
dist1(:,:,i)=plt2-trans1(i,1);
end
Then create a simple wrapper function which calls do_some_stuff as well as defines the inputs. This file should really be only 5 rows, with only the bare essentials needed. Matlab Coder uses the wrapper function to understand what typical proper inputs to do_some_stuff are.
You can now fire up the Matlab Coder gui from the Apps section and simply add do_some_stuff under Entry-Point Files. Press Autodefine types and select your wrapper function. Go to build and press build, and you are good to go! This approach usually bumps up the execution speed substantially with almost no effort.
BR
Magnus

How to sort in ascending order the solution vector in each iteration using ODE?

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.

how to create a changing variable for fsolve

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.

MATLAB: alternatives to calling feval in ode45

I hope I am on topic here. I'm asking here since it said on the faq page: a question concerning (among others) a software algorithm :) So here it goes:
I need to solve a system of ODEs (like $ \dot x = A(t) x$. The Matrix A may change and is given as a string in the function call (Calc_EDS_v2('Sys_EDS_a',...)
Then I'm using ode45 in a loop to find my x:
function [intervals, testing] = EDS_calc_v2(smA,options,debug)
[..]
for t=t_start:t_step:t_end)
[Te,Qe]=func_int(#intQ_2_v2,[t,t+t_step],q);
q=Qe(end,:);
[..]
end
[..]
with func_int being ode45 and #intQ_2_v2 my m-file. q is given back to the call as the starting vector. As you can see I'm just using ode45 on the intervall [t, t+t_step]. That's because my system matrix A can force ode45 to use a lot of steps, leading it to hit the AbsTol or RelTol very fast.
Now my A is something like B(t)*Q(t), so in the m-file intQ_2_v2.m I need to evaluate both B and Q at the times t.
I first done it like so: (v1 -file, so function name is different)
function q=intQ_2_v1(t,X)
[..]
B(1)=...; ... B(4)=...;
Q(1)=...; ...
than that is naturally only with the assumption that A is a 2x2 matrix. With that setup it took a basic system somewhere between 10 and 15 seconds to compute.
Instead of the above I now use the files B1.m to B4.m and Q1.m to B4.m (I know that that's not elegant, but I need to use quadgk on B later and quadgk doesn't support matrix functions.)
function q=intQ_2_v2(t,X)
[..]
global funcnameQ, funcnameB, d
for k=1:d
Q(k)=feval(str2func([funcnameQ,int2str(k)]),t);
B(k)=feval(str2func([funcnameB,int2str(k)]),t);
end
[..]
funcname (string) referring to B or Q (with added k) and d is dimension of the system.
Now I knew that it would cost me more time than the first version but I'm seeing the computing times are ten times as high! (getting 150 to 160 seconds) I do understand that opening 4 files and evaluate roughly 40 times per ode-loop is costly... and I also can't pre-evalute B and Q, since ode45 uses adaptive step sizes...
Is there a way to not use that last loop?
Mostly I'm interested in a solution to drive down the computing times. I do have a feeling that I'm missing something... but can't really put my finger on it. With that one taking nearly three minutes instead of 10 seconds I can get a coffee in between each testrun now... (plz don't tell me to get a faster computer)
(sorry for such a long question )
I'm not sure that I fully understand what you're doing here, but I can offer a few tips.
Use the profiler, it will help you understand exactly where the bottlenecks are.
Using feval is slower than using function handles directly, especially when using str2func to build the handle each time. There is also a slowdown from using the global variables (and it's a good habit to avoid these unless absolutely necessary). Each of these really adds up when using them repeatedly (as it looks like here). Store function handles to each of your mfiles in a cell array and either pass them directly to the function or use nested function for the optimization so that the cell array of handles is visible to the function being optimized. Personally, I prefer the nested method, but passing is better if you will use those mfiles elsewhere.
I expect this will get your runtime back to close to what the first method gave. Be sure to tell us if this was the problem or if you found another solution.