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
findClonesoperation.Simulink.CloneDetection.ReplacementConfig to add conditions to the
replaceClonesoperation.
Programmatically 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
cloneResultsobject hasClones, which is a structure with two fields,SummaryandCloneGroups.cloneResults.Clones
ans = struct with fields: Summary: [1×1 struct] CloneGroups: [1×2 struct]View the
Summaryfield.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
CloneGroupswith matching subsystem patterns, fiveSimilarClones, and zeroExactClones, and the five subsystemClones.View the
CloneGroupsfield.cloneResults.Clones.CloneGroups
ans = 1×2 struct array with fields: Name Summary CloneListThe model in this example returns an array of two
CloneGroups. Each array includes theName,SummaryandCloneList.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: 1View the
CloneListof 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
CloneGroupsusing the above steps.
Programmatically Replace Clones in a Model
To replace clones in a model, use the function
Simulink.CloneDetection.replaceClones(). This function uses thecloneResultsobject from thefindClonesfunction.cloneReplacementResults = Simulink.CloneDetection.replaceClones(cloneResults)
cloneReplacementResults = ReplacementResults with properties: ReplacedClones: [1×5 struct] ExcludedClones: {}The
cloneReplacementResultsobject includes two properties,ReplacedClonesandExcludedClones.View the contents of
ReplacedClonesproperty.cloneReplacementResults.ReplacedClones
ans = 1×5 struct array with fields: Name ReferenceSubsystemThe 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 Library 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
ParamDifferenceThresholdparameter. 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
cloneDetectionSettingsobject. In this example,SSL1andSSL2are 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 andcloneDetectionSettingsobject.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
replaceClonesfunction, create a handle using theSimulink.CloneDetection.ReplacementConfig()class:cloneReplacementConfig = Simulink.CloneDetection.ReplacementConfig()
cloneReplacementConfig = ReplacementConfig with properties: LibraryNameToAddSubsystemsTo: 'newLibraryFile' IgnoredClones: {}Add subsystems to the
IgnoredCloneslist. In this example, ignoreSubsystem1to 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
replaceClonesfunction withcloneResultsandcloneReplacementConfigas the input arguments.cloneReplacementResults = Simulink.CloneDetection.replaceClones(cloneResults, cloneReplacementConfig)
cloneReplacementResults = ReplacementResults with properties: ReplacedClones: [1×4 struct] ExcludedClones: [1×1 struct]View the
ReplacedClonesproperty.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
SSL1andSSL2Reference Subsystem blocks from the reference library replaced the subsystem clones in the model.View the
ExcludedClonesproperty.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.