Today I am happy to welcome guest blogger Reid Spence. Reid helps Simulink users running simulations in parallel using functions like parsim or batchsim. In this post, he shares best practices to manage the data needed by Simulink models in the context of parallel simulations. You can download the examples used in this blog post here. The Problem
Did you ever run into a situation where you have a model that simulates successfully when using the sim command or the play button, but errors out when simulated using parsim and the Parallel Computing Toolbox? This can happen for various reasons, let's begin with the one I see the most often. Let's start with this simple model, which uses 3 variables defined in the MATLAB base workspace: k, c, and m:
I can successfully simulate this model:
mdl = 'simpleSuspension';
in(1:2) = Simulink.SimulationInput(mdl);
in(1) = in(1).setVariable('k',10);
in(2) = in(2).setVariable('k',20);
out = sim(in,'ShowProgress','off');
plot(out(1).logsout.get('x').Values); hold on
plot(out(2).logsout.get('x').Values);
Now, let's try to use parsim to simulate the model in parallel with different values of k:
mdl = 'simpleSuspension';
in(1:2) = Simulink.SimulationInput(mdl);
in(1) = in(1).setVariable('k',10);
in(2) = in(2).setVariable('k',20);
out = parsim(in,'ShowProgress','on','ShowSimulationManager','on');
[20-Nov-2022 11:25:57] Checking for availability of parallel pool...
Starting parallel pool (parpool) using the 'Processes' profile ...
Connected to the parallel pool (number of workers: 2).
[20-Nov-2022 11:26:19] Starting Simulink on parallel workers...
[20-Nov-2022 11:26:26] Configuring simulation cache folder on parallel workers...
[20-Nov-2022 11:26:27] Loading model on parallel workers...
[20-Nov-2022 11:26:32] Running simulations...
Warning: One or more simulations completed with errors. For more information, inspect the SimulationOutput objects at these indices:
[1 2]
[20-Nov-2022 11:26:34] Cleaning up parallel workers...
Warning: Error in the simulation was caused by missing variable 'm'. Set "TransferBaseWorkspaceVariables" option to "on" to fix the issue.
As you can see, the simulations errored out. We can look at the Simulation Manager to learn more on the error. What Happened?
Let's look in details at what happened. For that, we can look at the progress displayed by parsim. The first thing we see is that parsim starts a parallel pool.
Starting a parallel pool means the MATLAB session you are interacting with (the Client in the next image) is launching new MATLAB sessions in the background, without the user interface (the Workers in the next image)
Once the parallel workers are up and running, we start Simulink on each worker:
To avoid conflicts between workers, we configure each of them to use a different cache folder:
The model is loaded on each worker:
Finally, the model is being simulated:
Hopefully, you see where I am going with that... the parallel workers need to be configured! In the above example, "be configured" means loading variables in the base workspace. If you are dealing with large complex models, you probably understand that "be configured" can mean a lot of things.
What we will discuss in this post are the different options offered by parsim and batchsim to automate the configuration of the parallel workers
Multiple Options to Configure Parallel Workers
Articles have been published on this blog on the topic of parallel simulations:
If you go through those posts, you will see that the process of configuring parallel workers have been significantly simplified throughout the years. As of MATLAB R2022b, parsim offers many options to automatically configure the parallel workers.
Here is a picture giving an overview of what parsim configures automatically versus what you can optionally opt-in.
In the next sections, we will cover the following options to configure parallel workers:
- Data Dictionary and Model Workspace
- Transferring the Client Base Workspace
- Project Startup Tasks
- Model Callbacks
- SetupFcn Callback
- preSimFcn Callback
Data Dictionary and Model Workspace
If all your model is missing is data, one option is to store the data in a Data Dictionary or in the Model Workspace. That way parsim will automatically make the associated files available to the parallel workers. With a data dictionary, all you need to do is use setVariable to specify the variables to be different in each simulation: mdl = 'simpleSuspensionWithSldd';
in(1:2) = Simulink.SimulationInput(mdl);
in(1) = in(1).setVariable('k',10);
in(2) = in(2).setVariable('k',20);
out = parsim(in,'ShowProgress','off');
Transferring the Client Base Workspace
If, for some reason, you cannot or don't want to use a data dictionary, it is possible is to use the TransferBaseWorkspaceVariables option of parsim and batchsim to send a copy of the client's base workspace to the workers. mdl = 'simpleSuspension';
in(1:2) = Simulink.SimulationInput(mdl);
in(1) = in(1).setVariable('k',10);
in(2) = in(2).setVariable('k',20);
out = parsim(in,'TransferBaseWorkspaceVariables','on','ShowProgress','on');
[20-Nov-2022 11:26:53] Checking for availability of parallel pool...
[20-Nov-2022 11:26:53] Starting Simulink on parallel workers...
[20-Nov-2022 11:26:53] Configuring simulation cache folder on parallel workers...
[20-Nov-2022 11:26:53] Transferring base workspace variables used in the model to parallel workers...
[20-Nov-2022 11:26:53] Loading model on parallel workers...
[20-Nov-2022 11:26:54] Running simulations...
[20-Nov-2022 11:26:55] Completed 1 of 2 simulation runs
[20-Nov-2022 11:26:55] Completed 2 of 2 simulation runs
[20-Nov-2022 11:26:55] Cleaning up parallel workers...
What are the pros and cons of this approach?
- Pro: Simplicity, one additional argument and we automatically copy the entire client base workspace to the workers.
- Con: Possibly inefficient if the client session has many large variables in its base workspace that are not needed by the simulation.
Project Startup Tasks
If your model is part of a MATLAB Project and the MATLAB Project is open on the client, parsim will transfer and open the project on the the workers, which will execute the Project Startup Tasks. openProject('ParsimDataManagment.prj');
mdl = 'simpleSuspension';
in(1:2) = Simulink.SimulationInput(mdl);
in(1) = in(1).setVariable('k',10);
in(2) = in(2).setVariable('k',20);
out = parsim(in,'ShowProgress','off');
Model Callbacks
If you are not using a MATLAB Project, another option is to use callback functions such as the model preLoadFcn. For my example model, I can define k, c and m that way: When the model will be loaded on the workers, the preLoadFcn callback will execute and define the variables needed by the model.
mdl = 'simpleSuspensionWithCallback';
in(1:2) = Simulink.SimulationInput(mdl);
in(1) = in(1).setVariable('k',10);
in(2) = in(2).setVariable('k',20);
out = parsim(in,'ShowProgress','off');
SetupFcn Callback
If none of the above works for you, parsim offers a SetupFcn callback that can be used to run any additional custom setup on the workers. The setupFcn callback will be run once per worker. As a simple example, the SetupFcn can evaluate code in the worker's Base Workspace. mdl = 'simpleSuspension';
in(1:2) = Simulink.SimulationInput(mdl);
in(1) = in(1).setVariable('k',10);
in(2) = in(2).setVariable('k',20);
out = parsim(in, 'SetupFcn',@()mySetupFunction());
[20-Nov-2022 11:27:08] Checking for availability of parallel pool...
[20-Nov-2022 11:27:08] Starting Simulink on parallel workers...
Analyzing and transferring files to the workers ...done.
[20-Nov-2022 11:27:10] Configuring simulation cache folder on parallel workers...
[20-Nov-2022 11:27:10] Running SetupFcn on parallel workers...
[20-Nov-2022 11:27:12] Loading model on parallel workers...
[20-Nov-2022 11:27:13] Running simulations...
[20-Nov-2022 11:27:13] Completed 1 of 2 simulation runs
[20-Nov-2022 11:27:13] Completed 2 of 2 simulation runs
[20-Nov-2022 11:27:13] Cleaning up parallel workers...
With the setup function being:
preSimFcn Callback
In addition to the SetupFcn callback that runs once per worker, the SimulationInput object offers the preSimFcn callback to run any MATLAB code on the workers before each simulation. The SimulationInput object is passed as an argument so we can make changes to the object on the worker. We can use preSimFcn's to parallelize time intensive setups. The flexibility of the preSimFcn can also make it ideal for integrating legacy MATLAB code you may have for setting up simulation runs. mdl = 'simpleSuspension';
in(1:2) = Simulink.SimulationInput(mdl);
in(1) = in(1).setPreSimFcn(@(in) presim(in,10));
in(2) = in(2).setPreSimFcn(@(in) presim(in,20));
out = parsim(in);
[20-Nov-2022 11:27:15] Checking for availability of parallel pool...
[20-Nov-2022 11:27:15] Starting Simulink on parallel workers...
[20-Nov-2022 11:27:15] Configuring simulation cache folder on parallel workers...
[20-Nov-2022 11:27:15] Loading model on parallel workers...
[20-Nov-2022 11:27:16] Running simulations...
[20-Nov-2022 11:27:17] Completed 1 of 2 simulation runs
[20-Nov-2022 11:27:17] Completed 2 of 2 simulation runs
[20-Nov-2022 11:27:17] Cleaning up parallel workers...
With the presim function:
Now it’s your turn
Let us know in the comments below which combinations of the methods listed in this post you use to set up your parallel simulations.
Comments
To leave a comment, please click here to sign in to your MathWorks Account or create a new one.