Contenido principal

Run Parallel Simulations Using parsim on Model in Project

R2026b

This example uses parsim to run multiple simulations in parallel for a Monte Carlo study.

This example shows how to:

  • Run a parallel parameter sweep on a project-based model using parsim, without manually transferring dependencies to workers

  • Use fast restart and a post-processing function to reduce recompilation and output data

  • Monitor and debug parallel simulations using Simulation Manager and worker diaries

  • Visualize results live using the parallel pool ValueStore and iterate with refined sweeps

Parallel execution leverages the multiple cores of your host machine to speed up multiple simulations. These simulations can also be run in parallel on compute clusters using MATLAB® Parallel Server™. If you do not have Parallel Computing Toolbox™ or MATLAB Parallel Server, the simulations in this example run serially.

Model Overview

The model sldemo_absbrake simulates a single wheel under hard braking conditions using a simple anti-lock braking system (ABS). You can replicate the wheel to create a multi-wheel vehicle model. For more information about the model, see Model an Anti-Lock Braking System.

This model uses multiple referenced models in accelerator mode and a project startup file to load required variables into the base workspace. The model and the dependent files including cache files are part of a project sldemo_absbrake.prj.

This Monte Carlo study examines the effect of varying the desired relative slip between the road and the wheel on vehicle dynamics.

mdl = "sldemo_absbrake";
prj = openProject("RunParsimOnModelInProjectExample/sldemo_absbrake.prj");
open_system(mdl)

Configure Multiple Simulations Using SimulationInput Array

To define the parameter sweep, store the sweep values in slipsweep in the base workspace.

slipsweep = 0.16:0.001:0.24;

Store the number of simulations in numSims.

numSims = numel(slipsweep);

Use a for loop to:

  1. Create a SimulationInput object array, simin, with one element representing one simulation.

  2. Set the desired slip sweep value on each SimulationInput object.

clear simin;
simin(1:numSims) = Simulink.SimulationInput(mdl);
for idx = 1:numSims
    simin(idx) = setVariable(simin(idx),"desiredSlip",slipsweep(idx));
end

Reduce Output Data with a Post-Processing Function

The model logs several signals during simulation, including actual slip and distance traveled. For this Monte Carlo study, you need only the mean slip and stopping distance. Add a post-processing function myPostSimFcn to the SimulationInput objects to extract these metrics and write them to a ValueStore object for live plot updates. This function runs on workers after each simulation.

The function extracts three metrics from each simulation: mean slip, desired slip, and stopping distance. It also writes slip data to the current ValueStore object so the live plot updates during the run. If a simulation error occurs, the function returns the output unchanged.

simin = simin.setPostSimFcn(@(simOut,simIn) myPostSimFcn(simOut,simIn));

function out = myPostSimFcn(simOut,simIn)
    if ~isempty(simOut.ErrorMessage)
        out = simOut;
        return
    end

    logs = simOut.logsout;
    slp = getElement(logs,"slp");
    slpData = slp.Values.Data;
    out.MeanSlip = mean(slpData);

    desiredSlip = getVariable(simIn,"desiredSlip");
    out.DesiredSlip = desiredSlip;
    
    sd = getElement(logs,"Sd");
    sdData = sd.Values.Data;
    out.StoppingDistance = sdData(end);

    slipdata = getCurrentValueStore;
    if ~isempty(slipdata)
        [~, key, ~] = fileparts(tempname);
        slipdata(key) = struct("DesiredSlip",out.DesiredSlip,"MeanSlip",out.MeanSlip);
    end
end

myPostSimFcn returns a structure instead of a Simulink.SimulationOutput object, but parsim outputs a Simulink.SimulationOutput object array containing the structure fields, SimulationMetadata and ErrorMessage. If you do not need logged signals, this step reduces output size and data transferred from workers, which helps avoid out-of-memory issues.

Set Up Plot for Live Visualization

Before running parsim, create a figure for the "Desired Slip vs Mean Slip" scatter plot and register a KeyUpdatedFcn callback on the pool ValueStore if available. As each simulation completes, myPostSimFcn writes results to the ValueStore on the worker, which triggers the callback on the client and updates the plot incrementally.

fig1 = figure;
ax = axes(fig1);
xlabel(ax,"Desired Slip")
ylabel(ax,"Mean Slip")
title(ax,"Desired Slip vs Mean Slip")
grid on
hold on

Figure contains an axes object. The axes object with title Desired Slip vs Mean Slip, xlabel Desired Slip, ylabel Mean Slip contains 81 objects of type scatter.

pool = gcp("nocreate");
if ~isempty(pool)
    slipdata = pool.ValueStore;
    slipdata.KeyUpdatedFcn = @(src,key) updatePlot(src,key,ax);
end

function updatePlot(src,key,ax)
    plotdata = src(key);
    scatter(ax,plotdata.DesiredSlip,plotdata.MeanSlip,"filled",MarkerFaceColor="b")
    drawnow nocallbacks
end

Simulation Manager can also visualize post-processed results using scatter and surf plots, without the need to write values to the pool ValueStore. This example uses a manual plot to show how to retrieve results programmatically outside Simulation Manager and overlay results from multiple parsim calls.

Run Parallel Simulations with Fast Restart

Pass the SimulationInput array, simin, to parsim. parsim returns a Simulink.SimulationOutput array stored in out. Set ShowSimulationManager to on to view simulation progress.

Because non-tunable parameters do not change across simulations, set UseFastRestart to on. This reduces initialization and termination time for later simulations. For more information on fast restart, see Get Started with Fast Restart.

When you use a remote cluster, parsim automatically archives and transfers the project files, startup scripts, and shutdown scripts to workers. parsim loads the project on workers, so the startup script runs before simulations begin.

out = parsim(simin,ShowSimulationManager="on",UseFastRestart="on");
[29-Jul-2026 12:44:50] Checking for availability of parallel pool...
[29-Jul-2026 12:44:50] Starting Simulink on parallel workers...
[29-Jul-2026 12:44:57] Loading project on parallel workers...
[29-Jul-2026 12:44:57] Configuring simulation cache folder on parallel workers...
[29-Jul-2026 12:44:57] Loading model on parallel workers...
[29-Jul-2026 12:45:07] Running simulations...
[29-Jul-2026 12:47:12] Cleaning up parallel workers...

As simulations run, the scatter plot updates incrementally as each simulation completes.

Monitor Simulations in Simulation Manager

The Simulations tab shows all simulations and their current state: Compiling, Running,and Completed. Click a simulation to open the Simulation Details pane. For more information, see Simulation Manager.

Effect of Fast Restart on Initialization Times

To verify the effect of fast restart, extract initialization times from the SimulationMetadata and plot them.

metadata = [out.SimulationMetadata];
timinginfo = [metadata.TimingInfo];
initTimes = [timinginfo.InitializationElapsedWallTime];
fig2 = figure;
plot(initTimes,".-",MarkerSize=12)
title("Fast Restart Initialization Times for Parallel Simulations")
xlabel("Run Index")
ylabel("Initialization Time (s)")
grid on

Figure contains an axes object. The axes object with title Fast Restart Initialization Times for Parallel Simulations, xlabel Run Index, ylabel Initialization Time (s) contains an object of type line.

The plot shows that the first simulation on each worker requires several seconds to initialize, but later simulations take negligible initialization time because they use fast restart.

Debug Simulations Using Worker Diaries

When simulations run in parallel, SimulationMetadata contains the diary of each simulation within the ExecutionInfo structure. The Diary captures everything printed to the Command Window on workers during setup, execution, and post-processing. This helps you to debug problems such as user-written callbacks causing unintended behavior on workers.

If the simulations ran in parallel, display the diary of the first simulation.

if isfield(out(1).SimulationMetadata.ExecutionInfo,"Diary")
    disp("Simulation 1 diary:")
    disp(out(1).SimulationMetadata.ExecutionInfo.Diary)
    disp("***End of Diary***")
end
Simulation 1 diary:
### Searching for referenced models in model 'sldemo_absbrake'.
### Total of 2 models to build.
### Starting serial model build.
### Starting model reference simulation target build for: bang_bang_controller
### Successfully updated the model reference simulation target for: bang_bang_controller
### Starting model reference simulation target build for: sldemo_wheelspeed_absbrake
### Successfully updated the model reference simulation target for: sldemo_wheelspeed_absbrake

Build Summary

Model reference simulation targets:

Model                       Build Reason                                                   Status                        Build Duration
=======================================================================================================================================
bang_bang_controller        Target (bang_bang_controller_msf.mexw64) did not exist.        Code generated and compiled.  0h 0m 49.048s
sldemo_wheelspeed_absbrake  Target (sldemo_wheelspeed_absbrake_msf.mexw64) did not exist.  Code generated and compiled.  0h 0m 52.267s

2 of 2 models built (0 models already up to date)
Build duration: 0h 1m 46.398s
***End of Diary***

The diary for the first simulation shows the model reference build logs. The referenced model targets did not exist on the worker, so parsim built them from scratch. If simulation cache files are available on the client, parsim copies them to workers and skips the rebuild.

Display the diary of the last simulation.

if isfield(out(1).SimulationMetadata.ExecutionInfo,"Diary")
    disp("Simulation " + string(numSims) + " diary:")
    disp(out(numSims).SimulationMetadata.ExecutionInfo.Diary)
    disp("***End of Diary***")
end
Simulation 81 diary:
***End of Diary***

You can verify that the simulations ran using fast restart because the diary of the last simulation is empty and no build logs appear.

Run a Refined Parameter Sweep

You can repeat this process as the model evolves, to sweep over other parameters or different parameter values.

In the plot, MeanSlip varies irregularly between 0.2 and 0.21. To better understand model behavior in that range, clear the previous simulation inputs and create a finer sweep around those values.

clear simin slipsweep numSims
slipsweep = 0.197:0.0001:0.21;
numSims = numel(slipsweep);

simin(1:numSims) = Simulink.SimulationInput(mdl);
for idx = 1:numSims
    simin(idx) = setVariable(simin(idx),"desiredSlip", slipsweep(idx));
end
simin = setPostSimFcn(simin,@(simOut,simIn) myPostSimFcn(simOut,simIn));

In the Simulation Manager window, select the Reuse Window button from the Options section of the toolstrip.

fig1.WindowStyle = "normal";

Figure contains an axes object. The axes object with title Desired Slip vs Mean Slip, xlabel Desired Slip, ylabel Mean Slip contains 212 objects of type scatter.

out = parsim(simin,ShowSimulationManager="on",UseFastRestart="on")
[29-Jul-2026 12:48:15] Checking for availability of parallel pool...
[29-Jul-2026 12:48:15] Starting Simulink on parallel workers...
[29-Jul-2026 12:48:20] Loading project on parallel workers...
[29-Jul-2026 12:48:20] Configuring simulation cache folder on parallel workers...
[29-Jul-2026 12:48:20] Loading model on parallel workers...
[29-Jul-2026 12:48:31] Running simulations...
[29-Jul-2026 12:50:32] Cleaning up parallel workers...
out = 
1x131 Simulink.SimulationOutput array


When you are done running parallel simulations, you can close the parallel pool to free worker resources by deleting the pool.

delete(gcp("nocreate"));

See Also

|

Topics