Node searching

It is often necessary to select one or several nodes matching a specific condition in a CGNSTree. maia.pytree provides various functions to do that, depending of what is needed.

Tutorial

Almost all the functions have the following pattern:

get_node(s)_from_{predicate}(s)(node, condition, **kwargs)

node has the same meaning for all the search functions, and is simply the tree in which the search is performed. Then, by choosing appropriate keyword for {predicate} and using or not the s suffixes, lot of cases can be covered.

To illustrate the different possibilities, let’s consider the following example tree:

ZoneBC ZoneBC_t
├───BC1 BC_t
│   ├───GridLocation GridLocation_t "Vertex"
│   ├───PointRange IndexRange_t [[ 1 11] [ 1  1]]
│   └───BCDataSet BCDataSet_t "Null"
│       ├───PointRange IndexRange_t [[1 5] [1 1]]
│       └───GridLocation GridLocation_t "FaceCenter"
└───BC2 BC_t
    ├───GridLocation GridLocation_t "Vertex"
    └───PointRange IndexRange_t [[ 1 11] [ 6  6]]

Search condition

The first customizable thing is {predicate}, which indicates which criteria is applied to every node to select it or not. The condition is the concrete value of the criteria:

Function

Condition kind

get_..._from_name()

str

get_..._from_label()

str

get_..._from_value()

value

get_..._from_predicate()

function

The first functions are easy to understand: note just here that from_name and from_label accept wildcards * in their condition.

The last one is the more general and take as predicate a function, which will be applied to the nodes of the tree, and must return True (node is selected) or False (node is not selected) : f(n:CGNSTree) -> bool

Here is an example of these functions:

>>> PT.get_node_from_name(node, 'BC2')
# Return node BC2
>>> PT.get_node_from_label(node, 'BC_t')
# Return node BC1
>>> PT.get_node_from_value(node, [[1,5],[1,1]])
# Return the PointRange node located under BCDataSet
>>> PT.get_node_from_predicate(node, lambda n: 'BC' in PT.get_label(n)
...    and PT.Subset.GridLocation(n) == 'FaceCenter')
# Return node BCDataSet

See also

There is also a get_..._from_name_and_label() form, which takes two str as condition: first one is for the name, second one for the label.

>>> PT.get_node_from_name_and_label(node, '*', '*Location_t')
# Return node GridLocation of BC1

Number of results

The second customizable thing is the s after node, which can be used to decide if the search will return the first node matching the predicate, or all the nodes matching the predicate:

Function

Return

get_node_from_...()

First node found or None

get_nodes_from_...()

List of all the nodes found or []

>>> PT.get_node_from_label(node, 'BC_t')
# Return node BC1
>>> PT.get_nodes_from_label(node, 'BC_t')
# Return a list containing BC1, BC2
>>> PT.get_node_from_label(node, 'DataArray_t')
# Return None
>>> PT.get_nodes_from_label(node, 'DataArray_t')
# Return an empty list

See also

All the get_nodes_from_...() functions have a iter_nodes_from_...() variant, which return a generator instead of a list and can be used for looping

Chaining searches (advanced)

When looking for a particular node, it is often necessary to chain several searches. For example, if we want to select the BCData nodes under a BCDataSet node, we can do

>>> for bcds in PT.get_nodes_from_label(node, 'BCDataSet_t'):
>>>   for bcdata in PT.get_nodes_from_label(bcds, 'BCData_t'):
>>>     # Do something with bcdata nodes

This code can be reduced to a single function call by just adding a s to the search function, and changing the condition to a list :

>>> for bcdata in PT.get_nodes_from_labels(node, ['BCDataSet_t', 'BCData_t']):
>>>   # Do something with bcdata nodes

Just as before, a search will be performed starting from node, using the first condition; from the results, a second search will be performed using the second condition; and so on.

Tip

Since it can be cumbersome to write manually several predicate functions, the get_..._from_predicates() come with “autopredicate” feature: the list of functions can be replaced by a string, which is converted from the following steps:

  • String is split from separator '/'

  • Each substring is replaced by get_label if it ends with _t, and by get_name otherwise.

>>> for bcdata in PT.get_nodes_from_predicates(node, 'BCDataSet_t/BCData_t'):
>>>   # Do something wih bcdata nodes

Note that the generic versions get_..._from_predicates() expect a list of predicate functions as condition, and can thus be used to mix the kind of criteria used to compare at each level :

>>> is_bc = lambda n : PT.get_label(n) == 'BC_t' and
...                    PT.get_node_from_label(n, 'BCDataSet_t') is None
>>> is_pr = lambda n : PT.get_name(n) == 'PointRange'
>>> for pr in PT.get_nodes_from_predicates(node, [is_bc, is_pr]):
>>>   # Do something with pr nodes

Fine tuning searches

Here is a selection of the most usefull kwargs accepted by the functions. See API reference for the full list.

  • depth (integer): Apply to all the functions

    Restrict the search to the nth level of children, where level 0 is the input node itself. If unset, search is not restricted.

    Tip

    Limiting the search to a single level is so common that all the functions have a specific variant to do that :

    • get_child_from_...() means get_node_from_...() with depth==1

    • get_children_from_...() means get_nodes_from_...() with depth==1

    >>> PT.get_nodes_from_label(node, 'GridLocation_t')
    # Return the 3 GridLocation nodes
    >>> PT.get_nodes_from_label(node, 'GridLocation_t', depth=2)
    # Return the 2 GridLocation nodes under the BC nodes
    
  • explore (‘shallow’ or ‘deep’): Apply to get_nodes_from_… functions

    If explore == ‘shallow’, the children of a node matching the predicate are not tested. If explore=’deep’, all the nodes are tested. Default is ‘shallow’.

    >>> PT.get_nodes_from_label(node, 'BC*_t')
    # Return nodes BC1 and BC2
    >>> PT.get_nodes_from_label(node, 'BC*_t', explore='deep')
    # Return nodes BC1, BCDataSet and BC2
    
  • ancestors (bool): Advanced – Apply to get_…_from_predicates functions

    If True, return tuple of nodes instead of the terminal node. Tuple is of size len(conditions) and contains all the intermediate results. Default is False.

    >>> for bc, loc in PT.get_nodes_from_predicates(node,
    ...                                             'BC_t/GridLocation_t',
    ...                                             ancestors=True):
    ...   print(PT.get_name(bc), PT.get_value(loc))
    BC1 Vertex
    BC1 FaceCenter
    BC2 Vertex
    

Summary

Here is an overview of the available searching functions:

Generic version of search functions

Return first match

Return all matches

Iterate all matches

Single predicate

get_node_from_predicate()

get_nodes_from_predicate()

iter_nodes_from_predicate()

Multiple predicates

get_node_from_predicates()

get_nodes_from_predicates()

iter_nodes_from_predicates()

Specialized versions of search functions

Return first match

Return all matches

Iterate all matches

Single predicate

get_node_from_name() get_node_from_label() get_node_from_value() get_node_from_name_and_label() get_child_from_name() get_child_from_label() get_child_from_value() get_child_from_name_and_label()

get_nodes_from_name() get_nodes_from_label() get_nodes_from_value() get_nodes_from_name_and_label() get_children_from_name() get_children_from_label() get_children_from_value() get_children_from_name_and_label()

iter_nodes_from_name() iter_nodes_from_label() iter_nodes_from_value() iter_nodes_from_name_and_label() iter_children_from_name() iter_children_from_label() iter_children_from_value() iter_children_from_name_and_label()

Multiple predicates

get_node_from_names() get_node_from_labels() get_node_from_values() get_node_from_name_and_labels() get_child_from_names() get_child_from_labels() get_child_from_values() get_child_from_name_and_labels()

get_nodes_from_names() get_nodes_from_labels() get_nodes_from_values() get_nodes_from_name_and_labels() get_children_from_names() get_children_from_labels() get_children_from_values() get_children_from_name_and_labels()

iter_nodes_from_names() iter_nodes_from_labels() iter_nodes_from_values() iter_nodes_from_name_and_labels() iter_children_from_names() iter_children_from_labels() iter_children_from_values() iter_children_from_name_and_labels()

The following functions do not directly derive from the previous one, but allow additional usefull searches:

get_node_from_path(root, path)

Return the node in input tree matching given path, or None

get_all_CGNSBase_t(root)

Return the list of all the CGNSBase_t nodes found in input tree

get_all_Zone_t(root)

Return the list of all the Zone_t nodes found in input tree

API reference

get_node_from_predicate(root, predicate, **kwargs)

Return the first node in input tree matching the given predicate, or None

The search can be fine-tuned with the following kwargs:

  • depth (int or pair of int): limit the search between the depths minD and maxD, 0 beeing the input node itself and None meaning unlimited. If a single int is provided, it is assigned to maxD. Defaults to (0,None).

  • search (str): use a Depth-First-Search ('dfs') or Breath-First-Search ('bfs') algorithm. Defaults to 'dfs'.

Parameters
  • root (CGNSTree) – Tree is which the search is performed

  • predicate (callable) – condition to select node, which must have the following signature: f(n:CGNSTree) -> bool

  • **kwargs – Additional options (see above)

Returns

CGNSTree or None – Node found

Note

This function admits the following shorcuts:

  • get_node_from_name|label|value|name_and_label() (embedded predicate)

  • get_child_from_name|label|value|name_and_label() (embedded predicate + depth=[1,1])

get_nodes_from_predicate(root, predicate, **kwargs)

Return the list of all nodes in input tree matching the given predicate

The search can be fine-tuned with the following kwargs:

  • depth (int or pair of int): see get_node_from_predicate()

  • search (str): see get_node_from_predicate()

  • explore (str): Explore the whole tree ('deep') or stop exploring the current branch once predicate is satisfied ('shallow'). Defaults to 'shallow'.

Parameters
  • root (CGNSTree) – Tree is which the search is performed

  • predicate (callable) – condition to select node, which must have the following signature: f(n:CGNSTree) -> bool

  • **kwargs – Additional options (see above)

Returns

list of CGNSTree – Nodes found

Note

This function admits the following shorcuts:

  • get_nodes_from_name|label|value|name_and_label() (embedded predicate)

  • get_children_from_name|label|value|name_and_label() (embedded predicate + depth=[1,1])

iter_nodes_from_predicate(root, predicate, **kwargs)

Iterator version of get_nodes_from_predicate()

Note

This function admits the following shorcuts:

  • iter_nodes_from_name|label|value|name_and_label() (embedded predicate)

  • iter_children_from_name|label|value|name_and_label() (embedded predicate + depth=[1,1])

get_node_from_predicates(root, predicates, **kwargs)

Return the first node in input tree matching the chain of predicates, or None

The search can be fine-tuned with the following kwargs:

  • depth (int or pair of int): see get_node_from_predicate()

  • search (str): see get_node_from_predicate()

  • ancestors (bool): If False (default), keep only the terminal node. If True, keep the intermediate nodes and return a tuple of nodes instead of a single node.

Parameters
  • root (CGNSTree) – Tree is which the search is performed

  • predicates (list of callable) – conditions to select next node, each one having the following signature: f(n:CGNSTree) -> bool

  • **kwargs – Additional options (see above)

Returns

CGNSTree or None – Node found

Note

This function admits the following shorcuts:

  • get_node_from_names|labels|values|name_and_labels() (embedded predicate)

  • get_child_from_names|labels|values|name_and_labels() (embedded predicate + depth=[1,1])

get_nodes_from_predicates(root, predicates, **kwargs)

Return the list of all nodes in input tree matching the chain of predicates

The search can be fine-tuned with the following kwargs:

Parameters
  • root (CGNSTree) – Tree is which the search is performed

  • predicates (list of callable) – conditions to select next node, each one having the following signature: f(n:CGNSTree) -> bool

  • **kwargs – Additional options (see above)

Returns

list of CGNSTree – Nodes found

Note

This function admits the following shorcuts:

  • get_nodes_from_names|labels|values|name_and_labels() (embedded predicate)

  • get_children_from_names|labels|values|name_and_labels() (embedded predicate + depth=[1,1])

iter_nodes_from_predicates(root, predicates, **kwargs)

Iterator version of get_nodes_from_predicates()

Note

This function admits the following shorcuts:

  • iter_nodes_from_names|labels|values|name_and_labels() (embedded predicate)

  • iter_children_from_names|labels|values|name_and_labels() (embedded predicate + depth=[1,1])

get_node_from_path(root, path)

Return the node in input tree matching given path, or None

A path is a str containing a full list of names, separated by '/', leading to the node to select. Root name should not be included in path. Wildcards are not accepted in path.

Parameters
  • root (CGNSTree) – Tree is which the search is performed

  • path (str) – path of the node to select

Returns

CGNSTree or None – Node found

Example

>>> zone = PT.yaml.to_node('''
... Zone Zone_t:
...   ZoneBC ZoneBC_t:
...     BC BC_t "Null":
...       GridLocation GridLocation_t "Vertex":
... ''')
>>> PT.get_node_from_path(zone, 'ZoneBC/BC/GridLocation')
# Return node GridLocation
>>> PT.get_node_from_path(zone, 'ZoneBC/BC/PointRange')
# Return None
get_all_CGNSBase_t(root)

Return the list of all the CGNSBase_t nodes found in input tree

This function is SIDS aware, and will only search nodes in relevant places.

Parameters

root (CGNSTree) – Tree is which the search is performed

Returns

list of CGNSTree – Nodes found

See also

This function has the iterator counterpart iter_all_CGNSBase_t()

Example

>>> tree = PT.yaml.to_cgns_tree('''
... BaseA CGNSBase_t:
...   Zone1 Zone_t:
...   Zone2 Zone_t:
... BaseB CGNSBase_t:
...   Zone3 Zone_t:
... ''')
>>> [PT.get_name(n) for n in PT.get_all_CGNSBase_t(tree)]
['BaseA', 'BaseB']
get_all_Zone_t(root)

Return the list of all the Zone_t nodes found in input tree

This function is SIDS aware, and will only search nodes in relevant places.

Parameters

root (CGNSTree) – Tree is which the search is performed

Returns

list of CGNSTree – Nodes found

See also

This function has the iterator counterpart iter_all_Zone_t()

Example

>>> tree = PT.yaml.to_cgns_tree('''
... BaseA CGNSBase_t:
...   Zone1 Zone_t:
...   Zone2 Zone_t:
... BaseB CGNSBase_t:
...   Zone3 Zone_t:
... ''')
>>> [PT.get_name(n) for n in PT.iter_all_Zone_t(tree)]
['Zone1', 'Zone2', 'Zone3']