Can I force Matlab to wait 'til it finishes one command to run another?
72 views (last 30 days)
Show older comments
I have a script that loads a SimBiology model using the simbiology() command. Then I try to get a handle for the model
simbiology('mymodel.sbproj'); % There are reasons why I use simbiology and not sbioloadproject
sbr = sbioroot;
mdls = sbr.models;
nmdls = numel(mdls);
mc = mdls(nmdls);
The problem is when I first try to get mdls. I get an empty array. Apparently, the model is still loading when the sbr=sbioroot and mdls = sbr.models commands run.
In windows command line files, you can use
START /WAIT myprogram.exe
to force myprogram.exe to finish running before going on the next line. Is there a similar artifice in Matab/Simbiology? Something like
finish('simbiology('mymodel.sbproj')' ;
% or
whilerunning
simbiology('mymodel.sbproj');
end
I keep thinking that there's an easy way that I've forgotten...
The above is a general case. Of course, if simbiology() were re-written to return the model handle, and when the handle was requested, would not allow the script to proceed until the model was loaded, it would be great. Logical, too, because generally when you're loading a model you want to do something with that model before proceeding.
mc = simbiology('mymodel.sbproj'); % This solves the specific problem!
% or
mc = simbiology('mymodel.sbproj','WaitToComplete'); % or this
10 Comments
Accepted Answer
Arthur Goldsipe
on 19 Sep 2019
Hi Jim,
The previous responses are correct: The simbiology command returns before the desktop completely loads the project, because the desktop is operating on different threads. So, welcome to the world of multi-threaded / parallel / asynchronous / <insert buzzword> complexity! Believe me, it makes life harder for SimBiology's developers, too. But hopefully you're mostly seeing the benefits of us living in that complexity and hiding it from you as much as possible.
Right now, there's one-line command that does what you want, but I'll suggest a workaround below. But thinking longer term, we hope to eliminate the need to open a project in the desktop just to preserve the diagram. If you can think of other reasons why it's important to know when a project is fully loaded, let us know so we can address those workflows, too.
Anyway, if all you care about is whether the model is accessible from the MATLAB command prompt (and not whether the desktop has completely finished loading the project), I came up with a solution (pasted below) that uses timer objects to periodically check whether the models have been loaded.
Here's the function. It takes the name of a project, the name of a variable to assign models to in the base workspace, and an optional callback that you can use to execute tasks that take the models as input arguments. So here's an example usage that simulates the Lotka demo project as soon as it's loaded (assigning the result to the base workspace variable sd): simbiologyNotify('lotka.sbproj', 'models', @(m) assignin('base', 'sd', sbiosimulate(m)))
function simbiologyNotify(projectName, varName, callback)
if ~exist('callback', 'var')
callback = @(models) [];
end
root = sbioroot;
oldModels = root.Models;
t = timer('ExecutionMode', 'fixedSpacing');
t.TimerFcn = @(t,e) timerFcn(t, root, oldModels, varName, callback);
simbiology(projectName);
start(t);
end
function timerFcn(t, root, oldModels, varName, callback)
models = setdiff(root.Models, oldModels);
if isempty(models)
return
end
beep
fprintf('Models have been loaded. Assigning to base workspace variable "%s".\n', varName);
assignin('base', varName, models);
stop(t);
delete(t);
callback(models);
end
Note that you can't directly call this function from a script or function. If you do, you'll block the MATLAB interpreter, and that will prevent the desktop from loading the project. So you have to start thinking about asynchronous tasks the way we developers do: as a series of callback functions that get called as soon as their preconditions are met.
And one last note: If you really need to know whether the desktop has fully loaded the project into the GUI, I'll see if there's a way to get that information.
-Arthur
10 Comments
Arthur Goldsipe
on 26 May 2020
The reason that SimBiologyNotify doesn't just return the model as an output is because the model may not be loaded yet when the function exits. I don't know how to write the function in a way that waits for the the model to load before it exits. All the things I can think of to try (like pause) are things you tried that can end up preventing/delaying the loading of the model.
And the reason that TimerFcn doesn't just return the model as an output is that it has nowhere to return that output to. TimerFcn is called by the timer object, and that object doesn't provide any way for a TimerFcn to return results to the user. So I use assignin as a way of getting that information back to you in the base workspace.
I guess the big picture here is that I needed to think differently about how to write code that works with the SimBiology graphical interface. Instead of writing precedural code (do A, then B, then C), I need to write "event-driven code." When an event happens (in this case, when a model gets loaded), it calls a function that I specify. That function does whatever task I want to do next. But I leave the details of when to execute this code to someone else (in this case, to SimBiologyNotify and its Timer). Whenever that task gets executed (let's assume it's a simulation), then we presumably want to store the results somewhere we can access them later. That could be saving them to a file, assigning them to a variable in the base workspace, plotting them, or passing the results on to the next step of your analysis. But we can't just return those results as an output in an event-driven world, unless the machinery that drives the events specifically supports it.
More Answers (0)
See Also
Categories
Find more on Build Models in Help Center and File Exchange
Products
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!