Transfer module

The maia.transfer contains functions that exchange data between the partitioned and distributed meshes.

Fields transfer

High level APIs allow to exchange data at CGNS Tree or Zone level. All the provided functions take similar parameters: a distributed tree (resp. zone), the corresponding partitioned tree (resp. list of zones), the MPI communicator and optionally a filtering parameter.

The following kind of data are supported: FlowSolution_t, DiscreteData_t, ArbitraryGridMotion_t, ZoneSubRegion_t and BCDataSet_t.

When transferring from distributed meshes to partitioned meshes, fields are supposed to be known on the source mesh across all the ranks (according to disttree definition). Geometric patches (such as ZoneSubRegion or BCDataSet) must exists on the relevant partitions, meaning that only fields are transfered.

When transferring from partitioned meshes to distributed meshes, geometric patches may or may not exist on the distributed zone: they will be created if needed. This allows to transfer fields that have been created on the partitioned meshes. It is however assumed that global data (e.g. FlowSolution) are defined on every partition.

Tree level

All the functions of this section operate inplace and require the following parameters:

  • dist_tree (CGNSTree) – Distributed CGNS Tree

  • part_tree (CGNSTree) – Corresponding partitioned CGNS Tree

  • comm (MPIComm) – MPI communicator

dist_tree_to_part_tree_all(dist_tree, part_tree, comm)

Transfer all the data fields from a distributed tree to the corresponding partitioned tree.

Example

from mpi4py import MPI
import os
import maia
import maia.pytree as PT
from   maia.utils.test_utils import sample_mesh_dir

filename = os.path.join(sample_mesh_dir, 'quarter_crown_square_8.yaml')
dist_tree = maia.io.file_to_dist_tree(filename, MPI.COMM_WORLD)
part_tree = maia.factory.partition_dist_tree(dist_tree, MPI.COMM_WORLD)
maia.transfer.dist_tree_to_part_tree_all(dist_tree, part_tree, MPI.COMM_WORLD)

zone = PT.get_all_Zone_t(part_tree)[0]
assert PT.get_node_from_path(zone, 'FlowSolution/DataX') is not None
assert PT.get_node_from_path(zone, 'ZoneSubRegion/Tata') is not None
assert PT.get_node_from_path(zone, 'ZoneBC/Bnd2/BCDataSet/DirichletData/TutuZ') is not None
part_tree_to_dist_tree_all(dist_tree, part_tree, comm)

Transfer all the data fields from the partitioned tree to the corresponding distributed tree.

Parameters
  • dist_tree (CGNSDistTree) – Distributed tree to receive data

  • part_tree (CGNSPartTree) – Partitioned tree to transfer from

  • comm (MPIComm) – MPI communicator

In addition, the next two methods expect the parameter labels (list of str) which allow to pick one or more kind of data to transfer from the supported labels.

dist_tree_to_part_tree_only_labels(dist_tree, part_tree, labels, comm)

Transfer all the data fields of the specified labels from a distributed tree to the corresponding partitioned tree.

Example

from mpi4py import MPI
import os
import maia
import maia.pytree as PT
from   maia.utils.test_utils import sample_mesh_dir

comm = MPI.COMM_WORLD
filename = os.path.join(sample_mesh_dir, 'quarter_crown_square_8.yaml')

dist_tree = maia.io.file_to_dist_tree(filename, comm)
part_tree = maia.factory.partition_dist_tree(dist_tree, comm)
maia.transfer.dist_tree_to_part_tree_only_labels(dist_tree, part_tree, ['FlowSolution_t', 'ZoneSubRegion_t'], comm)

zone = PT.get_all_Zone_t(part_tree)[0]
assert PT.get_node_from_path(zone, 'FlowSolution/DataX') is not None
assert PT.get_node_from_path(zone, 'ZoneSubRegion/Tata') is not None
assert PT.get_node_from_path(zone, 'ZoneBC/Bnd2/BCDataSet/DirichletData/TutuZ') is None

maia.transfer.dist_tree_to_part_tree_only_labels(dist_tree, part_tree, ['BCDataSet_t'], comm)
assert PT.get_node_from_path(zone, 'ZoneBC/Bnd2/BCDataSet/DirichletData/TutuZ') is not None
part_tree_to_dist_tree_only_labels(dist_tree, part_tree, labels, comm)

Transfer only the data fields matching the provided labels from the partitioned tree to the corresponding distributed tree.

Parameters
  • dist_tree – Distributed tree to receive data

  • part_tree – Partitioned tree to transfer from

  • labels – List of labels to transfer

  • comm – MPI communicator

Zone level

All the functions of this section operate inplace and require the following parameters:

  • dist_zone (CGNSTree) – Distributed CGNS Zone

  • part_zones (list of CGNSTree) – Corresponding partitioned CGNS Zones

  • comm (MPIComm) – MPI communicator

In addition, filtering is possible with the use of the include_dict or exclude_dict dictionaries. These dictionaries map each supported label to a list of cgns paths to include (or exclude). Paths starts from the Zone_t node and ends at the targeted DataArray_t node. Wildcard * are allowed in paths : for example, considering the following tree structure,

Zone (Zone_t)
├── FirstSolution (FlowSolution_t)
│   ├── Pressure (DataArray_t)
│   ├── MomentumX (DataArray_t)
│   └── MomentumY (DataArray_t)
├── SecondSolution (FlowSolution_t)
│   ├── Pressure (DataArray_t)
│   ├── MomentumX (DataArray_t)
│   └── MomentumY (DataArray_t)
└── SpecialSolution (FlowSolution_t)
    ├── Density (DataArray_t)
    └── MomentumZ (DataArray_t)
"FirstSolution/Momentum*" maps to ["FirstSolution/MomentumX", "FirstSolution/MomentumY"],
"*/Pressure maps to ["FirstSolution/Pressure", "SecondSolution/Pressure"], and
"S*/M*" maps to ["SecondSolution/MomentumX", "SecondSolution/MomentumY", "SpecialSolution/MomentumZ"].

For convenience, we also provide the magic path ['*'] meaning “everything related to this label”.

Lastly, we use the following rules to manage missing label keys in dictionaries:

  • For _only functions, we do not transfer any field related to the missing labels;

  • For _all functions, we do transfer all the fields related to the missing labels.

dist_zone_to_part_zones_only(dist_zone, part_zones, comm, include_dict)

Transfer the data fields specified in include_dict from a distributed zone to the corresponding partitioned zones.

Example

from mpi4py import MPI
import os
import maia
import maia.pytree as PT
from   maia.utils.test_utils import sample_mesh_dir

comm = MPI.COMM_WORLD
filename = os.path.join(sample_mesh_dir, 'quarter_crown_square_8.yaml')

dist_tree = maia.io.file_to_dist_tree(filename, comm)
dist_zone = PT.get_all_Zone_t(dist_tree)[0]
part_tree = maia.factory.partition_dist_tree(dist_tree, comm)
part_zones = PT.get_all_Zone_t(part_tree)

include_dict = {'FlowSolution_t' : ['FlowSolution/DataX', 'FlowSolution/DataZ'],
                'BCDataSet_t'    : ['*']}
maia.transfer.dist_zone_to_part_zones_only(dist_zone, part_zones, comm, include_dict)

for zone in part_zones:
  assert PT.get_node_from_path(zone, 'FlowSolution/DataX') is not None
  assert PT.get_node_from_path(zone, 'ZoneSubRegion/Tata') is     None
  assert PT.get_node_from_path(zone, 'ZoneBC/Bnd2/BCDataSet/DirichletData/TutuZ') is not None
part_zones_to_dist_zone_only(dist_zone, part_zones, comm, include_dict)

Transfer the data fields specified in include_dict from the partitioned zones to the corresponding distributed zone.

Parameters
  • dist_zone – Distributed zone to receive data

  • part_zones – List of partitioned zones to transfer from

  • comm – MPI communicator

  • include_dict – Dictionary mapping labels to paths to include

dist_zone_to_part_zones_all(dist_zone, part_zones, comm, exclude_dict={})

Transfer all the data fields, excepted those specified in exclude_dict, from a distributed zone to the corresponding partitioned zones.

Example

from mpi4py import MPI
import os
import maia
import maia.pytree as PT
from   maia.utils.test_utils import sample_mesh_dir

comm = MPI.COMM_WORLD
filename = os.path.join(sample_mesh_dir, 'quarter_crown_square_8.yaml')

dist_tree = maia.io.file_to_dist_tree(filename, comm)
dist_zone = PT.get_all_Zone_t(dist_tree)[0]
part_tree = maia.factory.partition_dist_tree(dist_tree, comm)
part_zones = PT.get_all_Zone_t(part_tree)

exclude_dict = {'FlowSolution_t' : ['FlowSolution/DataX', 'FlowSolution/DataZ'],
                'BCDataSet_t'    : ['*']}
maia.transfer.dist_zone_to_part_zones_all(dist_zone, part_zones, comm, exclude_dict)

for zone in part_zones:
  assert PT.get_node_from_path(zone, 'FlowSolution/DataX') is     None
  assert PT.get_node_from_path(zone, 'FlowSolution/DataY') is not None
  assert PT.get_node_from_path(zone, 'ZoneSubRegion/Tata') is not None
  assert PT.get_node_from_path(zone, 'ZoneBC/Bnd2/BCDataSet/DirichletData/TutuZ') is None
part_zones_to_dist_zone_all(dist_zone, part_zones, comm, exclude_dict={})

Transfer all the data fields, excepted those specified in exclude_dict, from the partitioned zone to the corresponding distributed zone.

Parameters
  • dist_zone – Distributed zone to receive data

  • part_zones – List of partitioned zones to transfer from

  • comm – MPI communicator

  • exclude_dict – Dictionary mapping labels to paths to exclude

Metadata transfer

The functions described in the previous section allows to transfer local data (ie fields defined on entities of the mesh such as cells, vertices, etc.).

In addition, we provide two functions helping users to copy global data between their meshes. Nodes are simply copied from one tree to the other, regardless of their content. These functions are suited to transfer metadata (such as Family_t nodes) or UserDefinedData nodes storing global data.

For these two functions, predicates must be a pattern leading to the nodes to copy, starting from the root of the dist_tree (see maia.pytree corresponding section). When nodes names are used in predicates, they should by provided in their original version, without maia splitting conventions. For example,

  • "Base/AIRFOIL/ZoneBC_t/BC_t/.Solver#Property" will transfer nodes named .Solver#Property found under any BC, only for zone AIRFOIL,

  • "CGNSBase_t/Zone_t/ZoneBC_t/BC_t/.Solver#Property" will do the same for all the zones of the mesh,

  • ["CGNSBase_t", "Family_t", lambda n: PT.get_name(n).startswith('.Solver#')] will transfer any node whose names starts with .Solver# under all the families of the tree.

If requested nodes already exists on the target tree, they will be updated.

dist_tree_to_part_tree_copy(dist_tree, part_tree, predicates, comm)

Copy nodes matching the input predicates chain from dist_tree to part_tree

Parameters
  • dist_tree (CGNSDistTree) – Distributed tree

  • part_tree (CGNSPartTree) – Corresponding partitioned tree

  • predicates (str or list) – Predicates chain, starting from tree level

  • comm (MPIComm) – MPI communicator

Example

from mpi4py.MPI import COMM_WORLD
import maia
import maia.pytree as PT

dist_tree = maia.factory.generate_dist_block(11, 'HEXA_8', COMM_WORLD)
part_tree = maia.factory.partition_dist_tree(dist_tree, COMM_WORLD)

dist_base = PT.get_node_from_label(dist_tree, 'CGNSBase_t')
PT.new_Family('BCWall', family_bc='BCWall', parent=dist_base)

maia.transfer.dist_tree_to_part_tree_copy(dist_tree, part_tree,
                             'CGNSBase_t/Family_t', COMM_WORLD)
assert len(PT.get_nodes_from_label(part_tree, 'Family_t')) == 1
part_tree_to_dist_tree_copy(dist_tree, part_tree, predicates, comm)

Copy nodes matching the input predicates chain from part_tree to dist_tree

Parameters
  • dist_tree (CGNSDistTree) – Distributed tree

  • part_tree (CGNSPartTree) – Corresponding partitioned tree

  • predicates (str or list) – Predicates chain, starting from tree level

  • comm (MPIComm) – MPI communicator

Example

from mpi4py.MPI import COMM_WORLD
import maia
import maia.pytree as PT

dist_tree = maia.factory.generate_dist_block(11, 'TRI_3', COMM_WORLD)
part_tree = maia.factory.partition_dist_tree(dist_tree, COMM_WORLD)

for bc in PT.iter_nodes_from_label(part_tree, 'BC_t'):
  PT.new_UserDefinedData('.solver#BC',       parent=bc)
  PT.new_UserDefinedData('.solver#Property', parent=bc)

maia.transfer.part_tree_to_dist_tree_copy(dist_tree, part_tree,
                 'Base/zone/ZoneBC/*max/.solver#*', COMM_WORLD)
assert len(PT.get_nodes_from_name(dist_tree, '.solver#*')) == 4