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 |
|---|---|
|
str |
|
str |
|
value |
|
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 |
|---|---|
|
First node found or |
|
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_labelif it ends with _t, and byget_nameotherwise.
>>> 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 functionsRestrict 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_...()meansget_node_from_...()withdepth==1get_children_from_...()meansget_nodes_from_...()withdepth==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_… functionsIf 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 functionsIf
True, return tuple of nodes instead of the terminal node. Tuple is of sizelen(conditions)and contains all the intermediate results. Default isFalse.>>> 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:
Return first match |
Return all matches |
Iterate all matches |
|
|---|---|---|---|
Single predicate |
|
|
|
Multiple predicates |
|
|
|
Return first match |
Return all matches |
Iterate all matches |
|
|---|---|---|---|
Single predicate |
|
|
|
Multiple predicates |
|
|
|
The following functions do not directly derive from the previous one, but allow additional usefull searches:
|
Return the node in input tree matching given path, or None |
|
Return the list of all the CGNSBase_t nodes found in input tree |
|
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): seeget_node_from_predicate()search(str): seeget_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): seeget_node_from_predicate()search(str): seeget_node_from_predicate()ancestors(bool): IfFalse(default), keep only the terminal node. IfTrue, 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:
depth(int or pair of int): seeget_node_from_predicate()search(str): seeget_node_from_predicate()explore(str): seeget_nodes_from_predicate()ancestors(bool): IfFalse(default), keep only the terminal nodes. IfTrue, keep the intermediate nodes and return a list of tuples of nodes instead of a list of nodes.
- 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']