labs4capella / python4capella

Python for Capella
Eclipse Public License 2.0
52 stars 10 forks source link

Extracting the Applied Property values from Interactions #209

Closed mm-capella closed 2 weeks ago

mm-capella commented 6 months ago

I have created OABs and OESs in the Operational Analysis layer and am trying to extract the Applied Property value data allocated to the element. This is my code, which returns an empty list for the applied property values. I also had a question about how you could have Property values applied across multiple diagrams, considering I am allocating them to interactions on the OES but they do not appear in the OAB.

model = CapellaModel() model.open(aird_path)

se = model.get_system_engineering() op_layer = se.get_operational_analysis() scen_layer = op_layer.get_all_contents_by_type(Scenario)

for scen in scen_layer: print(scen.get_name())

for sf in scen.get_all_contents_by_type(StateFragment):
    if sf.get_name() is not None:
        print (sf.get_name())

for sm in scen.get_all_contents_by_type(SequenceMessage):
    if sm.get_name() is not None:
        print (sm.get_name())
        print (sm.get_applied_property_values())
ylussaud commented 6 months ago

Modifying the semantic model might not create graphical element on a diagram if it's not synchronized. I don't know how you could add the semantic element to a diagram at a meaningful position...

Did you also check that the semantic element in both cases is the same ? You might be adding a property value to an element and it's an other element that is represented on the other diagram.

In the Capella forum for scripting there are a number of posts related to property value:

Their is also a sample script that read property value to extract them to a .xlsx file.

mm-capella commented 6 months ago

I was reading through the part on synchronization and confused how you turn it on.

I have also attached how I have added the property value as it is not clear how the (sample script) code is trying to extract it. image

This is how I have adjusted my code to incorporate how the property value is being extracted, but nothing is being read and only the Interactions (Sequence Message is printing)

model = CapellaModel() model.open(aird_path)

gets the SystemEngineering and print its name

se = model.get_system_engineering() op_layer = se.get_operational_analysis() scen_layer = op_layer.get_all_contents_by_type(Scenario)

for scen in scen_layer:

print('Activities in Scenario', scen.get_name(), ':')

print(scen.get_name())    
allPVs = []
allSM = se.get_all_contents_by_type(SequenceMessage)

for sm in allSM:
    for PVName in PVMT.get_p_v_names(sm):
        if pvName not in allPVs:
            all.PVs.append(pvName)

#for sf in scen.get_all_contents():
for sm in allSM:
    if sm.get_name() is not None:
        print ('Interaction is',sm.get_name())
        for pvName in allPVs:
            print('- Connection is',PVMT.get_p_v_value(sm, PVName))
ylussaud commented 6 months ago

The syncronization setting is defined in the diagram description (by Capella developpers). I don't think the end user can change this setting.

The implementation of List in Python4Capella dosn't implement the str method, see this issue. You should try to iterate with a for loop to see if the collection is really empty.

mm-capella commented 6 months ago

I have been trying to apply Property values with a test vpd to the provided 'Export_Property_Values_associated_to_elements_to_xlsx.py' example script and unable to get the code to show any existence of property values being applied. I have adapted the code as follows, however, the PVs still appear to be empty. I have also attached a snippet of the semantic browser and console print. Am I applying my properties incorrectly or trying to read the wrong thing.

aird_path = '/In-Flight Entertainment System/In-Flight Entertainment System.aird'

model = CapellaModel() model.open(aird_path)

se = model.get_system_engineering() print('starting export of model ' + se.get_name())

allSF = se.get_all_contents_by_type(SystemFunction)

for sf in allSF:

worksheet.cell(row = i, column = 1).value = sf.get_name()

print('System function is:', sf.get_name())
pv_name = PVMT.get_p_v_names(sf)
print(pv_name)

image

ylussaud commented 6 months ago

replace:

print(pv_name)

with

for name in pv_name:
    print(name, ' ', PVMT.get_p_v_value(sf, name))

The list will print as empty event if it's not. That's why you need to loop oven it.

mm-capella commented 6 months ago

Unfortunately, with the change, pv_name seems to be empty.

image

ylussaud commented 6 months ago

Your property value is not applied in a group:

    pvs = sf.get_applied_property_values()
    for pv in pvs:
        print(' -', pv.get_name(), pv.get_value())
mm-capella commented 5 months ago

I have managed to get this working and was wondering if I could extract the corresponding activities/ state fragments for the interactions/ state messages

ylussaud commented 5 months ago

I'm not sure what you are trying to do. But if you have this information in the semantic browser view, you can call the query by name:

capella_query_by_name(myCapellaElement, "query name", expected_class)

for instance

capella_query_by_name(capability, "Involved Exchanges", FunctionalExchange)

Let me know if it helps.

mm-capella commented 5 months ago

So I was extracting interactions from scenarios and obtained the following:

se = model.get_system_engineering() op_layer = se.get_operational_analysis() scen_layer = op_layer.get_all_contents_by_type(Scenario)

for oa in op_layer.get_all_contents_by_type(OperationalActor): pvs = oa.get_applied_property_values()

for scen in scen_layer: allSM = scen.get_all_contents_by_type(SequenceMessage) for sm in allSM:

    pvs = sm.get_applied_property_values()
    if sm.get_name() is not None:
    #sending role and receiving role
        sr = sm.get_sending_instance_role()
        rr = sm.get_receiving_instance_role()
        if sr and rr is not None:
            for pv in pvs:
                worksheet.cell(row=i, column=1).value = pv.get_value()    
            worksheet.cell(row=i, column=2).value = sm.get_name()
            worksheet.cell(row=i, column=3).value = sr.get_name()
            worksheet.cell(row=i, column=4).value = rr.get_name()               
            worksheet.cell(row=i, column=5).value = scen.get_name()
            worksheet.cell(row=i, column=6).value = sm.get_id()
            i = i+1

I was wondering if there was a way to obtain the activity names that attach to the State Fragments of the sending and receiving instance roles (i.e sending/ receiving activities correlating to the interaction/ Sequence message). It is coming up blank for me.

ylussaud commented 5 months ago

You can use something like:

interaction_state_e_class = get_e_classifier("http://www.polarsys.org/capella/core/interaction/" + capella_version(), "InstanceRole")
for interaction_state in eInverseByType(rr.get_java_object(), interaction_state_e_class):
    value =  interaction_state.getRelatedAbstractState()
    if value is not None:
        e_object_class = getattr(sys.modules["__main__"], "EObject")
        specific_cls = e_object_class.get_class(value)
        if specific_cls is not None:
            state = specific_cls(value)

Some part of the Capella metamodel doesn't exists in the Python API... That's why we need to use Java API.

mm-capella commented 5 months ago

I have implemented the code as follows,

for scen in scen_layer:

allSM = scen.get_all_contents_by_type(SequenceMessage)
for sm in allSM:    

    pvs = sm.get_applied_property_values()
    if sm.get_name() is not None:
    #sending role and receiving role
        sr = sm.get_sending_instance_role()
        rr = sm.get_receiving_instance_role()
        if sr and rr is not None:
            interaction_state_e_class = get_e_classifier("http://www.polarsys.org/capella/core/interaction/" + capella_version(), "InstanceRole")
            for interaction_state in eInverseByType(rr.get_java_object(), interaction_state_e_class):
                value =  interaction_state.getRelatedAbstractState()
                if value is not None:
                    e_object_class = getattr(sys.modules["__main__"], "EObject")
                    specific_cls = e_object_class.get_class(value)
                    if specific_cls is not None:
                        state = specific_cls(value)
                        worksheet.cell(row=i, column=7).value = value
            for pv in pvs:
                worksheet.cell(row=i, column=1).value = pv.get_value()    
            worksheet.cell(row=i, column=2).value = sm.get_name()
            worksheet.cell(row=i, column=3).value = sr.get_name()
            worksheet.cell(row=i, column=4).value = rr.get_name()               
            worksheet.cell(row=i, column=5).value = scen.get_name()
            worksheet.cell(row=i, column=6).value = sm.get_id()
            i = i+1

But the value doesn't appear to show. Have I assumed the wrong variable would be the activity or has the rr variable not been integrated in correctly?

ylussaud commented 5 months ago

In some cases sr and rr might be None, you need to add a check before calling anything on them:

            if rr is not None:
                for interaction_state in eInverseByType(rr.get_java_object(), interaction_state_e_class):
mm-capella commented 4 months ago

Has that not been established in the line: if sr and rr is not None:

Are we calling the correct element with the code? image Just to clarify, I have been able to extract the Sequence Message (Communication), Sending instance role (NCO), and Receiving instance role (NSAM) but I am looking to get the Related Function (Check with NSAM + Communicates extent of failure) to the State Fragment. image

ylussaud commented 4 months ago

You can use:

value = interaction_state.getRelatedAbstractFunction()
if value is not None:
    e_object_class = getattr(sys.modules["__main__"], "EObject")
    specific_cls = e_object_class.get_class(value)
    if specific_cls is not None:
        function = specific_cls(value)

I forgot this part of your question.

mm-capella commented 4 months ago

Thanks, did think I was calling the wrong element but it's still coming up blank. I was wondering if there was a way to communicate with you and work on the code live. Really appreciate the help you've provided and believe it would be easier if you could make changes on the spot.

ylussaud commented 4 months ago

I'm not sure I can help you more on this topic... You might ask on the Capella forum how to navigate between those elements. You need someone that has better understanding of the Capella metamodel than I do.

mm-capella commented 4 months ago

No worries! Grateful for all the help and advice you've provided thus far.