plaid.utils.cgns_helper ======================= .. py:module:: plaid.utils.cgns_helper .. autoapi-nested-parse:: Utility functions for working with CGNS trees and nodes. Functions --------- .. autoapisummary:: plaid.utils.cgns_helper.get_base_names plaid.utils.cgns_helper.get_time_values plaid.utils.cgns_helper.show_cgns_tree plaid.utils.cgns_helper.fix_cgns_tree_types plaid.utils.cgns_helper.compare_cgns_trees plaid.utils.cgns_helper.compare_leaves plaid.utils.cgns_helper.compare_cgns_trees_no_types plaid.utils.cgns_helper.summarize_cgns_tree plaid.utils.cgns_helper.flatten_cgns_tree plaid.utils.cgns_helper.nodes_to_tree plaid.utils.cgns_helper.unflatten_cgns_tree plaid.utils.cgns_helper.update_features_for_CGNS_compatibility Module Contents --------------- .. py:function:: get_base_names(tree: plaid.types.CGNSTree, full_path: bool = False, unique: bool = False) -> list[str] Get a list of base names from a CGNSTree. :param tree: The CGNSTree containing the CGNSBase_t nodes. :type tree: CGNSTree :param full_path: If True, return full base paths including '/' separators. Defaults to False. :type full_path: bool, optional :param unique: If True, return unique base names. Defaults to False. :type unique: bool, optional :returns: A list of base names. :rtype: list[str] .. py:function:: get_time_values(tree: plaid.types.CGNSTree) -> numpy.ndarray Get consistent time values from CGNSBase_t nodes in a CGNSTree. :param tree: The CGNSTree containing CGNSBase_t nodes. :type tree: CGNSTree :returns: An array of consistent time values. :rtype: np.ndarray :raises AssertionError: If the time values across bases are not consistent. .. py:function:: show_cgns_tree(pyTree: plaid.types.CGNSTree, pre: str = '') Pretty print for CGNS Tree. :param pyTree: CGNS tree to print :type pyTree: CGNSTree :param pre: indentation of print. Defaults to ''. :type pre: str, optional .. py:function:: fix_cgns_tree_types(tree: plaid.types.CGNSTree) -> plaid.types.CGNSTree Recursively fix the data types of a CGNS tree node and its children. This function ensures that data arrays match the expected CGNS types: - "IndexArray_t": converted to integer arrays and stacked - "Zone_t": stacked as numpy arrays - "Elements_t", "CGNSBase_t", "BaseIterativeData_t": converted to integer arrays :param tree: A CGNS tree of the form [name: str, data: Any, children: List[CGNSTree], cgns_type: str]. :type tree: CGNSTree :returns: A new CGNS tree node with corrected data types and recursively fixed children. :rtype: CGNSTree .. rubric:: Example >>> node = ["Zone1", [[1, 2], [3, 4]], [], "Zone_t"] >>> fixed_node = fix_cgns_tree_types(node) >>> fixed_node[1].shape (2, 2) .. py:function:: compare_cgns_trees(tree1: plaid.types.CGNSTree, tree2: plaid.types.CGNSTree, path: str = 'CGNSTree') -> bool Recursively compare two CGNS trees for exact equality, ignoring the order of children. This function checks: - Node names - Node data (numpy arrays or scalars) with exact dtype and values - Number and names of children nodes - CGNS type (stored as the extra field) It prints informative messages whenever a mismatch is found, including the path in the tree where the mismatch occurs. :param tree1: The first CGNS tree node to compare. :type tree1: CGNSTree :param tree2: The second CGNS tree node to compare. :type tree2: CGNSTree :param path: The current path in the tree for error messages. Defaults to "CGNSTree". :type path: str, optional :returns: True if the trees are identical (including node names, data, types, and children), False otherwise. :rtype: bool .. rubric:: Example >>> identical = compare_cgns_trees(tree1, tree2) >>> if identical: >>> print("The trees are identical") >>> else: >>> print("The trees differ") .. py:function:: compare_leaves(d1: Any, d2: Any) -> bool Compare two leaf values in a CGNS tree or flattened structure, handling arrays and scalars. This function supports: - NumPy arrays, including byte arrays (converted to str) - Floating-point arrays or scalars (compared with tolerance) - Integer arrays or scalars (exact comparison) - Strings and None :param d1: First value to compare (scalar or np.ndarray). :type d1: Any :param d2: Second value to compare (scalar or np.ndarray). :type d2: Any :returns: True if the values are considered equal, False otherwise. :rtype: bool .. note:: - Floating-point comparisons use `np.allclose` or `np.isclose` with `rtol=1e-7` and `atol=0`. - Byte arrays (`dtype.kind == "S"`) are converted to string before comparison. .. rubric:: Examples >>> compare_leaves(np.array([1.0, 2.0]), np.array([1.0, 2.0])) True >>> compare_leaves(3.0, 3.00000001) True >>> compare_leaves(np.array([1, 2]), np.array([2, 1])) False .. py:function:: compare_cgns_trees_no_types(tree1: plaid.types.CGNSTree, tree2: plaid.types.CGNSTree, path: str = 'CGNSTree') -> bool Recursively compare two CGNS trees ignoring the order of children and relaxing strict type checks. This function is useful for heterogeneous or nested CGNS samples, such as those encountered in Hugging Face Arrow datasets. It compares: - Node names - Node data using `compare_leaves` (supports arrays, scalars, strings) - CGNS type (extra field) - Children nodes by name, ignoring their order :param tree1: The first CGNS tree node to compare. :type tree1: CGNSTree :param tree2: The second CGNS tree node to compare. :type tree2: CGNSTree :param path: Path for error reporting. Defaults to "CGNSTree". :type path: str, optional :returns: True if the trees are considered equivalent, False otherwise. :rtype: bool .. rubric:: Example >>> identical = compare_cgns_trees_no_types(tree1, tree2) >>> if identical: >>> print("The trees match ignoring types") >>> else: >>> print("The trees differ") .. py:function:: summarize_cgns_tree(pyTree: plaid.types.CGNSTree, verbose=True) -> str Provide a summary of a CGNS tree's contents. :param pyTree: The CGNS tree to summarize. :type pyTree: CGNSTree :param verbose: If True, include detailed field information. Defaults to True. :type verbose: bool, optional .. rubric:: Example >>> summarize_cgns_tree(pyTree) Number of Bases: 2 Number of Zones: 5 Number of Nodes: 20 Number of Elements: 10 Number of Fields: 8 Fields: 'Base1/Zone1/Solution1/Field1' 'Base1/Zone1/Solution1/Field2' 'Base2/Zone2/Solution2/Field1' ... .. py:function:: flatten_cgns_tree(pyTree: plaid.types.CGNSTree) -> tuple[dict[str, object], dict[str, str]] Flatten a CGNS tree into dictionaries of primitives. :param pyTree: The CGNS tree to flatten. :type pyTree: CGNSTree :returns: - flat: dict of paths to primitive values - cgns_types: dict of paths to CGNS type strings :rtype: tuple[dict[str, object], dict[str, str]] .. py:function:: nodes_to_tree(nodes: dict[str, plaid.types.CGNSTree]) -> Optional[plaid.types.CGNSTree] Reconstruct a CGNS tree from a dictionary of nodes keyed by their paths. Each node is assumed to follow the CGNSTree format: [name: str, data: Any, children: List[CGNSTree], cgns_type: str] The dictionary keys are the full paths to each node, e.g. "Base1/Zone1/Field1". :param nodes: A dictionary mapping node paths to CGNSTree nodes. :type nodes: Dict[str, CGNSTree] :returns: The root CGNSTree node with all children linked, or None if the input dictionary is empty. :rtype: Optional[CGNSTree] .. note:: - Nodes with a path of length 1 are treated as root-level nodes. - The root node is named "CGNSTree" with type "CGNSTree_t". - Parent-child relationships are reconstructed using path prefixes. .. py:function:: unflatten_cgns_tree(flat: dict[str, object], cgns_types: dict[str, str]) -> plaid.types.CGNSTree Reconstruct a CGNS tree from flattened dictionaries of data and types. This function takes a "flat" representation of a CGNS tree, where each node is stored in a dictionary keyed by its full path (e.g., "Base1/Zone1/Field1"), and another dictionary mapping each path to its CGNS type. It rebuilds the original tree structure by creating nodes and linking them according to their paths. :param flat: Dictionary mapping node paths to their data values. The data can be a scalar, list, numpy array, or None. :type flat: dict[str, object] :param cgns_types: Dictionary mapping node paths to CGNS type strings (e.g., "Zone_t", "FlowSolution_t"). :type cgns_types: dict[str, str] :returns: The reconstructed CGNS tree with nodes properly nested according to their paths. Each node is a list in the format: [name: str, data: Any, children: List[CGNSTree], cgns_type: str] :rtype: CGNSTree .. rubric:: Example >>> flat = { >>> "Base1": None, >>> "Base1/Zone1": [10, 20], >>> "Base1/Zone1/Field1": [1.0, 2.0] >>> } >>> cgns_types = { >>> "Base1": "CGNSBase_t", >>> "Base1/Zone1": "Zone_t", >>> "Base1/Zone1/Field1": "FlowSolution_t" >>> } >>> tree = unflatten_cgns_tree(flat, cgns_types) .. py:function:: update_features_for_CGNS_compatibility(features: list[str], context_constant_features: list[str], context_variable_features: list[str]) Expand a list of feature paths to include all CGNS hierarchy nodes and metadata required for compatibility. This function takes a list of requested features and expands it to include all necessary CGNS tree nodes, metadata, and temporal information (_times suffixes) needed to maintain a valid and complete CGNS structure. It handles different feature types (global, fields, coordinates, elements, boundary conditions) and ensures all parent nodes and related metadata are included. :param features: List of feature paths to expand. Paths follow the CGNS hierarchy format (e.g., "Base/Zone/Solution/Field", "Global/parameter"). :type features: list[str] :param context_constant_features: Set of constant feature paths available in the context (e.g., grid coordinates, element connectivity). :type context_constant_features: list[str] :param context_variable_features: Set of variable feature paths available in the context (e.g., flow solution fields, time-varying parameters). :type context_variable_features: list[str] :returns: Expanded list of feature paths including: - Original requested features - Parent nodes in the CGNS hierarchy - Associated metadata nodes (GridLocation, ZoneType, FamilyName) - Temporal information (_times suffix for all features) - Related structural elements (coordinates, elements, boundary conditions) :rtype: list[str] :raises KeyError: If any requested feature is not found in the combined context features. .. rubric:: Example >>> context_const = {'Base/Zone', 'Base/Zone/GridCoordinates', ...} >>> context_var = {'Base/Zone/GridCoordinates/CoordinateX', ...} >>> features = ['Base/Zone/GridCoordinates/CoordinateX'] >>> expanded = update_features_for_CGNS_compatibility( ... features, context_const, context_var ... ) >>> 'Base/Zone/GridCoordinates' in expanded True >>> 'Base/Zone/GridCoordinates/CoordinateX_times' in expanded True .. note:: - The function creates a copy of the input features list to avoid modifying the original. - Features with type 'field' automatically include their parent FlowSolution node and GridLocation metadata. - Global features trigger inclusion of 'Global' and 'Global_times' nodes. - Spatial features (coordinates, elements, boundary conditions) include full zone hierarchy (Base, Zone, ZoneType, FamilyName) and related structural information.