Hello, I’m trying to extract connections from the model and I’m wondering if there is a convenient method to do?
Here’s an example model in its textual and graphical form (I hope it’s modeled correctly). What I would like to extract from the model is the following information:
- C connected to A
- C connected to B
- C connected to D
- C connected to E
What’s the best approach to do that?
Thanks!
Tom
package InterfaceExample {
port def MyPort;
part def A { port p:MyPort; }
part def B { port p:MyPort; }
part def C { port p1:MyPort; port p2:MyPort;}
part def D { port p:MyPort; }
part def E { port p:MyPort; }
part def SubsystemA {
part a : A;
part b : B;
port p : MyPort;
binding bind p = a.p;
binding bind p = b.p;
}
part def SubsystemB {
part c : C;
part d : D;
part e : E;
port p : MyPort;
binding bind c.p1 = p;
interface connect c.p2 to d.p;
interface connect c.p2 to e.p;
}
part def System {
part sa : SubsystemA;
part sb : SubsystemB;
interface connect sb.p to sa.p;
}
}
Hi,
The easiest, and likely most performant, approach to find elements of specific type is to use Model.nodes (or Document.nodes/Document.all_nodes):
import syside
SRC = """\
package InterfaceExample {
port def MyPort;
part def A { port p:MyPort; }
part def B { port p:MyPort; }
part def C { port p1:MyPort; port p2:MyPort;}
part def D { port p:MyPort; }
part def E { port p:MyPort; }
part def SubsystemA {
part a : A;
part b : B;
port p : MyPort;
binding bind p = a.p;
binding bind p = b.p;
}
part def SubsystemB {
part c : C;
part d : D;
part e : E;
port p : MyPort;
binding bind c.p1 = p;
interface connect c.p2 to d.p;
interface connect c.p2 to e.p;
}
part def System {
part sa : SubsystemA;
part sb : SubsystemB;
interface connect sb.p to sa.p;
}
}
"""
model, _ = syside.load_model(sysml_source=SRC)
for connector in model.elements(syside.ConnectorAsUsage, include_subtypes=True):
ends = connector.related_elements.collect()
# unwrap feature chainings with `feature_target`
print(f"{ends[0].feature_target} -> {ends[1].feature_target}")
Thanks! That’s really easy this way.
If I change the last line of your script to:
print(f"{ends[0].feature_target.owner.name} --{connector.cst_node.type}--> {ends[1].feature_target.owner.name}")
I get the following output (which is nearly what I’m looking for):
C --InterfaceUsage–> D
C --InterfaceUsage–> E
SubsystemB --InterfaceUsage–> SubsystemA
SubsystemA --BindingConnectorAsUsage–> A
SubsystemA --BindingConnectorAsUsage–> B
C --BindingConnectorAsUsage–> SubsystemB
Is there an easy way to “remove” the binding connector usages and the “inbetween” interfaces? The logic I’m thinking of is:
C --BindingConnectorAsUsage–> SubsystemB --InterfaceUsage–> SubsystemA --BindingConnectorAsUsage–> A = C → A
No built-in way, you will need to record the links as you go, and then assemble them the way you want:
links: dict[syside.Element, list[tuple[syside.ConnectorAsUsage, syside.Element]]] = {}
for ...:
links.setdefault(ends[0].feature_target, []).append(
(connector, ends[1].feature_target)
)
Then you can start at some element, and continue following links.
PS. Not all elements have cst_node, e.g. implicit elements inserted during semantic resolution. To get the type name it is better to use type(element).__name__ which works on all elements.