%% Parallel Simulations Using Parsim: Test-Case Sweep
% This example shows how you can run multiple Simulink(R) simulations
% corresponding to different test cases in the Signal Editor block using
% SimulationInput objects and the |parsim| command. The parsim command uses
% Parallel Computing Toolbox(TM), if it is available, to run simulations in
% parallel, otherwise the simulations are run in serial.

% Copyright 2011-2018 The MathWorks, Inc.
%% Model Overview
% The model <matlab:sldemo_suspn_3dof  sldemo_suspn_3dof> shown below
% simulates the vehicle dynamics based on the road - suspension interaction
% for different road profiles. The vehicle dynamics are captured in three
% degrees of freedom: vertical displacement, roll, and pitch. The road
% profile data for the left and right tires is imported into the Signal
% Editor block as different test cases. The Road-Suspension Interaction
% subsystem calculates the suspension forces on the vehicle at the four
% tire locations based on the road data and the current vehicle state. In
% the Body Dynamics subsystem these forces and the resulting pitch and roll
% moments are used to determine the vehicle motion in three degrees of
% freedom: vertical displacement, roll, and pitch.
% 
% The suspension model is simulated using different road
% profiles to determine if the design meets desired performance goals.
% Parallel Computing Toolbox is used to speed up these multiple
% simulations, as illustrated below.
mdl               = 'sldemo_suspn_3dof';
isModelOpen       = bdIsLoaded(mdl);
open_system(mdl);

%% Set up Data Required for Multiple Simulations
% Determine the number of cases in the Signal Editor block using the
% NumberOfScenarios parameter of the Signal Editor block. 
% The number of cases is used to determine the number of 
% iterations to run in step 3.
sigEditBlk = [mdl '/Road Profiles'];
numCases   = str2double(get_param(sigEditBlk,'NumberOfScenarios'));
%%
% Create an array of <matlab:doc('Simulink.SimulationInput')
% |Simulink.SimulationInput|> objects to define the set of simulations to
% run. Each SimulationInput object corresponds to one simulation and will be 
% stored as an array in a variable, |in|. The mask parameter, |ActiveScenario|, 
% specifies the sweep value for the Signal Editor block scenario.  The active 
% scenario is set for each simulation.  
%%
for idx = numCases:-1:1
    in(idx) = Simulink.SimulationInput(mdl);
    in(idx) = setBlockParameter(in(idx), sigEditBlk, 'ActiveScenario', idx);
end
%%
% Note that specifying the model parameter on the SimulationInput object
% does not apply it to the model immediately. The specified value will be
% applied during the simulation and reverted back to its original value, if
% possible, after the simulation finishes.

%% Run Simulations in Parallel Using Parsim
% Use the <matlab:doc('parsim') |parsim|> function to execute the
% simulations in parallel. The array of SimulationInput objects, |in|,
% created in the last step is passed into the |parsim| function as the
% first argument. The output from the |parsim| command is an array of
% |Simulink.SimulationOutput| objects which is stored in the variable
% |out|. Set the 'ShowProgress' option to 'on' to print a progress of the
% simulations on the MATLAB command window.

out = parsim(in, 'ShowProgress', 'on');
%%
% Each SimulationOutput object contains the logged signal along with the
% <matlab:doc('Simulink.SimulationMetadata') |SimulationMetadata|> . When
% running multiple simulations using |parsim|, errors are captured so that
% subsequent simulations can continue to run. Any errors would show up in
% the |ErrorMessage| property of the SimulationOutput object.
%
%% Plot Results
% Plot the vertical vehicle displacement from the different simulations to
% see how the vehicle performed to the different road profiles. The
% signal is logged in the SimulationOutput object in the Dataset format.
% Use the |get| method to obtain the timeseries object containing the time
% and signal data from each element of |out|.
legend_labels = cell(1,numCases);
for i = 1:numCases
        simOut = out(i);
        ts = simOut.logsout.get('vertical_disp').Values;
        ts.plot;
        legend_labels{i} = ['Run ' num2str(i)]; 
        hold all
end
title('Response of a 3-DoF Suspension Model')
xlabel('Time (s)');
ylabel('Vehicle vertical displacement (m)');
legend(legend_labels,'Location','NorthEastOutside');

%% Close MATLAB Workers
% Last, close the parallel pool and the model if they were not previously
% opened.
if(~isModelOpen)
    close_system(mdl, 0);
end
delete(gcp('nocreate'));
displayEndOfDemoMessage(mfilename)
