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()) mesh

  • the global size of a distributed or partitioned mesh (n_xxx()), collectively computed in the partitioned case

  • the 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_2 of a Zone_t node

This 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_2 element 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 VStrideArray describing the connectivity of the provided Elements_t node

For distributed polyedric or mixed sections, the ElementStartOffset is automatticaly shifted to obtain the displs array.

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 name is 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 name is 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_path has the pattern 'BaseName/ZoneName', or from base level, in which case zone_path has the pattern 'ZoneName'. In both cases, ZoneName is 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_new parameter, 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, Y and Z) and 2 (components ending with XX, 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. having VelocityZ without VelocityX/Y) will result in a error.

Parameters:
  • tol (float) – tolerance

  • comm (MPIComm) – MPI communicator