TL;DR: How should custom simulation runs be managed in Matlab? Detailed Questions at the end.
I am working with matlab where i created some code to check the influence of various parameters on a simulated system. It has a lot of inputs and outputs but a MWE would be:
function [number2x,next_letter] = test(number, letter)
number2x = number * 2;
next_letter = letter + 1;
disp(['next letter is ' next_letter])
disp(['number times 2 is ' num2str(number2x)])
end
This works if this is all there is to test. However with time multiple new inputs and outputs had to be added. Also because of the growing number of paramters that have been test some sort of log had to be created:
xlswrite('testfile.xlsx',[num2str(number), letter,num2str(number2x),next_letter],'append');
Also because the calculation takes a few hours and should run over night multiple parameter sets had to be started at one point. This is easily done with [x1,y1] = test(1,'a');[x2,y2] = test(2,'b'); in one line or adding new tasks while the old still run. However this way you can't keep track on how many are still open.
So in total I need some sort of testing framework, that can keep up with changeging inpus and outputs, keeps track on already doen calculations and ideally also handles the open runs.
I feel like i can't be the only one who faces this issue, in fact I think so many people face this issue that Mathworks would already came up with a solution.
For Simulink this has been done in form of a Simluationmanager, but for Matlab functions the closest thing i found is the Testing framework (example below) which seems to be rather for software development and debugging and not at all for what i am trying. And somepoint there seem to be 3rd party solutions but they are no longer continued in favor of this Testing framework.
function solutions = sampleTest
solutions = functiontests({#paramtertest});
end
function paramtertest(vargin)
test(1,'a');
test(2,'b');
end
function [number2x,next_letter] = test(number, letter)
number2x = number * 2;
next_letter = letter + 1;
disp(['next letter is ' next_letter])
disp(['number times 2 is ' num2str(number2x)])
xlswrite('testfile.xlsx',[num2str(number), letter,num2str(number2x),next_letter],'append');
end
Alternatively I could create my test as a class, create an interface similar to the Simulationmanager, create numerous functions for managing inputs and outputs and visualize the progress and then spawn multiple instances of if i want to set up a new set of parameters while already running a simulation. Possible, yet a lot of work that does not involve the simulation directly.
In total following questions arise:
Is there a build in Matlab function for managing simulations that i totally missed so far?
Can the the Testing framework be used for this purpose?
Is there already some Framework (not from Mathworks) that can handle this?
If i create my own class, could multiple instances run individually and keep track of their own progress? And would those be handled simultaniously or would matlab end up running the in the order they started?
I know this question is somewhat in the off-topic: recommend or find a tool, library or favorite off-site resource area. If you feel it is too much so, please focus on the last question.
Thank you!
I've done similar tests using GUI elements. Basic part of simulation was inside while loop, for example in your case:
iter = 0;
iter_max = 5; %the number of your times, you will call script
accu_step = 2; %the accuracy of stored data
Alphabet = 'abcdefghijklmnopqrstuvwxyz'
while iter < iter_max
iter = iter+1;
[x1,y1] = test(i,Alphabet(i));
end
Now you should create a handle to progress bar inside your computation script. It will show you both on which step you are, and the progress of current step.
global h;
global iter_opt;
if isempty(h)
h=waitbar(0,'Solving...');
else
waitbar(t/t_end,h,sprintf('Solving... current step is:%d',iter));
end
You didn't specified which function you use, if it is for example time-depended the above t/t_end example is an estimation of current progress.
The solving of result also require to be changed on every execution of loop, for example:
global iter;
i_line = (t_end/accu_step+2)*(iter-1);
xlswrite('results.xlsx',{'ITERATION ', iter},sheet,strcat('A',num2str(i_line+5)))
xlswrite('results.xlsx',results_matrix(1:6),sheet,strcat('D',num2str(i_line+5)))
The above example were also with assumption that your results are time-related, so you store data every 2 units of time (day, hours, min, what you need), from t_0 to t_end, with additional 2 rows of separation, between steps. The number of columns is just exemplary, you can adjust it to your needs.
After the calculation is done, you can close waitbar with:
global h
close(h)
Related
I'm brand new to Julia (v1.7.1) and I've been using VSCode as an IDE. In VSCode (v1.64) I've installed the Julia Extension (v1.5.10). When plotting in VSCode, the plot shows up in the plot pane by default. I'm using the Plots (v1.25.7) package and the "gr" backend, as it's one of the "faster" options.
I'm trying to make a "live" time series plot, in which the series is updated in a loop. This seems to be a popular problem, as there are many questions addressing this, but I've found no "clean" solution yet. I should emphasize that I'm not trying to make an animation, which is fabricated upon termination of the loop. I want to update the plot as the loop is running. I've looked at SmoothLivePlot, but I think this requires that I know the series size before hand, which is not the case in my application. Then again, maybe I'm misinterpreting the package.
I'm going to present what I've done this far, with hopes for improvement. I first created a plotting function
function plt_update(p,time_series,var_series)
plot!(time_series, var_series,
label = "",
linecolor = :red)
display(p)
end
Then I initialized the plot
model_time = 100
p = plot([0.0],[0.0],
label = "",
linecolor = :red,
xlims = (0, model_time),
ylims = (0, 1),
display(p)
My loop is then called (NOTE: that all the code shown in this post is wrapped in a function and run in the RPEL, hence variables do not need to be defined with "global" inside the while loop. This is due to Julia's optimization and scope design...from what I've read. See another discussion on this for an example).
run_time = 0.0
time_series = [0.0]
var_series = [0.0]
while run_time < model_time
# Calculate new timestep
timestep = rand(Float64) # Be sure to add Random
run_time += timestep
# Computations
sleep(timestep/10)
# Build vector
push!(time_series,run_time)
push!(var_series,timestep)
# Live plots
plt_update(p,time_series,var_series)
end
I've encountered a few problems with this. First, I don't know if this is just an issue with VSCode or who to point the finger at, but putting display(p) inside the function to update the plot in the VSCode plot pane ends up creating a new plot for each iteration in the loop. Clearly this is not what is intended. I found that if I shut off the "plot in pane" option (File > Preferences > Settings > Extensions > Julia), then a single plot window is created. I'm not sure if "create new plot in pane" is expected or an issue (again, I'm new to this). Nevertheless, when plotting outside the VSCode, the above code works as I expected.
For the next issue, which I think is most important here, is that inside the plotting function, the call to plot! adds a new vector to p, while saving the previous one as well. In other words, p is not being updated with the new series, it is growing by appending a whole new vector. This is clear as the plotting comes to a grinding halt after many iterations. Also, if you remove the "color" attribute, you'll see the line changes color with each iteration. In effect, what is being plotted is many lines, all overlapping.
I then dove into p to look more closely at what is going on and made some changes to the plotting function
function plt_update(p,time_series,var_series)
push!(p.series_list[1].plotattributes[:x],time_series[:][end])
push!(p.series_list[1].plotattributes[:y],var_series[:][end])
display(p)
end
Above, instead of creating a new series_list (as was the case before w/ plot!), I'm now updating the series w/ the new data. This works much better than before and behaves as expected. While it's only a slight improvement, I've further modified the function and the function call by passing a scalar instead of a vecotr
function plt_update(p,run_time,variable)
push!(p.series_list[1].plotattributes[:x],run_time)
push!(p.series_list[1].plotattributes[:y],variable)
display(p)
end
in which the function call is now plt_update(p,run_time,timestep). As you can see, I sleep for a random time then divide that by 10, which I found to be about as much lag as I can afford before it loses it's "near realtime" appeal. Dividing by 100, for example, results in rather noticeable lag.
So my question is...is there a way to improve this, where the lag is reduced? Being new to Julia, I'm not aware of all the plotting options or how to access the "guts" to make improvements on my own.
EDIT:
I've just become aware of "Makie" and "Observables". I'm going to do a bit more research on those to see if this offers an improvement in the latency.
EDIT2:
In my research, I found a much cleaner way to express the last function (also see here for further confirmation of the approach)
function plt_update(p,run_time,variable)
push!(p,1,run_time,variable)
display(p)
end
The solution I found w/ Makie & observables is without a doubt the best! Between the YouTube video and code, I was able to apply it to my example above. Granted, my loop is only ~150 iterations, there is negligible lag (which was far from the case prior). Taking out the sleep function, the plot is instantaneous. I would encourage others to try this approach for "near real-time" plots.
The packages needed are
using GLMakie
using GeometryTypes
I'm not sure if GeometryTypes is needed explicitly (I thought GLMakie would bring in the necessary libs), but I was getting an error stating that Point2f0 was not found.
First, create the observable (note that it's a vector of type Point2f0)
pt_series = Observable([Point2f0(0, 0)])
Then initialize the plot
fig = Figure(); display(fig)
ax = Axis(fig[1,1])
lines!(ax, pt_series; linewidth = 4, color = :purple)
# Static elements
ax.title = "Time Series"
ax.xlabel = "Time (s)"
ax.ylabel = "Data"
xlims!(ax, 0, 100)
ylims!(ax, 0, 1)
Then run the loop
model_time = 100
run_time = 0.0
while run_time < model_time
# Calculate new timestep
timestep = rand(Float64)
run_time += timestep
# Computations
#sleep(timestep/1000)
# Live plots
push!(pt_series[], Point2f0(run_time, timestep))
pt_series[] = pt_series[]
end
As I stated in the question, all of the code above should be wrapped in a function to prevent scoping errors.
I have a code that goes like this which I want to run using parpool:
result = zeros(J,K)
for k = 1:K
for j = 1:J
build(:,1) = old1(:,j,k)
build(:,2) = old2(:,j,k)
result(j,k) = call_function(build); %Takes a long time to run
end
end
It takes a long time to run this code and I have to run this multiple times for my simulation so I want to run the outermost loop (k = 1:K) in parallel in MATLAB.
From what I have read, I cannot use parfor since all each function uses the same variables old1 and old2. I could use spmd and distribute my matrices old1 and old2. But I read this creates as many copies of the variable as the workers and I do not want this to happen. I could use drange. But I am not sure how it exactly works. I am finding it difficult to actually use what I have been reading in MATLAB references. Any resource and pointers would be of great help!
Constraints are as follows:
Must not create multiple copies of the variables old1, old2. But I can slice it across workers as each iteration doesn't require other iterations.
Have to distribute for the outermost loop only. For ease of accessing data outside this block of code.
Thank you.
old1 and old2 can be used, I think. Initialize as constants using:
old1 = parallel.pool.Constant(old1);
old2 = parallel.pool.Constant(old2);
Have you seen this post?
https://www.mathworks.com/help/distcomp/improve-parfor-performance.html
my code inside a parfor loop is getting longer and longer and I would like to split it up. Having parts of the code saved in different script files seems logical and very attractive and since it doesn't change anything except where the code is saved it seems like it should work. But it doesn't.
I get the usual "Transparency violation error".
The problem seems typical but I did not find this question asked or answered anywhere.
Below is a small working example.
(Yes, this could be made as a function. But in case of many more Input and Output variables this becomes really ugly imo and probably also slower due to communicating the arguments)
C = NaN(10,1); %Result vector
parfor loop = 1:10
a = 1;
b = 2;
MFile_Test %Run the m-file which contains only one line:
% c = a + b;
C(loop)=c;
end
the MFile_Test is a script just containing the line one line c = a + b.
I am beginning to understand why parallel computing has an issue here but not how to solve it. Since this would be possible without any problem if I just had the line c = a + b inside the parfor file I cannot belief there is no simple way to solve this (e.g. in the worst case something like tell matlab to load the text from another file and run it as code here and now).
If there are alternative ways to structure my code without using the script files (and, if possible, without using only functions ;)) I would appreciate such comments as well, of course.
Many thanks,
Daniel
parfor has various constraints that make using scripts inside the loop generally a bad option. The main constraint is that the text of the parfor loop must be analysable to see what new variables might be created - this is referred to as "transparency" in the doc. Try using a function instead.
So, for other people or for possible hints to improve, here is how I did it with a function and loading the input variables.
a = 1;
b = 2;
save('Input.mat');
pseudo_input = NaN;%for the function
D= NaN(10,1);%result vector
parfor loop = 1:10
D(loop) = Parfor_Fun_Test(pseudo_input);
end
And the function looks like this:
function d = Parfor_Fun_Test(InputArgs)
load('Input.mat');
d = a + b ;
end
I would have preferred to also save the output, i.e. 'd', within the function and then load it in the parfor loop, but that causes an error, probably because the same file is accessed for loading and saving at the same time by different parallel workers. So this will have to do it. (This can apparently be circumvented by saving under a different name each time, but that would probably really slow down the code.)
By the way, it seems that using cells or structures is slightly faster, but then I have to write the code inside the function as this, I assume:
d = Input.a + Input.b ;
which is more ugly and more work. So I use the save and load method as above for now.
I have written a MATLAB program which performs calculations on a video. I think it is a perfect candidate to adapt to multiple cpu cores as there is a lot of averaging done. I am just sturggling with the first bit of sending each section of frames to each lab. Say (for simplicity) it is a 200 frame file. I have read some guides and using SPMD gotten this.
spmd
limitA = 1;
limitB = 200;
a = floor(((limitB-limitA)/numlabs)*(labindex-1)+limitA);
b = floor((((limitB-limitA)/numlabs)*(labindex-1)+limitA)+(((limitB-limitA)/numlabs)));
fprintf (1,'Lab %d works on [%f,%f].\n',labindex,a,b);
end
It successfully outputs that each worker will work on their respective section (Eg Lab 1 works on 1:50, Lab 2 50:100 etc).
Now where I am stuck is how do actually make my main body of code work on each Lab's section of frames. Is there a tip or an easy way to now edit my main code so it knows what frames to work on based on labindex? Adding spmd to the loop results in an error hence my question.
Thanks
Following on from what you had, don't you simply need something like this:
spmd
% each lab has its own different values for 'a' and 'b'
for idx = a:b
frame = readFrame(idx); % or whatever
newFrame = doSomethingWith(frame);
writeFrame(idx, newFrame);
end
end
Of course, if that's the sort of thing you're doing, you may need to serialize the frame writing (i.e. make sure only one process at a time is writing).
I'm going to write a program in MATLAB that takes a function, sets the value D from 10 to 100 (the for loop), integrates the function with Simpson's rule (the while loop) and then displays it. Now, this works fine for the first 7-8 values, but then it takes longer time and eventually I run out of memory, and I don't understand the reason for this. This is the code so far:
global D;
s=200;
tolerance = 9*10^(-5);
for D=10:1:100
r = Simpson(#f,0,D,s);
error = 1;
while(error>tolerance)
s = 2*s;
error = (1/15)*(Simpson(#f,0,D,s)-r);
r = Simpson(#f,0,D,s);
end
clear error;
disp(r)
end
mtrw's comment probably already answers the question in part: s should be reinitialized inside the for loop. The posted code results in s increasing irreversibly every time the error was too large, so for larger values of D the largest s so far will be used.
Additionally, since the code re-evaluates the entire integration instead of reusing the previous integration from [0, D-1] you waste lots of resources unless you want to explicitly show the error tolerance of your Simpson function - s will have to increase a lot for large D to maintain the same low error (since you integrate over a larger range you have to sum up more points).
Finally, your implementation of Simpson could of course do funny stuff as well, which no one can tell without seeing it...