Extracting Redefinitions

Hello, I’m trying to “get to” the part def of the redefined products (ProductA, ProductB, etc.). What’s the best way to navigate through? If I understand the CST Explorer, I need to somehow get from PartUsage to heritage (Redefinition) to target (FeatureReference)?

Here’s my example model and my extractions script so far:

import syside
import sys

sys.path.append('framework/utilities')

from syside_helper import get_element_by_superclassifier, get_children_of_type, get_feature_typing_of_element, get_superclassifier_of_element

SRC = """\

package Ontology {
    abstract part def System;
    abstract part def Product;
    abstract part def ExternalSystem;
    abstract part def SystemUseContext;
    abstract part def User;
}

package Systems {
	
    part def System :> Ontology::System {
        part productA [0..4] : Products::ProductA;
        part productB [0..1] : Products::ProductB;
        part productC [0..*] : Products::ProductC;
    }

}

package Products {
    part def ProductA :> Ontology::Product;
    part def ProductB :> Ontology::Product;
    part def ProductC :> Ontology::Product;
}

package ExternalSystems {
    part def Room :> Ontology::ExternalSystem;
    part def Mains :> Ontology::ExternalSystem;
}

package Users {
    part def Surgeon :> Ontology::User;
    part def Nurse :> Ontology::User;
    part def FieldServiceEngineer :> Ontology::User;
}

package UseContexts {

    part def ClinicalUseContext :> Ontology::SystemUseContext {
        part room : ExternalSystems::Room;
        part mains : ExternalSystems::Mains;
        part system : Systems::System {
            part [2] :>> productA;
            part [1] :>> productB;

            interface connect productA to productB;
        }    
    }

    part def MaintenanceUseContext :> Ontology::SystemUseContext {
        part room : ExternalSystems::Room;
        part mains : ExternalSystems::Mains;
        part system : Systems::System {
            part [4] :>> productA;
            part [2] :>> productC;

            interface connect productA to productC;
        }    
    }

}
"""


# Load model

model, _ = syside.load_model(sysml_source=SRC)
contexts = get_element_by_superclassifier(model, "SystemUseContext")

for context in contexts:
    print(f"Use context: {context.name}")

    usages = get_children_of_type(context, "PartUsage")

    systems = []
    external_systems = []
    users = []
    for usage in usages:
        usage_type = get_feature_typing_of_element(usage)        
        print(f"  - {usage.name} : {usage_type}")

        classifiers = get_superclassifier_of_element(usage_type)
        if "System" in [c.name for c in classifiers]:
            systems.append(usage_type)
            system = usage
            products = get_children_of_type(system, "PartUsage")
            for product in products:
                print(f"    - {product.name}")

This seems to be working for me? (by replacing the last two lines with the following)

            for product in products:
                for redefinition in product.owned_redefinitions:
                    original_usage = redefinition.redefined_feature
                    original = get_feature_typing_of_element(original_usage)
                    print(f"   - {product.name} is redefining {original_usage} : {original.name}")

Is this a good approach?

Hi Tom,

Your approach seems good, though original_usage may be a chained feature as well in a general case (.feature_target will select the last segment or self). On a side note, types of product will be the same as types of original_usage unless product has other specializations since Redefinition is also an inheritance relationship.

Also, owned_redefinitions does not have an efficient __iter__ method at the moment so it would be better to use .collect() before iteration. Python is trying to be helpful and synthesizing __iter__ via __getitem__ which is inefficient in this case, and we would like to remove it in a future update to prevent a performance pitfall.