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
strobjectsnode values can be either
None, or a numpy F-contiguous arraynodes 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:
|
Return the name of a CGNSNode |
|
Set the name of a CGNSNode |
|
Return the label of a CGNSNode |
|
Set the label of a CGNSNode |
|
Return the list of children of a CGNSNode |
|
Append a child node to the children list of a CGNSNode. |
|
Remove the node |
|
Set the children list of a CGNSNode |
|
Return the value of a CGNSNode |
|
Set the value of a CGNSNode |
|
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:
|
Create a new CGNS node |
|
Create a new CGNS node as a child of an other node |
|
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
Nonenor 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
childalready 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
childto the children list of nodenode.- Parameters
node (CGNSTree) – Input node
child (CGNSTree) – Child node to remove
- Raises
RuntimeError – If
childdoes not exists innodechildren 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
node (CGNSTree) – Input node
others – See
set_name(),set_label(),set_value(),set_children()
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
parentis 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 mandatoryparentargument.- 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 ofnew_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 toTruefor stdout or stderr output, andFalsefor 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 toFalse.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 toTrueare 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, exceptout, 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]