diff --git a/geos-mesh/src/geos/mesh/utils/arrayHelpers.py b/geos-mesh/src/geos/mesh/utils/arrayHelpers.py index ad88ba02..dbfb62b7 100644 --- a/geos-mesh/src/geos/mesh/utils/arrayHelpers.py +++ b/geos-mesh/src/geos/mesh/utils/arrayHelpers.py @@ -25,23 +25,24 @@ - Checks The getter functions: - - get the array of an attribute (one for dataset, one for multiblockDataset, one for the both and one for fieldData) - - get the component names of an attribute (one for dataset, one for multiblockDataset and one for the both) - - get the number of components of an attribute (one for dataset, one for multiblockDataset and one for the both) - - get the piece of an attribute (for any meshes) - - get the values of an attribute as data frame (for polyData only) - - get the vtk type of an attribute (one for dataset, one for multiblockDataset and one for the both) - - get the set of attributes on one piece of a mesh (for any mesh) - - get the attribute and they number of component on one piece of a mesh (one for dataset, one for multiblockDataset and one for the both) - - get all the cells dimension of a mesh (for any meshes) - - get the GlobalIds array on one piece of a mesh (for any meshes) + - get the vtk or array data of an attribute (dataset and vtkFieldData only) + - get the component names of an attribute + - get the number of components of an attribute + - get the piece of an attribute + - get the values of an attribute as data frame (polyData only) + - get the vtk type of an attribute + - get the set of attributes on one piece of a mesh + - get the attribute and they number of component on one piece of a mesh + - get all the cells dimension of a mesh + - get the GlobalIds array on one piece of a mesh - get the cell center coordinates of a mesh - get the mapping between cells or points shared by two meshes The check functions: - - check if an attribute is on a mesh (one for dataset, one for multiblockDataset, one for the both and one for a list of attributes) - - check if an attribute is global (for multiblockDataset meshes) - - check if a value is a value of an attribute (one for dataset and one for multiblockDataset) + - check if an attribute is on a mesh + - check if at least one attribute from a list of attributes is on a mesh (dataset only) + - check if an attribute is global (multiblock dataset only) + - check if a value is a value of an attribute """ @@ -192,15 +193,12 @@ def hasArray( mesh: vtkUnstructuredGrid, arrayNames: list[ str ] ) -> bool: Returns: bool: True if at least one array is found, else False. """ - # Check the cell data fields - data: Union[ vtkFieldData, None ] - for data in ( mesh.GetCellData(), mesh.GetFieldData(), mesh.GetPointData() ): - if data is None: - continue # type: ignore[unreachable] + for piece in [ Piece.CELLS, Piece.POINTS, Piece.FIELD ]: for arrayName in arrayNames: - if data.HasArray( arrayName ): - logging.error( f"The mesh contains the array named '{arrayName}'." ) + if isAttributeInObject( mesh, arrayName, piece ): + logging.error( f"The mesh contains the array named '{ arrayName }'." ) return True + return False @@ -229,69 +227,57 @@ def getAttributePieceInfo( return Piece.NONE -def checkValidValuesInMultiBlock( - multiBlockDataSet: vtkMultiBlockDataSet, +def checkValidValuesInObject( + mesh: vtkMultiBlockDataSet | vtkDataSet, attributeName: str, listValues: list[ Any ], piece: Piece, ) -> tuple[ list[ Any ], list[ Any ] ]: - """Check if each value is valid , ie if that value is a data of the attribute in at least one dataset of the multiblock. + """Check if each value is valid, ie if that value is a data of the mesh's attribute. Args: - multiBlockDataSet (vtkMultiBlockDataSet): The multiblock dataset mesh to check. + mesh (vtkMultiBlockDataSet | vtkDataSet): The mesh to check. attributeName (str): The name of the attribute with the data. listValues (list[Any]): The list of values to check. piece (Piece): The piece of the attribute. Returns: tuple[list[Any], list[Any]]: Tuple containing the list of valid values and the list of the invalid ones. - """ - validValues: list[ Any ] = [] - invalidValues: list[ Any ] = [] - listFlatIdDataSet: list[ int ] = getBlockElementIndexesFlatten( multiBlockDataSet ) - for flatIdDataSet in listFlatIdDataSet: - dataSet: vtkDataSet = vtkDataSet.SafeDownCast( multiBlockDataSet.GetDataSet( flatIdDataSet ) ) - # Get the valid values of the dataset. - validValuesDataSet: list[ Any ] = checkValidValuesInDataSet( dataSet, attributeName, listValues, piece )[ 0 ] - - # Keep the new true values. - for value in validValuesDataSet: - if value not in validValues: - validValues.append( value ) - - # Get the false indexes. - for value in listValues: - if value not in validValues: - invalidValues.append( value ) - return ( validValues, invalidValues ) - - -def checkValidValuesInDataSet( - dataSet: vtkDataSet, - attributeName: str, - listValues: list[ Any ], - piece: Piece, -) -> tuple[ list[ Any ], list[ Any ] ]: - """Check if each value is valid , ie if that value is a data of the attribute in the dataset. - - Args: - dataSet (vtkDataSet): The dataset mesh to check. - attributeName (str): The name of the attribute with the data. - listValues (list[Any]): The list of values to check. - piece (Piece): The piece of the attribute. - - Returns: - tuple[list[Any], list[Any]]: Tuple containing the list of valid values and the list of the invalid ones. + Raises: + TypeError: The mesh has to be inherited from vtkMultiBlockDataSet or vtkDataSet. + AttributeError: The attribute must be global for multiblock dataset. """ - attributeNpArray = getArrayInObject( dataSet, attributeName, piece ) validValues: list[ Any ] = [] invalidValues: list[ Any ] = [] - for value in listValues: - if value in attributeNpArray: - validValues.append( value ) - else: - invalidValues.append( value ) + if isinstance( mesh, vtkDataSet ): + attributeNpArray = getArrayInObject( mesh, attributeName, piece ) + for value in listValues: + if value in attributeNpArray: + validValues.append( value ) + else: + invalidValues.append( value ) + elif isinstance( mesh, vtkMultiBlockDataSet ): + if not isAttributeGlobal( mesh, attributeName, piece ): + raise AttributeError( f"The attribute { attributeName } must be global." ) + + listFlatIdDataSet: list[ int ] = getBlockElementIndexesFlatten( mesh ) + for flatIdDataSet in listFlatIdDataSet: + dataSet: vtkDataSet = vtkDataSet.SafeDownCast( mesh.GetDataSet( flatIdDataSet ) ) + # Get the valid values of the dataset. + validValuesDataSet: list[ Any ] = checkValidValuesInObject( dataSet, attributeName, listValues, piece )[ 0 ] + + # Keep the new true values. + for value in validValuesDataSet: + if value not in validValues: + validValues.append( value ) + + # Get the false indexes. + for value in listValues: + if value not in validValues: + invalidValues.append( value ) + else: + raise TypeError( "Input mesh must be a vtkDataSet or vtkMultiBlockDataSet." ) return ( validValues, invalidValues ) @@ -315,6 +301,7 @@ def getNumpyGlobalIdsArray( data: Union[ vtkCellData, vtkPointData ] ) -> npt.ND global_ids: Optional[ vtkDataArray ] = data.GetGlobalIds() if global_ids is None: raise AttributeError( "There is no GlobalIds in the given fieldData." ) + return vtk_to_numpy( global_ids ) @@ -351,23 +338,13 @@ def getAttributeSet( mesh: Union[ vtkMultiBlockDataSet, vtkDataSet ], piece: Pie Args: mesh (Union[vtkMultiBlockDataSet, vtkDataSet]): Mesh where to find the attributes. - piece (Piece): The piece of the attribute. + piece (Piece): The piece of the attributes to get. Returns: set[str]: Set of attribute names present in input mesh. """ - attributeSet: set[ str ] - if isinstance( mesh, vtkMultiBlockDataSet ): - listDataSetIds: list[ int ] = getBlockElementIndexesFlatten( mesh ) - attributeSet = set() - for dataSetId in listDataSetIds: - dataset: vtkDataSet = vtkDataSet.SafeDownCast( mesh.GetDataSet( dataSetId ) ) - attributeSet.update( getAttributeSet( dataset, piece ) ) - elif isinstance( mesh, vtkDataSet ): - fieldData: vtkPointData | vtkCellData = mesh.GetPointData() if piece == Piece.POINTS else mesh.GetCellData() - attributeSet = { fieldData.GetArrayName( i ) for i in range( fieldData.GetNumberOfArrays() ) } - else: - raise TypeError( "Input mesh must be a vtkDataSet or vtkMultiBlockDataSet." ) + dictAttributes: dict[ str, int ] = getAttributesWithNumberOfComponents( mesh, piece ) + attributeSet: set[ str ] = set( dictAttributes.keys() ) return attributeSet @@ -379,78 +356,52 @@ def getAttributesWithNumberOfComponents( """Get the dictionary of all attributes from object on points or cells. Args: - mesh (Any): Mesh where to find the attributes. - piece (Piece): The piece of the attribute. + mesh (vtkMultiBlockDataSet | vtkDataSet): Mesh where to find the attributes. + piece (Piece): The piece of the attributes to get. Returns: dict[str, int]: Dictionary where keys are the names of the attributes and values the number of components. - """ - attributes: dict[ str, int ] - if isinstance( mesh, ( vtkMultiBlockDataSet, vtkCompositeDataSet ) ): - attributes = getAttributesFromMultiBlockDataSet( mesh, piece ) - elif isinstance( mesh, vtkDataSet ): - attributes = getAttributesFromDataSet( mesh, piece ) - else: - raise TypeError( "Input mesh must be a vtkDataSet or vtkMultiBlockDataSet." ) - return attributes - - -def getAttributesFromMultiBlockDataSet( multiBlockDataSet: Union[ vtkMultiBlockDataSet, vtkCompositeDataSet ], - piece: Piece ) -> dict[ str, int ]: - """Get the dictionary of all attributes of object on points or on cells. - Args: - multiBlockDataSet (vtkMultiBlockDataSet | vtkCompositeDataSet): multiBlockDataSet where to find the attributes. - piece (Piece): The piece of the attribute. - - Returns: - dict[str, int]: Dictionary of the names of the attributes as keys, and number of components as values. + Raises: + ValueError: The piece must be cells or points only + AttributeError: One attribute one the mesh is null. + TypeError: Input mesh must be a vtkDataSet or vtkMultiBlockDataSet. """ attributes: dict[ str, int ] = {} - elementaryBlockIndexes: list[ int ] = getBlockElementIndexesFlatten( multiBlockDataSet ) - for blockIndex in elementaryBlockIndexes: - dataSet: vtkDataSet = vtkDataSet.SafeDownCast( multiBlockDataSet.GetDataSet( blockIndex ) ) - blockAttributes: dict[ str, int ] = getAttributesFromDataSet( dataSet, piece ) - for attributeName, nbComponents in blockAttributes.items(): - if attributeName not in attributes: - attributes[ attributeName ] = nbComponents - - return attributes - - -def getAttributesFromDataSet( dataSet: vtkDataSet, piece: Piece ) -> dict[ str, int ]: - """Get the dictionary of all attributes of a vtkDataSet on points or cells. + if isinstance( mesh, ( vtkMultiBlockDataSet, vtkCompositeDataSet ) ): + elementaryBlockIndexes: list[ int ] = getBlockElementIndexesFlatten( mesh ) + for blockIndex in elementaryBlockIndexes: + dataSet: vtkDataSet = vtkDataSet.SafeDownCast( mesh.GetDataSet( blockIndex ) ) + blockAttributes: dict[ str, int ] = getAttributesWithNumberOfComponents( dataSet, piece ) + for attributeName, nbComponents in blockAttributes.items(): + if attributeName not in attributes: + attributes[ attributeName ] = nbComponents + elif isinstance( mesh, vtkDataSet ): + data: Union[ vtkPointData, vtkCellData ] + if piece == Piece.POINTS: + data = mesh.GetPointData() + elif piece == Piece.CELLS: + data = mesh.GetCellData() + else: + raise ValueError( f"The attribute piece must be { Piece.POINTS.value } or { Piece.CELLS.value }." ) - Args: - dataSet (vtkDataSet): DataSet where to find the attributes. - piece (Piece): The piece of the attribute. + nbAttributes: int = data.GetNumberOfArrays() + for i in range( nbAttributes ): + attributeName = data.GetArrayName( i ) + attribute: vtkDataArray = data.GetArray( attributeName ) + if attribute is None: + raise AttributeError( f"The attribute { attributeName } is null" ) - Returns: - dict[str, int]: List of the names of the attributes. - """ - attributes: dict[ str, int ] = {} - data: Union[ vtkPointData, vtkCellData ] - if piece == Piece.POINTS: - data = dataSet.GetPointData() - elif piece == Piece.CELLS: - data = dataSet.GetCellData() + nbComponents = attribute.GetNumberOfComponents() + attributes[ attributeName ] = nbComponents else: - raise ValueError( f"The attribute piece must be { Piece.POINTS.value } or { Piece.CELLS.value }." ) - - assert data is not None, f"Data on { piece.value } was not recovered." + raise TypeError( "Input mesh must be a vtkDataSet or vtkMultiBlockDataSet." ) - nbAttributes: int = data.GetNumberOfArrays() - for i in range( nbAttributes ): - attributeName: str = data.GetArrayName( i ) - attribute: vtkDataArray = data.GetArray( attributeName ) - assert attribute is not None, f"Attribute { attributeName } is null" - nbComponents: int = attribute.GetNumberOfComponents() - attributes[ attributeName ] = nbComponents return attributes def isAttributeInObject( mesh: Union[ vtkMultiBlockDataSet, vtkDataSet ], attributeName: str, piece: Piece ) -> bool: - """Check if an attribute is in the input object. + """Check if an attribute is in the input mesh for the given piece. Args: mesh (vtkMultiBlockDataSet | vtkDataSet): Input mesh. @@ -458,62 +409,34 @@ def isAttributeInObject( mesh: Union[ vtkMultiBlockDataSet, vtkDataSet ], attrib piece (Piece): The piece of the attribute. Returns: - bool: True if the attribute is in the table, False otherwise. - """ - if isinstance( mesh, vtkMultiBlockDataSet ): - return isAttributeInObjectMultiBlockDataSet( mesh, attributeName, piece ) - elif isinstance( mesh, vtkDataSet ): - return isAttributeInObjectDataSet( mesh, attributeName, piece ) - else: - raise TypeError( "Input object must be a vtkDataSet or vtkMultiBlockDataSet." ) - - -def isAttributeInObjectMultiBlockDataSet( multiBlockDataSet: vtkMultiBlockDataSet, attributeName: str, - piece: Piece ) -> bool: - """Check if an attribute is in the input object. + bool: True if the attribute is on the mesh, False otherwise. - Args: - multiBlockDataSet (vtkMultiBlockDataSet): Input multiBlockDataSet. - attributeName (str): Name of the attribute. - piece (Piece): The piece of the attribute. - - Returns: - bool: True if the attribute is in the table, False otherwise. + Raises: + TypeError: The mesh has to be inherited from vtkMultiBlockDataSet or vtkDataSet. """ - elementaryBlockIndexes: list[ int ] = getBlockElementIndexesFlatten( multiBlockDataSet ) - for blockIndex in elementaryBlockIndexes: - dataSet: vtkDataSet = vtkDataSet.SafeDownCast( multiBlockDataSet.GetDataSet( blockIndex ) ) - if isAttributeInObjectDataSet( dataSet, attributeName, piece ): - return True + if isinstance( mesh, vtkDataSet ): + if piece == Piece.FIELD: + return bool( mesh.GetFieldData().HasArray( attributeName ) ) + elif piece == Piece.POINTS: + return bool( mesh.GetPointData().HasArray( attributeName ) ) + elif piece == Piece.CELLS: + return bool( mesh.GetCellData().HasArray( attributeName ) ) + elif piece == Piece.BOTH: + onPoints: int = mesh.GetPointData().HasArray( attributeName ) + onCells: int = mesh.GetCellData().HasArray( attributeName ) + return onCells == onPoints == 1 + elif isinstance( mesh, vtkMultiBlockDataSet ): + elementaryBlockIndexes: list[ int ] = getBlockElementIndexesFlatten( mesh ) + for blockIndex in elementaryBlockIndexes: + dataSet: vtkDataSet = vtkDataSet.SafeDownCast( mesh.GetDataSet( blockIndex ) ) + if isAttributeInObject( dataSet, attributeName, piece ): + return True + else: + raise TypeError( "Input mesh must be a vtkDataSet or vtkMultiBlockDataSet." ) return False -def isAttributeInObjectDataSet( dataSet: vtkDataSet, attributeName: str, piece: Piece ) -> bool: - """Check if an attribute is in the input object for the input piece. - - Args: - dataSet (vtkDataSet): Input dataSet. - attributeName (str): Name of the attribute. - piece (Piece): The piece of the attribute. - - Returns: - bool: True if the attribute is in the table, False otherwise. - """ - if piece == Piece.FIELD: - return bool( dataSet.GetFieldData().HasArray( attributeName ) ) - elif piece == Piece.POINTS: - return bool( dataSet.GetPointData().HasArray( attributeName ) ) - elif piece == Piece.CELLS: - return bool( dataSet.GetCellData().HasArray( attributeName ) ) - elif piece == Piece.BOTH: - onPoints: int = dataSet.GetPointData().HasArray( attributeName ) - onCells: int = dataSet.GetCellData().HasArray( attributeName ) - return onCells == onPoints == 1 - else: - return False - - def isAttributeGlobal( multiBlockDataSet: vtkMultiBlockDataSet, attributeName: str, piece: Piece ) -> bool: """Check if an attribute is global in the input multiBlockDataSet. @@ -528,13 +451,14 @@ def isAttributeGlobal( multiBlockDataSet: vtkMultiBlockDataSet, attributeName: s elementaryBlockIndexes: list[ int ] = getBlockElementIndexesFlatten( multiBlockDataSet ) for blockIndex in elementaryBlockIndexes: dataSet: vtkDataSet = vtkDataSet.SafeDownCast( multiBlockDataSet.GetDataSet( blockIndex ) ) - if not isAttributeInObjectDataSet( dataSet, attributeName, piece ): + if not isAttributeInObject( dataSet, attributeName, piece ): return False + return True def getArrayInObject( dataSet: vtkDataSet, attributeName: str, piece: Piece ) -> npt.NDArray[ Any ]: - """Return the numpy array corresponding to input attribute name in table. + """Return the numpy array corresponding to input attribute name in the mesh. Args: dataSet (vtkDataSet): Input dataSet. @@ -542,80 +466,64 @@ def getArrayInObject( dataSet: vtkDataSet, attributeName: str, piece: Piece ) -> piece (Piece): The piece of the attribute. Returns: - ArrayLike[Any]: The numpy array corresponding to input attribute name. + NDArray[Any]: The numpy array corresponding to input attribute name. """ vtkArray: vtkDataArray = getVtkArrayInObject( dataSet, attributeName, piece ) npArray: npt.NDArray[ Any ] = vnp.vtk_to_numpy( vtkArray ) # type: ignore[no-untyped-call] + return npArray -def getVtkDataTypeInObject( mesh: Union[ vtkDataSet, vtkMultiBlockDataSet ], attributeName: str, piece: Piece ) -> int: +def getVtkArrayTypeInObject( mesh: Union[ vtkDataSet, vtkMultiBlockDataSet ], attributeName: str, piece: Piece ) -> int: """Return VTK type of requested array from input mesh. Args: - mesh (Union[vtkDataSet, vtkMultiBlockDataSet]): Input multiBlockDataSet. + mesh (Union[vtkDataSet, vtkMultiBlockDataSet]): Input mesh. attributeName (str): Name of the attribute. piece (Piece): The piece of the attribute. Returns: int: The type of the vtk array corresponding to input attribute name. + + Raises: + AttributeError: The attribute 'attributeName' is not in the mesh. + TypeError: The mesh has to be inherited from vtkMultiBlockDataSet or vtkDataSet. """ if isinstance( mesh, vtkDataSet ): - return getVtkArrayTypeInObject( mesh, attributeName, piece ) + array: vtkDataArray = getVtkArrayInObject( mesh, attributeName, piece ) + vtkArrayType: int = array.GetDataType() + return vtkArrayType + elif isinstance( mesh, vtkMultiBlockDataSet ): + elementaryBlockIndexes: list[ int ] = getBlockElementIndexesFlatten( mesh ) + for blockIndex in elementaryBlockIndexes: + dataSet: vtkDataSet = vtkDataSet.SafeDownCast( mesh.GetDataSet( blockIndex ) ) + try: + return getVtkArrayTypeInObject( dataSet, attributeName, piece ) + except Exception: + continue + raise AttributeError( f"The attribute { attributeName } is not in input mesh." ) else: - return getVtkArrayTypeInMultiBlock( mesh, attributeName, piece ) - - -def getVtkArrayTypeInObject( dataSet: vtkDataSet, attributeName: str, piece: Piece ) -> int: - """Return VTK type of requested array from dataset input. - - Args: - dataSet (vtkDataSet): Input dataSet. - attributeName (str): Name of the attribute. - piece (Piece): The piece of the attribute. - - Returns: - int: The type of the vtk array corresponding to input attribute name. - """ - array: vtkDataArray = getVtkArrayInObject( dataSet, attributeName, piece ) - vtkArrayType: int = array.GetDataType() - - return vtkArrayType - - -def getVtkArrayTypeInMultiBlock( multiBlockDataSet: vtkMultiBlockDataSet, attributeName: str, piece: Piece ) -> int: - """Return VTK type of requested array from multiblock dataset input, if existing. - - Args: - multiBlockDataSet (vtkMultiBlockDataSet): Input multiBlockDataSet. - attributeName (str): Name of the attribute. - piece (Piece): The piece of the attribute. - - Returns: - int: Type of the requested vtk array if existing in input multiblock dataset. - """ - elementaryBlockIndexes: list[ int ] = getBlockElementIndexesFlatten( multiBlockDataSet ) - for blockIndex in elementaryBlockIndexes: - dataSet: vtkDataSet = vtkDataSet.SafeDownCast( multiBlockDataSet.GetDataSet( blockIndex ) ) - listAttributes: set[ str ] = getAttributeSet( dataSet, piece ) - if attributeName in listAttributes: - return getVtkArrayTypeInObject( dataSet, attributeName, piece ) - - raise AssertionError( "The vtkMultiBlockDataSet has no attribute with the name " + attributeName + "." ) + raise TypeError( "Input object must be a vtkDataSet or vtkMultiBlockDataSet." ) def getVtkArrayInObject( dataSet: vtkDataSet, attributeName: str, piece: Piece ) -> vtkDataArray: - """Return the array corresponding to input attribute name in table. + """Return the array corresponding to input attribute name in the mesh. Args: - dataSet (vtkDataSet): Input dataSet. - attributeName (str): Name of the attribute. - piece (Piece): The piece of the attribute. + dataSet (vtkDataSet): Input mesh with the attribute to get. + attributeName (str): Name of the attribute to get. + piece (Piece): The piece of the attribute to get. Returns: vtkDataArray: The vtk array corresponding to input attribute name. + + Raises: + ValueError: The piece must be cells, points or fields. + AttributeError: The attribute 'attributeName' is not in the mesh. """ - assert isAttributeInObject( dataSet, attributeName, piece ), f"{attributeName} is not in input mesh." + if not isAttributeInObject( dataSet, attributeName, piece ): + raise AttributeError( f"The attribute { attributeName } is not in input mesh." ) + dataArray: vtkDataArray if piece == Piece.POINTS: dataArray = dataSet.GetPointData().GetArray( attributeName ) @@ -635,7 +543,7 @@ def getNumberOfComponents( attributeName: str, piece: Piece, ) -> int: - """Get the number of components of attribute attributeName in dataSet. + """Get the number of components of the attribute 'attributeName' in the mesh for a given piece. Args: mesh (vtkMultiBlockDataSet | vtkCompositeDataSet | vtkDataSet): Mesh where the attribute is. @@ -644,52 +552,31 @@ def getNumberOfComponents( Returns: int: Number of components. + + Raises: + AttributeError: The attribute 'attributeName' is not in the mesh for the given piece. + TypeError: The mesh has to be inherited from vtkMultiBlockDataSet or vtkDataSet. + ValueError: The attribute's piece must be 'cells', 'points' or 'field'. """ + nbComponents: int = 0 if isinstance( mesh, vtkDataSet ): - return getNumberOfComponentsDataSet( mesh, attributeName, piece ) + array: vtkDataArray = getVtkArrayInObject( mesh, attributeName, piece ) + nbComponents = array.GetNumberOfComponents() elif isinstance( mesh, ( vtkMultiBlockDataSet, vtkCompositeDataSet ) ): - return getNumberOfComponentsMultiBlock( mesh, attributeName, piece ) + elementaryBlockIndexes: list[ int ] = getBlockElementIndexesFlatten( mesh ) + for blockIndex in elementaryBlockIndexes: + dataSet: vtkDataSet = vtkDataSet.SafeDownCast( mesh.GetDataSet( blockIndex ) ) + try: + return getNumberOfComponents( dataSet, attributeName, piece ) + except ValueError as e: + raise e + except AttributeError: + continue + raise AttributeError( f"The attribute '{ attributeName }' is not in the mesh for the given piece { piece }." ) else: raise TypeError( "The mesh has to be inherited from vtkMultiBlockDataSet or vtkDataSet." ) - -def getNumberOfComponentsDataSet( dataSet: vtkDataSet, attributeName: str, piece: Piece ) -> int: - """Get the number of components of attribute attributeName in dataSet. - - Args: - dataSet (vtkDataSet): DataSet where the attribute is. - attributeName (str): Name of the attribute. - piece (Piece): The piece of the attribute. - - Returns: - int: Number of components. - """ - array: vtkDataArray = getVtkArrayInObject( dataSet, attributeName, piece ) - return array.GetNumberOfComponents() - - -def getNumberOfComponentsMultiBlock( - multiBlockDataSet: Union[ vtkMultiBlockDataSet, vtkCompositeDataSet ], - attributeName: str, - piece: Piece, -) -> int: - """Get the number of components of attribute attributeName in dataSet. - - Args: - multiBlockDataSet (vtkMultiBlockDataSet | vtkCompositeDataSet): multi block data Set where the attribute is. - attributeName (str): Name of the attribute. - piece (Piece): The piece of the attribute. - - Returns: - int: Number of components. - """ - elementaryBlockIndexes: list[ int ] = getBlockElementIndexesFlatten( multiBlockDataSet ) - for blockIndex in elementaryBlockIndexes: - dataSet: vtkDataSet = vtkDataSet.SafeDownCast( multiBlockDataSet.GetDataSet( blockIndex ) ) - if isAttributeInObject( dataSet, attributeName, piece ): - array: vtkDataArray = getVtkArrayInObject( dataSet, attributeName, piece ) - return array.GetNumberOfComponents() - return 0 + return nbComponents def getComponentNames( @@ -697,7 +584,7 @@ def getComponentNames( attributeName: str, piece: Piece, ) -> tuple[ str, ...]: - """Get the name of the components of attribute attributeName in dataSet. + """Get the name of the components of the attribute 'attributeName' in a mesh. Args: mesh (vtkDataSet | vtkMultiBlockDataSet | vtkCompositeDataSet | vtkDataObject): Mesh where the attribute is. @@ -706,57 +593,34 @@ def getComponentNames( Returns: tuple[str,...]: Names of the components. + + Raises: + AttributeError: The attribute 'attributeName' is not in the mesh for the given piece. + TypeError: The mesh has to be inherited from vtkMultiBlockDataSet or vtkDataSet. + ValueError: The attribute's piece must be 'cells', 'points' or 'field'. """ + componentNames: list[ str ] = [] if isinstance( mesh, vtkDataSet ): - return getComponentNamesDataSet( mesh, attributeName, piece ) + array: vtkDataArray = getVtkArrayInObject( mesh, attributeName, piece ) + if array.GetNumberOfComponents() > 1: + componentNames += [ array.GetComponentName( i ) for i in range( array.GetNumberOfComponents() ) ] elif isinstance( mesh, ( vtkMultiBlockDataSet, vtkCompositeDataSet ) ): - return getComponentNamesMultiBlock( mesh, attributeName, piece ) + elementaryBlockIndexes: list[ int ] = getBlockElementIndexesFlatten( mesh ) + for blockIndex in elementaryBlockIndexes: + dataSet: vtkDataSet = vtkDataSet.SafeDownCast( mesh.GetDataSet( blockIndex ) ) + try: + return getComponentNames( dataSet, attributeName, piece ) + except ValueError as e: + raise e + except AttributeError: + continue + raise AttributeError( f"The attribute '{ attributeName }' is not in the mesh for the given piece { piece }." ) else: - raise TypeError( "Mesh type is not managed." ) - - -def getComponentNamesDataSet( dataSet: vtkDataSet, attributeName: str, piece: Piece ) -> tuple[ str, ...]: - """Get the name of the components of attribute attributeName in dataSet. - - Args: - dataSet (vtkDataSet): DataSet where the attribute is. - attributeName (str): Name of the attribute. - piece (Piece): The piece of the attribute. - - Returns: - tuple[str,...]: Names of the components. - """ - array: vtkDataArray = getVtkArrayInObject( dataSet, attributeName, piece ) - componentNames: list[ str ] = [] + raise TypeError( "The mesh has to be inherited from vtkMultiBlockDataSet or vtkDataSet." ) - if array.GetNumberOfComponents() > 1: - componentNames += [ array.GetComponentName( i ) for i in range( array.GetNumberOfComponents() ) ] return tuple( componentNames ) -def getComponentNamesMultiBlock( - multiBlockDataSet: Union[ vtkMultiBlockDataSet, vtkCompositeDataSet ], - attributeName: str, - piece: Piece, -) -> tuple[ str, ...]: - """Get the name of the components of attribute in MultiBlockDataSet. - - Args: - multiBlockDataSet (vtkMultiBlockDataSet | vtkCompositeDataSet): DataSet where the attribute is. - attributeName (str): Name of the attribute. - piece (Piece): The piece of the attribute. - - Returns: - tuple[str,...]: Names of the components. - """ - elementaryBlockIndexes: list[ int ] = getBlockElementIndexesFlatten( multiBlockDataSet ) - for blockIndex in elementaryBlockIndexes: - dataSet: vtkDataSet = vtkDataSet.SafeDownCast( multiBlockDataSet.GetDataSet( blockIndex ) ) - if isAttributeInObject( dataSet, attributeName, piece ): - return getComponentNamesDataSet( dataSet, attributeName, piece ) - return () - - def getAttributeValuesAsDF( surface: vtkPolyData, attributeNames: tuple[ str, ...], piece: Piece = Piece.CELLS ) -> pd.DataFrame: diff --git a/geos-mesh/src/geos/mesh/utils/arrayModifiers.py b/geos-mesh/src/geos/mesh/utils/arrayModifiers.py index 6bc763b3..835dd127 100644 --- a/geos-mesh/src/geos/mesh/utils/arrayModifiers.py +++ b/geos-mesh/src/geos/mesh/utils/arrayModifiers.py @@ -29,17 +29,12 @@ from vtkmodules.vtkCommonCore import ( vtkDataArray, vtkPoints, vtkLogger ) from geos.mesh.utils.arrayHelpers import ( getComponentNames, - getComponentNamesDataSet, getAttributesWithNumberOfComponents, getArrayInObject, isAttributeInObject, - isAttributeInObjectDataSet, - isAttributeInObjectMultiBlockDataSet, isAttributeGlobal, getVtkArrayTypeInObject, - getVtkArrayTypeInMultiBlock, - getVtkDataTypeInObject, - getNumberOfComponentsMultiBlock, + getNumberOfComponents, ) from geos.mesh.utils.multiblockHelpers import getBlockElementIndexesFlatten from geos.utils.Errors import VTKError @@ -97,7 +92,7 @@ def fillPartialAttributes( raise TypeError( "Input mesh has to be inherited from vtkMultiBlockDataSet." ) # Check if the attribute exist in the input mesh. - if not isAttributeInObjectMultiBlockDataSet( multiBlockDataSet, attributeName, piece ): + if not isAttributeInObject( multiBlockDataSet, attributeName, piece ): raise AttributeError( f"The attribute { attributeName } is not in the mesh." ) # Check if the attribute is partial. @@ -105,8 +100,8 @@ def fillPartialAttributes( raise AttributeError( f"The attribute { attributeName } is already global." ) # Get information of the attribute to fill. - vtkDataType: int = getVtkArrayTypeInMultiBlock( multiBlockDataSet, attributeName, piece ) - nbComponents: int = getNumberOfComponentsMultiBlock( multiBlockDataSet, attributeName, piece ) + vtkDataType: int = getVtkArrayTypeInObject( multiBlockDataSet, attributeName, piece ) + nbComponents: int = getNumberOfComponents( multiBlockDataSet, attributeName, piece ) componentNames: tuple[ str, ...] = () if nbComponents > 1: componentNames = getComponentNames( multiBlockDataSet, attributeName, piece ) @@ -154,7 +149,7 @@ def fillPartialAttributes( elementaryBlockIndexes: list[ int ] = getBlockElementIndexesFlatten( multiBlockDataSet ) for blockIndex in elementaryBlockIndexes: dataSet: vtkDataSet = vtkDataSet.SafeDownCast( multiBlockDataSet.GetDataSet( blockIndex ) ) - if not isAttributeInObjectDataSet( dataSet, attributeName, piece ): + if not isAttributeInObject( dataSet, attributeName, piece ): createConstantAttributeDataSet( dataSet, listValues, attributeName, componentNames, piece, vtkDataType, logger ) @@ -333,7 +328,7 @@ def createConstantAttributeMultiBlock( raise ValueError( f"The attribute must be created on { Piece.POINTS.value } or { Piece.CELLS.value }." ) # Check if the attribute already exist in the input mesh. - if isAttributeInObjectMultiBlockDataSet( multiBlockDataSet, attributeName, piece ): + if isAttributeInObject( multiBlockDataSet, attributeName, piece ): raise AttributeError( f"The attribute { attributeName } is already present in the mesh." ) # Parse the multiBlockDataSet to create the constant attribute on each blocks. @@ -474,12 +469,12 @@ def createAttribute( raise TypeError( "Input dataSet has to be inherited from vtkDataSet." ) # Check if the attribute already exist in the input mesh. - if isAttributeInObjectDataSet( dataSet, attributeName, piece ): + if isAttributeInObject( dataSet, attributeName, piece ): raise AttributeError( f"The attribute { attributeName } is already present in the mesh." ) # Check if an attribute with the same name exist on the opposite piece (points or cells) on the input mesh. oppositePiece: Piece = Piece.CELLS if piece == Piece.POINTS else Piece.POINTS - if isAttributeInObjectDataSet( dataSet, attributeName, oppositePiece ): + if isAttributeInObject( dataSet, attributeName, oppositePiece ): logger.warning( f"The attribute { attributeName } exist on the opposite piece { oppositePiece.value }." ) # Check the coherency between the given array type and the vtk array type if it exist. @@ -574,11 +569,11 @@ def copyAttribute( raise TypeError( "Final mesh has to be inherited from vtkMultiBlockDataSet." ) # Check if the attribute exist in the multiBlockDataSetFrom. - if not isAttributeInObjectMultiBlockDataSet( multiBlockDataSetFrom, attributeNameFrom, piece ): + if not isAttributeInObject( multiBlockDataSetFrom, attributeNameFrom, piece ): raise AttributeError( f"The attribute { attributeNameFrom } is not present in the source mesh." ) # Check if the attribute already exist in the multiBlockDataSetTo. - if isAttributeInObjectMultiBlockDataSet( multiBlockDataSetTo, attributeNameTo, piece ): + if isAttributeInObject( multiBlockDataSetTo, attributeNameTo, piece ): raise AttributeError( f"The attribute { attributeNameTo } is already present in the final mesh." ) # Check if the two multiBlockDataSets are similar. @@ -592,7 +587,7 @@ def copyAttribute( dataSetFrom: vtkDataSet = vtkDataSet.SafeDownCast( multiBlockDataSetFrom.GetDataSet( idBlock ) ) dataSetTo: vtkDataSet = vtkDataSet.SafeDownCast( multiBlockDataSetTo.GetDataSet( idBlock ) ) - if isAttributeInObjectDataSet( dataSetFrom, attributeNameFrom, piece ): + if isAttributeInObject( dataSetFrom, attributeNameFrom, piece ): copyAttributeDataSet( dataSetFrom, dataSetTo, attributeNameFrom, attributeNameTo, piece, logger ) return @@ -631,11 +626,11 @@ def copyAttributeDataSet( raise TypeError( "Source mesh has to be inherited from vtkDataSet." ) # Check if the attribute exist in the dataSetFrom. - if not isAttributeInObjectDataSet( dataSetFrom, attributeNameFrom, piece ): + if not isAttributeInObject( dataSetFrom, attributeNameFrom, piece ): raise AttributeError( f"The attribute { attributeNameFrom } is not in the source mesh." ) npArray: npt.NDArray[ Any ] = getArrayInObject( dataSetFrom, attributeNameFrom, piece ) - componentNames: tuple[ str, ...] = getComponentNamesDataSet( dataSetFrom, attributeNameFrom, piece ) + componentNames: tuple[ str, ...] = getComponentNames( dataSetFrom, attributeNameFrom, piece ) vtkArrayType: int = getVtkArrayTypeInObject( dataSetFrom, attributeNameFrom, piece ) createAttribute( dataSetTo, npArray, attributeNameTo, componentNames, piece, vtkArrayType, logger ) @@ -717,7 +712,7 @@ def transferAttributeToDataSetWithElementMap( componentNames: tuple[ str, ...] = getComponentNames( meshFrom, attributeName, piece ) nbComponents: int = len( componentNames ) - vtkDataType: int = getVtkDataTypeInObject( meshFrom, attributeName, piece ) + vtkDataType: int = getVtkArrayTypeInObject( meshFrom, attributeName, piece ) defaultValue: Any if vtkDataType in ( VTK_FLOAT, VTK_DOUBLE ): defaultValue = np.nan @@ -812,7 +807,7 @@ def transferAttributeWithElementMap( if isinstance( meshTo, vtkDataSet ): transferAttributeToDataSetWithElementMap( meshFrom, meshTo, elementMap, attributeName, piece, logger=logger ) elif isinstance( meshTo, vtkMultiBlockDataSet ): - if isAttributeInObjectMultiBlockDataSet( meshTo, attributeName, piece ): + if isAttributeInObject( meshTo, attributeName, piece ): raise AttributeError( f"The attribute { attributeName } is already in the final mesh." ) listFlatIdDataSetTo: list[ int ] = getBlockElementIndexesFlatten( meshTo ) @@ -919,7 +914,7 @@ def createCellCenterAttribute( logger = getLogger( "createCellCenterAttribute", True ) if isinstance( mesh, vtkMultiBlockDataSet ): - if isAttributeInObjectMultiBlockDataSet( mesh, cellCenterAttributeName, Piece.CELLS ): + if isAttributeInObject( mesh, cellCenterAttributeName, Piece.CELLS ): raise AttributeError( f"The attribute { cellCenterAttributeName } in already in the mesh." ) elementaryBlockIndexes: list[ int ] = getBlockElementIndexesFlatten( mesh ) diff --git a/geos-mesh/tests/test_arrayHelpers.py b/geos-mesh/tests/test_arrayHelpers.py index 4c8a31c6..0b18c47c 100644 --- a/geos-mesh/tests/test_arrayHelpers.py +++ b/geos-mesh/tests/test_arrayHelpers.py @@ -103,27 +103,59 @@ def test_computeElementMappingValueError() -> None: arrayHelpers.computeElementMapping( vtkMultiBlockDataSet(), vtkMultiBlockDataSet(), pieceWrongValue ) -@pytest.mark.parametrize( "piece, expected", [ ( Piece.POINTS, { - 'GLOBAL_IDS_POINTS': 1, - 'collocated_nodes': 2, - 'PointAttribute': 3, -} ), ( Piece.CELLS, { - 'CELL_MARKERS': 1, - 'PERM': 3, - 'PORO': 1, - 'FAULT': 1, - 'GLOBAL_IDS_CELLS': 1, - 'CellAttribute': 3, -} ) ] ) -def test_getAttributeFromMultiBlockDataSet( dataSetTest: vtkMultiBlockDataSet, piece: Piece, - expected: dict[ str, int ] ) -> None: - """Test getting attribute list as dict from multiblock.""" - multiBlockTest: vtkMultiBlockDataSet = dataSetTest( "multiblock" ) - attributes: dict[ str, int ] = arrayHelpers.getAttributesFromMultiBlockDataSet( multiBlockTest, piece ) +@pytest.mark.parametrize( "meshName, piece, expected", [ + ( "multiblock", Piece.POINTS, { + 'GLOBAL_IDS_POINTS': 1, + 'collocated_nodes': 2, + 'PointAttribute': 3 + } ), + ( "multiblock", Piece.CELLS, { + 'CELL_MARKERS': 1, + 'PERM': 3, + 'PORO': 1, + 'FAULT': 1, + 'GLOBAL_IDS_CELLS': 1, + 'CellAttribute': 3 + } ), + ( "dataset", Piece.POINTS, { + 'GLOBAL_IDS_POINTS': 1, + 'PointAttribute': 3 + } ), + ( "dataset", Piece.CELLS, { + 'CELL_MARKERS': 1, + 'PERM': 3, + 'PORO': 1, + 'FAULT': 1, + 'GLOBAL_IDS_CELLS': 1, + 'CellAttribute': 3 + } ), +] ) +def test_getAttributesWithNumberOfComponents( dataSetTest: Any, meshName: str, piece: Piece, + expected: dict[ str, int ] ) -> None: + """Test getting attribute list as dict from a mesh.""" + mesh: vtkMultiBlockDataSet | vtkDataSet = dataSetTest( meshName ) + attributes: dict[ str, int ] = arrayHelpers.getAttributesWithNumberOfComponents( mesh, piece ) assert attributes == expected +def test_getAttributesWithNumberOfComponentsRaises() -> None: + """Test the fails of the function getAttributesWithNumberOfComponents.""" + # ValueError + with pytest.raises( ValueError ): + arrayHelpers.getAttributesWithNumberOfComponents( vtkPolyData(), Piece.BOTH ) + + # AttributeError + mesh: vtkPolyData = vtkPolyData() + mesh.GetCellData().AddArray( vtkDoubleArray() ) + with pytest.raises( AttributeError ): + arrayHelpers.getAttributesWithNumberOfComponents( mesh, Piece.CELLS ) + + # TypeError + with pytest.raises( TypeError ): + arrayHelpers.getAttributesWithNumberOfComponents( vtkCellData(), Piece.CELLS ) + + @pytest.mark.parametrize( "meshName, attributeName, pieceTest", [ ( "dataset", "CellAttribute", Piece.CELLS ), ( "dataset", "PointAttribute", Piece.POINTS ), @@ -186,13 +218,6 @@ def test_getAttributeSet( assert obtainedAttributeSet == expectedAttributeSet -def test_getAttributeSetTypeError() -> None: - """Test getAttributeSet TypeError raises.""" - mesh: vtkFieldData = vtkFieldData() - with pytest.raises( TypeError ): - arrayHelpers.getAttributeSet( mesh, Piece.CELLS ) - - @pytest.mark.parametrize( "arrayName, sorted, piece, expectedNpArray", [ ( "PORO", True, Piece.CELLS, np.array( [ 0.20000000298 for _ in range( 1740 ) ], dtype=np.float32 ) ), ( "PORO", False, Piece.CELLS, np.array( [ 0.20000000298 for _ in range( 1740 ) ], dtype=np.float32 ) ), @@ -221,66 +246,43 @@ def test_getNumpyArrayByNameAttributeError( dataSetTest: vtkDataSet ) -> None: arrayHelpers.getNumpyArrayByName( fieldData, "Attribute" ) -@pytest.mark.parametrize( "attributeName, listValues, piece, validValuesTest, invalidValuesTest", [ - ( "GLOBAL_IDS_POINTS", [ 0, 1, 11, -9 ], Piece.POINTS, [ 0, 1, 11 ], [ -9 ] ), - ( "GLOBAL_IDS_CELLS", [ 0, 1, 11, -9 ], Piece.CELLS, [ 0, 1, 11 ], [ -9 ] ), +@pytest.mark.parametrize( "meshName, attributeName, listValues, piece, validValuesTest, invalidValuesTest", [ + ( "multiblock", "GLOBAL_IDS_POINTS", [ 0, 1, 11, -9 ], Piece.POINTS, [ 0, 1, 11 ], [ -9 ] ), + ( "multiblock", "GLOBAL_IDS_CELLS", [ 0, 1, 11, -9 ], Piece.CELLS, [ 0, 1, 11 ], [ -9 ] ), + ( "dataset", "PointAttribute", [ [ 12.4, 9.7, 10.5 ], [ 0, 0, 0 ] ], Piece.POINTS, [ [ 12.4, 9.7, 10.5 ] + ], [ [ 0, 0, 0 ] ] ), + ( "dataset", "CellAttribute", [ [ 24.8, 19.4, 21 ], [ 0, 0, 0 ] ], Piece.CELLS, [ [ 24.8, 19.4, 21 ] + ], [ [ 0, 0, 0 ] ] ), + ( "dataset", "FAULT", [ 0, 100, 101, 2 ], Piece.CELLS, [ 0, 100, 101 ], [ 2 ] ), ] ) -def test_checkValidValuesInMultiBlock( - dataSetTest: vtkMultiBlockDataSet, +def test_checkValidValuesInObject( + dataSetTest: Any, + meshName: str, attributeName: str, listValues: list[ Any ], piece: Piece, validValuesTest: list[ Any ], invalidValuesTest: list[ Any ], ) -> None: - """Test the function checkValidValuesInDataSet.""" - multiBlockDataSet: vtkMultiBlockDataSet = dataSetTest( "multiblock" ) + """Test the function checkValidValuesInObject.""" + mesh: vtkMultiBlockDataSet | vtkDataSet = dataSetTest( meshName ) validValues: list[ Any ] invalidValues: list[ Any ] - validValues, invalidValues = arrayHelpers.checkValidValuesInMultiBlock( multiBlockDataSet, attributeName, - listValues, piece ) + validValues, invalidValues = arrayHelpers.checkValidValuesInObject( mesh, attributeName, listValues, piece ) assert validValues == validValuesTest assert invalidValues == invalidValuesTest -@pytest.mark.parametrize( "attributeName, listValues, piece, validValuesTest, invalidValuesTest", [ - ( "PointAttribute", [ [ 12.4, 9.7, 10.5 ], [ 0, 0, 0 ] ], Piece.POINTS, [ [ 12.4, 9.7, 10.5 ] ], [ [ 0, 0, 0 ] ] ), - ( "CellAttribute", [ [ 24.8, 19.4, 21 ], [ 0, 0, 0 ] ], Piece.CELLS, [ [ 24.8, 19.4, 21 ] ], [ [ 0, 0, 0 ] ] ), - ( "FAULT", [ 0, 100, 101, 2 ], Piece.CELLS, [ 0, 100, 101 ], [ 2 ] ), -] ) -def test_checkValidValuesInDataSet( - dataSetTest: vtkDataSet, - attributeName: str, - listValues: list[ Any ], - piece: Piece, - validValuesTest: list[ Any ], - invalidValuesTest: list[ Any ], -) -> None: - """Test the function checkValidValuesInDataSet.""" - dataSet: vtkDataSet = dataSetTest( "dataset" ) - validValues: list[ Any ] - invalidValues: list[ Any ] - validValues, invalidValues = arrayHelpers.checkValidValuesInDataSet( dataSet, attributeName, listValues, piece ) - assert validValues == validValuesTest - assert invalidValues == invalidValuesTest - +def test_checkValidValuesInObjectRaises( dataSetTest: Any ) -> None: + """Test the fails of checkValidValuesInObject.""" + # AttributeError + mesh: vtkMultiBlockDataSet = dataSetTest( "multiblock" ) + with pytest.raises( AttributeError ): + arrayHelpers.checkValidValuesInObject( mesh, "PORO", [], Piece.CELLS ) -@pytest.mark.parametrize( "piece, expected", [ ( Piece.POINTS, { - 'GLOBAL_IDS_POINTS': 1, - 'PointAttribute': 3, -} ), ( Piece.CELLS, { - 'CELL_MARKERS': 1, - 'PERM': 3, - 'PORO': 1, - 'FAULT': 1, - 'GLOBAL_IDS_CELLS': 1, - 'CellAttribute': 3, -} ) ] ) -def test_getAttributesFromDataSet( dataSetTest: vtkDataSet, piece: Piece, expected: dict[ str, int ] ) -> None: - """Test getting attribute list as dict from dataset.""" - vtkDataSetTest: vtkDataSet = dataSetTest( "dataset" ) - attributes: dict[ str, int ] = arrayHelpers.getAttributesFromDataSet( vtkDataSetTest, piece ) - assert attributes == expected + # TypeError + with pytest.raises( TypeError ): + arrayHelpers.checkValidValuesInObject( vtkCellData(), "AttributeName", [], Piece.CELLS ) @pytest.mark.parametrize( "meshName, attributeName, piece, expected", [ @@ -288,8 +290,7 @@ def test_getAttributesFromDataSet( dataSetTest: vtkDataSet, piece: Piece, expect ( "dataset", "GLOBAL_IDS_CELLS", Piece.CELLS, True ), ( "dataset", "GLOBAL_IDS_POINTS", Piece.POINTS, True ), ( "multiblockGeosOutput", "TIME", Piece.FIELD, True ), - ( "multiblockGeosOutput", "ghostRank", Piece.CELLS, True ), - ( "multiblockGeosOutput", "ghostRank", Piece.POINTS, True ), + ( "multiblockGeosOutput", "ghostRank", Piece.BOTH, True ), ] ) def test_isAttributeInObject( dataSetTest: Any, @@ -310,33 +311,6 @@ def test_isAttributeInObjectTypeError() -> None: arrayHelpers.isAttributeInObject( mesh, "Attribute", Piece.CELLS ) -@pytest.mark.parametrize( "attributeName, piece", [ - ( "rockPorosity_referencePorosity", Piece.CELLS ), - ( "ghostRank", Piece.POINTS ), - ( "TIME", Piece.FIELD ), - ( "ghostRank", Piece.BOTH ), -] ) -def test_isAttributeInObjectMultiBlockDataSet( dataSetTest: vtkMultiBlockDataSet, attributeName: str, - piece: Piece ) -> None: - """Test presence of attribute in a multiblock.""" - multiBlockDataset: vtkMultiBlockDataSet = dataSetTest( "multiblockGeosOutput" ) - obtained: bool = arrayHelpers.isAttributeInObjectMultiBlockDataSet( multiBlockDataset, attributeName, piece ) - assert obtained - - -@pytest.mark.parametrize( "attributeName, piece, expected", [ - ( "PointAttribute", Piece.POINTS, True ), - ( "PORO", Piece.CELLS, True ), - ( "PORO", Piece.POINTS, False ), -] ) -def test_isAttributeInObjectDataSet( dataSetTest: vtkDataSet, attributeName: str, piece: Piece, - expected: bool ) -> None: - """Test presence of attribute in a dataset.""" - vtkDataset: vtkDataSet = dataSetTest( "dataset" ) - obtained: bool = arrayHelpers.isAttributeInObjectDataSet( vtkDataset, attributeName, piece ) - assert obtained == expected - - @pytest.mark.parametrize( "attributeName, piece, expected", [ ( "PORO", Piece.CELLS, False ), ( "GLOBAL_IDS_POINTS", Piece.POINTS, True ), @@ -377,47 +351,30 @@ def test_getArrayInObject( request: pytest.FixtureRequest, arrayExpected: npt.ND ( "dataset", "PointAttribute", Piece.POINTS, 11 ), ( "multiblock", "collocated_nodes", Piece.POINTS, 12 ), ] ) -def test_getVtkDataTypeInObject( +def test_getVtkArrayTypeInObject( dataSetTest: Any, meshName: str, attributeName: str, piece: Piece, expectedVtkType: int, ) -> None: - """Test the function getVtkDataTypeInObject.""" + """Test the function getVtkArrayTypeInObject.""" mesh: vtkDataSet | vtkMultiBlockDataSet = dataSetTest( meshName ) - obtainedVtkType: int = arrayHelpers.getVtkDataTypeInObject( mesh, attributeName, piece ) + obtainedVtkType: int = arrayHelpers.getVtkArrayTypeInObject( mesh, attributeName, piece ) assert obtainedVtkType == expectedVtkType -@pytest.mark.parametrize( "attributeName, vtkDataType, piece", [ - ( "CellAttribute", 11, Piece.CELLS ), - ( "PointAttribute", 11, Piece.POINTS ), - ( "collocated_nodes", 12, Piece.POINTS ), -] ) -def test_getVtkArrayTypeInMultiBlock( dataSetTest: vtkMultiBlockDataSet, attributeName: str, vtkDataType: int, - piece: Piece ) -> None: - """Test getting the type of the vtk array of an attribute from multiBlockDataSet.""" - multiBlockDataSet: vtkMultiBlockDataSet = dataSetTest( "multiblock" ) - - vtkDataTypeTest: int = arrayHelpers.getVtkArrayTypeInMultiBlock( multiBlockDataSet, attributeName, piece ) - - assert ( vtkDataTypeTest == vtkDataType ) - - -@pytest.mark.parametrize( "attributeName, piece", [ - ( "CellAttribute", Piece.CELLS ), - ( "PointAttribute", Piece.POINTS ), -] ) -def test_getVtkArrayTypeInObject( dataSetTest: vtkDataSet, attributeName: str, piece: Piece ) -> None: - """Test getting the type of the vtk array of an attribute from dataset.""" - vtkDataSetTest: vtkDataSet = dataSetTest( "dataset" ) - - obtained: int = arrayHelpers.getVtkArrayTypeInObject( vtkDataSetTest, attributeName, piece ) - expected: int = 11 +def test_getVtkArrayTypeInObjectRaises( dataSetTest: Any ) -> None: + """Test the fails of the function getVtkArrayTypeInObject.""" + # AttributeError + mesh: vtkDataSet = dataSetTest( "dataset" ) + with pytest.raises( AttributeError ): + arrayHelpers.getVtkArrayTypeInObject( mesh, "attributeName", Piece.CELLS ) - assert ( obtained == expected ) + # TypeError + with pytest.raises( TypeError ): + arrayHelpers.getVtkArrayTypeInObject( vtkCellData(), "PORO", Piece.CELLS ) @pytest.mark.parametrize( "arrayExpected, piece", [ @@ -438,44 +395,12 @@ def test_getVtkArrayInObject( request: pytest.FixtureRequest, arrayExpected: npt assert ( obtained_as_np == arrayExpected ).all() -@pytest.mark.parametrize( "attributeName, piece, expected", [ - ( "PORO", Piece.CELLS, 1 ), - ( "PERM", Piece.CELLS, 3 ), - ( "PointAttribute", Piece.POINTS, 3 ), -] ) -def test_getNumberOfComponentsDataSet( - dataSetTest: vtkDataSet, - attributeName: str, - piece: Piece, - expected: int, -) -> None: - """Test getting the number of components of an attribute from a dataset.""" - vtkDataSetTest: vtkDataSet = dataSetTest( "dataset" ) - obtained: int = arrayHelpers.getNumberOfComponentsDataSet( vtkDataSetTest, attributeName, piece ) - assert obtained == expected - - -@pytest.mark.parametrize( "attributeName, piece, expected", [ - ( "PORO", Piece.CELLS, 1 ), - ( "PERM", Piece.CELLS, 3 ), - ( "PointAttribute", Piece.POINTS, 3 ), -] ) -def test_getNumberOfComponentsMultiBlock( - dataSetTest: vtkMultiBlockDataSet, - attributeName: str, - piece: Piece, - expected: int, -) -> None: - """Test getting the number of components of an attribute from a multiblock.""" - vtkMultiBlockDataSetTest: vtkMultiBlockDataSet = dataSetTest( "multiblock" ) - obtained: int = arrayHelpers.getNumberOfComponentsMultiBlock( vtkMultiBlockDataSetTest, attributeName, piece ) - - assert obtained == expected - - @pytest.mark.parametrize( "meshName, attributeName, piece, expected", [ ( "dataset", "PORO", Piece.CELLS, 1 ), ( "dataset", "PERM", Piece.CELLS, 3 ), + ( "dataset", "PointAttribute", Piece.POINTS, 3 ), + ( "multiblock", "PORO", Piece.CELLS, 1 ), + ( "multiblock", "PERM", Piece.CELLS, 3 ), ( "multiblock", "PointAttribute", Piece.POINTS, 3 ), ] ) def test_getNumberOfComponents( @@ -490,42 +415,54 @@ def test_getNumberOfComponents( assert arrayHelpers.getNumberOfComponents( mesh, attributeName, piece ) == expected -def test_getNumberOfComponentsTypeError() -> None: - """Test getNumberOfComponents TypeError raises.""" - mesh: vtkCellData = vtkCellData() +def test_getNumberOfComponentsRaises( dataSetTest: Any, ) -> None: + """Test getNumberOfComponents fails.""" + # TypeError + meshWrongType: vtkCellData = vtkCellData() with pytest.raises( TypeError ): - arrayHelpers.getNumberOfComponents( mesh, "attribute", Piece.CELLS ) + arrayHelpers.getNumberOfComponents( meshWrongType, "PORO", Piece.CELLS ) + # AttributeError + mesh: vtkDataSet = dataSetTest( "multiblockGeosOutput" ) + with pytest.raises( AttributeError ): + arrayHelpers.getNumberOfComponents( mesh, "attributeName", Piece.POINTS ) -@pytest.mark.parametrize( "attributeName, piece, expected", [ - ( "PERM", Piece.CELLS, ( "AX1", "AX2", "AX3" ) ), - ( "PORO", Piece.CELLS, () ), -] ) -def test_getComponentNamesDataSet( dataSetTest: vtkDataSet, attributeName: str, piece: Piece, - expected: tuple[ str, ...] ) -> None: - """Test getting the component names of an attribute from a dataset.""" - vtkDataSetTest: vtkDataSet = dataSetTest( "dataset" ) - obtained: tuple[ str, ...] = arrayHelpers.getComponentNamesDataSet( vtkDataSetTest, attributeName, piece ) - assert obtained == expected + # ValueError + with pytest.raises( ValueError ): + arrayHelpers.getNumberOfComponents( mesh, "ghostRank", Piece.BOTH ) -@pytest.mark.parametrize( "attributeName, piece, expected", [ - ( "PERM", Piece.CELLS, ( "AX1", "AX2", "AX3" ) ), - ( "PORO", Piece.CELLS, () ), +@pytest.mark.parametrize( "meshName, attributeName, piece, expected", [ + ( "dataset", "PERM", Piece.CELLS, ( "AX1", "AX2", "AX3" ) ), + ( "dataset", "PORO", Piece.CELLS, () ), + ( "multiblock", "PERM", Piece.CELLS, ( "AX1", "AX2", "AX3" ) ), + ( "multiblock", "PORO", Piece.CELLS, () ), ] ) -def test_getComponentNamesMultiBlock( - dataSetTest: vtkMultiBlockDataSet, - attributeName: str, - piece: Piece, - expected: tuple[ str, ...], -) -> None: - """Test getting the component names of an attribute from a multiblock.""" - vtkMultiBlockDataSetTest: vtkMultiBlockDataSet = dataSetTest( "multiblock" ) - obtained: tuple[ str, ...] = arrayHelpers.getComponentNamesMultiBlock( vtkMultiBlockDataSetTest, attributeName, - piece ) +def test_getComponentNames( dataSetTest: Any, meshName: str, attributeName: str, piece: Piece, + expected: tuple[ str, ...] ) -> None: + """Test getting the component names of an attribute from a mesh.""" + vtkDataSetTest: Any = dataSetTest( meshName ) + obtained: tuple[ str, ...] = arrayHelpers.getComponentNames( vtkDataSetTest, attributeName, piece ) assert obtained == expected +def test_getComponentNamesRaises( dataSetTest: Any, ) -> None: + """Test getting the component names fails.""" + # TypeError + meshWrongType: vtkFieldData = vtkFieldData() + with pytest.raises( TypeError ): + arrayHelpers.getComponentNames( meshWrongType, "PORO", Piece.CELLS ) + + # AttributeError + mesh: vtkDataSet = dataSetTest( "multiblockGeosOutput" ) + with pytest.raises( AttributeError ): + arrayHelpers.getComponentNames( mesh, "attributeName", Piece.POINTS ) + + # ValueError + with pytest.raises( ValueError ): + arrayHelpers.getComponentNames( mesh, "ghostRank", Piece.BOTH ) + + @pytest.mark.parametrize( "attributeNames, piece, expected_columns", [ ( ( "collocated_nodes", ), Piece.POINTS, ( "collocated_nodes_0", "collocated_nodes_1" ) ), ] ) diff --git a/geos-processing/src/geos/processing/generic_processing_tools/CreateConstantAttributePerRegion.py b/geos-processing/src/geos/processing/generic_processing_tools/CreateConstantAttributePerRegion.py index 572f1f09..3cfed92e 100644 --- a/geos-processing/src/geos/processing/generic_processing_tools/CreateConstantAttributePerRegion.py +++ b/geos-processing/src/geos/processing/generic_processing_tools/CreateConstantAttributePerRegion.py @@ -14,8 +14,7 @@ from geos.utils.pieceEnum import Piece from geos.utils.Logger import ( getLogger, Logger, CountWarningHandler ) from geos.mesh.utils.arrayHelpers import ( getArrayInObject, getComponentNames, getNumberOfComponents, - getVtkDataTypeInObject, isAttributeGlobal, getAttributePieceInfo, - checkValidValuesInDataSet, checkValidValuesInMultiBlock ) + getVtkArrayTypeInObject, getAttributePieceInfo, checkValidValuesInObject ) from geos.mesh.utils.arrayModifiers import ( createAttribute, createConstantAttributeDataSet, createConstantAttributeMultiBlock ) from geos.mesh.utils.multiblockHelpers import getBlockElementIndexesFlatten @@ -185,17 +184,12 @@ def applyFilter( self: Self ) -> None: ) listIndexes: list[ Any ] = list( self.dictRegionValues.keys() ) - validIndexes: list[ Any ] = [] - invalidIndexes: list[ Any ] = [] + validIndexes: list[ Any ] + invalidIndexes: list[ Any ] + validIndexes, invalidIndexes = checkValidValuesInObject( self.mesh, self.regionName, listIndexes, self.piece ) regionArray: npt.NDArray[ Any ] newArray: npt.NDArray[ Any ] if isinstance( self.mesh, vtkMultiBlockDataSet ): - # Check if the attribute region is global. - if not isAttributeGlobal( self.mesh, self.regionName, self.piece ): - raise AttributeError( f"The region attribute { self.regionName } has to be global." ) - - validIndexes, invalidIndexes = checkValidValuesInMultiBlock( self.mesh, self.regionName, listIndexes, - self.piece ) if len( validIndexes ) == 0: if len( self.dictRegionValues ) == 0: self.logger.warning( "No region index entered." ) @@ -230,8 +224,6 @@ def applyFilter( self: Self ) -> None: logger=self.logger ) else: - validIndexes, invalidIndexes = checkValidValuesInDataSet( self.mesh, self.regionName, listIndexes, - self.piece ) if len( validIndexes ) == 0: if len( self.dictRegionValues ) == 0: self.logger.warning( "No region index entered." ) @@ -273,7 +265,7 @@ def _setInfoRegion( self: Self ) -> None: """ # Get the numpy type from the vtk typecode. dictType: dict[ int, Any ] = vnp.get_vtk_to_numpy_typemap() - regionVtkType: int = getVtkDataTypeInObject( self.mesh, self.regionName, self.piece ) + regionVtkType: int = getVtkArrayTypeInObject( self.mesh, self.regionName, self.piece ) regionNpType: type = dictType[ regionVtkType ] # Set the correct type of values and region index. diff --git a/geos-processing/src/geos/processing/pre_processing/MeshQualityEnhanced.py b/geos-processing/src/geos/processing/pre_processing/MeshQualityEnhanced.py index 930c64c4..929c7f18 100644 --- a/geos-processing/src/geos/processing/pre_processing/MeshQualityEnhanced.py +++ b/geos-processing/src/geos/processing/pre_processing/MeshQualityEnhanced.py @@ -19,7 +19,7 @@ from geos.processing.pre_processing.CellTypeCounterEnhanced import CellTypeCounterEnhanced from geos.mesh.model.CellTypeCounts import CellTypeCounts from geos.mesh.model.QualityMetricSummary import ( QualityMetricSummary, StatTypes ) -from geos.mesh.utils.arrayHelpers import getAttributesFromDataSet +from geos.mesh.utils.arrayHelpers import getAttributesWithNumberOfComponents from geos.mesh.stats.meshQualityMetricHelpers import ( getQualityMeasureNameFromIndex, getQualityMetricFromIndex, VtkCellQualityMetricEnum, CellQualityMetricAdditionalEnum, QualityMetricOtherEnum, MeshQualityMetricEnum, @@ -355,7 +355,7 @@ def _evaluateCellQuality( self: Self, metricIndex: int ) -> None: metricIndex (int): Quality metric index """ arrayName: str = getQualityMetricArrayName( metricIndex ) - if arrayName in getAttributesFromDataSet( self._outputMesh, piece=Piece.CELLS ): + if arrayName in getAttributesWithNumberOfComponents( self._outputMesh, piece=Piece.CELLS ): # Metric is already computed (by default computed for all cell types if applicable ) return diff --git a/geos-processing/tests/test_SurfaceGeomechanics.py b/geos-processing/tests/test_SurfaceGeomechanics.py index e42f3110..92f53a80 100644 --- a/geos-processing/tests/test_SurfaceGeomechanics.py +++ b/geos-processing/tests/test_SurfaceGeomechanics.py @@ -80,5 +80,5 @@ def test_failingSurfaceGeomechanics() -> None: """Test failing of SurfaceGeomechanics due to absence of attributes in the mesh.""" failingCase: TriangulatedSurfaceTestCase = TriangulatedSurfaceTestCase( pointsCoords, triangles, None ) sgFilter: SurfaceGeomechanics = SurfaceGeomechanics( failingCase.mesh ) - with pytest.raises( AssertionError ): + with pytest.raises( AttributeError ): sgFilter.applyFilter()