@@ -110,7 +110,12 @@ def __init__(self, json_description, system: System, resources: dict):
110110 listofsystems = []
111111 ## add components
112112 for comp in unit ["components" ]:
113- comp_path = "." .join ([solver_path ] + [comp ["name" ][- 1 ]])
113+ if len (comp ["name" ]) <= 2 :
114+ comp_path = "." .join ([solver_path ] + [comp ["name" ][- 1 ]])
115+ else :
116+ ## add prefix to nested systems to avoid name conflicts while flattening the system during instantiation, e.g. sub-system1_Add1, sub-system1_Gain1
117+ comp_name = f"{ comp ['name' ][- 2 ]} _{ comp ['name' ][- 1 ]} "
118+ comp_path = "." .join ([solver_path ] + [comp_name ])
114119 currentSystem = "." .join (comp ["name" ][:- 1 ])
115120 if currentSystem not in listofsystems :
116121 listofsystems .append (currentSystem )
@@ -124,6 +129,10 @@ def __init__(self, json_description, system: System, resources: dict):
124129 ## parse connector geometry for the component if exist and set it to capi after adding the component, this is needed for proper mapping of connector geometry
125130 if "connectors" in comp :
126131 for connector in comp ["connectors" ]:
132+ comp_name = "." .join (comp ["name" ])
133+ connector_name = "." .join ([comp_name ]+ [connector ["name" ]])
134+ if not connector_name in self .mappedCrefs :
135+ self .mappedCrefs [connector_name ] = f"{ comp_path } .{ connector ['name' ]} "
127136 if "geometry" in connector :
128137 connector_path = "." .join ([comp_path , connector ["name" ]])
129138 geometry = connector ["geometry" ]
@@ -168,10 +177,16 @@ def __init__(self, json_description, system: System, resources: dict):
168177
169178 ## add connections
170179 for connection in unit ["connections" ]:
171- start_element = "." .join (connection ['start element' ])
172- end_element = "." .join (connection ['end element' ])
173- start = self .mappedCrefs [start_element ] + f".{ connection ['start connector' ]} "
174- end = self .mappedCrefs [end_element ] + f".{ connection ['end connector' ]} "
180+ start_element = "." .join (connection ['start element' ] + [connection ['start connector' ]])
181+ end_element = "." .join (connection ['end element' ] + [connection ['end connector' ]])
182+
183+ if start_element not in self .mappedCrefs :
184+ raise KeyError (f"No mapping found for { start_element } " )
185+ if end_element not in self .mappedCrefs :
186+ raise KeyError (f"No mapping found for { end_element } " )
187+
188+ start = self .mappedCrefs [start_element ]
189+ end = self .mappedCrefs [end_element ]
175190 self .apiCall .append (f'oms_addConnection("{ start } ", "{ end } ")' )
176191 status = Capi .addConnection (start , end )
177192 if status != Status .ok :
@@ -265,6 +280,27 @@ def validatePath(self, mapped_prefix : list, suffix : list):
265280
266281 return "." .join (mapped_prefix + result )
267282
283+ def validate_cref (self , systemName : str , suffix : str ) -> str :
284+ ## remove common path from suffix
285+ ## e.g. systemName = model.root.solver2.gain1
286+ ## suffix = gain1.R1.T
287+ ## result = model.root.solver2.gain1.R1.T
288+
289+ a_parts = systemName .split ("." )
290+ b_parts = suffix .split ("." )
291+
292+ # detect overlap
293+ overlap = 0
294+ for i in range (1 , min (len (a_parts ), len (b_parts )) + 1 ):
295+ if a_parts [- i :] == b_parts [:i ]:
296+ overlap = i
297+ cref = "." .join (a_parts + b_parts [overlap :])
298+ if cref in self .mappedCrefs :
299+ return self .mappedCrefs [cref ]
300+ else :
301+ ## it is possible some variables are not listed in connectors but it is still valid signal
302+ return self .map_cref (systemName , suffix )
303+
268304 def setStartValues (self , value : Values , systemName : str , ssm : SSM | None ):
269305 if value .empty ():
270306 return
@@ -280,13 +316,15 @@ def setStartValues(self, value: Values, systemName: str, ssm: SSM | None):
280316 for entry in targets :
281317 target = entry ["target" ]
282318 linearTransformation = entry ["linearTransformation" ]
283- value_path = self .map_cref (systemName , str (target ))
319+ cref = f"{ systemName } .{ str (target )} "
320+ value_path = self .validate_cref (systemName , str (target ))
284321 if linearTransformation :
285322 source_value = source_value * float (linearTransformation .factor ) + float (linearTransformation .offset )
286323 self .apply_start_value (value_path , source_value , type )
287324 else :
288325 for key , (source_value , type , _ , _ ) in value .start_values .items ():
289- value_path = self .map_cref (systemName , str (key ))
326+ cref = f"{ systemName } .{ str (key )} "
327+ value_path = self .validate_cref (systemName , str (key ))
290328 self .apply_start_value (value_path , source_value , type )
291329
292330 def apply_start_value (self , value_path :str , value , type ):
@@ -314,8 +352,14 @@ def apply_start_value(self, value_path:str, value, type):
314352
315353 def _addConnector (self , connectors , systemName ):
316354 for connector in connectors :
317- name = [systemName ] + [str (connector .name )]
318- connector_path = "." .join ([self .mappedCrefs [systemName ], str (connector .name )])
355+ connector_name = "." .join ([systemName ]+ [str (connector .name )])
356+ system_name = systemName .split ("." )
357+ if len (system_name ) == 1 :
358+ connector_path = "." .join ([self .mappedCrefs [systemName ], str (connector .name )])
359+ else :
360+ ## add prefix to nested systems to avoid name conflicts while flattening the system during instantiation, e.g. sub-system1_input1, sub-system1_param1
361+ connector_name_prefix = f"{ system_name [- 1 ]} _{ str (connector .name )} " # replace '-' with '_' for sub-system name in connector path
362+ connector_path = "." .join ([self .mappedCrefs [systemName ], connector_name_prefix ])
319363 self .apiCall .append (f'oms_addConnector("{ connector_path } ", "{ connector .causality } ", { connector .signal_type } )' )
320364 status = Capi .addConnector (connector_path , connector .causality .value , connector .c_signal_type .value )
321365 if status != Status .ok :
@@ -336,11 +380,14 @@ def _addConnector(self, connectors, systemName):
336380 raise RuntimeError (f"Failed to set connector geometry for { connector_path } : { status } " )
337381
338382 export_name = systemName
339- if not export_name in self .mappedCrefs :
340- self .mappedCrefs [export_name ] = connector_path
383+ if not connector_name in self .mappedCrefs :
384+ self .mappedCrefs [connector_name ] = connector_path
341385 status = Capi .setExportName (connector_path , export_name ) # Set export name if provided
342386 if status != Status .ok :
343387 raise RuntimeError (f"Failed to set export name: { status } " )
388+ status = Capi .setAliasName (connector_path , str (connector .name )) # Set alias name for connector
389+ if status != Status .ok :
390+ raise RuntimeError (f"Failed to set alias name: { status } " )
344391
345392 def addConnectorFromElements (self , elements , currentSystem ):
346393 ## add connectors mapped with currentSystem
@@ -359,11 +406,18 @@ def dumpApiCalls(self):
359406
360407 def setValue (self , cref : CRef , value ):
361408 """Sets a value for a specific CRef in the model."""
362- name = "." .join (cref .names [:- 1 ])
363- if name not in self .mappedCrefs :
364- raise KeyError (f"Missing required key: '{ name } '" )
409+ name = "." .join (cref .names )
365410
366- value_path = "." .join ([self .mappedCrefs [name ], cref .names [- 1 ]])
411+ ## check for top level connectors with alias names first
412+ ## e.g model.root.sub_system_input which will be in mapped crefs
413+ if name in self .mappedCrefs :
414+ value_path = self .mappedCrefs [name ]
415+ else :
416+ ## check for other crefs by splitting with suffixes
417+ name = "." .join (cref .names [:- 1 ])
418+ if name not in self .mappedCrefs :
419+ raise KeyError (f"Missing required key: '{ cref .names } '" )
420+ value_path = "." .join ([self .mappedCrefs [name ], cref .names [- 1 ]])
367421
368422 # Determine the variable type
369423 type , status = Capi .getVariableType (value_path )
@@ -387,35 +441,41 @@ def setValue(self, cref: CRef, value):
387441 raise TypeError (f"Unsupported type: { type } " )
388442
389443 def _setReal (self , mapped_cref : str , value : float ):
390- self .apiCall .append (f'oms_setReal("{ mapped_cref } , { value } )' )
444+ self .apiCall .append (f'oms_setReal("{ mapped_cref } " , { value } )' )
391445 status = Capi .setReal (mapped_cref , value ) # Get the value from the CAPI
392446 if status != Status .ok :
393447 raise RuntimeError (f"Failed to set value for { mapped_cref } : { status } " )
394448
395449 def _setInteger (self , mapped_cref : str , value : int ):
396- self .apiCall .append (f'oms_setInteger("{ mapped_cref } , { value } )' )
450+ self .apiCall .append (f'oms_setInteger("{ mapped_cref } " , { value } )' )
397451 status = Capi .setInteger (mapped_cref , value ) # Get the value from the CAPI
398452 if status != Status .ok :
399453 raise RuntimeError (f"Failed to set value for { mapped_cref } : { status } " )
400454
401455 def _setBoolean (self , mapped_cref : str , value : bool ):
402- self .apiCall .append (f'oms_setBoolean("{ mapped_cref } , { value } )' )
456+ self .apiCall .append (f'oms_setBoolean("{ mapped_cref } " , { value } )' )
403457 status = Capi .setBoolean (mapped_cref , value ) # Get the value from the CAPI
404458 if status != Status .ok :
405459 raise RuntimeError (f"Failed to set value for { mapped_cref } : { status } " )
406460
407461 def _setString (self , mapped_cref : str , value : str ):
408- self .apiCall .append (f'oms_setString("{ mapped_cref } , { value } )' )
462+ self .apiCall .append (f'oms_setString("{ mapped_cref } " , { value } )' )
409463 status = Capi .setString (mapped_cref , value ) # Get the value from the CAPI
410464 if status != Status .ok :
411465 raise RuntimeError (f"Failed to set value for { mapped_cref } : { status } " )
412466
413467 def getValue (self , cref : CRef ):
414- name = "." .join (cref .names [:- 1 ])
415- if name not in self .mappedCrefs :
416- raise KeyError (f"Missing required key: '{ name } '" )
417-
418- value_path = "." .join ([self .mappedCrefs [name ], cref .names [- 1 ]])
468+ name = "." .join (cref .names )
469+ ## check for top level connectors with alias names first
470+ ## e.g model.root.sub_system_input which will be in mapped crefs
471+ if name in self .mappedCrefs :
472+ value_path = self .mappedCrefs [name ]
473+ else :
474+ ## check for other crefs by splitting with suffixes
475+ name = "." .join (cref .names [:- 1 ])
476+ if name not in self .mappedCrefs :
477+ raise KeyError (f"Missing required key: '{ cref .names } '" )
478+ value_path = "." .join ([self .mappedCrefs [name ], cref .names [- 1 ]])
419479
420480 # Determine the variable type
421481 type , status = Capi .getVariableType (value_path )
0 commit comments