Detect and Replace Subsystem Clones Programmatically
Clones are modeling patterns that have identical block types and connections. You can refactor your model by creating library blocks from subsystem clones and replacing the clones with links to those library blocks, which enable you to reuse components. For more information about clones, see Enable Component Reuse by Using Clone Detection.
Programmatically checking for clones during the model submission process helps you identify opportunities to reuse subsystems before the model is deployed into the main product branch. When updating your model, you can use the Clone Detector app and clone detector API simultaneously. When you use the clone detector API, the detected clones appear in the Simulink® Editor.
This example shows how to use the clone detection APIs to identify and replace clones in a single model by creating a library file with subsystem blocks and replacing the clones with links to blocks in the library file.
In this example, you learn how to use:
Simulink.CloneDetection.findClones to find clones in a model.
Simulink.CloneDetection.replaceClones to replace clones in a model.
Simulink.CloneDetection.checkEquivalency to check the equivalency of the updated model with the original model.
Simulink.CloneDetection.Settings to add conditions to the
findClones
operation.Simulink.CloneDetection.ReplacementConfig to add conditions to the
replaceClones
operation.
Identify Clones in a Model
Open the model
ex_detect_clones_B
.openExample('ex_detect_clones_B');
Save the model in the current working directory.
To find subsystem clones, use the function
Simulink.CloneDetection.findClones()
. This function creates an object calledcloneResults
.cloneResults = Simulink.CloneDetection.findClones('ex_detect_clones_B')
cloneResults = Results with properties: Clones: [1×1 struct] ExceptionLog: ''
The
cloneResults
object hasClones
, which is a structure with two fields,Summary
andCloneGroups
.cloneResults.Clones
ans = struct with fields: Summary: [1×1 struct] CloneGroups: [1×2 struct]
View the
Summary
field.cloneResults.Clones.Summary
ans = struct with fields: CloneGroups: 2 SimilarClones: 5 ExactClones: 0 Clones: 5 PotentialReusePercentage: [1×1 struct]
In this example, the model has two
CloneGroups
with matching subsystem patterns, fiveSimilarClones
, and zeroExactClones
, and the five subsystemClones
.View the
CloneGroups
field.cloneResults.Clones.CloneGroups
ans = 1×2 struct array with fields: Name Summary CloneList
The model in this example returns an array of two
CloneGroups
. Each array includes theName
,Summary
andCloneList
.View the details of first clone group.
cloneResults.Clones.CloneGroups(1)
ans = struct with fields: Name: 'Similar Clone Group 1' Summary: [1×1 struct] CloneList: {3×1 cell}
View the
Summary
.cloneResults.Clones.CloneGroups(1).Summary
ans = struct with fields: ParameterDifferences: [1×1 struct] Clones: 3 BlocksPerClone: 8 CloneType: 'Similar' BlockDifference: 1
View the
CloneList
of the first CloneGroup.cloneResults.Clones.CloneGroups(1).CloneList
ans = 3×1 cell array {'ex_detect_clones_B/Subsystem1'} {'ex_detect_clones_B/Subsystem2'} {'ex_detect_clones_B/Subsystem3'}
Similarly, You can find the results of other
CloneGroups
using the above steps.
Replace Clones in a Model
To replace clones in a model, use the function
Simulink.CloneDetection.replaceClones()
. This function uses thecloneResults
object from thefindClones
function.cloneReplacementResults = Simulink.CloneDetection.replaceClones(cloneResults)
cloneReplacementResults = ReplacementResults with properties: ReplacedClones: [1×5 struct] ExcludedClones: {}
The
cloneReplacementResults
object includes two properties,ReplacedClones
andExcludedClones
.View the contents of
ReplacedClones
property.cloneReplacementResults.ReplacedClones
ans = 1×5 struct array with fields: Name ReferenceSubsystem
The 1-by-5 array indicates that the function replaced five subsystem clones in the model.
View the list of replaced subsystem clones.
struct2table(cloneReplacementResults.ReplacedClones)
ans = 5×2 table Name ReferenceSubsystem ___________________________________ _____________________________ {'ex_detect_clones_B/Subsystem1'} {'newLibraryFile/Subsystem1'} {'ex_detect_clones_B/Subsystem2'} {'newLibraryFile/Subsystem1'} {'ex_detect_clones_B/Subsystem3'} {'newLibraryFile/Subsystem1'} {'ex_detect_clones_B/SS3' } {'newLibraryFile/SS1' } {'ex_detect_clones_B/SS4' } {'newLibraryFile/SS1' }
Identify Clones Using Subsystem Reference Blocks
Save the model and library file in the current working directory.
ex_detect_clones_E clones_library
Use the
Simulink.CloneDetection.Settings()
class to create an object that specifies certain conditions for finding clones in a model.cloneDetectionSettings = Simulink.CloneDetection.Settings()
cloneDetectionSettings = Settings with properties: IgnoreSignalName: 0 IgnoreBlockProperty: 0 ExcludeModelReferences: 0 ExcludeLibraryLinks: 0 ExcludeInactiveRegions: 0 SelectedSystemBoundary: '' DetectClonesAcrossModel: 0 FindClonesRecursivelyInFolders: 1 ParamDifferenceThreshold: 50 ReplaceExactClonesWithSubsystemReference: 0 Libraries: {} Folders: {}
Set the
ParamDifferenceThreshold
parameter. This parameter specifies the number of differences that subsystems must have to be considered clones.cloneDetectionSettings.ParamDifferenceThreshold = 0
cloneDetectionSettings = Settings with properties: IgnoreSignalName: 0 IgnoreBlockProperty: 0 ExcludeModelReferences: 0 ExcludeLibraryLinks: 0 ExcludeInactiveRegions: 0 SelectedSystemBoundary: '' DetectClonesAcrossModel: 0 FindClonesRecursivelyInFolders: 1 ParamDifferenceThreshold: 0 ReplaceExactClonesWithSubsystemReference: 0 Libraries: {} Folders: {}
A value of 0 indicates the subsystems must be identical.
Add a reference library file to use to match the clone patterns in the
cloneDetectionSettings
object. In this example,SSL1
andSSL2
are subsystem patterns in the libraryclones_library
.cloneDetectionSettings = cloneDetectionSettings.addLibraries('clones_library')
cloneDetectionSettings = Settings with properties: IgnoreSignalName: 1 IgnoreBlockProperty: 0 ExcludeModelReferences: 0 ExcludeLibraryLinks: 0 ExcludeInactiveRegions: 0 SelectedSystemBoundary: '' DetectClonesAcrossModel: 0 FindClonesRecursivelyInFolders: 1 ParamDifferenceThreshold: 50 ReplaceExactClonesWithSubsystemReference: 0 Libraries: {'C:\Users\Examples\clones_library.slx'} Folders: {}
To find clones, execute the function
Simulink.CloneDetection.findClones()
using the model name andcloneDetectionSettings
object.cloneResults = Simulink.CloneDetection.findClones('ex_detect_clones_E', cloneDetectionSettings)
cloneResults = Results with properties: Clones: [1×1 struct]
cloneResults.Clones.Summary
ans = struct with fields: CloneGroups: 2 SimilarClones: 5 ExactClones: 0 Clones: 5 PotentialReusePercentage: [1×1 struct]
In this example, the model has two
CloneGroups
, fiveSimilarClones
, zeroExactClones
, and five subsystemClones
.View the details of first
CloneGroup
.cloneResults.Clones.CloneGroups(1)
ans = struct with fields: Name: 'clones_library/SSL1' Summary: [1×1 struct] CloneList: {3×1 cell}
Replace Clones with Conditions
1. To specify conditions for
replaceClones
function, create a handle using theSimulink.CloneDetection.ReplacementConfig()
class:cloneReplacementConfig = Simulink.CloneDetection.ReplacementConfig()
cloneReplacementConfig = ReplacementConfig with properties: LibraryNameToAddSubsystemsTo: 'newLibraryFile' IgnoredClones: {}
Add subsystems to the
IgnoredClones
list. In this example, ignoreSubsystem1
to avoid replacing it with a clone.cloneReplacementConfig.addCloneToIgnoreList('ex_detect_clones_E/Subsystem1')
ans = ReplacementConfig with properties: LibraryNameToAddSubsystemsTo: 'newLibraryFile' IgnoredClones: {'ex_detect_clones_E/Subsystem1'}
To replace clones, use the
replaceClones
function withcloneResults
andcloneReplacementConfig
as the input arguments.cloneReplacementResults = Simulink.CloneDetection.replaceClones(cloneResults, cloneReplacementConfig)
cloneReplacementResults = ReplacementResults with properties: ReplacedClones: [1×4 struct] ExcludedClones: [1×1 struct]
View the
ReplacedClones
property.struct2table(cloneReplacementResults.ReplacedClones)
ans = 4×2 table Name ReferenceSubsystem ___________________________________ __________________ {'ex_detect_clones_E/SS3' } {'clones_library/SSL1'} {'ex_detect_clones_E/SS4' } {'clones_library/SSL1'} {'ex_detect_clones_E/Subsystem1'} {'clones_library/SSL2'} {'ex_detect_clones_E/Subsystem2'} {'clones_library/SSL2'}
The
SSL1
andSSL2
Reference Subsystem blocks from the reference library replaced the subsystem clones in the model.View the
ExcludedClones
property.struct2table(cloneReplacementResults.ExcludedClones)
ans = 1×2 table Name ReferenceSubsystem ___________________________________ __________________ {'ex_detect_clones_E/Subsystem1'} {'unselected'}
Check the Equivalency of the Model
You can check if the updated model is equivalent with the original model by using the
Simulink.CloneDetection.checkEquivalency()
function. This
function uses Simulink Test Manager to compare the simulation results of the saved
original model with the updated model and saves the results in the
checkEquiResults
handle.
checkEquiResults = Simulink.CloneDetection.checkEquivalency(cloneReplacementResults)
[21-Dec-2020 16:35:13] Running simulations... [21-Dec-2020 16:35:32] Completed 1 of 2 simulation runs [21-Dec-2020 16:35:33] Completed 2 of 2 simulation runs checkEquiResults = EquivalencyCheckResults with properties: List: [1×1 struct]
View the check equivalence results.
checkEquiResults.List
ans = struct with fields: IsEquivalencyCheckPassed: 1 OriginalModel: 'm2m_ex_detect_clones_E/snapshot_2020_12_21_16_35_06_ex_detect_clones_E.slx' UpdatedModel: 'ex_detect_clones_E.slx'
The property IsEquivalencyCheckPassed
is 1, which suggests that the
models are equivalent. The OriginalModel
and
UpdatedModel
properties show which models the function
checked.