Pytree extension
Maia provides an extension to the pytree module in order to
gather the application specific tree manipulation shortcuts: pytree.maia.
Unless otherwise specified, all the functions described here are accessible
from the module namespace, shortened as MT:
import maia.pytree.maia as MT
Node inspection
The following functions extend Node inspection and provide getters for data specific to maia trees. They use the same namespace classification as pytree. Within each namespace, the functions provided are typically getters for:
the local sizes of a distributed (
dn_xxx()) or partitioned (pn_xxx()) meshthe global size of a distributed or partitioned mesh (
n_xxx()), collectively computed in the partitioned casethe distribution (
distribution()) or global numbering (globalnumbering()) arrays
- class Zone
The following functions apply to Zone_t nodes
- static EdgeNode(zone_node)
Return the Elements_t node of kind
BAR_2of a Zone_t nodeThis function aims to be the counterpart of
NGonNode()for 2D polyedric zones.- Parameters:
zone_node (CGNSTree) – Input Zone_t node
- Returns:
CGNSTree – BAR_2 node
- Raises:
RuntimeError – if not exactly one
BAR_2element node exists in zone
- static cell_distribution(zone_node)
Return the cells distribution array of a distributed zone
- Parameters:
zone_node (CGNSDistTree) – Input Zone_t node
- Returns:
NDArray – distribution array for cells
Example
>>> zone = PT.new_Zone(type='Unstructured', size=[[77, 60, 0]]) >>> MT.new_Distribution({'Cell' : [45, 60, 60]}, parent=zone) >>> MT.Zone.cell_distribution(zone) array([45, 60, 60], dtype=int32)
- static cell_globalnumbering(zone_node)
Return the cells absolute numbering array of a partitioned zone
- Parameters:
zone_node (CGNSPartTree) – Input Zone_t node
- Returns:
NDArray – global numbering array for cells
Example
>>> zone = PT.new_Zone(type='Unstructured', size=[[8, 3, 0]]) >>> MT.new_GlobalNumbering({'Cell' : [5,1,9]}, parent=zone) >>> MT.Zone.cell_globalnumbering(zone) array([5, 1, 9], dtype=int32)
- static dn_cell(zone_node)
Return the local number of cells of a distributed zone
- Parameters:
zone_node (CGNSDistTree) – Input Zone_t node
- Returns:
int – local number of cells
Example
>>> zone = PT.new_Zone(type='Unstructured', size=[[77, 60, 0]]) >>> MT.new_Distribution({'Cell' : [30, 45, 60]}, parent=zone) >>> MT.Zone.dn_cell(zone) 15
- static dn_vtx(zone_node)
Return the local number of vertices of a distributed zone
- Parameters:
zone_node (CGNSDistTree) – Input Zone_t node
- Returns:
int – local number of vertices
Example
>>> zone = PT.new_Zone(type='Unstructured', size=[[77, 60, 0]]) >>> MT.new_Distribution({'Vertex' : [39, 58, 77]}, parent=zone) >>> MT.Zone.dn_vtx(zone) 19
- static n_cell(zone_node, comm=None)
Return the total number of cells of a zone.
The input zone can be either distributed (a single node is expected) or partitioned (the whole list of partitions is expected).
- Parameters:
zone_node (CGNSDistTree or List[CGNSPartTree]) – Input Zone_t node(s)
comm (MPIComm) – MPI communicator, mandatory for partitioned zones
- Returns:
int – total number of cells
Examples
>>> zone = PT.new_Zone('Zone', type='Unstructured', size=[[14, 6, 0]]) >>> MT.new_Distribution({'Cell' : [3,6,6]}, parent=zone) >>> MT.Zone.n_cell(zone) 6
>>> zones = [PT.new_Zone('Zone.P1.N0', type='Unstructured', size=[[6, 2, 0]]), ... PT.new_Zone('Zone.P1.N1', type='Unstructured', size=[[10, 4, 0]])] >>> MT.new_GlobalNumbering({'Cell' : [4,1]}, parent=zones[0]) >>> MT.new_GlobalNumbering({'Cell' : [2,6,3,5]}, parent=zones[1]) >>> MT.Zone.n_cell(zones, comm) 6
- static n_vtx(zone_node, comm=None)
Return the total number of vertices of a zone.
The input zone can be either distributed (a single node is expected) or partitioned (the whole list of partitions is expected).
- Parameters:
zone_node (CGNSDistTree or List[CGNSPartTree]) – Input Zone_t node(s)
comm (MPIComm) – MPI communicator, mandatory for partitioned zones
- Returns:
int – total number of vertices
Examples
>>> zone = PT.new_Zone('Zone', type='Unstructured', size=[[5, 4, 0]]) >>> MT.new_Distribution({'Vertex' : [3,5,5]}, parent=zone) >>> MT.Zone.n_vtx(zone) 5
>>> zones = [PT.new_Zone('Zone.P1.N0', type='Unstructured', size=[[3, 2, 0]]), ... PT.new_Zone('Zone.P1.N1', type='Unstructured', size=[[3, 2, 0]])] >>> MT.new_GlobalNumbering({'Vertex' : [1,3,2]}, parent=zones[0]) >>> MT.new_GlobalNumbering({'Vertex' : [3,4,5]}, parent=zones[1]) >>> MT.Zone.n_vtx(zones, comm) 5
- static pn_cell(zone_node)
Return the local number of cells of the input partitioned zone
- Parameters:
zone_node (CGNSPartTree) – Input Zone_t node
- Returns:
int – local number of cells
Example
>>> zone = PT.new_Zone(type='Unstructured', size=[[14, 6, 0]]) >>> MT.new_GlobalNumbering({'Cell' : [21,61,41,51,11,31]}, parent=zone) >>> MT.Zone.pn_cell(zone) 6
- static pn_vtx(zone_node)
Return the local number of vertices of the input partitioned zone
- Parameters:
zone_node (CGNSPartTree) – Input Zone_t node
- Returns:
int – local number of vertices
Example
>>> zone = PT.new_Zone(type='Unstructured', size=[[8, 3, 0]]) >>> MT.new_GlobalNumbering({'Vertex' : [9,11,13,14,16,10,12,15]}, parent=zone) >>> MT.Zone.pn_vtx(zone) 8
- static vtx_distribution(zone_node)
Return the vertices distribution array of a distributed zone
- Parameters:
zone_node (CGNSDistTree) – Input Zone_t node
- Returns:
NDArray – distribution array for vertices
Example
>>> zone = PT.new_Zone(type='Unstructured', size=[[77, 60, 0]]) >>> MT.new_Distribution({'Vertex' : [39, 58, 77]}, parent=zone) >>> MT.Zone.vtx_distribution(zone) array([39, 58, 77], dtype=int32)
- static vtx_globalnumbering(zone_node)
Return the vertices absolute numbering array of a partitioned zone
- Parameters:
zone_node (CGNSPartTree) – Input Zone_t node
- Returns:
NDArray – global numbering array for vertices
Example
>>> zone = PT.new_Zone(type='Unstructured', size=[[8, 3, 0]]) >>> MT.new_GlobalNumbering({'Vertex' : [9,11,13,14,16,10,12,15]}, parent=zone) >>> MT.Zone.vtx_globalnumbering(zone) array([ 9, 11, 13, 14, 16, 10, 12, 15], dtype=int32)
- class Element
The following functions apply to Elements_t nodes
- static connectivity(elt_node)
Return a
VStrideArraydescribing the connectivity of the provided Elements_t nodeFor distributed polyedric or mixed sections, the ElementStartOffset is automatticaly shifted to obtain the
displsarray.- Parameters:
elt_node (CGNSTree) – Input Elements_t node
- Returns:
VSrideArray – element connectivity
Example
>>> ng = PT.new_NGonElements(eso=[0,3,7,10], ec=[1,5,4, 2,3,6,5, 4,9,8]) >>> MT.Element.connectivity(ng) vsarray([ [1, 5, 4], [2, 3, 6, 5], [4, 9, 8], ], dtype=int32)
- static distribution(elt_node)
Return the distribution array of a distributed element section
- Parameters:
elt_node (CGNSTree) – Input Elements_t node, distributed
- Returns:
NDArray – distribution array
Example
>>> elt = PT.new_Elements(type='TRI_3', erange=[1,10], econn=[1,5,4, 2,8,12]) >>> MT.new_Distribution({'Element' : [4, 6, 10]}, parent=elt) >>> MT.Element.distribution(elt) array([ 4, 6, 10], dtype=int32)
- static dn_elt(elt_node)
Return the local number of elements of a distributed element section
- Parameters:
elt_node (CGNSTree) – Input Elements_t node, distributed
- Returns:
int – local number of elements
Example
>>> elt = PT.new_Elements(type='TRI_3', erange=[1,10], econn=[1,5,4, 2,8,12]) >>> MT.new_Distribution({'Element' : [4, 6, 10]}, parent=elt) >>> MT.Element.dn_elt(elt) 2
- static globalnumbering(elt_node)
Return the absolute numbering array of a partitioned element section
- Parameters:
elt_node (CGNSTree) – Input Elements_t node, partitioned
- Returns:
NDArray – global numbering array
Example
>>> elt = PT.new_Elements(type='TRI_3', erange=[1,3]) >>> MT.new_GlobalNumbering({'Element' : [4, 9, 3]}, parent=elt) >>> MT.Element.globalnumbering(elt) array([4, 9, 3], dtype=int32)
- static n_elt(elt_node, comm=None)
Return the total number of elements of a element section.
The input Elements_t can be either distributed (a single node is expected) or partitioned (the whole list of related nodes is expected).
- Parameters:
elt_node (CGNSTree or List[CGNSTree]) – Input Elements_t node(s)
comm (MPIComm) – MPI communicator, mandatory for partitioned elements
- Returns:
int – total number of elements
Examples
>>> tris = [PT.new_Elements(type='TRI_3', erange=[1,3]), ... PT.new_Elements(type='TRI_3', erange=[1,4])] >>> MT.new_GlobalNumbering({'Element' : [1,5,4]}, parent=tris[0]) >>> MT.new_GlobalNumbering({'Element' : [4,3,5,2]}, parent=tris[1]) >>> MT.Element.n_elt(tris, comm) 5
- static pn_elt(elt_node)
Return the local number of elements of the input partitioned element section
- Parameters:
elt_node (CGNSTree) – Input Elements_t node, partitioned
- Returns:
int – local number of elements
Example
>>> elt = PT.new_Elements(type='TRI_3', erange=[1,3]) >>> MT.new_GlobalNumbering({'Element' : [4, 9, 3]}, parent=elt) >>> MT.Element.pn_elt(elt) 3
- class Subset
A subset is a node defining a subregion of the mesh through a PointList or a PointRange node (eg BC_t, some ZoneSubRegion_t, …).
- static distribution(subset_node)
Return the distribution array of a distributed subset
- Parameters:
subset_node (CGNSTree) – Input subset node, distributed
- Returns:
NDArray – distribution array
Example
>>> bc = PT.new_BC(point_list=[[23, 55, 42, 13, 56]]) >>> MT.new_Distribution({'Index' : [5,10,20]}, parent=bc) >>> MT.Subset.distribution(bc) array([ 5, 10, 20], dtype=int32)
- static dn_elem(subset_node)
Return the local number of entities of a distributed subset
- Parameters:
subset_node (CGNSTree) – Input subset node, distributed
- Returns:
int – local number of entities
Example
>>> bc = PT.new_BC(point_list=[[23, 55, 42, 13, 56]]) >>> MT.new_Distribution({'Index' : [5,10,20]}, parent=bc) >>> MT.Subset.dn_elem(bc) 5
- static globalnumbering(subset_node)
Return the absolute numbering of a partitioned subset
- Parameters:
subset_node (CGNSTree) – Input subset node, partitioned
- Returns:
NDArray – global numbering array
Example
>>> zsr = PT.new_ZoneSubRegion(point_list=[[4,6,2,8]]) >>> MT.new_GlobalNumbering({'Index' : [9,11,13,14]}, parent=zsr) >>> MT.Subset.globalnumbering(zsr) array([ 9, 11, 13, 14], dtype=int32)
- static n_elem(subset_node, comm=None)
Return the total number of entities of a subset.
The input subset can be either distributed (a single node is expected) or partitioned (the whole list of related nodes is expected).
- Parameters:
subset_node (CGNSTree or List[CGNSTree]) – Input subset node(s)
comm (MPIComm) – MPI communicator, mandatory for partitioned zones
- Returns:
int – total number of entities
Examples
>>> bcs = [PT.new_BC(point_list=[[1,4,7,10]]), ... PT.new_BC(point_list=[[2,4,6,8]])] >>> MT.new_GlobalNumbering({'Index' : [1,3,5,7]}, parent=bcs[0]) >>> MT.new_GlobalNumbering({'Index' : [2,4,6,8]}, parent=bcs[1]) >>> MT.Subset.n_elem(bcs, comm) 8
- static pn_elem(subset_node)
Return the local number of entities of the input partitioned subset
- Parameters:
subset_node (CGNSTree) – Input subset node, partitioned
- Returns:
int – local number of entities
Example
>>> zsr = PT.new_ZoneSubRegion(point_list=[[4,6,2,8]]) >>> MT.new_GlobalNumbering({'Index' : [9,11,13,14]}, parent=zsr) >>> MT.Subset.pn_elem(zsr) 4
Node creation presets
The following functions extend node creation presets to easily create Maia-specific nodes.
Hint
Unlike PT.new_xxx() functions, these functions update the
target node if already existing.
- new_Distribution(fields={}, parent=None)
Create a :CGNS#Distribution node.
This Maia specific node describes how data is distributed (see specification).
- Parameters:
fields (dict) – distribution values to create under the container (see fields setting)
parent (CGNSTree) – Node to which created distribution should be attached
Example
>>> zone = PT.new_Zone(type='Unstructured', size=[[77,60,0]]) >>> MT.new_Distribution({'Cell' : [0,15,60], 'Vertex' : [0,20,77]}, parent=zone) >>> PT.print_tree(zone) Zone Zone_t I4 [[77 60 0]] ├───ZoneType ZoneType_t "Unstructured" └───:CGNS#Distribution UserDefinedData_t ├───Cell DataArray_t I4 [ 0 15 60] └───Vertex DataArray_t I4 [ 0 20 77]
- new_GlobalNumbering(fields={}, parent=None)
Create a :CGNS#GlobalNumbering node.
This Maia specific node describes how data is reordered after partitioning (see specification).
- Parameters:
fields (dict) – gnum values to create under the container (see fields setting)
parent (CGNSTree) – Node to which created numberings should be attached
Example
>>> gn = MT.new_GlobalNumbering({'Cell' : [6,4,7], 'Vertex' : [24,59,23,11,5]}) >>> PT.print_tree(gn) :CGNS#GlobalNumbering UserDefinedData_t ├───Cell DataArray_t I4 [6 4 7] └───Vertex DataArray_t I4 [24 59 23 11 5]
Node searching
The following functions extend searches to easily get Maia-specific nodes.
- get_Distribution(root, name=None)
Get a distribution node under the specified root
If
nameis not None, the DataArray_t node of corresponding name is returned. Otherwise, the distribution container is returned itself.- Parameters:
root (CGNSTree) – Root in which search is performed (distributed)
name (str, optional) – Name a specific array to get
- Returns:
CGNSTree or None – Node found
Example
>>> zone = PT.new_Zone(type='Unstructured', size=[[77,60,0]]) >>> MT.new_Distribution({'Cell' : [0,15,60], 'Vertex' : [0,20,77]}, parent=zone) >>> PT.print_tree(MT.get_Distribution(zone)) :CGNS#Distribution UserDefinedData_t ├───Cell DataArray_t I4 [ 0 15 60] └───Vertex DataArray_t I4 [ 0 20 77] >>> PT.print_tree(MT.get_Distribution(zone, 'Vertex')) Vertex DataArray_t I4 [ 0 20 77]
- get_GlobalNumbering(root, name=None)
Get a global numbering node under the specified root
If
nameis not None, the DataArray_t node of corresponding name is returned. Otherwise, the global numbering container is returned itself.- Parameters:
root (CGNSTree) – Root in which search is performed (partitioned)
name (str, optional) – Name a specific array to get
- Returns:
CGNSTree or None – Node found
Example
>>> zsr = PT.new_ZoneSubRegion(point_list=[[4,6,2,8]]) >>> MT.new_GlobalNumbering({'Index' : [9,11,13,14]}, parent=zsr) >>> PT.print_tree(MT.get_GlobalNumbering(zsr)) :CGNS#GlobalNumbering UserDefinedData_t └───Index DataArray_t I4 [ 9 11 13 14] >>> MT.get_GlobalNumbering(zsr, 'Index') ['Index', array([ 9, 11, 13, 14], dtype=int32), [], 'DataArray_t']
See also
These two functions have counterpart find_Distribution() and find_GlobalNumbering() that
raise an error if no result is found.
- get_partitioned_zones(part_tree, zone_path)
Return the list of partitioned zones created from the specified initial domain.
Search can be performed from tree level, in which case
zone_pathhas the pattern'BaseName/ZoneName', or from base level, in which casezone_pathhas the pattern'ZoneName'. In both cases,ZoneNameis the name of the corresponding distributed zone (without maia naming conventions).- Parameters:
part_tree (CGNSPartTree) – Partitioned tree in which search is performed
zone_path (str) – searched pattern (see above)
- Returns:
list of CGNSTree – Partitioned zones found
Example
>>> part_tree = PT.yaml.to_cgns_tree(''' ... Base CGNSBase_t: ... Zone1.P0.N1 Zone_t: ... Zone1.P0.N2 Zone_t: ... Zone2.P0.N0 Zone_t: ... Zone2.P0.N1 Zone_t: ... Zone3.P0.N0 Zone_t: ... ''') >>> pzones = MT.get_partitioned_zones(part_tree, 'Base/Zone2') >>> [PT.get_name(z) for z in pzones] ['Zone2.P0.N0', 'Zone2.P0.N1']
Tree operations
The following functions extend Tree operations with operations running on parallel trees.
Tree editing
- rename_zones(part_tree, old_to_new_path, comm)
Rename the Zone_t nodes of a partitioned tree.
New names are provided through
old_to_newparameter, which maps zone pathes to their new value. Note that:the parent base of each zone is not allowed to change,
you are responsible of preserving maia Naming conventions,
zones that keep their original names may be omitted from mapping.
The GridConnectivity_t values are updated by this function.
- Parameters:
part_tree (CGNSPartTree) – Partitioned tree, starting at top level
old_to_new_path (dict) – azezae
comm (MPIComm) – MPI communicator
Example
>>> part_tree = PT.yaml.to_cgns_tree(''' ... Base CGNSBase_t: ... ZoneA.P2.N0 Zone_t: ... ZoneA.P2.N1 Zone_t: ... ZoneGridConnectivity ZoneGridConnectivity_t: ... match GridConnectivity_t "ZoneB.P2.N0": ... ZoneB.P2.N0 Zone_t: ... ''') >>> pzones = MT.rename_zones(part_tree, {'Base/ZoneB.P2.N0' : 'Base/ZoneC.P2.N0'}, comm) >>> PT.print_tree(PT.get_child_from_label(part_tree, 'CGNSBase_t')) Base CGNSBase_t ├───ZoneA.P2.N0 Zone_t ├───ZoneA.P2.N1 Zone_t │ └───ZoneGridConnectivity ZoneGridConnectivity_t │ └───match GridConnectivity_t "Base/ZoneC.P2.N0" └───ZoneC.P2.N0 Zone_t
Tree comparisons
The MT extension provides comparison operators that can
be used by diff_tree() to compare distributed
trees.
These functions are available in MT.compare namespace.
- EqualArray(comm)
A callable object generating a report for
diff_tree(), using an exact point-to-point comparison.This is the extension of
EqualArray()for distributed trees.- Parameters:
comm (MPIComm) – MPI communicator
Example
>>> comp = MT.compare.EqualArray(comm) >>> sol1 = PT.new_FlowSolution(fields={'Density' : [1., 1.002, 1.]}) >>> sol2 = PT.new_FlowSolution(fields={'Density' : [1., 1.001, 1.]}) >>> PT.diff_tree(sol1, sol2, comp=comp) DiffReport( status=False, errors='/FlowSolution/Density -- Values differ: [1. 1.002 1. ] <> [1. 1.001 1. ]\n', warnings='' )
- FieldComparison(tol, comm)
A comparison object for
diff_tree()that compare arrays with a relative tolerance.Floating points arrays are considered equal if \(||a-b|| \leq \mathrm{tol}\ ||b||\), where \(||\cdot||\) is the \(L^2\) norm, while integer arrays fallback to
EqualArray()comparison.This function operate on distributed trees.
- Parameters:
tol (float) – tolerance
comm (MPIComm) – MPI communicator
Example
>>> comp = MT.compare.FieldComparison(1E-2, comm) >>> sol1 = PT.new_FlowSolution(fields={'Density' : [1., 1.002, 1.]}) >>> sol2 = PT.new_FlowSolution(fields={'Density' : [1., 1.001, 1.]}) >>> PT.diff_tree(sol1, sol2, comp=comp) DiffReport( status=True, errors='', warnings='/FlowSolution/Density -- Values differ: RMS mean diff: 5.773e-04, RMS ref mean: 1.000e+00, rel error: 5.771e-04\n' )
- TensorFieldComparison(tol, comm)
A comparison object for
diff_tree()that compare tensorial fields with a relative tolerance.This comparison method is similar to
FieldComparison(), but tensors fields components are treated together.Tensors of rank 0 (i.e. scalar field), 1 (components ending with
X,YandZ) and 2 (components ending withXX,XY, …,ZZ) are supported. Rank-2 tensors that only have components[XX, XY, YY]or[XX, XY, XZ, YY, YZ, ZZ]are interpreted as symmetric tensors. Missing components (e.g. havingVelocityZwithoutVelocityX/Y) will result in a error.- Parameters:
tol (float) – tolerance
comm (MPIComm) – MPI communicator