Matlab can't see a specific function when running in parallel - matlab

This has got me stumped.
I've written a function parObjectiveFunction that runs several simulations in parallel using createJob and createTask. It takes as an argument an objectiveFunction which is passed deeper into the code to calculate the objective function value for each simulation.
When I run parObjectiveFunction from the directory where objectiveFunction is found, it works as expected, but when I go one level up, it can no longer find objectiveFunction. The specific error I get is
Error using parallel.Job/fetchOutputs (line 1255)
An error occurred during execution of Task with ID 1.
Error in parObjectiveFunction (line 35)
taskoutput = fetchOutputs(job);
Caused by:
Error using behaviourObjective/getPenalty (line 57)
Undefined function 'objectiveFunction' for input arguments of type 'double'.
(behaviourObjective is an object)
This is weird for several reasons.
objectiveFunction is definitely in path, and when I try which objectiveFunction, it points to the correct function.
I have other components of the deeper code in other directories, and they are found without issue (they are objects rather than functions, but that shouldn't make a difference).
There's a line of code in parObjectiveFunction that runs the simulation, and when I run that directly in the matlab command window it finds objectiveFunction without issue.
I get the same results on my local machine and an HPC server.
My first thought was that the individual task might have its own path which didn't include objectiveFunction, but then that should cause problems for the other components (it doesn't). The problem is compounded because I can't work out how to debug the parallel code.
What am I doing wrong? Code that produced the issue is below.
Are there any known issues where matlab can't find functions when
using parallel processing with createJob, createTask, submit
and fetchOutputs?.
How can you debug in matlab when the issue is
only when operating in parallel? None of my print statements appear.
To make something work for external testing would take quite a bit of hacking, but for the sake of the question, the parallel function is:
function penalty = parObjectiveFunction(params, objectiveFunction, N)
% Takes a vector of input parameters, runs N instances of them in parallel
% then assesses the output through the objectiveFunction
n = params(1);
np = params(2);
ees = params(3);
ms = params(4);
cct = params(5);
wt = params(6);
vf = params(7);
dt = 0.001;
bt = 10;
t = 10;
c = parcluster;
job = createJob(c);
testFunction = #(run_number)behaviourObjective(objectiveFunction,n,np,ees,ms,cct,wt,vf,t,dt,bt,run_number);
for i = 1:N
createTask(job, testFunction, 1, {i});
end
submit(job);
wait(job);
taskoutput = fetchOutputs(job);
pensum = 0;
for i = 1:N
pensum = pensum + taskoutput{i}.penalty;
end
penalty = pensum/N;
end

It sounds like you need to attach some additional files to your job. You can see which files were picked up by MATLAB's dependency analysis by running listAutoAttachedFiles, i.e.
job.listAutoAttachedFiles()
If this isn't showing your objectiveFunction, then you can manually attach this by modifying the AttachedFiles property of the job.
It seems as though objectiveFunction is a function_handle though, so you might need to something like this:
f = functions(objectiveFunction)
job.AttachedFiles = {f.file}

Related

Why does geometryFromEdges give a parse error when used in parfor on a thread-based pool?

I want to solve multiple PDEs in parallel on threads using the Parallel Computing Toolbox in Matlab. I have the following code:
delete(gcp('nocreate'));
parpool('threads')
parfor i = 1:1
model = createpde();
R1 = [3,4,0,1,1,0,1,1,0,0]';
sf = 'R1';
ns = char('R1');
ns = ns';
gm = R1;
g = decsg(gm,sf,ns);
geometryFromEdges(model, g);
end
This results in the following error:
Error using pde.EquationModel/geometryFromEdges
The specified superclass 'pde.GeometricModel' contains a parse error,
cannot be found on MATLAB's search path, or is shadowed by another file
with the same name.
Error in codeFile (line 4)
parfor i = 1:1
When I change the parfor into a for, the code runs (and consequently I am able to numerically solve PDEs). The problem does not happen when I leave out parpool('threads'), and the parallel computations are done on processes.
I have already restored the default Matlab paths, the solution suggested for this type of error.
What could the problem be?
MATLAB only supports a subset of functions in thread-based parallel computation, less than is supported in process-based parallel computation. You can find the list here. It appears that geometryFromEdges isn't one of them.

Creating a Closure in Matlab

I've have functions in Matlab that takes two arguments, an image and a kernel and does various image processing applications on it. The signature is Gen_Filt(kernel,img) for various filtering operations. I'm trying to create a second function that closes over the filterings operation with a specific kernel so it can do a particular operation with images.
function [closure] =Close_Over(General,kernel)
function[out_img]=inner(img)
out_img=General(kernel,img);
end
closure=#inner;
end
So this will take a specific type of filtering operation (Gen_Filt signature) and a specific kernel and return a function handler with the kernel bound to that specific filtering operation. However, it seems to call the filtering operation function and gives the following error:
Error in Gen_Filt (line 61)
out_img=conv2(img,kernel,'same');
which makes me think it's trying to evaluate the filtering operation Gen_Filt before I can call the handler with a specific image argument.
Do I understand the problem correctly and/or am I making a mistake?
As others have mentioned there are problems with the code you have provided. But, for purposes of answering the title of the post, here is how you create a closure, using nested functions to capture variables in MATLAB.
function fun = createPlusOneFunc
x = 0; % x is captured
fun = #inner
function out = inner(y)
x = x+y;
out = x;
end
end
>> fun = createPlusOneFunc();
>> out = fun(1) % Increments captured variable state by 1.
>> out = fun(2) % Increments captured variable state by 2.

Parallel Computing in MATLAB using drange

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

(Matlab) Option to turn pause on and off from output callback of system(string)?

For an aerospace course aerelasticity I am doing an assignment with Nastran in Matlab (by using system(command) and bdf as input file).
I have attached a piece of my code as explanation. In this case the program Nastran produces a punch file (text) with displacements.
Currently the problem is that Matlab disregards the time Nastran needs for analysis to produce this punch file and continues on with the loop, however this punch file is not created yet so matlab turns out an error saying it does not exist and stops the loop.
I "have" a workaround for this by setting the pause times manually found from running it manually for increasing mesh sizes, this gives me at least some data on mesh convergence, however this is not a suitable method to use the rest of the assignment as it will take way too much time, therefore it must be automated.
I was thinking of setting a condition temporarily pausing the loop if the punch file does not exist and turning on again if it exists, however I got stuck with using a pause condition inside a while loop alltogether, it does not seem a solution to me.
Do you have any suggestions / ideas on what I could use / do how to get around this problem
or
know if there is a way to sent a callback from system(nastran) which i can use to create a condition to control the loop or something in that direction?
The following is a piece of code of the created function which turns out the Residual Mean squared error of the mesh which I use to see if the mesh converges:
%% Run Nastran
system('"C:\Users\$$$$\AppData\Roaming\MSC.Software\MSC_Nastran_Student_Edition\2014\Nastran\bin\nastranw.exe" nastranfile.bdf mem=1gb'); % Run the created bdf file
pause(15);
%% Read results and save all relevant results
fpc = fopen('nastranfile.pch','r')
line = 0;
for j=1:6;
line = line+1;
fgets(fpc);
end
line;
counter=0;
data = [];
while ~feof(fpc)
counter= counter+1;
str = fgets(fpc);
line=line+1;
str = str(61:73);
data(counter) = str2num(str)
fgets(fpc);
line=line+1;
end
line;
fclose(fpc);
% Find RMSE
mdl = fitlm(1:length(data),data);
RMEA = mdl.Rsquared.Adjusted;
RMSE = mdl.RMSE;

How can I get a waitbar to work in Matlab?

I want to have a waitbar for an operation that takes quite a while. Here is my code:
h = waitbar(0,'Please wait...');
for i=1:counterend
waitbar(i/waitbarcounter)
Atemp = At+i*step;
handle = #(M) 1/M^2*((2/(gamma+1))*(1+(gamma-1)*M^2/2))^((gamma+1)/(gamma-1))-(Atemp/At)^2;
Mach = fzero(handle, 5);
Aplot(i) = Atemp/At;
Tplot(i) = Tc / (1+(gamma-1)*Mach^2/2);
Mplot(i) = Mach;
plot(Aplot, Tplot)
end
close(h)
The error Matlab gives is:
??? Error using ==> waitbar at 249
Improper arguments for waitbar
After investigation, I am sure that this error must occur because of the sorrounding code in the loop.
Note: The loop works fine without the waitbar.
Running
counterend = 10000;
>> h = waitbar(0,'Please wait...');
for i=1:counterend
waitbar(i/counterend)
end
close(h);
Works as expected on 2007a / Windows XP.
On a side note, it would help knowing what countered is defined as. Something quick to check would be to ensure that you are not passing it a CELL.
Running
counterend = {10000};
h = waitbar(0,'Please wait...');
for i=1:counterend
waitbar(i/counterend)
end
close(h);
Yields a different error (see below) in 2007a, but this error message may have changed in 2008.
??? Undefined function or method
'_colonobj' for input arguments of
type 'cell'.
My last bit of advice would be caution you on the use of waitbar for large arrays/data sets. While I think it is important to inform the user of the progress, to me there is also a concern for how much time is added to the loop. Working with arrays that have 100k+ entries, I became a religious user of the Profiler to see where the time was really being spent. I can tell you the time is not in the calculation of the i/X, it was all in updating the waitbar's display. To soften the blow of the update/drawnow, I only updated the waitbar every 100 to 1000 entry which helped tremendously.
EDIT: Updated response to match latest code
I first started to attack this problem at the anonymous function, having problems with them in the past it's a personal vendetta of mine. When looking into the function I found that you are using gamma, do you have this defined as a constant (constant to the loop / function)? The reason I ask is that 'gamma' is a Matlab function and was giving me errors when trying to run your function by itself. Below I have modified you code slightly and this does run fine here. If any of the assumptions I have made are wrong please let me know.
In addition, if you did intend to use the gamma function, your function is missing any arguments to it. Hope this helps!
clc
h = waitbar(0,'Please wait...');
counterend = 1000;
waitbarcounter = counterend;
g_amma = 7;
At = 34;
step = 2;
Tc = 42;
for i=1:counterend
waitbar(i/waitbarcounter)
Atemp = At+i*step;
handle = #(M) 1/M^2*((2/(g_amma+1))*(1+(g_amma-1)*M^2/2))^((g_amma+1)/(g_amma-1))-(Atemp/At)^2;
Mach = fzero(handle, 5);
Aplot(i) = Atemp/At;
Tplot(i) = Tc / (1+(g_amma-1)*Mach^2/2);
Mplot(i) = Mach;
plot(Aplot, Tplot)
end
close(h)
Regards,
Adam
I have checked waitbar on R2008b. So far, the only ways I was able to reproduce your error was by having i/counterend evaluate to an array with multiple rows (a 1x2 vector gives interesting results), and by closing the waitbar before calling waitbar(i/counterend).
I do not get any error running the following:
h = waitbar(0,'Please wait...');
counterend = 1000;
for i=1:counterend
waitbar(i/counterend)
end
close(h)
Could you make sure that the small example above runs without error? If yes, please check that the waitbar is not closed during the execution of the loop, and that counterend is a scalar (use dbstop if error to stop execution of your code at the time of the error).
If the above example does not work without error, you should use which waitbar to check that you are using Matlab's waitbar, and not any of the many updated version from the Matlab File Exchange.
Running
counterned=1000;
h = waitbar(0,'Please wait...');
for i=1:counterend
waitbar(i/counterend)
end
close(h)
works perfectly as expected on MATLAB R2009a on Windows XP.
The above runs fine on R2008a on XP also.
However, you get the error you describe if you kill the waitbar window before the next waitbar command comes around. If you want to be nice about it you should check if the handle h is still valid before issuing waitbar.
I prefer to use progressbar written by Steve Hoelzer on the MATLAB FEX. I haven't had any problems with it.
Your suppose to use the handle that you created with your first line of code when you want to update the waiter,
Waiter(it/itmax,h,'progress')