@@ -109,9 +109,12 @@ def _parent(self):
109109 Returns
110110 -------
111111 EmitNode
112- Parent node name .
112+ Parent node.
113113 """
114- return self ._get_property ("Parent" , True )
114+ parent_name = self ._get_property ("Parent" , True )
115+ parent_name = parent_name .replace ("NODE-*-" , "" )
116+ node_id = self ._oRevisionData .GetTopLevelNodeID (0 , parent_name )
117+ return self ._get_node (node_id )
115118
116119 @property
117120 def properties (self ) -> dict :
@@ -130,6 +133,22 @@ def properties(self) -> dict:
130133 def node_warnings (self ) -> str :
131134 """Warnings for the node, if any.
132135
136+ .. deprecated: 0.21.3
137+ Use warnings property instead
138+
139+ Returns
140+ -------
141+ str
142+ Warning message(s).
143+ """
144+ warnings .warn ("This property is deprecated in 0.21.3. Use the warnings property instead." , DeprecationWarning )
145+
146+ return self .warnings
147+
148+ @property
149+ def warnings (self ) -> str :
150+ """Warnings for the node, if any.
151+
133152 Returns
134153 -------
135154 str
@@ -174,6 +193,7 @@ def _get_node(self, node_id: int):
174193 >>> new_node = node._get_node(node_id)
175194 """
176195 from ansys .aedt .core .emit_core .nodes import generated
196+ from ansys .aedt .core .emit_core .nodes .emitter_node import EmitterNode
177197
178198 props = self ._oRevisionData .GetEmitNodeProperties (self ._result_id , node_id , True )
179199 props = self .props_to_dict (props )
@@ -183,7 +203,23 @@ def _get_node(self, node_id: int):
183203
184204 node = None
185205 try :
186- type_class = getattr (generated , f"{ prefix } { node_type } " )
206+ type_class = EmitNode
207+ if node_type == "RadioNode" and props ["IsEmitter" ] == "true" :
208+ type_class = EmitterNode
209+ # TODO: enable when we add ReadOnlyNodes
210+ # if prefix == "":
211+ # type_class = EmitterNode
212+ # else:
213+ # type_class = ReadOnlyEmitterNode
214+ elif node_type == "Band" and props ["IsEmitterBand" ] == "true" :
215+ type_class = getattr (generated , f"{ prefix } Waveform" )
216+ elif node_type == "TxSpectralProfNode" :
217+ if self .properties ["IsEmitterBand" ] == "true" :
218+ type_class = getattr (generated , f"{ prefix } TxSpectralProfEmitterNode" )
219+ else :
220+ type_class = getattr (generated , f"{ prefix } TxSpectralProfNode" )
221+ else :
222+ type_class = getattr (generated , f"{ prefix } { node_type } " )
187223 node = type_class (self ._emit_obj , self ._result_id , node_id )
188224 except AttributeError :
189225 node = EmitNode (self ._emit_obj , self ._result_id , node_id )
@@ -203,7 +239,7 @@ def children(self):
203239 child_nodes = [self ._get_node (child_id ) for child_id in child_ids ]
204240 return child_nodes
205241
206- def _get_property (self , prop , skipChecks = False ) -> Union [str , List [str ]]:
242+ def _get_property (self , prop , skipChecks = False , isTable = False ) -> Union [str , List [str ]]:
207243 """Fetch the value of a given property.
208244
209245 Parameters
@@ -226,7 +262,14 @@ def _get_property(self, prop, skipChecks=False) -> Union[str, List[str]]:
226262 selected_kv_pair = selected_kv_pairs [0 ]
227263 val = selected_kv_pair [1 ]
228264
229- if val .find ("|" ) != - 1 :
265+ if isTable :
266+ # Node Prop tables
267+ # Data formatted using compact string serialization
268+ # with ';' separating rows and '|' separating columns
269+ rows = val .split (";" )
270+ table = [tuple (row .split ("|" )) for row in rows if row ]
271+ return table
272+ elif val .find ("|" ) != - 1 :
230273 return val .split ("|" )
231274 else :
232275 return val
@@ -271,6 +314,7 @@ def _string_to_value_units(value) -> tuple[float, str]:
271314 # see if we can split it based on a space between number
272315 # and units
273316 vals = value .split (" " )
317+ units = ""
274318 if len (vals ) == 2 :
275319 dec_val = float (vals [0 ])
276320 units = vals [1 ].strip ()
@@ -281,7 +325,11 @@ def _string_to_value_units(value) -> tuple[float, str]:
281325 dec_val = float (value [:i ])
282326 units = value [i :]
283327 return dec_val , units
284- raise ValueError (f"{ value } is not valid for this property." )
328+ # maybe it's a string but with no units
329+ try :
330+ return float (value ), units
331+ except ValueError :
332+ raise ValueError (f"{ value } is not valid for this property." )
285333
286334 def _convert_to_internal_units (self , value : float | str , unit_system : str ) -> float :
287335 """Takes a value and converts to internal EMIT units used for storing values.
@@ -301,9 +349,20 @@ def _convert_to_internal_units(self, value: float | str, unit_system: str) -> fl
301349 """
302350 if isinstance (value , float ) or isinstance (value , int ):
303351 # unitless, so assume SI Units
304- units = consts .SI_UNITS [unit_system ]
352+ if unit_system == "Data Rate" :
353+ # Data rate isn't included as part of PyAedt's unit class
354+ units = "bps"
355+ else :
356+ units = consts .SI_UNITS [unit_system ]
305357 else :
306358 value , units = self ._string_to_value_units (value )
359+ # make sure units were specified, if not use SI Units
360+ if units == "" :
361+ if unit_system == "Data Rate" :
362+ # Data rate isn't included as part of PyAedt unit class
363+ units = "bps"
364+ else :
365+ units = consts .SI_UNITS [unit_system ]
307366 # verify the units are valid for the specified type
308367 if units not in EMIT_VALID_UNITS [unit_system ]:
309368 raise ValueError (f"{ units } are not valid units for this property." )
@@ -331,10 +390,11 @@ def _convert_from_internal_units(value: float, unit_system: str) -> float:
331390 Value in SI units.
332391 """
333392 # get the SI units
334- units = consts .SI_UNITS [unit_system ]
335393 if unit_system == "Data Rate" :
394+ units = "bps"
336395 converted_value = data_rate_conv (value , units , False )
337396 else :
397+ units = consts .SI_UNITS [unit_system ]
338398 converted_value = consts .unit_converter (value , unit_system , EMIT_INTERNAL_UNITS [unit_system ], units )
339399 return converted_value
340400
@@ -424,28 +484,88 @@ def _get_child_node_id(self, child_name: str) -> int:
424484 """
425485 return self ._oRevisionData .GetChildNodeID (self ._result_id , self ._node_id , child_name )
426486
487+ def _is_column_data_table (self ):
488+ """Returns true if the node uses column data tables.
489+
490+ Returns
491+ -------
492+ bool
493+ True if the table is ColumnData, False otherwise.
494+ """
495+ # BB Emission Nodes can have ColumnData or NodeProp tables
496+ # so handle them first
497+ if self ._node_type == "TxBbEmissionNode" :
498+ if self ._get_property ("Noise Behavior" ) == "BroadbandEquation" :
499+ return False
500+ return True
501+
502+ table_title = self ._get_property ("CDTableTitle" , True )
503+ if table_title == "" :
504+ # No ColumnData Table Title, so it's a NodePropTable
505+ return False
506+ return True
507+
427508 def _get_table_data (self ):
428509 """Returns the node's table data.
429510
430511 Returns
431512 -------
432- list
433- The node's table data.
513+ list of tuples
514+ The node's table data as a list of tuples.
515+ [(x1, y1, z1), (x2, y2, z2)]
434516 """
435- rows = self ._oRevisionData .GetTableData (self ._result_id , self ._node_id )
436- nested_list = [col .split (" " ) for col in rows ]
437- return nested_list
517+ try :
518+ if self ._is_column_data_table ():
519+ # Column Data tables
520+ # Data formatted using compact string serialization
521+ # with '|' separating rows and ';' separating columns
522+ data = self ._oRevisionData .GetTableData (self ._result_id , self ._node_id )
523+ rows = data .split ("|" )
524+ string_table = [tuple (row .split (";" )) for row in rows if row ]
525+ table = [tuple (float (x ) for x in t ) for t in string_table ]
526+ else :
527+ # Node Prop tables
528+ # Data formatted using compact string serialization
529+ # with ';' separating rows and '|' separating columns
530+ table_key = self ._get_property ("TableKey" , True )
531+ string_table = self ._get_property (table_key , True , True )
532+
533+ def try_float (val ):
534+ try :
535+ return float (val )
536+ except ValueError :
537+ return val # keep as string for non-numeric (e.g. equations)
538+
539+ table = [tuple (try_float (x ) for x in t ) for t in string_table ]
540+ except Exception as e :
541+ print (f"Failed to get table data for node { self .name } . Error: { e } " )
542+ return table
438543
439- def _set_table_data (self , nested_list ):
544+ def _set_table_data (self , table ):
440545 """Sets the table data for the node.
441546
442547 Parameters
443548 ----------
444- nested_list : list
549+ list of tuples
445550 Data to populate the table with.
551+ [(x1, y1, z1), (x2, y2, z2)]
446552 """
447- rows = [col .join (" " ) for col in nested_list ]
448- self ._oRevisionData .SetTableData (self ._result_id , self ._node_id , rows )
553+ try :
554+ if self ._is_column_data_table ():
555+ # Column Data tables
556+ # Data formatted using compact string serialization
557+ # with '|' separating rows and ';' separating columns
558+ data = "|" .join (";" .join (map (str , row )) for row in table )
559+ self ._oRevisionData .SetTableData (self ._result_id , self ._node_id , data )
560+ else :
561+ # Node Prop tables
562+ # Data formatted using compact string serialization
563+ # with ';' separating rows and '|' separating columns
564+ table_key = self ._get_property ("TableKey" , True )
565+ data = ";" .join ("|" .join (map (str , row )) for row in table )
566+ self ._set_property (table_key , data )
567+ except Exception as e :
568+ print (f"Failed to set table data for node { self .name } . Error: { e } " )
449569
450570 def _add_child_node (self , child_type , child_name = None ):
451571 """Creates a child node of the given type and name.
@@ -455,28 +575,29 @@ def _add_child_node(self, child_type, child_name=None):
455575 child_type : EmitNode
456576 Type of child node to create.
457577 child_name : str, optional
458- Optional name to use for the child node. If None, a default name is used.
578+ Name to use for the child node. If None, a default name is used.
459579
460580 Returns
461581 -------
462- int
463- Unique node ID assigned to the created child node.
582+ node: EmitNode
583+ The node.
464584
465585 Raises
466586 ------
467587 ValueError
468588 If the specified child type is not allowed.
469589 """
470590 if not child_name :
471- child_name = f"New { child_type } "
591+ child_name = f"{ child_type } "
472592
473- new_id = None
593+ new_node = None
474594 if child_type not in self .allowed_child_types :
475595 raise ValueError (
476596 f"Child type { child_type } is not allowed for this node. Allowed types are: { self .allowed_child_types } "
477597 )
478598 try :
479599 new_id = self ._oRevisionData .CreateEmitNode (self ._result_id , self ._node_id , child_name , child_type )
600+ new_node = self ._get_node (new_id )
480601 except Exception as e :
481602 print (f"Failed to add child node of type { child_type } to node { self .name } . Error: { e } " )
482- return new_id
603+ return new_node
0 commit comments