Basic node editing

This page describe the maia.pytree functions to read or write the different attributes of a CGNSTree. These functions are simple but provide the basis for complex operations.

Vocabulary

According to the CGNS standard, a CGNS node is a structure described by three attributes:

  • a name, which is a case-sensitive identifier shorter than 32 characters;

  • a label, which must be taken from a predefined list;

  • a optional value, which is a (possibly multidimensional) array of data;

plus a list of children which are themselves nodes. Due to that, nodes have in fact a hierarchic structure, which is why we rather employ the word tree to refer to them.

The organisation of this structure (for example: what are the allowed labels under each node, or what are the allowed values for each label) is defined by the CGNS/SIDS description and will not be described here.

In addition, the sids-to-python specification defines how to describe a node structure in python. maia.pytree conforms to this mapping which, in short, states that:

  • node names and labels are simple str objects

  • node values can be either None, or a numpy F-contiguous array

  • nodes are defined by a list following the pattern [name, value, children_list, label]

Node edition

Accessing to the different attributes of a node with the [] operator is possible but error-prone. Consequently, we advice the user to use the available getters and setters:

get_name(node)

Return the name of a CGNSNode

set_name(node, name)

Set the name of a CGNSNode

get_label(node)

Return the label of a CGNSNode

set_label(node, label)

Set the label of a CGNSNode

get_children(node)

Return the list of children of a CGNSNode

add_child(node, child)

Append a child node to the children list of a CGNSNode.

rm_child(node, child)

Remove the node child to the children list of node node.

set_children(node, children)

Set the children list of a CGNSNode

get_value(node[, raw])

Return the value of a CGNSNode

set_value(node, value)

Set the value of a CGNSNode

update_node(node[, name, label, value, children])

Update some attribute of a CGNSNode

Here is few examples using theses functions:

>>> node = ["MyNode", None, [], "UserDefinedData_t"]
>>> PT.get_name(node)
'MyNode'
>>> PT.set_value(node, [1,2,3])
>>> PT.get_value(node)
array([1, 2, 3], dtype=int32)
>>> pnode = ["ParentNode", np.array([3.14]), [], "UserDefinedData_t"]
>>> PT.set_children(pnode, [node])
>>> len(PT.get_children(pnode))
1
>>> PT.update_node(node, name="MyUpdatedNode")
>>> [PT.get_name(n) for n in PT.get_children(pnode)]
['MyUpdatedNode']

Similarly, although trees can be displayed with the print() function, it is preferable to use print_tree() for a better rendering:

>>> print(pnode)
['ParentNode', array([3.14]), [['MyUpdatedNode', array([1, 2, 3], dtype=int32), [], 'UserDefinedData_t']], 'UserDefinedData_t']
>>> PT.print_tree(pnode)
ParentNode UserDefinedData_t R8 [3.14]
└───MyUpdatedNode UserDefinedData_t I4 [1 2 3]

See also

In practice, it is common to use searches to navigate in tree hierarchie and inspection to get relevant data.

Node creation

In the same idea of avoiding to manipulate the underlying list by hand, the following functions can be used to create new nodes:

new_node([name, label, value, children, parent])

Create a new CGNS node

new_child(parent, name[, label, value, children])

Create a new CGNS node as a child of an other node

update_child(parent, name[, label, value, ...])

Create a child or update its attributes

The previous snippet can thus be rewritted in more compact form:

>>> pnode = PT.new_node("ParentNode", "UserDefinedData_t", 3.14)
>>> node = PT.new_child(pnode, "MyNode", "UserDefinedData_t", [1,2,3])
>>> PT.update_node(node, name="MyUpdatedNode")
>>> PT.print_tree(pnode)
ParentNode UserDefinedData_t R8 [3.14]
└───MyUpdatedNode UserDefinedData_t I4 [1 2 3]

See also

In practice, it is common to use presets for a quicker and CGNS/SIDS-compliant creation of nodes with a specific label.

API reference

get_name(node)

Return the name of a CGNSNode

Parameters

node (CGNSTree) – Input node

Returns

str – Name of the node

Example

>>> PT.get_name(PT.new_node(name='MyNodeName', label='Zone_t'))
'MyNodeName'
get_label(node)

Return the label of a CGNSNode

Parameters

node (CGNSTree) – Input node

Returns

str – Label of the node

Example

>>> PT.get_label(PT.new_node('Zone', label='Zone_t'))
'Zone_t'
get_value(node, raw=False)

Return the value of a CGNSNode

If value is an array of characters, it returned as a (or a sequence of) string, unless raw parameter is True.

Parameters
  • node (CGNSTree) – Input node

  • raw (bool) – If True, always return the numpy array

Returns

CGNSValue – Value of the node

Example

>>> PT.get_value(PT.new_node('MyNode', value=3.14))
array([3.14], dtype=float32)
get_value_type(node)

Return the value type of a CGNSNode

This two letters string identifies the datatype of the node and belongs to ["MT", "B1", "C1", "I4", "U4", "I8", "U8", "R4", "R8", "X4", "X8"]

Parameters

node (CGNSTree) – Input node

Returns

str – Value type of the node

Example

>>> PT.get_value_type(PT.new_node('MyNode', value=None))
'MT'
get_value_kind(node)

Return the value kind of a CGNSNode

If node is not empty, this one letter string identifies the datakind of the node and belongs to ["MT", "B", "C", "I", "U", "R", "X"]

Parameters

node (CGNSTree) – Input node

Returns

str – Value kind of the node

Example

>>> PT.get_value_kind(PT.new_node('MyNode', value=3.14))
'R'
get_children(node)

Return the list of children of a CGNSNode

Parameters

node (CGNSTree) – Input node

Returns

List[CGNSTree] – Children of the node

Example

>>> len(PT.get_children(PT.new_node('MyNode')))
0
set_name(node, name)

Set the name of a CGNSNode

Parameters
  • node (CGNSTree) – Input node

  • name (str) – Name to be set

Warns

RuntimeWarning – If name is longer than 32 characters

Raises

ValueError – If name is not valid

Example

>>> node = PT.new_node('Node')
>>> PT.set_name(node, 'UpdatedNodeName')
set_label(node, label)

Set the label of a CGNSNode

Parameters
  • node (CGNSTree) – Input node

  • label (str) – Label to be set

Warns

RuntimeWarning – If label does not belong to SIDS label list

Raises

ValueError – If label is not valid

Example

>>> node = PT.new_node('BCNode')
>>> PT.set_label(node, 'BC_t')
set_value(node, value)

Set the value of a CGNSNode

If value is neither None nor a f-contiguous numpy array, it is converted to a suitable numpy array depending on its type:

  • Literal (or sequence of) floats are converted to R4 arrays

  • Literal (or sequence of) ints are converted to I4 arrays if possible, I8 otherwise

  • Numpy scalars keep their corresponding kind

  • Strings are converted to numpy bytearrays

  • Sequence of N strings are converted to numpy (32,N) shaped bytearrays

  • Nested sequence of strings (M sequences of N strings) are converted to numpy (32, N, M) shaped bytearrays

Parameters
  • node (CGNSTree) – Input node

  • value (Any) – Value to be set

Example

>>> node = PT.new_node('Node')
>>> PT.set_value(node, [3,2,1])
set_children(node, children)

Set the children list of a CGNSNode

This will replace the existing children with the provided list. See also: add_child()

Parameters
  • node (CGNSTree) – Input node

  • children (List[CGNSTree]) – Children to be set

Example

>>> node = PT.new_node('Zone', 'Zone_t')
>>> PT.add_child(node, PT.new_node('ZoneType', 'ZoneType_t', 'Structured'))
>>> PT.set_children(node, []) # Replace the children with the given list
>>> len(PT.get_children(node))
0
add_child(node, child)

Append a child node to the children list of a CGNSNode.

Parameters
  • node (CGNSTree) – Input node

  • child (CGNSTree) – Child node to be add

Raises

RuntimeError – If a node with same name than child already exists

Example

>>> node = PT.new_node('Zone', 'Zone_t')
>>> PT.add_child(node, PT.new_node('ZoneType', 'ZoneType_t', 'Structured'))
rm_child(node, child)

Remove the node child to the children list of node node.

Parameters
  • node (CGNSTree) – Input node

  • child (CGNSTree) – Child node to remove

Raises

RuntimeError – If child does not exists in node children list

Example

>>> node = PT.new_node('Zone', 'Zone_t')
>>> child = PT.new_node('ZoneType', 'ZoneType_t', 'Structured')
>>> PT.add_child(node, child)
>>> PT.rm_child(node, child)
>>> PT.get_children(node)
[]
update_node(node, name=UNSET, label=UNSET, value=UNSET, children=UNSET)

Update some attribute of a CGNSNode

Parameters which are provided to the function trigger the update of their corresponding attribute.

Parameters

Example

>>> node = PT.new_node('Zone')
>>> PT.update_node(node, label='Zone_t', value=[[11,10,0]])
>>> node
['Zone', array([[11, 10,  0]], dtype=int32), [], 'Zone_t']
new_node(name='Node', label='UserDefinedData_t', value=None, children=[], parent=None)

Create a new CGNS node

If parent is not None, this node is appended as a child to the parent node.

Parameters
  • name (str) – Name of the created node – see set_name()

  • label (str) – Label of the created node – see set_label()

  • value (Any) – Value of the created node – see set_value()

  • children (List[CGNSTree]) – Value of the created node – see set_children()

  • parent (CGNSTree or None) – Other node, where created node should be attached

Returns

CGNSTree – Created node

Example

>>> zone = PT.new_node('Zone', label='Zone_t') # Basic node creation
>>> PT.new_node('ZoneType', 'ZoneType_t', "Unstructured",
...             parent=zone) # Create and attach to a parent
>>> PT.print_tree(zone)
Zone Zone_t
└───ZoneType ZoneType_t "Unstructured"
new_child(parent, name, label='UserDefinedData_t', value=None, children=[])

Create a new CGNS node as a child of an other node

This is an alternative form of new_node(), with mandatory parent argument.

Parameters

all – See new_node()

Returns

CGNSTree – Created node

Example

>>> zone = PT.new_node('Zone', label='Zone_t') # Basic node creation
>>> PT.new_child(zone, 'ZoneType', 'ZoneType_t', "Unstructured")
>>> PT.print_tree(zone)
Zone Zone_t
└───ZoneType ZoneType_t "Unstructured"
update_child(parent, name, label=UNSET, value=UNSET, children=UNSET)

Create a child or update its attributes

This is an alternative form of new_child(), but this function allow the parent node to already have a child of the given name: in this case, its attributes are updated. Otherwise, the child is created with the default values of new_child()

Parameters

all – See new_child()

Returns

CGNSTree – Created node

Example

>>> zone = PT.new_node('Zone', label='Zone_t') # Basic node creation
>>> PT.update_child(zone, 'ZoneType', 'ZoneType_t') # Child is created
>>> PT.update_child(zone, 'ZoneType', value="Unstructured") # Child is updated
>>> PT.print_tree(zone)
Zone Zone_t
└───ZoneType ZoneType_t "Unstructured"
print_tree(tree, out=sys.stdout, **kwargs)

Display the arborescence of a CGNSTree

By default, display will be done in the standard output. It is possible to print in a file by setting out to either a string or a python file object:

PT.print_tree(tree)                # Print tree in stdout
PT.print_tree(tree, 'tree.txt')    # Print tree in a tree.txt file
with open('out.txt', 'w') as f:
    PT.print_tree(tree, f)         # Print tree in f

In addition, the following kwargs can be used to parametrize the output:

  • colors (bool) – If False, disable the colors in rendered text. Default to True for stdout or stderr output, and False for file output.

  • verbose (bool) – If True, data arrays are displayed (using numpy display settings). Otherwise, small arrays are printed, and large arrays only show their size. Defaults to False.

  • max_depth (int) – Stop printing once max_depth is reached. By default, displays all nodes.

  • print_if (callable) – If set, it must be a function with the signature : f(n:CGNSTree) -> bool. The branches not leading to a node that evaluates to True are removed from displayed tree.

Parameters
  • tree (CGNSTree) – Node to be printed

  • out (TextIO) – Where to print

See also

To display a tree in custom output, use function to_string() which takes the same parameters, except out, and return the string representation of the tree.

Examples

>>> tree = PT.yaml.to_node('''
... Base CGNSBase_t [3,3]:
...   Wall Family_t:
...   MyZone Zone_t I4 [[16,6,0]]:
...     GridCoordinates GridCoordinates_t:
...       CoordinateX DataArray_t [0,1,2,3,0,1,2,3,0,1,2,3,0,1,2,3]:
... ''')
>>> PT.print_tree(tree)
Base CGNSBase_t I4 [3 3]
├───Wall Family_t
└───MyZone Zone_t I4 [[16  6  0]]
    └───GridCoordinates GridCoordinates_t
        └───CoordinateX DataArray_t I4 (16,)
>>> PT.print_tree(tree, max_depth=1)
Base CGNSBase_t I4 [3 3]
├───Wall Family_t
└───MyZone Zone_t I4 [[16  6  0]]
    ╵╴╴╴ (1 child masked)

On the next example, notice that the branches not leading to ‘CoordinateX’ are not printed; and, because of verbose option, all the coordinate array is displayed.

>>> PT.print_tree(tree, verbose=True,
...               print_if=lambda n : PT.get_name(n) == 'CoordinateX')
Base CGNSBase_t I4 [3 3]
└───MyZone Zone_t I4 [[16  6  0]]
    └───GridCoordinates GridCoordinates_t
        └───CoordinateX DataArray_t I4 (16,)
            [0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3]