Automated computation of N^2 matrix: issue with scripted

Systems engineering related questions and discussions.

Moderator: Moderators

Automated computation of N^2 matrix: issue with scripted

Postby mzampare@eso.org » Wed Nov 24, 2021 9:25 am

Dear all,
we would like to produce a dependency matrix which displays connections between blocks (actually part properties) using ports, possibly nested ones.
A model example is attached for completeness and the primary image here below shows the model with the desired outcome:

N2Matrix.png


The problem is that we cannot find an easy way to achieve that.
The code which we came up with appears a bit of a twisted monstrosity and we think there must be some better way.

Code: Select all

#
# Script to find connections through ports
# used in dependency table to build an n-square matrix with
# interfaces between blocks (there is an interface if there is a connectorthrough ports).
#
# Expects two arguments:
#   - inputElement: an element to search for connectors
#   - metachainResult:
#     just for comparison, the result of a metachain that tries to
#     do a similar job:
#       Block [Class]   ->    Owned Port
#       Port            ->    End
#       ConnectorEnd    ->    Owner
#       Connector       ->    End
#       ConnectorEnd    ->    Role
#       Port            ->    Owner
#     The corresponding code is normally commented out and shall be uncommented
#     just if we want to see what the metachain would do.
#
from com.nomagic.magicdraw.core       import Application
from com.nomagic.magicdraw.core       import Project
from com.nomagic.uml2.ext.jmi.helpers import StereotypesHelper

res=""         # Initialize the final result to bereturned

# --- Support functions ---

#
# utility function for compact logging and
# to switch on/off logging of diagnostic messages
#
def log(message):                                         
  logging = True
  if logging :
       Application.getInstance().getGUILog().log(message)

#
# A recursive function to build a list     
# of all nested ports given an initial set of ports
# ar returned by element.getOwnedPort()
#
def buildResursiveListOfPorts(ports):
   log("+++++ buildRecursiveListOfPorts") 
   
   # First puts the given ports in a list
   resultPorts = list(ports)             
   
   # Then iterates over all given ports to find nested ports
   for port in ports:
      log("+++ Port: " + port.getHumanName())               
     
      # Only ports of type "Interface Block" can have nested ports
      portType = port.getType()     
      if portType != None:     
         log("+++ Port not none: " + portType.getHumanName())
         if portType.getHumanType() == "Interface Block":
            log("+++ Port is Interface Block")
            subPorts = list(portType.getOwnedPort())           
            # If there are really snested ports, I call recursively the
            # function to find even more nested ports and I extend the given list
            # with what I found
            if len(subPorts) > 0:
               resultPorts.extend(buildResursiveListOfPorts(subPorts))
               for subPort in subPorts:
                   log("+++++ subport: " + subPort.getHumanName())
   # I return the list extended with all recursively found ports.
   return resultPorts                       

#
# Checks if the given element is in the given propertyPath
#
def isInPropertyPath(element, propertyPath):
   elementFound = False
   for property in propertyPath:
      if element == property.getType():
        elementFound = True
        break
   return elementFound
       
# --- End support functions ---

log("========= " + inputElement.getHumanName() + " ===  Input Element")     

#
#
#
from com.nomagic.magicdraw.uml   import ConnectorsCollector
from com.nomagic.uml2.ext.magicdraw.compositestructures.mdinternalstructures   import ConnectableElement

# Prepares an empty list to store the found elements that are connected
# with the input elemen through ports and connectors         
ends = list()           

# Gets all ports owned by the input element
ownedPorts = inputElement.getOwnedPort() 
       
# Now retrieve all ports recursively nested in these and creates a new
# list with all of them, to iterate on all of them to find all
# existing Connectors.
       
ports = list()
if len(ownedPorts) > 0:           
   ports = buildResursiveListOfPorts(ownedPorts)

for port in ports:                 

   log("- port: " + port.getHumanName())

   # Collects a list with all direct and indirect connectors
   # attached to this port.                                                   
   allConnectors = ConnectorsCollector.collectConnectors(port)
   
   # IMPORTANT:
   # I was thinking that this would have found all connector just by giving the ports returned
   # by inputElements.getOwnedPort()
   # ConnectorsCollector collects also indirect Connectors, but APPARENTLY ONLY 1 LEVEL down.
   # If there are multiple levels of nested ports, it does not return the corresponding Connectors     
   # The strange thing is that I can find ALL connectors in the Connector member of the
   # specification for all elements and ports traversed by a nested connection, even if
   # has multiple levels.
   # This is why I build the recursive list of all nested orts by calling buildResursiveListOfPorts()
   # But this has a side effect to be taken into account...... see comments below
   
   # ..... I can now iterate of all connectors for this port.
   # BUT.... if the port is not one directly attached to the part property coming in a inputElement
   #         I get also all connector eventually attached to OTHER part properties.       
   #         Therefore I have check that the connector I am analysing has really one end
   #         on inputElement.
   #         Then I return the element at the other end as a valid one connected to inputElement.
   #         All other Connectors I ignore.
   #  This seems to work fine :-)
   #
   for conn in allConnectors:
      log("0.0 - connector: " + str(conn))     
     
      # A connector has two ends (ordered)
      # One shall be the one I am starting from.
      # The other one is the one I am lookig for and I have to add it to the return list.
      theEnds = conn.getEnd()
      elementSelf  = None
      elementOther = None
      for anEnd in theEnds: 
                                     
         # An End is a NestedConnector and has a property path
         # that lists all the elements from the initial block down the nested ports
         # to the connector itself                           
         project = Application.getInstance().getProject()
         nestedConnectorEndStereotype = StereotypesHelper.getStereotype(project, "NestedConnectorEnd");

          # Get the list of all elements of the property path
         propertyPath = StereotypesHelper.getStereotypePropertyValue(anEnd, nestedConnectorEndStereotype, "propertyPath")
         if len(propertyPath) > 0:
            for pathElement in propertyPath:
              log("||| PropertyPath:  " + pathElement.getHumanName())           
            element = propertyPath[0].getType()
            log("||| === Root: " + element.getHumanName())                 
         
            # The inputElement can be any of the elements
            # in the propertyPath of its end, if it is included inside another element
            # recursively, therefore I have to search the whole path
            if isInPropertyPath(inputElement, propertyPath):
               elementSelf = inputElement             
               log("1.0 - Element found: " + element.getHumanName() + " ==== Self.")
            else:   
               elementOther = element
               log("1.1 - Element found: " + element.getHumanName())                         
         else:
            log("No elements in propertyPath")                             
     
      # I do not care here if elementOther has been alreaded added to the list.
      # For the purpose of this script/dependency diagram I do not need to care about multiplicity.
      # But in other applications I might need to check if a multiplicity ir real (multiple connections between two elements)
      # or if it is an artefact of retrieving the Conectorsat all levels in the nested ports.
      if elementSelf != None and elementOther != None:
         ends.append(elementOther)

# #
# # For comparison....
# # Prints what are the elements found by the metachain in arg2
# # that is what is actually returned.
# #           
# log("- Metachain results -----")
       
result.set(ends)


The need to produce a classical interface N^2 diagram should be common to many in the MBSE community.
Did anyone else solve it in a different way?

thanks in advance,

Michele & Gianluca
You do not have the required permissions to view the files attached to this post.
mzampare@eso.org
Forum Newbie
Forum Newbie
 
Posts: 4
Posts Rating:0
Joined: Thu Sep 17, 2015 12:29 am

Return to Model Based Systems Engineering (MBSE)

Who is online

Users browsing this forum: No registered users and 2 guests