diff --git a/kadmos/cmdows/schemas/0.8/cmdows.xsd b/kadmos/cmdows/schemas/0.8/cmdows.xsd index 84271528da29140150e8df950ecec7f970ecc2bc..b15d484ae5cb92c371f9e2c04e22f25a4da22252 100644 --- a/kadmos/cmdows/schemas/0.8/cmdows.xsd +++ b/kadmos/cmdows/schemas/0.8/cmdows.xsd @@ -191,28 +191,12 @@ <xs:element name="designCompetence" maxOccurs="unbounded"> <xs:complexType> <xs:sequence> - <xs:element name="ID" type="xs:string"> - <xs:annotation> - <xs:documentation>Identifier of the tool to be executed</xs:documentation> - </xs:annotation> - </xs:element> - <xs:element name="modeID" type="xs:string"> - <xs:annotation> - <xs:documentation>Identifier of the tool mode to be executed (as a tool can usually be executed in different modes)</xs:documentation> - </xs:annotation> - </xs:element> - <xs:element name="instanceID" type="xs:string"/> - <xs:element name="relatedInstanceUID" type="xs:string" minOccurs="0"> - <xs:annotation> - <xs:documentation>Element used to refer to the first instance if a certain DC has instanceID>1. modeID, ID and metadata are not stored in this case.</xs:documentation> - </xs:annotation> - </xs:element> - <xs:element name="version" type="xs:string"/> <xs:element name="label" type="xs:string"> <xs:annotation> <xs:documentation>Label of the design competence which can be used for clean printouts (e.g. 'F')</xs:documentation> </xs:annotation> </xs:element> + <xs:element name="instanceID" type="xs:string"/> <xs:element name="inputs"> <xs:complexType> <xs:sequence> @@ -231,167 +215,187 @@ </xs:complexType> </xs:element> <xs:element name="outputs" type="outputsType"/> - <xs:element name="metadata" minOccurs="0"> - <xs:complexType> - <xs:sequence> - <xs:element name="generalInfo" minOccurs="0"> - <xs:complexType> - <xs:all> - <xs:element name="description" type="xs:string" minOccurs="0"> - <xs:annotation> - <xs:documentation>Description of the design competence</xs:documentation> - </xs:annotation> - </xs:element> - <xs:element name="status" type="xs:string" minOccurs="0"> - <xs:annotation> - <xs:documentation>Describing the state of the design competence, e.g. draft, final, for verification, ...</xs:documentation> - </xs:annotation> - </xs:element> - <xs:element name="creationDate" type="xs:date" minOccurs="0"/> - <xs:element name="owner" type="contactType" minOccurs="0"> - <xs:annotation> - <xs:documentation>Owner(s) of the design competence</xs:documentation> - </xs:annotation> - </xs:element> - <xs:element name="creator" type="contactType" minOccurs="0"> - <xs:annotation> - <xs:documentation>Creator(s) of the design competence</xs:documentation> - </xs:annotation> - </xs:element> - <xs:element name="operator" type="contactType" minOccurs="0"> - <xs:annotation> - <xs:documentation>Operator(s) of the design competence to be contacted in case of problems</xs:documentation> - </xs:annotation> - </xs:element> - <xs:element name="modelDefinition" minOccurs="0"> - <xs:annotation> - <xs:documentation>Optional element for 'surrogateModel' competence types</xs:documentation> - </xs:annotation> - <xs:complexType> - <xs:all> - <xs:element name="referenceDataSet" type="xs:string" minOccurs="0"/> - <xs:element name="analysisMethod" type="xs:string" minOccurs="0"/> - <xs:element name="fittingMethod" type="xs:string" minOccurs="0"/> - <xs:element name="relatedDesignCompetenceID" type="xs:string" minOccurs="0"/> - <xs:element name="relatedDesignCompetenceVersion" type="xs:string" minOccurs="0"/> - </xs:all> - </xs:complexType> - </xs:element> - </xs:all> - </xs:complexType> - </xs:element> - <xs:element name="performanceInfo" minOccurs="0"> - <xs:complexType> - <xs:all> - <xs:element name="precision" type="xs:decimal" minOccurs="0"/> - <xs:element name="fidelityLevel" type="xs:decimal" minOccurs="0"/> - <xs:element name="runTime" type="xs:decimal" minOccurs="0"/> - <xs:element name="standardDeviation" type="xs:decimal" minOccurs="0"/> - <xs:element name="verifications" minOccurs="0"> - <xs:complexType> - <xs:sequence> - <xs:element name="verification" maxOccurs="unbounded"> - <xs:complexType> - <xs:all> - <xs:element name="method" type="xs:string"/> - <xs:element name="verifier" type="contactType"/> - <xs:element name="result" type="xs:string"/> - <xs:element name="date" type="xs:date"/> - <xs:element name="version" type="xs:string"/> - </xs:all> - </xs:complexType> - </xs:element> - </xs:sequence> - </xs:complexType> - </xs:element> - </xs:all> - </xs:complexType> - </xs:element> - <xs:element name="executionInfo" minOccurs="0"> - <xs:complexType> - <xs:all> - <xs:element name="availabilityConstraints" minOccurs="0"> - <xs:complexType> - <xs:all> - <xs:element name="fromDate" type="xs:date" minOccurs="0"/> - <xs:element name="toDate" type="xs:date" minOccurs="0"/> - <xs:element name="fromOfficeHour" type="xs:time" minOccurs="0"/> - <xs:element name="toOfficeHour" type="xs:time" minOccurs="0"/> - <xs:element name="maximumTotalExecutions" type="xs:int" minOccurs="0"/> - <xs:element name="maximumParallelExecutions" type="xs:int" minOccurs="0"/> - </xs:all> - </xs:complexType> - </xs:element> - <xs:element name="authorizationConstraints" minOccurs="0"> - <xs:complexType> - <xs:all> - <xs:element name="authorizedUsers" minOccurs="0"> - <xs:complexType> - <xs:sequence> - <xs:element name="authorizedUser" type="contactType" maxOccurs="unbounded"/> - </xs:sequence> - </xs:complexType> - </xs:element> - <xs:element name="unauthorizedUsers" minOccurs="0"> - <xs:complexType> - <xs:sequence> - <xs:element name="unauthorizedUser" type="contactType" maxOccurs="unbounded"/> - </xs:sequence> - </xs:complexType> - </xs:element> - </xs:all> - </xs:complexType> - </xs:element> - <xs:element name="remoteComponentInfo" minOccurs="0"> - <xs:complexType> - <xs:all> - <xs:element name="jobSettings" minOccurs="0"> - <xs:complexType> - <xs:all> - <xs:element name="singleOrMultiExecution" minOccurs="0"> - <xs:simpleType> - <xs:restriction base="xs:string"> - <xs:enumeration value="single"/> - <xs:enumeration value="multiple"/> - </xs:restriction> - </xs:simpleType> - </xs:element> - <xs:element name="jobName" type="xs:string" minOccurs="0"/> - <xs:element name="remoteEngineer" type="contactType" minOccurs="0"/> - <xs:element name="notificationMessage" type="xs:string" minOccurs="0"/> - </xs:all> - </xs:complexType> - </xs:element> - <xs:element name="dataExchangeSettings" minOccurs="0"> - <xs:complexType> - <xs:all> - <xs:element name="dataserver" type="xs:string" minOccurs="0"/> - <xs:element name="urlsite" type="xs:string" minOccurs="0"/> - <xs:element name="webAuthenticationProtocol" type="xs:string" minOccurs="0"/> - <xs:element name="context" type="xs:string" minOccurs="0"/> - <xs:element name="folder" type="xs:string" minOccurs="0"/> - <xs:element name="pollingTime" type="xs:float" minOccurs="0"/> - <xs:element name="maxIterations" type="xs:int" minOccurs="0"/> - <xs:element name="timeOut" type="xs:float" minOccurs="0"/> - <xs:element name="sharedFilePolicy" type="xs:string" minOccurs="0"/> - <xs:element name="servermutex" type="xs:string" minOccurs="0"/> - </xs:all> - </xs:complexType> - </xs:element> - </xs:all> - </xs:complexType> - </xs:element> - </xs:all> - </xs:complexType> - </xs:element> - </xs:sequence> - </xs:complexType> - </xs:element> - <xs:element name="projectSpecific" type="xs:anyType" minOccurs="0"> - <xs:annotation> - <xs:documentation>Free element containing any project specific information (e.g. for RCE or Optimus).</xs:documentation> - </xs:annotation> - </xs:element> + <xs:choice> + <xs:element name="relatedInstanceUID" type="xs:string" minOccurs="0"> + <xs:annotation> + <xs:documentation>Element used to refer to the first instance if a certain DC has instanceID>1. modeID, ID and metadata are not stored in this case.</xs:documentation> + </xs:annotation> + </xs:element> + <xs:sequence> + <xs:element name="ID" type="xs:string"> + <xs:annotation> + <xs:documentation>Identifier of the tool to be executed</xs:documentation> + </xs:annotation> + </xs:element> + <xs:element name="modeID" type="xs:string"> + <xs:annotation> + <xs:documentation>Identifier of the tool mode to be executed (as a tool can usually be executed in different modes)</xs:documentation> + </xs:annotation> + </xs:element> + <xs:element name="version" type="xs:string"/> + <xs:element name="metadata" minOccurs="0"> + <xs:complexType> + <xs:sequence> + <xs:element name="generalInfo" minOccurs="0"> + <xs:complexType> + <xs:all> + <xs:element name="description" type="xs:string" minOccurs="0"> + <xs:annotation> + <xs:documentation>Description of the design competence</xs:documentation> + </xs:annotation> + </xs:element> + <xs:element name="status" type="xs:string" minOccurs="0"> + <xs:annotation> + <xs:documentation>Describing the state of the design competence, e.g. draft, final, for verification, ...</xs:documentation> + </xs:annotation> + </xs:element> + <xs:element name="creationDate" type="xs:date" minOccurs="0"/> + <xs:element name="owner" type="contactType" minOccurs="0"> + <xs:annotation> + <xs:documentation>Owner(s) of the design competence</xs:documentation> + </xs:annotation> + </xs:element> + <xs:element name="creator" type="contactType" minOccurs="0"> + <xs:annotation> + <xs:documentation>Creator(s) of the design competence</xs:documentation> + </xs:annotation> + </xs:element> + <xs:element name="operator" type="contactType" minOccurs="0"> + <xs:annotation> + <xs:documentation>Operator(s) of the design competence to be contacted in case of problems</xs:documentation> + </xs:annotation> + </xs:element> + <xs:element name="modelDefinition" minOccurs="0"> + <xs:annotation> + <xs:documentation>Optional element for 'surrogateModel' competence types</xs:documentation> + </xs:annotation> + <xs:complexType> + <xs:all> + <xs:element name="referenceDataSet" type="xs:string" minOccurs="0"/> + <xs:element name="analysisMethod" type="xs:string" minOccurs="0"/> + <xs:element name="fittingMethod" type="xs:string" minOccurs="0"/> + <xs:element name="relatedDesignCompetenceID" type="xs:string" minOccurs="0"/> + <xs:element name="relatedDesignCompetenceVersion" type="xs:string" minOccurs="0"/> + </xs:all> + </xs:complexType> + </xs:element> + </xs:all> + </xs:complexType> + </xs:element> + <xs:element name="performanceInfo" minOccurs="0"> + <xs:complexType> + <xs:all> + <xs:element name="precision" type="xs:decimal" minOccurs="0"/> + <xs:element name="fidelityLevel" type="xs:decimal" minOccurs="0"/> + <xs:element name="runTime" type="xs:decimal" minOccurs="0"/> + <xs:element name="standardDeviation" type="xs:decimal" minOccurs="0"/> + <xs:element name="verifications" minOccurs="0"> + <xs:complexType> + <xs:sequence> + <xs:element name="verification" maxOccurs="unbounded"> + <xs:complexType> + <xs:all> + <xs:element name="method" type="xs:string"/> + <xs:element name="verifier" type="contactType"/> + <xs:element name="result" type="xs:string"/> + <xs:element name="date" type="xs:date"/> + <xs:element name="version" type="xs:string"/> + </xs:all> + </xs:complexType> + </xs:element> + </xs:sequence> + </xs:complexType> + </xs:element> + </xs:all> + </xs:complexType> + </xs:element> + <xs:element name="executionInfo" minOccurs="0"> + <xs:complexType> + <xs:all> + <xs:element name="availabilityConstraints" minOccurs="0"> + <xs:complexType> + <xs:all> + <xs:element name="fromDate" type="xs:date" minOccurs="0"/> + <xs:element name="toDate" type="xs:date" minOccurs="0"/> + <xs:element name="fromOfficeHour" type="xs:time" minOccurs="0"/> + <xs:element name="toOfficeHour" type="xs:time" minOccurs="0"/> + <xs:element name="maximumTotalExecutions" type="xs:int" minOccurs="0"/> + <xs:element name="maximumParallelExecutions" type="xs:int" minOccurs="0"/> + </xs:all> + </xs:complexType> + </xs:element> + <xs:element name="authorizationConstraints" minOccurs="0"> + <xs:complexType> + <xs:all> + <xs:element name="authorizedUsers" minOccurs="0"> + <xs:complexType> + <xs:sequence> + <xs:element name="authorizedUser" type="contactType" maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + </xs:element> + <xs:element name="unauthorizedUsers" minOccurs="0"> + <xs:complexType> + <xs:sequence> + <xs:element name="unauthorizedUser" type="contactType" maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + </xs:element> + </xs:all> + </xs:complexType> + </xs:element> + <xs:element name="remoteComponentInfo" minOccurs="0"> + <xs:complexType> + <xs:all> + <xs:element name="jobSettings" minOccurs="0"> + <xs:complexType> + <xs:all> + <xs:element name="singleOrMultiExecution" minOccurs="0"> + <xs:simpleType> + <xs:restriction base="xs:string"> + <xs:enumeration value="single"/> + <xs:enumeration value="multiple"/> + </xs:restriction> + </xs:simpleType> + </xs:element> + <xs:element name="jobName" type="xs:string" minOccurs="0"/> + <xs:element name="remoteEngineer" type="contactType" minOccurs="0"/> + <xs:element name="notificationMessage" type="xs:string" minOccurs="0"/> + </xs:all> + </xs:complexType> + </xs:element> + <xs:element name="dataExchangeSettings" minOccurs="0"> + <xs:complexType> + <xs:all> + <xs:element name="dataserver" type="xs:string" minOccurs="0"/> + <xs:element name="urlsite" type="xs:string" minOccurs="0"/> + <xs:element name="webAuthenticationProtocol" type="xs:string" minOccurs="0"/> + <xs:element name="context" type="xs:string" minOccurs="0"/> + <xs:element name="folder" type="xs:string" minOccurs="0"/> + <xs:element name="pollingTime" type="xs:float" minOccurs="0"/> + <xs:element name="maxIterations" type="xs:int" minOccurs="0"/> + <xs:element name="timeOut" type="xs:float" minOccurs="0"/> + <xs:element name="sharedFilePolicy" type="xs:string" minOccurs="0"/> + <xs:element name="servermutex" type="xs:string" minOccurs="0"/> + </xs:all> + </xs:complexType> + </xs:element> + </xs:all> + </xs:complexType> + </xs:element> + </xs:all> + </xs:complexType> + </xs:element> + </xs:sequence> + </xs:complexType> + </xs:element> + <xs:element name="projectSpecific" type="xs:anyType" minOccurs="0"> + <xs:annotation> + <xs:documentation>Free element containing any project specific information (e.g. for RCE or Optimus).</xs:documentation> + </xs:annotation> + </xs:element> + </xs:sequence> + </xs:choice> </xs:sequence> <xs:attribute name="uID" type="xs:string" use="required"> <xs:annotation> @@ -491,40 +495,44 @@ <xs:sequence> <xs:element name="parameter" maxOccurs="unbounded"> <xs:complexType> - <xs:all> + <xs:sequence> <xs:element name="label" type="xs:string"> <xs:annotation> <xs:documentation>Label of the parameter which can be used for clean printouts (e.g. 'y1')</xs:documentation> </xs:annotation> </xs:element> - <xs:element name="description" type="xs:string" minOccurs="0"> - <xs:annotation> - <xs:documentation>Detailed description of the parameter</xs:documentation> - </xs:annotation> - </xs:element> - <xs:element name="schemaPath" type="xs:string" minOccurs="0"> - <xs:annotation> - <xs:documentation>The path of the parameter which is only saved when instanceID is 1.</xs:documentation> - </xs:annotation> - </xs:element> - <xs:element name="relatedInstanceUID" type="xs:string" minOccurs="0"> - <xs:annotation> - <xs:documentation>In case instanceID is higher than 1 the parameter is only referenced to the first instance of the parameter.</xs:documentation> - </xs:annotation> - </xs:element> - <xs:element name="InstanceID" type="xs:int" minOccurs="0"> + <xs:element name="instanceID" type="xs:int"> <xs:annotation> <xs:documentation>The instance of the parameter determines way in which it is referenced and what information is saved.</xs:documentation> </xs:annotation> </xs:element> - <xs:element name="note" type="xs:string" minOccurs="0"> - <xs:annotation> - <xs:documentation>Any additional note for the parameter</xs:documentation> - </xs:annotation> - </xs:element> - <xs:element name="unit" type="xs:string" minOccurs="0"/> - <xs:element name="dataType" type="xs:string" minOccurs="0"/> - </xs:all> + <xs:choice> + <xs:element name="relatedInstanceUID" type="xs:string"> + <xs:annotation> + <xs:documentation>In case instanceID is higher than 1 the parameter is only referenced to the first instance of the parameter.</xs:documentation> + </xs:annotation> + </xs:element> + <xs:sequence> + <xs:element name="description" type="xs:string" minOccurs="0"> + <xs:annotation> + <xs:documentation>Detailed description of the parameter</xs:documentation> + </xs:annotation> + </xs:element> + <xs:element name="schemaPath" type="xs:string" minOccurs="0"> + <xs:annotation> + <xs:documentation>The path of the parameter which is only saved when instanceID is 1.</xs:documentation> + </xs:annotation> + </xs:element> + <xs:element name="note" type="xs:string" minOccurs="0"> + <xs:annotation> + <xs:documentation>Any additional note for the parameter</xs:documentation> + </xs:annotation> + </xs:element> + <xs:element name="unit" type="xs:string" minOccurs="0"/> + <xs:element name="dataType" type="xs:string" minOccurs="0"/> + </xs:sequence> + </xs:choice> + </xs:sequence> <xs:attribute name="uID" type="xs:string" use="required"> <xs:annotation> <xs:documentation>Unique ID of the parameter which can be used as reference in the problem definition etc. (e.g. '/data_schema/analyses/y1')</xs:documentation> @@ -1227,12 +1235,12 @@ </xs:complexType> <xs:complexType name="simpleArchitectureElementsVariableType"> <xs:sequence> - <xs:element name="relatedParameterUID" type="xs:string"/> - <xs:element name="label" type="xs:string"/> <xs:choice> + <xs:element name="relatedParameterUID" type="xs:string"/> <xs:element name="relatedInstanceUID" type="xs:string"/> - <xs:element name="instanceID" type="xs:int"/> </xs:choice> + <xs:element name="label" type="xs:string"/> + <xs:element name="instanceID" type="xs:int"/> </xs:sequence> <xs:attribute name="uID" type="xs:string"/> </xs:complexType> diff --git a/kadmos/graph/graph_data.py b/kadmos/graph/graph_data.py index f9822028d1704e2253ba3975367c7820a599e10c..3d192006f6dc144414e3ea11810c739334a87bc2 100644 --- a/kadmos/graph/graph_data.py +++ b/kadmos/graph/graph_data.py @@ -684,7 +684,7 @@ class DataGraph(KadmosGraph): :rtype: int """ assert 'instance' in self.nodes[node], 'node {} does not have the expected attribute "instance".'.format(node) - highest_instance = self.nodes[node]['instance'] + highest_instance = int(self.nodes[node]['instance']) instance_exists = True while instance_exists: # Check for one higher instance @@ -4305,11 +4305,16 @@ class MdaoDataGraph(DataGraph, MdaoMixin): for graph_parameter_node in graph_parameter_nodes: cmdows_parameter_node = cmdows_parameter.add(make_camel_case(architecture_roles_var)) cmdows_parameter_node.set('uID', graph_parameter_node) - cmdows_parameter_node.add('relatedParameterUID', - self.nodes[graph_parameter_node].get('related_to_schema_node')) + instance = int(self.nodes[graph_parameter_node].get('instance')) + if instance > 1: + cmdows_parameter_node.add('relatedInstanceUID', + self.get_first_node_instance(self.nodes[graph_parameter_node])) + else: + cmdows_parameter_node.add('relatedParameterUID', + self.nodes[graph_parameter_node].get('related_to_schema_node')) cmdows_parameter_node.add('label', self.nodes[graph_parameter_node].get('label')) - cmdows_parameter_node.add('instanceID', self.nodes[graph_parameter_node].get('instance')) + cmdows_parameter_node.add('instanceID', instance) # Create architectureElements/executableBlocks cmdows_executable_blocks = cmdows_architecture_elements.add('executableBlocks') # Create architectureElements/executableBlocks/... diff --git a/kadmos/graph/graph_kadmos.py b/kadmos/graph/graph_kadmos.py index a1cf47f817858c1b40f849fbea0821f65ad80ddc..2f0d0d4677e37bb616a7bf48bd7806bc3c72b481 100644 --- a/kadmos/graph/graph_kadmos.py +++ b/kadmos/graph/graph_kadmos.py @@ -31,7 +31,7 @@ from ..utilities import prompting from ..utilities import printing from ..utilities.general import transform_data_into_strings, transform_string_into_format, get_list_entries, \ open_file, color_list, test_attr_cond, translate_list -from ..utilities.xmls import Element, parser, recursively_empty, recursively_stringify +from ..utilities.xmls import Element, parser, recursively_empty, recursively_stringify, get_uid_search_xpath from ..utilities.testing import check from mixin_equation import EquationMixin @@ -991,11 +991,12 @@ class KadmosGraph(nx.DiGraph, EquationMixin, VistomsMixin): graph_design_competence_data = self.nodes[graph_design_competence] cmdows_design_competence = cmdows_design_competences.add('designCompetence') cmdows_design_competence.set('uID', graph_design_competence) - cmdows_design_competence.add('ID', graph_design_competence_data.get('name')) - cmdows_design_competence.add('modeID', graph_design_competence_data.get('mode', 'main')) - cmdows_design_competence.add('instanceID', graph_design_competence_data.get('instance', '1')) - cmdows_design_competence.add('version', graph_design_competence_data.get('version', '1.0')) cmdows_design_competence.add('label', graph_design_competence_data.get('label')) + if graph_design_competence_data.get('instance', 1) is None: + instance = 1 + else: + instance = int(graph_design_competence_data.get('instance', 1)) + cmdows_design_competence.add('instanceID', instance) # Create designCompetences/designCompetence/inputs with children graph_inputs = self.in_edges(graph_design_competence, data=True) @@ -1013,18 +1014,30 @@ class KadmosGraph(nx.DiGraph, EquationMixin, VistomsMixin): cmdows_output = cmdows_outputs.add('output') cmdows_output.add('parameterUID', graph_output[1]) - # Create designCompetences/designCompetence/metadata with children - # TODO: Preferably make sure that contacts are always saved to the database? - cmdows_metadata = cmdows_design_competence.add('metadata') - cmdows_metadata.add('general_info', graph_design_competence_data.get('general_info'), - camel_case_conversion=True) - cmdows_metadata.add('performance_info', graph_design_competence_data.get('performance_info'), - camel_case_conversion=True) - cmdows_metadata.add('execution_info', graph_design_competence_data.get('execution_info'), - camel_case_conversion=True) + if instance > 1: + instance = graph_design_competence_data.get('instance') + cmdows_design_competence.add('relatedInstanceUID', + self.get_first_node_instance(self.nodes[cmdows_design_competence])) - # Create designCompetences/designCompetence/projectSpecific - cmdows_design_competence.add('projectSpecific', graph_design_competence_data.get('projectSpecific')) + else: + cmdows_design_competence.add('ID', graph_design_competence_data.get('name'), only_add_if_valued=True) + cmdows_design_competence.add('modeID', graph_design_competence_data.get('mode', 'main'), + only_add_if_valued=True) + cmdows_design_competence.add('version', graph_design_competence_data.get('version', '1.0'), + only_add_if_valued=True) + + # Create designCompetences/designCompetence/metadata with children + # TODO: Preferably make sure that contacts are always saved to the database? + cmdows_metadata = cmdows_design_competence.add('metadata') + cmdows_metadata.add('general_info', graph_design_competence_data.get('general_info'), + camel_case_conversion=True) + cmdows_metadata.add('performance_info', graph_design_competence_data.get('performance_info'), + camel_case_conversion=True) + cmdows_metadata.add('execution_info', graph_design_competence_data.get('execution_info'), + camel_case_conversion=True) + + # Create designCompetences/designCompetence/projectSpecific + cmdows_design_competence.add('projectSpecific', graph_design_competence_data.get('projectSpecific')) return cmdows_design_competences @@ -1040,10 +1053,21 @@ class KadmosGraph(nx.DiGraph, EquationMixin, VistomsMixin): cmdows_parameter = cmdows_parameters.add('parameter') cmdows_parameter.set('uID', graph_parameter) cmdows_parameter.add('label', self.nodes[graph_parameter].get('label')) - cmdows_parameter.add('description', self.nodes[graph_parameter].get('description')) - cmdows_parameter.add('note', self.nodes[graph_parameter].get('note')) - cmdows_parameter.add('unit', self.nodes[graph_parameter].get('unit')) - cmdows_parameter.add('dataType', self.nodes[graph_parameter].get('data_type')) + if self.nodes[graph_parameter].get('instance', 1) is None: + instance = 1 + else: + instance = int(self.nodes[graph_parameter].get('instance', 1)) + cmdows_parameter.add('instanceID', instance) + + if instance > 1: + cmdows_parameter.add('relatedInstanceUID', self.get_first_node_instance(self.nodes[graph_parameter])) + + else: + cmdows_parameter.add('description', self.nodes[graph_parameter].get('description'), + only_add_if_valued=True) + cmdows_parameter.add('note', self.nodes[graph_parameter].get('note'), only_add_if_valued=True) + cmdows_parameter.add('unit', self.nodes[graph_parameter].get('unit'), only_add_if_valued=True) + cmdows_parameter.add('dataType', self.nodes[graph_parameter].get('data_type'), only_add_if_valued=True) return cmdows_parameters @@ -1154,20 +1178,25 @@ class KadmosGraph(nx.DiGraph, EquationMixin, VistomsMixin): outputs_list = [] for function in cmdows.findall('executableBlocks/designCompetences/designCompetence'): + if function.findtext('relatedInstanceUID'): + related_function = cmdows.xpath(get_uid_search_xpath(function.findtext('relatedInstanceUID')))[0] + else: + related_function = function + self.add_node(function.get('uID'), category='function', - name=function.findtext('ID'), - mode=function.findtext('modeID'), + name=related_function.findtext('ID'), + mode=related_function.findtext('modeID'), instance=function.findtext('instanceID'), - version=function.findtext('version'), + version=related_function.findtext('version'), label=function.findtext('label'), - general_info=function.finddict('metadata/generalInfo', ordered=False, - camel_case_conversion=True), - performance_info=function.finddict('metadata/performanceInfo', ordered=False, - camel_case_conversion=True), - execution_info=function.finddict('metadata/executionInfo', ordered=False, - camel_case_conversion=True), - projectSpecific=function.finddict('projectSpecific')) + general_info=related_function.finddict('metadata/generalInfo', ordered=False, + camel_case_conversion=True), + performance_info=related_function.finddict('metadata/performanceInfo', ordered=False, + camel_case_conversion=True), + execution_info=related_function.finddict('metadata/executionInfo', ordered=False, + camel_case_conversion=True), + projectSpecific=related_function.finddict('projectSpecific')) for inp in function.findall('inputs/input'): self.add_edge(inp.findtext('parameterUID').replace("'", '"'), function.get('uID'), @@ -1228,14 +1257,27 @@ class KadmosGraph(nx.DiGraph, EquationMixin, VistomsMixin): def _load_cmdows_parameters(self, cmdows): for variable in cmdows.findall('parameters/parameter'): - self.add_node(variable.get('uID').replace("'", '"'), + uid = variable.get('uID').replace("'", '"') + + if variable.findtext('relatedInstanceUID'): + related_variable = cmdows.xpath(get_uid_search_xpath(variable.findtext('relatedInstanceUID')))[0] + else: + related_variable = variable + + self.add_node(uid, category='variable', shape='o', label=variable.findtext('label'), - description=variable.findtext('description'), - note=variable.findtext('note'), - unit=variable.findtext('unit'), - data_type=variable.findtext('dataType')) + instance=variable.findtext('instanceID')) + + if related_variable.findtext('description') is not None: + self.nodes[uid]['description'] = related_variable.findtext('description') + if related_variable.findtext('note') is not None: + self.nodes[uid]['note'] = related_variable.findtext('note') + if related_variable.findtext('unit') is not None: + self.nodes[uid]['unit'] = related_variable.findtext('unit') + if related_variable.findtext('dataType') is not None: + self.nodes[uid]['data_type'] = related_variable.findtext('dataType') return @@ -1963,6 +2005,89 @@ class KadmosGraph(nx.DiGraph, EquationMixin, VistomsMixin): for key in attr_dict: self.adj[u][v][key] = attr_dict[key] + def add_instance_of(self, file_path, node): + """Method to duplicate a function with a higher instance + + :param file_path: path to CMDOWS file + :type file_path: basestring + :param node: node to get instance of + :type node: str + :return: new node + :rtype: str + """ + + assert int(self.nodes[node]['instance']) == 1, 'first instance of the function has to be supplied' + + inputs_list = [] + outputs_list = [] + cmdows = etree.parse(file_path, parser).getroot() + cmdows.clean() + ignore_modes=False + + uid = self.add_instance(node) + + kwargs = {'name': self.nodes[node]['name'], 'mode': self.nodes[node]['mode'], 'instance': uid[-1:], + 'version': self.nodes[node]['version'], 'label': self.nodes[node]['label'], + 'general_info': self.nodes[node]['general_info'], + 'performance_info': self.nodes[node]['performance_info'], + 'execution_info': self.nodes[node]['execution_info'], + 'projectSpecific': self.nodes[node]['projectSpecific']} + + new_node = self.copy_node_with_suffix(node, self.INSTANCE_SUFFIX + uid[-1:], '', **kwargs) + + function = cmdows.xpath(get_uid_search_xpath(node))[0] + + for inp in function.findall('inputs/input'): + self.add_edge(inp.findtext('parameterUID').replace("'", '"'), new_node, + valid_ranges=inp.finddict('validRanges', ordered=False, camel_case_conversion=True)) + + if not function.findall('inputs/input'): + # Determine assumed input file location (same folder as CMDOWS file) + input_file_path = os.path.join(os.path.split(os.path.normpath(function.base))[0], + function.findtext('ID') + '-input.xml').replace('file:' + os.path.sep, '') + + if os.path.isfile(input_file_path): + inputs_list.append(input_file_path) + else: + logger.warning('Could not find inputs for function: ' + function.get('uID')) + + for output in function.findall('outputs/output'): + self.add_edge(new_node, output.findtext('parameterUID').replace("'", '"')) + + if not function.findall('outputs/output'): + # Determine assumed output file location (same folder as CMDOWS file) + output_file_path = os.path.join(os.path.split(os.path.normpath(function.base))[0], + function.findtext('ID') + '-output.xml').replace('file:' + os.path.sep, '') + if os.path.isfile(output_file_path): + outputs_list.append(output_file_path) + else: + logger.warning('Could not find outputs for function: ' + function.get('uID')) + + # Add inputs and outputs based on XML + for input_el in inputs_list: + inputs = _read_io_xml_file(input_el, function.findtext('modeID'), ignore_modes=ignore_modes) + for input in inputs['leafNodes']: + if not self.has_node(input['xpath']): + self.add_node(input['xpath'], + category='variable', + shape='o', # TODO: Extend this XML attributes for description, note, unit, data_type + label=input['xpath'].split('/')[-1]) + self.add_edge(input['xpath'], new_node) + + for output_el in outputs_list: + outputs = _read_io_xml_file(output_el, function.findtext('modeID'), ignore_modes=ignore_modes) + for output in outputs['leafNodes']: + # Add new parameter if it does not exist yet + if not self.has_node(output['xpath']): + self.add_node(output['xpath'], + category='variable', + shape='o', + label=output['xpath'].split('/')[ + -1]) # TODO: Extend this to pick up XML attributes for description, note, unit, data_type + self.add_edge(new_node, output['xpath']) + + return new_node + def has_nodes(self, nodes): """Function that checks whether all nodes given in a list are present in the graph. @@ -3322,7 +3447,7 @@ class KadmosGraph(nx.DiGraph, EquationMixin, VistomsMixin): new_instance = highest_instance+1 else: new_instance = instance - if node_instance > 1: + if int(node_instance) > 1: original_node = node[:-len(self.INSTANCE_SUFFIX + str(node_instance))] else: original_node = node @@ -3368,7 +3493,7 @@ class KadmosGraph(nx.DiGraph, EquationMixin, VistomsMixin): :type label_extension: str :param kwargs: keyword arguments will be added as node attributes :type kwargs: dict, int - :return: new node name and enriched graph + :return: new node and enriched graph :rtype: str """ @@ -3454,7 +3579,7 @@ class KadmosGraph(nx.DiGraph, EquationMixin, VistomsMixin): for design_competence in design_competences: id = self.nodes[design_competence].get('name', design_competence) mode = self.nodes[design_competence].get('mode', 'main') - instance = self.nodes[design_competence].get('instance', '1') + instance = self.nodes[design_competence].get('instance', 1) version = self.nodes[design_competence].get('version', '1.0') mapping[design_competence] = '{}[{}][{}][{}]'.format(id, mode, instance, version) des_comps.append(design_competence) @@ -4915,8 +5040,7 @@ def check_database(file_name, source_folder=None, check_list=None, keep_running= if not function.findall('inputs/input'): # Determine assumed input file location (same folder as CMDOWS file) input_file_path = os.path.join(os.path.split(os.path.normpath(function.base))[0], - function.findtext('ID') + '-input.xml').replace('file:' + os.path.sep, - '') + function.findtext('ID') + '-input.xml').replace('file:' + os.path.sep, '') if os.path.isfile(input_file_path): inputs_list.append([input_file_path, function]) else: @@ -4925,8 +5049,7 @@ def check_database(file_name, source_folder=None, check_list=None, keep_running= if not function.findall('inputs/input'): # Determine assumed input file location (same folder as CMDOWS file) output_file_path = os.path.join(os.path.split(os.path.normpath(function.base))[0], - function.findtext('ID') + '-output.xml').replace('file:' + os.path.sep, - '') + function.findtext('ID') + '-output.xml').replace('file:' + os.path.sep, '') if os.path.isfile(input_file_path): outputs_list.append([output_file_path, function]) else: