diff --git a/docs/geos-utils.rst b/docs/geos-utils.rst index 13afd0d8c..c42810958 100644 --- a/docs/geos-utils.rst +++ b/docs/geos-utils.rst @@ -63,6 +63,14 @@ PhysicalConstants module :undoc-members: :show-inheritance: +pieceEnum module +------------------------------ + +.. automodule:: geos.utils.pieceEnum + :members: + :undoc-members: + :show-inheritance: + UnitRepository module ------------------------------------- diff --git a/geos-mesh/src/geos/mesh/utils/arrayHelpers.py b/geos-mesh/src/geos/mesh/utils/arrayHelpers.py index 56a93734c..dbd2d2e06 100644 --- a/geos-mesh/src/geos/mesh/utils/arrayHelpers.py +++ b/geos-mesh/src/geos/mesh/utils/arrayHelpers.py @@ -16,6 +16,8 @@ from vtkmodules.vtkFiltersCore import vtkCellCenters from geos.mesh.utils.multiblockHelpers import getBlockElementIndexesFlatten +from geos.utils.pieceEnum import Piece + __doc__ = """ ArrayHelpers module contains several utilities methods to get information on arrays in VTK datasets. @@ -82,7 +84,7 @@ def getCellDimensionDataSet( dataSet: vtkDataSet ) -> set[ int ]: def computeElementMapping( meshFrom: Union[ vtkDataSet, vtkMultiBlockDataSet ], meshTo: Union[ vtkDataSet, vtkMultiBlockDataSet ], - points: bool, + piece: Piece, ) -> dict[ int, npt.NDArray ]: """Compute the map of points/cells between the source mesh and the final mesh. @@ -105,16 +107,16 @@ def computeElementMapping( Args: meshFrom (Union[vtkDataSet, vtkMultiBlockDataSet]): The source mesh with the element to map. meshTo (Union[vtkDataSet, vtkMultiBlockDataSet]): The final mesh with the reference element coordinates. - points (bool): True if elements to map are points, False if they are cells. + piece (Piece): The element to map. Returns: elementMap (dict[int, npt.NDArray[np.int64]]): The map of points/cells between the two meshes. """ elementMap: dict[ int, npt.NDArray ] = {} if isinstance( meshTo, vtkDataSet ): - UpdateElementMappingToDataSet( meshFrom, meshTo, elementMap, points ) + UpdateElementMappingToDataSet( meshFrom, meshTo, elementMap, piece ) elif isinstance( meshTo, vtkMultiBlockDataSet ): - UpdateElementMappingToMultiBlockDataSet( meshFrom, meshTo, elementMap, points ) + UpdateElementMappingToMultiBlockDataSet( meshFrom, meshTo, elementMap, piece ) return elementMap @@ -123,7 +125,7 @@ def UpdateElementMappingToMultiBlockDataSet( meshFrom: Union[ vtkDataSet, vtkMultiBlockDataSet ], multiBlockDataSetTo: vtkMultiBlockDataSet, elementMap: dict[ int, npt.NDArray ], - points: bool, + piece: Piece, ) -> None: """Update the map of points/cells between the source mesh and the final mesh. @@ -146,22 +148,22 @@ def UpdateElementMappingToMultiBlockDataSet( meshFrom (Union[vtkDataSet, vtkMultiBlockDataSet]): The source mesh with the element to map. multiBlockDataSetTo (vtkMultiBlockDataSet): The final mesh with the reference element coordinates. elementMap (dict[int, npt.NDArray[np.int64]]): The map of points/cells to update. - points (bool): True if elements to map are points, False if they are cells. + piece (Piece): The piece to map. """ listFlatIdDataSetTo: list[ int ] = getBlockElementIndexesFlatten( multiBlockDataSetTo ) for flatIdDataSetTo in listFlatIdDataSetTo: dataSetTo: vtkDataSet = vtkDataSet.SafeDownCast( multiBlockDataSetTo.GetDataSet( flatIdDataSetTo ) ) - UpdateElementMappingToDataSet( meshFrom, dataSetTo, elementMap, points, flatIdDataSetTo=flatIdDataSetTo ) + UpdateElementMappingToDataSet( meshFrom, dataSetTo, elementMap, piece, flatIdDataSetTo=flatIdDataSetTo ) def UpdateElementMappingToDataSet( meshFrom: Union[ vtkDataSet, vtkMultiBlockDataSet ], dataSetTo: vtkDataSet, elementMap: dict[ int, npt.NDArray ], - points: bool, + piece: Piece, flatIdDataSetTo: int = 0, ) -> None: - """Update the map of points/cells between the source mesh and the final mesh. + """Update the piece map of points/cells between the source mesh and the final mesh. If the source mesh is a vtkDataSet, its flat index (flatIdDataSetFrom) is set to 0. @@ -182,23 +184,30 @@ def UpdateElementMappingToDataSet( meshFrom (Union[vtkDataSet, vtkMultiBlockDataSet]): The source mesh with the element to map. dataSetTo (vtkDataSet): The final mesh with the reference element coordinates. elementMap (dict[int, npt.NDArray[np.int64]]): The map of points/cells to update. - points (bool): True if elements to map are points, False if they are cells. + piece (Piece): The piece to map. flatIdDataSetTo (int, Optional): The flat index of the final mesh considered as a dataset of a vtkMultiblockDataSet. Defaults to 0 for final meshes who are not datasets of vtkMultiBlockDataSet. """ - nbElementsTo: int = dataSetTo.GetNumberOfPoints() if points else dataSetTo.GetNumberOfCells() + nbElementsTo: int + if piece == Piece.POINTS: + nbElementsTo = dataSetTo.GetNumberOfPoints() + elif piece == Piece.CELLS: + nbElementsTo = dataSetTo.GetNumberOfCells() + else: + raise ValueError( f"Only { Piece.POINTS.value } or { Piece.CELLS.value } can be mapped." ) + elementMap[ flatIdDataSetTo ] = np.full( ( nbElementsTo, 2 ), -1, np.int64 ) if isinstance( meshFrom, vtkDataSet ): UpdateDictElementMappingFromDataSetToDataSet( meshFrom, dataSetTo, elementMap, - points, + piece, flatIdDataSetTo=flatIdDataSetTo ) elif isinstance( meshFrom, vtkMultiBlockDataSet ): UpdateElementMappingFromMultiBlockDataSetToDataSet( meshFrom, dataSetTo, elementMap, - points, + piece, flatIdDataSetTo=flatIdDataSetTo ) @@ -206,7 +215,7 @@ def UpdateElementMappingFromMultiBlockDataSetToDataSet( multiBlockDataSetFrom: vtkMultiBlockDataSet, dataSetTo: vtkDataSet, elementMap: dict[ int, npt.NDArray ], - points: bool, + piece: Piece, flatIdDataSetTo: int = 0, ) -> None: """Update the map of points/cells between the source mesh and the final mesh. @@ -225,7 +234,7 @@ def UpdateElementMappingFromMultiBlockDataSetToDataSet( elementMap (dict[int, npt.NDArray[np.int64]]): The map of points/cells to update with; The key is the flat index of the final mesh. The item is an array of size (nb elements in the final mesh, 2). - points (bool): True if elements to map are points, False if they are cells. + piece (Piece): The piece to map. flatIdDataSetTo (int, Optional): The flat index of the final mesh considered as a dataset of a vtkMultiblockDataSet. Defaults to 0 for final meshes who are not datasets of vtkMultiBlockDataSet. """ @@ -235,7 +244,7 @@ def UpdateElementMappingFromMultiBlockDataSetToDataSet( UpdateDictElementMappingFromDataSetToDataSet( dataSetFrom, dataSetTo, elementMap, - points, + piece, flatIdDataSetFrom=flatIdDataSetFrom, flatIdDataSetTo=flatIdDataSetTo ) @@ -244,7 +253,7 @@ def UpdateDictElementMappingFromDataSetToDataSet( dataSetFrom: vtkDataSet, dataSetTo: vtkDataSet, elementMap: dict[ int, npt.NDArray[ np.int64 ] ], - points: bool, + piece: Piece, flatIdDataSetFrom: int = 0, flatIdDataSetTo: int = 0, ) -> None: @@ -264,7 +273,7 @@ def UpdateDictElementMappingFromDataSetToDataSet( elementMap (dict[int, npt.NDArray[np.int64]]): The map of points/cells to update with; The key is the flat index of the final mesh. The item is an array of size (nb elements in the final mesh, 2). - points (bool): True if elements to map are points, False if they are cells. + piece (Piece): The piece to map. flatIdDataSetFrom (int, Optional): The flat index of the source mesh considered as a dataset of a vtkMultiblockDataSet. Defaults to 0 for source meshes who are not datasets of vtkMultiBlockDataSet. flatIdDataSetTo (int, Optional): The flat index of the final mesh considered as a dataset of a vtkMultiblockDataSet. @@ -272,16 +281,23 @@ def UpdateDictElementMappingFromDataSetToDataSet( """ idElementsFromFund: list[ int ] = [] nbElementsTo: int = len( elementMap[ flatIdDataSetTo ] ) - nbElementsFrom: int = dataSetFrom.GetNumberOfPoints() if points else dataSetFrom.GetNumberOfCells() + nbElementsFrom: int + if piece == Piece.POINTS: + nbElementsFrom = dataSetFrom.GetNumberOfPoints() + elif piece == Piece.CELLS: + nbElementsFrom = dataSetFrom.GetNumberOfCells() + else: + raise ValueError( f"Only { Piece.POINTS.value } or { Piece.CELLS.value } can be mapped." ) + for idElementTo in range( nbElementsTo ): # Test if the element of the final mesh is already mapped. if -1 in elementMap[ flatIdDataSetTo ][ idElementTo ]: typeElemTo: int coordElementTo: set[ tuple[ float, ...] ] = set() - if points: + if piece == Piece.POINTS: typeElemTo = 0 coordElementTo.add( dataSetTo.GetPoint( idElementTo ) ) - else: + elif piece == Piece.CELLS: cellTo: vtkCell = dataSetTo.GetCell( idElementTo ) typeElemTo = cellTo.GetCellType() # Get the coordinates of each points of the cell. @@ -297,10 +313,10 @@ def UpdateDictElementMappingFromDataSetToDataSet( if idElementFrom not in idElementsFromFund: typeElemFrom: int coordElementFrom: set[ tuple[ float, ...] ] = set() - if points: + if piece == Piece.POINTS: typeElemFrom = 0 coordElementFrom.add( dataSetFrom.GetPoint( idElementFrom ) ) - else: + elif piece == Piece.CELLS: cellFrom: vtkCell = dataSetFrom.GetCell( idElementFrom ) typeElemFrom = cellFrom.GetCellType() # Get the coordinates of each points of the face. @@ -355,37 +371,33 @@ def hasArray( mesh: vtkUnstructuredGrid, arrayNames: list[ str ] ) -> bool: def getAttributePieceInfo( mesh: Union[ vtkDataSet, vtkMultiBlockDataSet ], attributeName: str, -) -> tuple[ Union[ None, bool ], bool ]: - """Get the attribute piece information. - - Two information are given: - - onPoints (Union[None, bool]): True if the attribute is on points or on both pieces, False if it is on cells, None otherwise. - - onBoth (bool): True if the attribute is on points and on cells, False otherwise. +) -> Piece: + """Get the attribute piece. Args: mesh (Union[vtkDataSet, vtkMultiBlockDataSet]): The mesh with the attribute. attributeName (str): The name of the attribute. Returns: - tuple[Union[None, bool], bool]: The piece information of the attribute. + Piece: The piece of the attribute. """ - onPoints: Union[ bool, None ] = None - onBoth: bool = False - if isAttributeInObject( mesh, attributeName, False ): - onPoints = False - if isAttributeInObject( mesh, attributeName, True ): - if onPoints is False: - onBoth = True - onPoints = True - - return ( onPoints, onBoth ) + if isAttributeInObject( mesh, attributeName, Piece.FIELD ): + return Piece.FIELD + elif isAttributeInObject( mesh, attributeName, Piece.BOTH ): + return Piece.BOTH + elif isAttributeInObject( mesh, attributeName, Piece.POINTS ): + return Piece.POINTS + elif isAttributeInObject( mesh, attributeName, Piece.CELLS ): + return Piece.CELLS + else: + return Piece.NONE def checkValidValuesInMultiBlock( multiBlockDataSet: vtkMultiBlockDataSet, attributeName: str, listValues: list[ Any ], - onPoints: bool, + 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. @@ -393,7 +405,7 @@ def checkValidValuesInMultiBlock( multiBlockDataSet (vtkMultiBlockDataSet): The multiblock dataset mesh to check. attributeName (str): The name of the attribute with the data. listValues (list[Any]): The list of values to check. - onPoints (bool): True if the attribute is on points, False if on cells. + 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. @@ -404,7 +416,7 @@ def checkValidValuesInMultiBlock( 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, onPoints )[ 0 ] + validValuesDataSet: list[ Any ] = checkValidValuesInDataSet( dataSet, attributeName, listValues, piece )[ 0 ] # Keep the new true values. for value in validValuesDataSet: @@ -423,7 +435,7 @@ def checkValidValuesInDataSet( dataSet: vtkDataSet, attributeName: str, listValues: list[ Any ], - onPoints: bool, + 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. @@ -431,12 +443,12 @@ def checkValidValuesInDataSet( 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. - onPoints (bool): True if the attribute is on points, False if on cells. + 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. """ - attributeNpArray = getArrayInObject( dataSet, attributeName, onPoints ) + attributeNpArray = getArrayInObject( dataSet, attributeName, piece ) validValues: list[ Any ] = [] invalidValues: list[ Any ] = [] for value in listValues: @@ -559,21 +571,21 @@ def getNumpyArrayByName( data: Union[ vtkCellData, vtkPointData ], return None -def getAttributeSet( mesh: Union[ vtkMultiBlockDataSet, vtkDataSet ], onPoints: bool ) -> set[ str ]: +def getAttributeSet( mesh: Union[ vtkMultiBlockDataSet, vtkDataSet ], piece: Piece ) -> set[ str ]: """Get the set of all attributes from an mesh on points or on cells. Args: mesh (Any): Mesh where to find the attributes. - onPoints (bool): True if attributes are on points, False if they are on cells. + piece (Piece): The piece of the attribute. Returns: set[str]: Set of attribute names present in input mesh. """ attributes: dict[ str, int ] if isinstance( mesh, vtkMultiBlockDataSet ): - attributes = getAttributesFromMultiBlockDataSet( mesh, onPoints ) + attributes = getAttributesFromMultiBlockDataSet( mesh, piece ) elif isinstance( mesh, vtkDataSet ): - attributes = getAttributesFromDataSet( mesh, onPoints ) + attributes = getAttributesFromDataSet( mesh, piece ) else: raise TypeError( "Input mesh must be a vtkDataSet or vtkMultiBlockDataSet." ) @@ -584,34 +596,34 @@ def getAttributeSet( mesh: Union[ vtkMultiBlockDataSet, vtkDataSet ], onPoints: def getAttributesWithNumberOfComponents( mesh: Union[ vtkMultiBlockDataSet, vtkCompositeDataSet, vtkDataSet, vtkDataObject ], - onPoints: bool, + piece: Piece, ) -> dict[ str, int ]: """Get the dictionary of all attributes from object on points or cells. Args: mesh (Any): Mesh where to find the attributes. - onPoints (bool): True if attributes are on points, False if they are on cells. + piece (Piece): The piece of the attribute. 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, onPoints ) + attributes = getAttributesFromMultiBlockDataSet( mesh, piece ) elif isinstance( mesh, vtkDataSet ): - attributes = getAttributesFromDataSet( mesh, onPoints ) + attributes = getAttributesFromDataSet( mesh, piece ) else: raise TypeError( "Input mesh must be a vtkDataSet or vtkMultiBlockDataSet." ) return attributes def getAttributesFromMultiBlockDataSet( multiBlockDataSet: Union[ vtkMultiBlockDataSet, vtkCompositeDataSet ], - onPoints: bool ) -> dict[ str, int ]: + 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. - onPoints (bool): True if attributes are on points, False if they are on cells. + 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. @@ -620,7 +632,7 @@ def getAttributesFromMultiBlockDataSet( multiBlockDataSet: Union[ vtkMultiBlockD elementaryBlockIndexes: list[ int ] = getBlockElementIndexesFlatten( multiBlockDataSet ) for blockIndex in elementaryBlockIndexes: dataSet: vtkDataSet = vtkDataSet.SafeDownCast( multiBlockDataSet.GetDataSet( blockIndex ) ) - blockAttributes: dict[ str, int ] = getAttributesFromDataSet( dataSet, onPoints ) + blockAttributes: dict[ str, int ] = getAttributesFromDataSet( dataSet, piece ) for attributeName, nbComponents in blockAttributes.items(): if attributeName not in attributes: attributes[ attributeName ] = nbComponents @@ -628,64 +640,64 @@ def getAttributesFromMultiBlockDataSet( multiBlockDataSet: Union[ vtkMultiBlockD return attributes -def getAttributesFromDataSet( dataSet: vtkDataSet, onPoints: bool ) -> dict[ str, int ]: +def getAttributesFromDataSet( dataSet: vtkDataSet, piece: Piece ) -> dict[ str, int ]: """Get the dictionary of all attributes of a vtkDataSet on points or cells. Args: dataSet (vtkDataSet): DataSet where to find the attributes. - onPoints (bool): True if attributes are on points, False if they are on cells. + piece (Piece): The piece of the attribute. Returns: dict[str, int]: List of the names of the attributes. """ attributes: dict[ str, int ] = {} data: Union[ vtkPointData, vtkCellData ] - sup: str = "" - if onPoints: + if piece == Piece.POINTS: data = dataSet.GetPointData() - sup = "Point" - else: + elif piece == Piece.CELLS: data = dataSet.GetCellData() - sup = "Cell" - assert data is not None, f"{sup} data was not recovered." + 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." 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" + 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, onPoints: bool ) -> bool: +def isAttributeInObject( mesh: Union[ vtkMultiBlockDataSet, vtkDataSet ], attributeName: str, piece: Piece ) -> bool: """Check if an attribute is in the input object. Args: mesh (vtkMultiBlockDataSet | vtkDataSet): Input mesh. attributeName (str): Name of the attribute. - onPoints (bool): True if attributes are on points, False if they are on cells. + 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, onPoints ) + return isAttributeInObjectMultiBlockDataSet( mesh, attributeName, piece ) elif isinstance( mesh, vtkDataSet ): - return isAttributeInObjectDataSet( mesh, attributeName, onPoints ) + return isAttributeInObjectDataSet( mesh, attributeName, piece ) else: raise TypeError( "Input object must be a vtkDataSet or vtkMultiBlockDataSet." ) def isAttributeInObjectMultiBlockDataSet( multiBlockDataSet: vtkMultiBlockDataSet, attributeName: str, - onPoints: bool ) -> bool: + piece: Piece ) -> bool: """Check if an attribute is in the input object. Args: multiBlockDataSet (vtkMultiBlockDataSet): Input multiBlockDataSet. attributeName (str): Name of the attribute. - onPoints (bool): True if attributes are on points, False if they are on cells. + piece (Piece): The piece of the attribute. Returns: bool: True if the attribute is in the table, False otherwise. @@ -693,42 +705,44 @@ def isAttributeInObjectMultiBlockDataSet( multiBlockDataSet: vtkMultiBlockDataSe elementaryBlockIndexes: list[ int ] = getBlockElementIndexesFlatten( multiBlockDataSet ) for blockIndex in elementaryBlockIndexes: dataSet: vtkDataSet = vtkDataSet.SafeDownCast( multiBlockDataSet.GetDataSet( blockIndex ) ) - if isAttributeInObjectDataSet( dataSet, attributeName, onPoints ): + if isAttributeInObjectDataSet( dataSet, attributeName, piece ): return True return False -def isAttributeInObjectDataSet( dataSet: vtkDataSet, attributeName: str, onPoints: bool ) -> bool: - """Check if an attribute is in the input object. +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. - onPoints (bool): True if attributes are on points, False if they are on cells. + piece (Piece): The piece of the attribute. Returns: bool: True if the attribute is in the table, False otherwise. """ - data: Union[ vtkPointData, vtkCellData ] - sup: str = "" - if onPoints: - data = dataSet.GetPointData() - sup = "Point" + 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: - data = dataSet.GetCellData() - sup = "Cell" - assert data is not None, f"{ sup } data was not recovered." - return bool( data.HasArray( attributeName ) ) + return False -def isAttributeGlobal( multiBlockDataSet: vtkMultiBlockDataSet, attributeName: str, onPoints: bool ) -> bool: +def isAttributeGlobal( multiBlockDataSet: vtkMultiBlockDataSet, attributeName: str, piece: Piece ) -> bool: """Check if an attribute is global in the input multiBlockDataSet. Args: multiBlockDataSet (vtkMultiBlockDataSet): Input multiBlockDataSet. attributeName (str): Name of the attribute. - onPoints (bool): True if attributes are on points, False if they are on cells. + piece (Piece): The piece of the attribute. Returns: bool: True if the attribute is global, False if not. @@ -736,69 +750,69 @@ 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, onPoints ): + if not isAttributeInObjectDataSet( dataSet, attributeName, piece ): return False return True -def getArrayInObject( dataSet: vtkDataSet, attributeName: str, onPoints: bool ) -> npt.NDArray[ Any ]: +def getArrayInObject( dataSet: vtkDataSet, attributeName: str, piece: Piece ) -> npt.NDArray[ Any ]: """Return the numpy array corresponding to input attribute name in table. Args: dataSet (vtkDataSet): Input dataSet. attributeName (str): Name of the attribute. - onPoints (bool): True if attributes are on points, False if they are on cells. + piece (Piece): The piece of the attribute. Returns: ArrayLike[Any]: The numpy array corresponding to input attribute name. """ - vtkArray: vtkDataArray = getVtkArrayInObject( dataSet, attributeName, onPoints ) + vtkArray: vtkDataArray = getVtkArrayInObject( dataSet, attributeName, piece ) npArray: npt.NDArray[ Any ] = vnp.vtk_to_numpy( vtkArray ) # type: ignore[no-untyped-call] return npArray def getVtkDataTypeInObject( multiBlockDataSet: Union[ vtkDataSet, vtkMultiBlockDataSet ], attributeName: str, - onPoints: bool ) -> int: + piece: Piece ) -> int: """Return VTK type of requested array from input mesh. Args: multiBlockDataSet (Union[vtkDataSet, vtkMultiBlockDataSet]): Input multiBlockDataSet. attributeName (str): Name of the attribute. - onPoints (bool): True if attributes are on points, False if they are on cells. + piece (Piece): The piece of the attribute. Returns: int: The type of the vtk array corresponding to input attribute name. """ if isinstance( multiBlockDataSet, vtkDataSet ): - return getVtkArrayTypeInObject( multiBlockDataSet, attributeName, onPoints ) + return getVtkArrayTypeInObject( multiBlockDataSet, attributeName, piece ) else: - return getVtkArrayTypeInMultiBlock( multiBlockDataSet, attributeName, onPoints ) + return getVtkArrayTypeInMultiBlock( multiBlockDataSet, attributeName, piece ) -def getVtkArrayTypeInObject( dataSet: vtkDataSet, attributeName: str, onPoints: bool ) -> int: +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. - onPoints (bool): True if attributes are on points, False if they are on cells. + 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, onPoints ) + array: vtkDataArray = getVtkArrayInObject( dataSet, attributeName, piece ) vtkArrayType: int = array.GetDataType() return vtkArrayType -def getVtkArrayTypeInMultiBlock( multiBlockDataSet: vtkMultiBlockDataSet, attributeName: str, onPoints: bool ) -> int: +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. - onPoints (bool): True if attributes are on points, False if they are on cells. + piece (Piece): The piece of the attribute. Returns: int: Type of the requested vtk array if existing in input multiblock dataset. @@ -806,78 +820,88 @@ def getVtkArrayTypeInMultiBlock( multiBlockDataSet: vtkMultiBlockDataSet, attrib elementaryBlockIndexes: list[ int ] = getBlockElementIndexesFlatten( multiBlockDataSet ) for blockIndex in elementaryBlockIndexes: dataSet: vtkDataSet = vtkDataSet.SafeDownCast( multiBlockDataSet.GetDataSet( blockIndex ) ) - listAttributes: set[ str ] = getAttributeSet( dataSet, onPoints ) + listAttributes: set[ str ] = getAttributeSet( dataSet, piece ) if attributeName in listAttributes: - return getVtkArrayTypeInObject( dataSet, attributeName, onPoints ) + return getVtkArrayTypeInObject( dataSet, attributeName, piece ) raise AssertionError( "The vtkMultiBlockDataSet has no attribute with the name " + attributeName + "." ) -def getVtkArrayInObject( dataSet: vtkDataSet, attributeName: str, onPoints: bool ) -> vtkDataArray: +def getVtkArrayInObject( dataSet: vtkDataSet, attributeName: str, piece: Piece ) -> vtkDataArray: """Return the array corresponding to input attribute name in table. Args: dataSet (vtkDataSet): Input dataSet. attributeName (str): Name of the attribute. - onPoints (bool): True if attributes are on points, False if they are on cells. + piece (Piece): The piece of the attribute. Returns: vtkDataArray: The vtk array corresponding to input attribute name. """ - assert isAttributeInObject( dataSet, attributeName, onPoints ), f"{attributeName} is not in input mesh." - return dataSet.GetPointData().GetArray( attributeName ) if onPoints else dataSet.GetCellData().GetArray( - attributeName ) + assert isAttributeInObject( dataSet, attributeName, piece ), f"{attributeName} is not in input mesh." + dataArray: vtkDataArray + if piece == Piece.POINTS: + dataArray = dataSet.GetPointData().GetArray( attributeName ) + elif piece == Piece.CELLS: + dataArray = dataSet.GetCellData().GetArray( attributeName ) + elif piece == Piece.FIELD: + dataArray = dataSet.GetFieldData().GetArray( attributeName ) + else: + raise ValueError( + f"The attribute piece must be { Piece.FIELD.value }, { Piece.POINTS.value } or { Piece.CELLS.value }." ) + + return dataArray def getNumberOfComponents( mesh: Union[ vtkMultiBlockDataSet, vtkCompositeDataSet, vtkDataSet ], attributeName: str, - onPoints: bool, + piece: Piece, ) -> int: """Get the number of components of attribute attributeName in dataSet. Args: mesh (vtkMultiBlockDataSet | vtkCompositeDataSet | vtkDataSet): Mesh where the attribute is. attributeName (str): Name of the attribute. - onPoints (bool): True if attributes are on points, False if they are on cells. + piece (Piece): The piece of the attribute. Returns: int: Number of components. """ if isinstance( mesh, vtkDataSet ): - return getNumberOfComponentsDataSet( mesh, attributeName, onPoints ) + return getNumberOfComponentsDataSet( mesh, attributeName, piece ) elif isinstance( mesh, ( vtkMultiBlockDataSet, vtkCompositeDataSet ) ): - return getNumberOfComponentsMultiBlock( mesh, attributeName, onPoints ) + return getNumberOfComponentsMultiBlock( mesh, attributeName, piece ) else: raise AssertionError( "Object type is not managed." ) -def getNumberOfComponentsDataSet( dataSet: vtkDataSet, attributeName: str, onPoints: bool ) -> int: +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. - onPoints (bool): True if attributes are on points, False if they are on cells. + piece (Piece): The piece of the attribute. Returns: int: Number of components. """ - array: vtkDataArray = getVtkArrayInObject( dataSet, attributeName, onPoints ) + array: vtkDataArray = getVtkArrayInObject( dataSet, attributeName, piece ) return array.GetNumberOfComponents() def getNumberOfComponentsMultiBlock( multiBlockDataSet: Union[ vtkMultiBlockDataSet, vtkCompositeDataSet ], attributeName: str, - onPoints: bool, + 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. - onPoints (bool): True if attributes are on points, False if they are on cells. + piece (Piece): The piece of the attribute. Returns: int: Number of components. @@ -885,8 +909,8 @@ def getNumberOfComponentsMultiBlock( elementaryBlockIndexes: list[ int ] = getBlockElementIndexesFlatten( multiBlockDataSet ) for blockIndex in elementaryBlockIndexes: dataSet: vtkDataSet = vtkDataSet.SafeDownCast( multiBlockDataSet.GetDataSet( blockIndex ) ) - if isAttributeInObject( dataSet, attributeName, onPoints ): - array: vtkDataArray = getVtkArrayInObject( dataSet, attributeName, onPoints ) + if isAttributeInObject( dataSet, attributeName, piece ): + array: vtkDataArray = getVtkArrayInObject( dataSet, attributeName, piece ) return array.GetNumberOfComponents() return 0 @@ -894,38 +918,38 @@ def getNumberOfComponentsMultiBlock( def getComponentNames( mesh: Union[ vtkMultiBlockDataSet, vtkCompositeDataSet, vtkDataSet, vtkDataObject ], attributeName: str, - onPoints: bool, + piece: Piece, ) -> tuple[ str, ...]: """Get the name of the components of attribute attributeName in dataSet. Args: mesh (vtkDataSet | vtkMultiBlockDataSet | vtkCompositeDataSet | vtkDataObject): Mesh where the attribute is. attributeName (str): Name of the attribute. - onPoints (bool): True if attributes are on points, False if they are on cells. + piece (Piece): The piece of the attribute. Returns: tuple[str,...]: Names of the components. """ if isinstance( mesh, vtkDataSet ): - return getComponentNamesDataSet( mesh, attributeName, onPoints ) + return getComponentNamesDataSet( mesh, attributeName, piece ) elif isinstance( mesh, ( vtkMultiBlockDataSet, vtkCompositeDataSet ) ): - return getComponentNamesMultiBlock( mesh, attributeName, onPoints ) + return getComponentNamesMultiBlock( mesh, attributeName, piece ) else: raise AssertionError( "Mesh type is not managed." ) -def getComponentNamesDataSet( dataSet: vtkDataSet, attributeName: str, onPoints: bool ) -> tuple[ str, ...]: +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. - onPoints (bool): True if attributes are on points, False if they are on cells. + piece (Piece): The piece of the attribute. Returns: tuple[str,...]: Names of the components. """ - array: vtkDataArray = getVtkArrayInObject( dataSet, attributeName, onPoints ) + array: vtkDataArray = getVtkArrayInObject( dataSet, attributeName, piece ) componentNames: list[ str ] = [] if array.GetNumberOfComponents() > 1: @@ -936,14 +960,14 @@ def getComponentNamesDataSet( dataSet: vtkDataSet, attributeName: str, onPoints: def getComponentNamesMultiBlock( multiBlockDataSet: Union[ vtkMultiBlockDataSet, vtkCompositeDataSet ], attributeName: str, - onPoints: bool, + 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. - onPoints (bool): True if attributes are on points, False if they are on cells. + piece (Piece): The piece of the attribute. Returns: tuple[str,...]: Names of the components. @@ -951,33 +975,40 @@ def getComponentNamesMultiBlock( elementaryBlockIndexes: list[ int ] = getBlockElementIndexesFlatten( multiBlockDataSet ) for blockIndex in elementaryBlockIndexes: dataSet: vtkDataSet = vtkDataSet.SafeDownCast( multiBlockDataSet.GetDataSet( blockIndex ) ) - if isAttributeInObject( dataSet, attributeName, onPoints ): - return getComponentNamesDataSet( dataSet, attributeName, onPoints ) + if isAttributeInObject( dataSet, attributeName, piece ): + return getComponentNamesDataSet( dataSet, attributeName, piece ) return () def getAttributeValuesAsDF( surface: vtkPolyData, attributeNames: tuple[ str, ...], - onPoints: bool = False ) -> pd.DataFrame: + piece: Piece = Piece.CELLS ) -> pd.DataFrame: """Get attribute values from input surface. Args: surface (vtkPolyData): Mesh where to get attribute values. attributeNames (tuple[str,...]): Tuple of attribute names to get the values. - onPoints (bool, optional): True if attributes are on points, False if they are on cells. - Defaults to False. + piece (Piece): The piece of the attribute. + Defaults to Piece.CELLS Returns: pd.DataFrame: DataFrame containing property names as columns. """ - nbRows: int = surface.GetNumberOfPoints() if onPoints else surface.GetNumberOfCells() + nbRows: int + if piece == Piece.POINTS: + nbRows = surface.GetNumberOfPoints() + elif piece == Piece.CELLS: + nbRows = surface.GetNumberOfCells() + else: + raise ValueError( f"The attribute piece must be { Piece.POINTS.value } or { Piece.CELLS.value }." ) + data: pd.DataFrame = pd.DataFrame( np.full( ( nbRows, len( attributeNames ) ), np.nan ), columns=attributeNames ) for attributeName in attributeNames: - if not isAttributeInObject( surface, attributeName, onPoints ): + if not isAttributeInObject( surface, attributeName, piece ): logging.warning( f"Attribute {attributeName} is not in the mesh." ) continue - array: npt.NDArray[ np.float64 ] = getArrayInObject( surface, attributeName, onPoints ) + array: npt.NDArray[ np.float64 ] = getArrayInObject( surface, attributeName, piece ) if len( array.shape ) > 1: for i in range( array.shape[ 1 ] ): diff --git a/geos-mesh/src/geos/mesh/utils/arrayModifiers.py b/geos-mesh/src/geos/mesh/utils/arrayModifiers.py index 0874c3540..33fc93707 100644 --- a/geos-mesh/src/geos/mesh/utils/arrayModifiers.py +++ b/geos-mesh/src/geos/mesh/utils/arrayModifiers.py @@ -45,6 +45,8 @@ ) from geos.mesh.utils.multiblockHelpers import getBlockElementIndexesFlatten +from geos.utils.pieceEnum import Piece + __doc__ = """ ArrayModifiers contains utilities to process VTK Arrays objects. @@ -60,7 +62,7 @@ def fillPartialAttributes( multiBlockDataSet: Union[ vtkMultiBlockDataSet, vtkCompositeDataSet, vtkDataObject ], attributeName: str, - onPoints: bool = False, + piece: Piece = Piece.CELLS, listValues: Union[ list[ Any ], None ] = None, logger: Union[ Logger, None ] = None, fillAll: bool = False, @@ -70,8 +72,8 @@ def fillPartialAttributes( Args: multiBlockDataSet (vtkMultiBlockDataSet | vtkCompositeDataSet | vtkDataObject): MultiBlockDataSet where to fill the attribute. attributeName (str): Attribute name. - onPoints (bool, optional): True if attributes are on points, False if they are on cells. - Defaults to False. + piece (Piece): The piece of the attribute. + Defaults to Piece.CELLS listValues (list[Any], optional): List of filling value for each component. Defaults to None, the filling value is for all components: -1 for int VTK arrays. @@ -95,16 +97,16 @@ def fillPartialAttributes( return False # Check if the attribute is partial. - if isAttributeGlobal( multiBlockDataSet, attributeName, onPoints ): + if isAttributeGlobal( multiBlockDataSet, attributeName, piece ): logger.error( f"The attribute { attributeName } is already global." ) return False # Get information of the attribute to fill. - vtkDataType: int = getVtkArrayTypeInMultiBlock( multiBlockDataSet, attributeName, onPoints ) - nbComponents: int = getNumberOfComponentsMultiBlock( multiBlockDataSet, attributeName, onPoints ) + vtkDataType: int = getVtkArrayTypeInMultiBlock( multiBlockDataSet, attributeName, piece ) + nbComponents: int = getNumberOfComponentsMultiBlock( multiBlockDataSet, attributeName, piece ) componentNames: tuple[ str, ...] = () if nbComponents > 1: - componentNames = getComponentNames( multiBlockDataSet, attributeName, onPoints ) + componentNames = getComponentNames( multiBlockDataSet, attributeName, piece ) typeMapping: dict[ int, type ] = vnp.get_vtk_to_numpy_typemap() valueType: type = typeMapping[ vtkDataType ] @@ -150,8 +152,8 @@ def fillPartialAttributes( elementaryBlockIndexes: list[ int ] = getBlockElementIndexesFlatten( multiBlockDataSet ) for blockIndex in elementaryBlockIndexes: dataSet: vtkDataSet = vtkDataSet.SafeDownCast( multiBlockDataSet.GetDataSet( blockIndex ) ) - if not isAttributeInObjectDataSet( dataSet, attributeName, onPoints ) and \ - not createConstantAttributeDataSet( dataSet, listValues, attributeName, componentNames, onPoints, vtkDataType, logger ): + if not isAttributeInObjectDataSet( dataSet, attributeName, piece ) and \ + not createConstantAttributeDataSet( dataSet, listValues, attributeName, componentNames, piece, vtkDataType, logger ): return False return True @@ -185,11 +187,11 @@ def fillAllPartialAttributes( ) # Parse all partial attributes, onPoints and onCells to fill them. - for onPoints in [ True, False ]: - infoAttributes: dict[ str, int ] = getAttributesWithNumberOfComponents( multiBlockDataSet, onPoints ) + for piece in [ Piece.POINTS, Piece.CELLS ]: + infoAttributes: dict[ str, int ] = getAttributesWithNumberOfComponents( multiBlockDataSet, piece ) for attributeName in infoAttributes: - if not isAttributeGlobal( multiBlockDataSet, attributeName, onPoints ) and \ - not fillPartialAttributes( multiBlockDataSet, attributeName, onPoints=onPoints, logger=logger, fillAll=True ): + if not isAttributeGlobal( multiBlockDataSet, attributeName, piece ) and \ + not fillPartialAttributes( multiBlockDataSet, attributeName, piece=piece, logger=logger, fillAll=True ): return False return True @@ -231,7 +233,7 @@ def createConstantAttribute( listValues: list[ Any ], attributeName: str, componentNames: tuple[ str, ...] = (), # noqa: C408 - onPoints: bool = False, + piece: Piece = Piece.CELLS, vtkDataType: Union[ int, None ] = None, logger: Union[ Logger, None ] = None, ) -> bool: @@ -243,8 +245,8 @@ def createConstantAttribute( attributeName (str): Name of the attribute. componentNames (tuple[str,...], optional): Name of the components for vectorial attributes. If one component, gives an empty tuple. Defaults to an empty tuple. - onPoints (bool, optional): True if attributes are on points, False if they are on cells. - Defaults to False. + piece (Piece): The piece of the attribute. + Defaults to Piece.CELLS vtkDataType (Union[int, None], optional): Vtk data type of the attribute to create. Defaults to None, the vtk data type is given by the type of the values. @@ -264,12 +266,12 @@ def createConstantAttribute( # Deals with multiBlocksDataSets. if isinstance( mesh, ( vtkMultiBlockDataSet, vtkCompositeDataSet ) ): - return createConstantAttributeMultiBlock( mesh, listValues, attributeName, componentNames, onPoints, - vtkDataType, logger ) + return createConstantAttributeMultiBlock( mesh, listValues, attributeName, componentNames, piece, vtkDataType, + logger ) # Deals with dataSets. elif isinstance( mesh, vtkDataSet ): - return createConstantAttributeDataSet( mesh, listValues, attributeName, componentNames, onPoints, vtkDataType, + return createConstantAttributeDataSet( mesh, listValues, attributeName, componentNames, piece, vtkDataType, logger ) @@ -278,7 +280,7 @@ def createConstantAttributeMultiBlock( listValues: list[ Any ], attributeName: str, componentNames: tuple[ str, ...] = (), # noqa: C408 - onPoints: bool = False, + piece: Piece = Piece.CELLS, vtkDataType: Union[ int, None ] = None, logger: Union[ Logger, None ] = None, ) -> bool: @@ -290,8 +292,8 @@ def createConstantAttributeMultiBlock( attributeName (str): Name of the attribute. componentNames (tuple[str,...], optional): Name of the components for vectorial attributes. If one component, gives an empty tuple. Defaults to an empty tuple. - onPoints (bool, optional): True if attributes are on points, False if they are on cells. - Defaults to False. + piece (Piece): The piece of the attribute. + Defaults to Piece.CELLS vtkDataType (Union[int, None], optional): Vtk data type of the attribute to create. Defaults to None, the vtk data type is given by the type of the values. @@ -315,28 +317,22 @@ def createConstantAttributeMultiBlock( logger.error( f"The constant attribute { attributeName } has not been created into the mesh." ) return False + # Check the piece. + if piece != Piece.POINTS and piece != Piece.CELLS: + 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, onPoints ): + if isAttributeInObjectMultiBlockDataSet( multiBlockDataSet, attributeName, piece ): logger.error( f"The attribute { attributeName } is already present in the multiBlockDataSet." ) logger.error( f"The constant attribute { attributeName } has not been created into the mesh." ) return False - # Check if an attribute with the same name exist on the opposite piece (points or cells) on the input mesh. - oppositePiece: bool = not onPoints - oppositePieceName: str = "points" if oppositePiece else "cells" - if isAttributeInObjectMultiBlockDataSet( multiBlockDataSet, attributeName, oppositePiece ): - oppositePieceState: str = "global" if isAttributeGlobal( multiBlockDataSet, attributeName, - oppositePiece ) else "partial" - logger.warning( - f"A { oppositePieceState } attribute with the same name ({ attributeName }) is already present in the multiBlockDataSet but on { oppositePieceName }." - ) - # Parse the multiBlockDataSet to create the constant attribute on each blocks. elementaryBlockIndexes: list[ int ] = getBlockElementIndexesFlatten( multiBlockDataSet ) for blockIndex in elementaryBlockIndexes: dataSet: vtkDataSet = vtkDataSet.SafeDownCast( multiBlockDataSet.GetDataSet( blockIndex ) ) - if not createConstantAttributeDataSet( dataSet, listValues, attributeName, componentNames, onPoints, - vtkDataType, logger ): + if not createConstantAttributeDataSet( dataSet, listValues, attributeName, componentNames, piece, vtkDataType, + logger ): return False return True @@ -347,7 +343,7 @@ def createConstantAttributeDataSet( listValues: list[ Any ], attributeName: str, componentNames: tuple[ str, ...] = (), # noqa: C408 - onPoints: bool = False, + piece: Piece = Piece.CELLS, vtkDataType: Union[ int, None ] = None, logger: Union[ Logger, None ] = None, ) -> bool: @@ -359,8 +355,8 @@ def createConstantAttributeDataSet( attributeName (str): Name of the attribute. componentNames (tuple[str,...], optional): Name of the components for vectorial attributes. If one component, gives an empty tuple. Defaults to an empty tuple. - onPoints (bool, optional): True if attributes are on points, False if they are on cells. - Defaults to False. + piece (Piece): The piece of the attribute. + Defaults to Piece.CELLS vtkDataType (Union[int, None], optional): Vtk data type of the attribute to create. Defaults to None, the vtk data type is given by the type of the values. @@ -378,6 +374,10 @@ def createConstantAttributeDataSet( if logger is None: logger = getLogger( "createConstantAttributeDataSet", True ) + # Check the piece. + if piece not in [ Piece.POINTS, Piece.CELLS ]: + raise ValueError( f"The attribute must be created on { Piece.POINTS.value } or { Piece.CELLS.value }." ) + # Check if all the values of listValues have the same type. valueType: type = type( listValues[ 0 ] ) for value in listValues: @@ -414,14 +414,14 @@ def createConstantAttributeDataSet( # Create the numpy array constant per component. nbComponents: int = len( listValues ) - nbElements: int = ( dataSet.GetNumberOfPoints() if onPoints else dataSet.GetNumberOfCells() ) + nbElements: int = ( dataSet.GetNumberOfPoints() if piece == Piece.POINTS else dataSet.GetNumberOfCells() ) npArray: npt.NDArray[ Any ] if nbComponents > 1: npArray = np.array( [ listValues for _ in range( nbElements ) ], valueType ) else: npArray = np.array( [ listValues[ 0 ] for _ in range( nbElements ) ], valueType ) - return createAttribute( dataSet, npArray, attributeName, componentNames, onPoints, vtkDataType, logger ) + return createAttribute( dataSet, npArray, attributeName, componentNames, piece, vtkDataType, logger ) def createAttribute( @@ -429,7 +429,7 @@ def createAttribute( npArray: npt.NDArray[ Any ], attributeName: str, componentNames: tuple[ str, ...] = (), # noqa: C408 - onPoints: bool = False, + piece: Piece = Piece.CELLS, vtkDataType: Union[ int, None ] = None, logger: Union[ Logger, None ] = None, ) -> bool: @@ -441,8 +441,8 @@ def createAttribute( attributeName (str): Name of the attribute. componentNames (tuple[str,...], optional): Name of the components for vectorial attributes. If one component, gives an empty tuple. Defaults to an empty tuple. - onPoints (bool, optional): True if attributes are on points, False if they are on cells. - Defaults to False. + piece (Piece): The piece of the attribute. + Defaults to Piece.CELLS vtkDataType (Union[int, None], optional): Vtk data type of the attribute to create. Defaults to None, the vtk data type is given by the type of the array. @@ -460,6 +460,10 @@ def createAttribute( if logger is None: logger = getLogger( "createAttribute", True ) + # Check the piece. + if piece not in [ Piece.POINTS, Piece.CELLS ]: + raise ValueError( f"The attribute must be created on { Piece.POINTS.value } or { Piece.CELLS.value }." ) + # Check if the input mesh is inherited from vtkDataSet. if not isinstance( dataSet, vtkDataSet ): logger.error( "Input mesh has to be inherited from vtkDataSet." ) # type: ignore[unreachable] @@ -467,11 +471,16 @@ def createAttribute( return False # Check if the attribute already exist in the input mesh. - if isAttributeInObjectDataSet( dataSet, attributeName, onPoints ): + if isAttributeInObjectDataSet( dataSet, attributeName, piece ): logger.error( f"The attribute { attributeName } is already present in the dataSet." ) logger.error( f"The attribute { attributeName } has not been created into the mesh." ) return False + # 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 ): + 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. if vtkDataType is not None: vtkNumpyTypeMap: dict[ int, type ] = vnp.get_vtk_to_numpy_typemap() @@ -490,29 +499,19 @@ def createAttribute( data: Union[ vtkPointData, vtkCellData ] nbElements: int - oppositePieceName: str - if onPoints: + if piece == Piece.POINTS: data = dataSet.GetPointData() nbElements = dataSet.GetNumberOfPoints() - oppositePieceName = "cells" else: data = dataSet.GetCellData() nbElements = dataSet.GetNumberOfCells() - oppositePieceName = "points" # Check if the input array has the good size. if len( npArray ) != nbElements: - logger.error( f"The array has to have { nbElements } elements, but have only { len( npArray ) } elements" ) + logger.error( f"The array has to have { nbElements } elements, but have only { len( npArray ) } elements." ) logger.error( f"The attribute { attributeName } has not been created into the mesh." ) return False - # Check if an attribute with the same name exist on the opposite piece (points or cells). - oppositePiece: bool = not onPoints - if isAttributeInObjectDataSet( dataSet, attributeName, oppositePiece ): - logger.warning( - f"An attribute with the same name ({ attributeName }) is already present in the dataSet but on { oppositePieceName }." - ) - # Convert the numpy array int a vtkDataArray. createdAttribute: vtkDataArray = vnp.numpy_to_vtk( npArray, deep=True, array_type=vtkDataType ) createdAttribute.SetName( attributeName ) @@ -548,7 +547,7 @@ def copyAttribute( multiBlockDataSetTo: vtkMultiBlockDataSet, attributeNameFrom: str, attributeNameTo: str, - onPoints: bool = False, + piece: Piece = Piece.CELLS, logger: Union[ Logger, None ] = None, ) -> bool: """Copy an attribute from a multiBlockDataSet to a similar one on the same piece. @@ -558,8 +557,8 @@ def copyAttribute( multiBlockDataSetTo (vtkMultiBlockDataSet): MultiBlockDataSet where to copy the attribute. attributeNameFrom (str): Attribute name in multiBlockDataSetFrom. attributeNameTo (str): Attribute name in multiBlockDataSetTo. It will be a new attribute of multiBlockDataSetTo. - onPoints (bool, optional): True if attributes are on points, False if they are on cells. - Defaults to False. + piece (Piece): The piece of the attribute. + Defaults to Piece.CELLS logger (Union[Logger, None], optional): A logger to manage the output messages. Defaults to None, an internal logger is used. @@ -585,13 +584,13 @@ def copyAttribute( return False # Check if the attribute exist in the multiBlockDataSetFrom. - if not isAttributeInObjectMultiBlockDataSet( multiBlockDataSetFrom, attributeNameFrom, onPoints ): + if not isAttributeInObjectMultiBlockDataSet( multiBlockDataSetFrom, attributeNameFrom, piece ): logger.error( f"The attribute { attributeNameFrom } is not in the multiBlockDataSetFrom." ) logger.error( f"The attribute { attributeNameFrom } has not been copied." ) return False # Check if the attribute already exist in the multiBlockDataSetTo. - if isAttributeInObjectMultiBlockDataSet( multiBlockDataSetTo, attributeNameTo, onPoints ): + if isAttributeInObjectMultiBlockDataSet( multiBlockDataSetTo, attributeNameTo, piece ): logger.error( f"The attribute { attributeNameTo } is already in the multiBlockDataSetTo." ) logger.error( f"The attribute { attributeNameFrom } has not been copied." ) return False @@ -618,8 +617,8 @@ def copyAttribute( logger.error( f"The attribute { attributeNameFrom } has not been copied." ) return False - if isAttributeInObjectDataSet( dataSetFrom, attributeNameFrom, onPoints ) and \ - not copyAttributeDataSet( dataSetFrom, dataSetTo, attributeNameFrom, attributeNameTo, onPoints, logger ): + if isAttributeInObjectDataSet( dataSetFrom, attributeNameFrom, piece ) and \ + not copyAttributeDataSet( dataSetFrom, dataSetTo, attributeNameFrom, attributeNameTo, piece, logger ): return False return True @@ -630,7 +629,7 @@ def copyAttributeDataSet( dataSetTo: vtkDataSet, attributeNameFrom: str, attributeNameTo: str, - onPoints: bool = False, + piece: Piece = Piece.CELLS, logger: Union[ Logger, Any ] = None, ) -> bool: """Copy an attribute from a dataSet to a similar one on the same piece. @@ -640,8 +639,8 @@ def copyAttributeDataSet( dataSetTo (vtkDataSet): DataSet where to copy the attribute. attributeNameFrom (str): Attribute name in dataSetFrom. attributeNameTo (str): Attribute name in dataSetTo. It will be a new attribute of dataSetTo. - onPoints (bool, optional): True if attributes are on points, False if they are on cells. - Defaults to False. + piece (Piece): The piece of the attribute. + Defaults to Piece.CELLS logger (Union[Logger, None], optional): A logger to manage the output messages. Defaults to None, an internal logger is used. @@ -665,22 +664,22 @@ def copyAttributeDataSet( return False # Check if the attribute exist in the dataSetFrom. - if not isAttributeInObjectDataSet( dataSetFrom, attributeNameFrom, onPoints ): + if not isAttributeInObjectDataSet( dataSetFrom, attributeNameFrom, piece ): logger.error( f"The attribute { attributeNameFrom } is not in the dataSetFrom." ) logger.error( f"The attribute { attributeNameFrom } has not been copied." ) return False # Check if the attribute already exist in the dataSetTo. - if isAttributeInObjectDataSet( dataSetTo, attributeNameTo, onPoints ): + if isAttributeInObjectDataSet( dataSetTo, attributeNameTo, piece ): logger.error( f"The attribute { attributeNameTo } is already in the dataSetTo." ) logger.error( f"The attribute { attributeNameFrom } has not been copied." ) return False - npArray: npt.NDArray[ Any ] = getArrayInObject( dataSetFrom, attributeNameFrom, onPoints ) - componentNames: tuple[ str, ...] = getComponentNamesDataSet( dataSetFrom, attributeNameFrom, onPoints ) - vtkArrayType: int = getVtkArrayTypeInObject( dataSetFrom, attributeNameFrom, onPoints ) + npArray: npt.NDArray[ Any ] = getArrayInObject( dataSetFrom, attributeNameFrom, piece ) + componentNames: tuple[ str, ...] = getComponentNamesDataSet( dataSetFrom, attributeNameFrom, piece ) + vtkArrayType: int = getVtkArrayTypeInObject( dataSetFrom, attributeNameFrom, piece ) - return createAttribute( dataSetTo, npArray, attributeNameTo, componentNames, onPoints, vtkArrayType, logger ) + return createAttribute( dataSetTo, npArray, attributeNameTo, componentNames, piece, vtkArrayType, logger ) def transferAttributeToDataSetWithElementMap( @@ -688,7 +687,7 @@ def transferAttributeToDataSetWithElementMap( dataSetTo: vtkDataSet, elementMap: dict[ int, npt.NDArray[ np.int64 ] ], attributeName: str, - onPoints: bool, + piece: Piece, flatIdDataSetTo: int = 0, logger: Union[ Logger, Any ] = None, ) -> bool: @@ -713,7 +712,7 @@ def transferAttributeToDataSetWithElementMap( dataSetTo (vtkDataSet): The final mesh where to transfer the attribute. elementMap (dict[int, npt.NDArray[np.int64]]): The map of points/cells. attributeName (str): The name of the attribute to transfer. - onPoints (bool): True if the attribute is on points, False if it is on cells. + piece (Piece): The piece of the attribute. flatIdDataSetTo (int, Optional): The flat index of the final mesh considered as a dataset of a vtkMultiblockDataSet. Defaults to 0 for final meshes who are not datasets of vtkMultiBlockDataSet. logger (Union[Logger, None], optional): A logger to manage the output messages. @@ -726,21 +725,25 @@ def transferAttributeToDataSetWithElementMap( if logger is None: logger = getLogger( "transferAttributeToDataSetWithElementMap", True ) + # Check the piece. + if piece not in [ Piece.POINTS, Piece.CELLS ]: + raise ValueError( f"The attribute must be on { Piece.POINTS.value } or { Piece.CELLS.value }." ) + if flatIdDataSetTo not in elementMap: logger.error( f"The map is incomplete, there is no data for the final mesh (flat index { flatIdDataSetTo })." ) return False - nbElementsTo: int = dataSetTo.GetNumberOfPoints() if onPoints else dataSetTo.GetNumberOfCells() + nbElementsTo: int = dataSetTo.GetNumberOfPoints() if piece == Piece.POINTS else dataSetTo.GetNumberOfCells() if len( elementMap[ flatIdDataSetTo ] ) != nbElementsTo: logger.error( f"The map is wrong, there is { nbElementsTo } elements in the final mesh (flat index { flatIdDataSetTo })\ but { len( elementMap[ flatIdDataSetTo ] ) } elements in the map." ) return False - componentNames: tuple[ str, ...] = getComponentNames( meshFrom, attributeName, onPoints ) + componentNames: tuple[ str, ...] = getComponentNames( meshFrom, attributeName, piece ) nbComponents: int = len( componentNames ) - vtkDataType: int = getVtkDataTypeInObject( meshFrom, attributeName, onPoints ) + vtkDataType: int = getVtkDataTypeInObject( meshFrom, attributeName, piece ) defaultValue: Any if vtkDataType in ( VTK_FLOAT, VTK_DOUBLE ): defaultValue = np.nan @@ -766,11 +769,11 @@ def transferAttributeToDataSetWithElementMap( if idElementFrom != -1: dataFrom: Union[ vtkPointData, vtkCellData ] if isinstance( meshFrom, vtkDataSet ): - dataFrom = meshFrom.GetPointData() if onPoints else meshFrom.GetCellData() + dataFrom = meshFrom.GetPointData() if piece == Piece.POINTS else meshFrom.GetCellData() elif isinstance( meshFrom, vtkMultiBlockDataSet ): flatIdDataSetFrom: int = int( elementMap[ flatIdDataSetTo ][ idElementTo ][ 0 ] ) dataSetFrom: vtkDataSet = vtkDataSet.SafeDownCast( meshFrom.GetDataSet( flatIdDataSetFrom ) ) - dataFrom = dataSetFrom.GetPointData() if onPoints else dataSetFrom.GetCellData() + dataFrom = dataSetFrom.GetPointData() if piece == Piece.POINTS else dataSetFrom.GetCellData() arrayFrom: npt.NDArray[ Any ] = vnp.vtk_to_numpy( dataFrom.GetArray( attributeName ) ) valueToTransfer = arrayFrom[ idElementFrom ] @@ -781,7 +784,7 @@ def transferAttributeToDataSetWithElementMap( arrayTo, attributeName, componentNames, - onPoints=onPoints, + piece=piece, vtkDataType=vtkDataType, logger=logger ) @@ -791,7 +794,7 @@ def transferAttributeWithElementMap( meshTo: Union[ vtkDataSet, vtkMultiBlockDataSet ], elementMap: dict[ int, npt.NDArray[ np.int64 ] ], attributeName: str, - onPoints: bool, + piece: Piece, logger: Union[ Logger, Any ] = None, ) -> bool: """Transfer attributes from the source mesh to the final mesh using a map of points/cells. @@ -816,8 +819,7 @@ def transferAttributeWithElementMap( meshTo (Union[vtkDataSet, vtkMultiBlockDataSet]): The final mesh where to transfer the attribute. elementMap (dict[int, npt.NDArray[np.int64]]): The map of points/cells. attributeName (str): The name of the attribute to transfer. - onPoints (bool): True if the attribute is on points, False if it is on cells. - Defaults to 0 for final meshes who are not datasets of vtkMultiBlockDataSet. + piece (Piece): The piece of the attribute. logger (Union[Logger, None], optional): A logger to manage the output messages. Defaults to None, an internal logger is used. @@ -833,19 +835,15 @@ def transferAttributeWithElementMap( meshTo, elementMap, attributeName, - onPoints, + piece, logger=logger ) elif isinstance( meshTo, vtkMultiBlockDataSet ): listFlatIdDataSetTo: list[ int ] = getBlockElementIndexesFlatten( meshTo ) for flatIdDataSetTo in listFlatIdDataSetTo: dataSetTo: vtkDataSet = vtkDataSet.SafeDownCast( meshTo.GetDataSet( flatIdDataSetTo ) ) - if not transferAttributeToDataSetWithElementMap( meshFrom, - dataSetTo, - elementMap, - attributeName, - onPoints, - flatIdDataSetTo=flatIdDataSetTo, - logger=logger ): + if not transferAttributeToDataSetWithElementMap( + meshFrom, dataSetTo, elementMap, attributeName, piece, flatIdDataSetTo=flatIdDataSetTo, + logger=logger ): logger.error( f"The attribute transfer has failed for the dataset with the flat index { flatIdDataSetTo } of the final mesh." ) @@ -858,7 +856,7 @@ def renameAttribute( object: Union[ vtkMultiBlockDataSet, vtkDataSet ], attributeName: str, newAttributeName: str, - onPoints: bool, + piece: Piece, ) -> bool: """Rename an attribute. @@ -866,13 +864,19 @@ def renameAttribute( object (vtkMultiBlockDataSet): Object where the attribute is. attributeName (str): Name of the attribute. newAttributeName (str): New name of the attribute. - onPoints (bool): True if attributes are on points, False if they are on cells. + piece (Piece): The piece of the attribute. Returns: bool: True if renaming operation successfully ended. """ - if isAttributeInObject( object, attributeName, onPoints ): - dim: int = 0 if onPoints else 1 + if isAttributeInObject( object, attributeName, piece ): + dim: int + if piece == Piece.POINTS: + dim = 0 + elif piece == Piece.CELLS: + dim = 1 + else: + raise ValueError( "The attribute to rename must be on points or on Cells." ) filter = vtkArrayRename() filter.SetInputData( object ) filter.SetArrayName( dim, attributeName, newAttributeName ) diff --git a/geos-mesh/tests/conftest.py b/geos-mesh/tests/conftest.py index 6f0dea973..0d5b064bf 100644 --- a/geos-mesh/tests/conftest.py +++ b/geos-mesh/tests/conftest.py @@ -5,13 +5,15 @@ # ruff: noqa: E402 # disable Module level import not at top of file import os import pytest -from typing import Union, Any, Tuple, Dict +from typing import Union, Any import numpy as np import numpy.typing as npt from vtkmodules.vtkCommonDataModel import vtkDataSet, vtkMultiBlockDataSet, vtkPolyData from vtkmodules.vtkIOXML import vtkXMLGenericDataObjectReader +from geos.utils.pieceEnum import Piece + @pytest.fixture def arrayExpected( request: pytest.FixtureRequest ) -> npt.NDArray[ np.float64 ]: @@ -198,19 +200,19 @@ def getElementMap() -> Any: """Get the element indexes mapping dictionary using the function _get_elementMap() between two meshes. Returns: - elementMap (Dict[int, npt.NDArray[np.int64]]): The cell mapping dictionary. + elementMap (dict[int, npt.NDArray[np.int64]]): The cell mapping dictionary. """ - def _get_elementMap( meshFromName: str, meshToName: str, points: bool ) -> Dict[ int, npt.NDArray[ np.int64 ] ]: + def _get_elementMap( meshFromName: str, meshToName: str, piece: Piece ) -> dict[ int, npt.NDArray[ np.int64 ] ]: """Get the element indexes mapping dictionary between two meshes. Args: meshFromName (str): The name of the meshFrom. meshToName (str): The name of the meshTo. - points (bool): True if elements to map is points, False if it is cells. + piece (Piece): The element to map. Returns: - elementMap (Dict[int, npt.NDArray[np.int64]]): The element mapping dictionary. + elementMap (dict[int, npt.NDArray[np.int64]]): The element mapping dictionary. """ sharedCells2D3DId: npt.NDArray[ np.int64 ] = np.array( [ [ 0, 0 ], [ 1, 1 ], [ 2, 2 ], [ 3, 3 ], [ 4, 4 ], [ 5, 5 ], [ 6, 6 ], [ 7, 7 ], [ 8, 8 ], [ 9, 9 ], @@ -238,8 +240,8 @@ def _get_elementMap( meshFromName: str, meshToName: str, points: bool ) -> Dict[ ) sharedPoints1D2DId: npt.NDArray[ np.int64 ] = np.array( [ [ 0, 26 ] ], dtype=np.int64 ) sharedPoints1D3DId: npt.NDArray[ np.int64 ] = np.array( [ [ 0, 475 ] ], dtype=np.int64 ) - elementMap: Dict[ int, npt.NDArray[ np.int64 ] ] = {} - nbElements: Tuple[ int, int, int ] = ( 4092, 212, 11 ) if points else ( 1740, 156, 10 ) + elementMap: dict[ int, npt.NDArray[ np.int64 ] ] = {} + nbElements: tuple[ int, int, int ] = ( 4092, 212, 11 ) if piece == Piece.POINTS else ( 1740, 156, 10 ) if meshFromName == "well": if meshToName == "emptyWell": elementMap[ 0 ] = np.array( [ [ 0, element ] for element in range( nbElements[ 2 ] ) ] ) diff --git a/geos-mesh/tests/test_arrayHelpers.py b/geos-mesh/tests/test_arrayHelpers.py index 8f89b4867..be64ee787 100644 --- a/geos-mesh/tests/test_arrayHelpers.py +++ b/geos-mesh/tests/test_arrayHelpers.py @@ -16,7 +16,7 @@ from vtkmodules.vtkCommonDataModel import vtkDataSet, vtkMultiBlockDataSet, vtkPolyData from geos.mesh.utils import arrayHelpers -from geos.mesh.utils.arrayModifiers import createConstantAttribute +from geos.utils.pieceEnum import Piece @pytest.mark.parametrize( "meshName, cellDimExpected", [ @@ -37,48 +37,48 @@ def test_getCellDimension( @pytest.mark.parametrize( - "meshFromName, meshToName, points", + "meshFromName, meshToName, piece", [ - ( "well", "emptyWell", False ), # 1D vtu -> 1D vtu onCells - ( "well", "emptyWell", True ), # 1D vtu -> 1D vtu onPoints - ( "well", "emptyFracture", True ), # 1D vtu -> 2D vtu onCells - ( "well", "emptypolydata", True ), # 1D vtu -> 2D vtp onCells - ( "well", "emptydataset", True ), # 1D vtu -> 3D vtu onCells - ( "well", "emptymultiblock", True ), # 1D vtu -> vtm(3D vtu & 2D vtu) onPoints - ( "fracture", "emptyFracture", False ), # 2D vtu -> 2D vtu onCells - ( "fracture", "emptyWell", True ), # 2D vtu -> 1D vtu onPoints - ( "fracture", "emptypolydata", False ), # 2D vtu -> 2D vtp onCells - ( "fracture", "emptydataset", False ), # 2D vtu -> 3D vtu onCells - ( "fracture", "emptymultiblock", False ), # 2D vtu -> vtm(3D vtu & 2D vtu) onCells - ( "polydata", "emptypolydata", False ), # 2D vtp -> 2D vtp onCells - ( "polydata", "emptyWell", True ), # 2D vtp -> 1D vtu onPoints - ( "polydata", "emptyFracture", False ), # 2D vtp -> 2D vtu onCells - ( "polydata", "emptydataset", False ), # 2D vtp -> 3D vtu onCells - ( "polydata", "emptymultiblock", False ), # 2D vtp -> vtm(3D vtu & 2D vtu) onCells - ( "dataset", "emptydataset", False ), # 3D vtu -> 3D vtu onCells - ( "dataset", "emptyWell", True ), # 3D vtu -> 1D vtu onPoints - ( "dataset", "emptyFracture", False ), # 3D vtu -> 2D vtu onCells - ( "dataset", "emptypolydata", False ), # 3D vtu -> 2D vtp onCells - ( "dataset", "emptymultiblock", False ), # 3D vtu -> vtm(3D vtu & 2D vtu) onCells - ( "multiblock", "emptymultiblock", False ), # vtm( 3D vtu & 2D vtu ) -> vtm( 3D vtu & 2D vtu ) onCells - ( "multiblock", "emptyWell", True ), # vtm(3D vtu & 2D vtu) -> 1D vtu onPoints - ( "multiblock", "emptyFracture", False ), # vtm(3D vtu & 2D vtu) -> 2D vtu onCells - ( "multiblock", "emptypolydata", False ), # vtm(3D vtu & 2D vtu) -> 2D vtp onCells - ( "multiblock", "emptydataset", False ), # vtm(3D vtu & 2D vtu) -> 3D vtu onCells + ( "well", "emptyWell", Piece.CELLS ), # 1D vtu -> 1D vtu onCells + ( "well", "emptyWell", Piece.POINTS ), # 1D vtu -> 1D vtu onPoints + ( "well", "emptyFracture", Piece.POINTS ), # 1D vtu -> 2D vtu onCells + ( "well", "emptypolydata", Piece.POINTS ), # 1D vtu -> 2D vtp onCells + ( "well", "emptydataset", Piece.POINTS ), # 1D vtu -> 3D vtu onCells + ( "well", "emptymultiblock", Piece.POINTS ), # 1D vtu -> vtm(3D vtu & 2D vtu) onPoints + ( "fracture", "emptyFracture", Piece.CELLS ), # 2D vtu -> 2D vtu onCells + ( "fracture", "emptyWell", Piece.POINTS ), # 2D vtu -> 1D vtu onPoints + ( "fracture", "emptypolydata", Piece.CELLS ), # 2D vtu -> 2D vtp onCells + ( "fracture", "emptydataset", Piece.CELLS ), # 2D vtu -> 3D vtu onCells + ( "fracture", "emptymultiblock", Piece.CELLS ), # 2D vtu -> vtm(3D vtu & 2D vtu) onCells + ( "polydata", "emptypolydata", Piece.CELLS ), # 2D vtp -> 2D vtp onCells + ( "polydata", "emptyWell", Piece.POINTS ), # 2D vtp -> 1D vtu onPoints + ( "polydata", "emptyFracture", Piece.CELLS ), # 2D vtp -> 2D vtu onCells + ( "polydata", "emptydataset", Piece.CELLS ), # 2D vtp -> 3D vtu onCells + ( "polydata", "emptymultiblock", Piece.CELLS ), # 2D vtp -> vtm(3D vtu & 2D vtu) onCells + ( "dataset", "emptydataset", Piece.CELLS ), # 3D vtu -> 3D vtu onCells + ( "dataset", "emptyWell", Piece.POINTS ), # 3D vtu -> 1D vtu onPoints + ( "dataset", "emptyFracture", Piece.CELLS ), # 3D vtu -> 2D vtu onCells + ( "dataset", "emptypolydata", Piece.CELLS ), # 3D vtu -> 2D vtp onCells + ( "dataset", "emptymultiblock", Piece.CELLS ), # 3D vtu -> vtm(3D vtu & 2D vtu) onCells + ( "multiblock", "emptymultiblock", Piece.CELLS ), # vtm( 3D vtu & 2D vtu ) -> vtm( 3D vtu & 2D vtu ) onCells + ( "multiblock", "emptyWell", Piece.POINTS ), # vtm(3D vtu & 2D vtu) -> 1D vtu onPoints + ( "multiblock", "emptyFracture", Piece.CELLS ), # vtm(3D vtu & 2D vtu) -> 2D vtu onCells + ( "multiblock", "emptypolydata", Piece.CELLS ), # vtm(3D vtu & 2D vtu) -> 2D vtp onCells + ( "multiblock", "emptydataset", Piece.CELLS ), # vtm(3D vtu & 2D vtu) -> 3D vtu onCells ] ) def test_computeElementMapping( dataSetTest: vtkDataSet, getElementMap: dict[ int, npt.NDArray[ np.int64 ] ], meshFromName: str, meshToName: str, - points: bool, + piece: Piece, ) -> None: """Test getting the map between two meshes element.""" meshFrom: Union[ vtkDataSet, vtkMultiBlockDataSet ] = dataSetTest( meshFromName ) meshTo: Union[ vtkDataSet, vtkMultiBlockDataSet ] = dataSetTest( meshToName ) - elementMapComputed: dict[ int, npt.NDArray[ np.int64 ] ] = arrayHelpers.computeElementMapping( - meshFrom, meshTo, points ) - elementMapTest: dict[ int, npt.NDArray[ np.int64 ] ] = getElementMap( meshFromName, meshToName, points ) + elementMapComputed: dict[ int, + npt.NDArray[ np.int64 ] ] = arrayHelpers.computeElementMapping( meshFrom, meshTo, piece ) + elementMapTest: dict[ int, npt.NDArray[ np.int64 ] ] = getElementMap( meshFromName, meshToName, piece ) keysComputed: list[ int ] = list( elementMapComputed.keys() ) keysTest: list[ int ] = list( elementMapTest.keys() ) @@ -88,61 +88,56 @@ def test_computeElementMapping( assert np.all( elementMapComputed[ key ] == elementMapTest[ key ] ) -@pytest.mark.parametrize( "onpoints, expected", [ ( True, { +@pytest.mark.parametrize( "piece, expected", [ ( Piece.POINTS, { 'GLOBAL_IDS_POINTS': 1, 'collocated_nodes': 2, - 'PointAttribute': 3 -} ), ( False, { + 'PointAttribute': 3, +} ), ( Piece.CELLS, { 'CELL_MARKERS': 1, 'PERM': 3, 'PORO': 1, 'FAULT': 1, 'GLOBAL_IDS_CELLS': 1, - 'CellAttribute': 3 + 'CellAttribute': 3, } ) ] ) -def test_getAttributeFromMultiBlockDataSet( dataSetTest: vtkMultiBlockDataSet, onpoints: bool, +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, onpoints ) + attributes: dict[ str, int ] = arrayHelpers.getAttributesFromMultiBlockDataSet( multiBlockTest, piece ) assert attributes == expected -@pytest.mark.parametrize( "attributeName, onPointsTest, onBothTest", [ - ( "CellAttribute", False, False ), - ( "PointAttribute", True, False ), - ( "NewAttribute", None, False ), - ( "NewAttribute", True, True ), +@pytest.mark.parametrize( "meshName, attributeName, pieceTest", [ + ( "dataset", "CellAttribute", Piece.CELLS ), + ( "dataset", "PointAttribute", Piece.POINTS ), + ( "dataset", "NewAttribute", Piece.NONE ), + ( "multiblockGeosOutput", "ghostRank", Piece.BOTH ), + ( "multiblockGeosOutput", "TIME", Piece.FIELD ), ] ) def test_getAttributePieceInfo( dataSetTest: vtkDataSet, + meshName: str, attributeName: str, - onPointsTest: Union[ None, bool ], - onBothTest: bool, + pieceTest: Piece, ) -> None: """Test getting attribute piece information.""" - dataSet: vtkDataSet = dataSetTest( "dataset" ) - if onBothTest: # Create a case with an attribute with the same name on points and on cells. - createConstantAttribute( dataSet, [ 42. ], attributeName, onPoints=True ) - createConstantAttribute( dataSet, [ 42. ], attributeName, onPoints=False ) - onPoints: Union[ None, bool ] - onBoth: bool - onPoints, onBoth = arrayHelpers.getAttributePieceInfo( dataSet, attributeName ) - assert onPoints == onPointsTest - assert onBoth == onBothTest - - -@pytest.mark.parametrize( "attributeName, listValues, onPoints, validValuesTest, invalidValuesTest", [ - ( "PointAttribute", [ [ 12.4, 9.7, 10.5 ], [ 0, 0, 0 ] ], True, [ [ 12.4, 9.7, 10.5 ] ], [ [ 0, 0, 0 ] ] ), - ( "CellAttribute", [ [ 24.8, 19.4, 21 ], [ 0, 0, 0 ] ], False, [ [ 24.8, 19.4, 21 ] ], [ [ 0, 0, 0 ] ] ), - ( "FAULT", [ 0, 100, 101, 2 ], False, [ 0, 100, 101 ], [ 2 ] ), + dataSet: vtkDataSet = dataSetTest( meshName ) + pieceObtained = arrayHelpers.getAttributePieceInfo( dataSet, attributeName ) + assert pieceObtained == pieceTest + + +@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 ], - onPoints: bool, + piece: Piece, validValuesTest: list[ Any ], invalidValuesTest: list[ Any ], ) -> None: @@ -150,207 +145,210 @@ def test_checkValidValuesInDataSet( dataSet: vtkDataSet = dataSetTest( "dataset" ) validValues: list[ Any ] invalidValues: list[ Any ] - validValues, invalidValues = arrayHelpers.checkValidValuesInDataSet( dataSet, attributeName, listValues, onPoints ) + validValues, invalidValues = arrayHelpers.checkValidValuesInDataSet( dataSet, attributeName, listValues, piece ) assert validValues == validValuesTest assert invalidValues == invalidValuesTest -@pytest.mark.parametrize( "onpoints, expected", [ ( True, { +@pytest.mark.parametrize( "piece, expected", [ ( Piece.POINTS, { 'GLOBAL_IDS_POINTS': 1, 'PointAttribute': 3, -} ), ( False, { +} ), ( Piece.CELLS, { 'CELL_MARKERS': 1, 'PERM': 3, 'PORO': 1, 'FAULT': 1, 'GLOBAL_IDS_CELLS': 1, - 'CellAttribute': 3 + 'CellAttribute': 3, } ) ] ) -def test_getAttributesFromDataSet( dataSetTest: vtkDataSet, onpoints: bool, expected: dict[ str, int ] ) -> None: +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, onpoints ) + attributes: dict[ str, int ] = arrayHelpers.getAttributesFromDataSet( vtkDataSetTest, piece ) assert attributes == expected -@pytest.mark.parametrize( "attributeName, onpoints, expected", [ - ( "PORO", False, 1 ), - ( "PORO", True, 0 ), +@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, onpoints: bool, - expected: dict[ str, int ] ) -> None: +def test_isAttributeInObjectMultiBlockDataSet( dataSetTest: vtkMultiBlockDataSet, attributeName: str, + piece: Piece ) -> None: """Test presence of attribute in a multiblock.""" - multiBlockDataset: vtkMultiBlockDataSet = dataSetTest( "multiblock" ) - obtained: bool = arrayHelpers.isAttributeInObjectMultiBlockDataSet( multiBlockDataset, attributeName, onpoints ) - assert obtained == expected + multiBlockDataset: vtkMultiBlockDataSet = dataSetTest( "multiblockGeosOutput" ) + obtained: bool = arrayHelpers.isAttributeInObjectMultiBlockDataSet( multiBlockDataset, attributeName, piece ) + assert obtained -@pytest.mark.parametrize( "attributeName, onpoints, expected", [ - ( "PORO", False, 1 ), - ( "PORO", True, 0 ), +@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, onpoints: bool, +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, onpoints ) + obtained: bool = arrayHelpers.isAttributeInObjectDataSet( vtkDataset, attributeName, piece ) assert obtained == expected -@pytest.mark.parametrize( "attributeName, onpoints, expected", [ - ( "PORO", False, False ), - ( "GLOBAL_IDS_POINTS", True, True ), +@pytest.mark.parametrize( "attributeName, piece, expected", [ + ( "PORO", Piece.CELLS, False ), + ( "GLOBAL_IDS_POINTS", Piece.POINTS, True ), ] ) def test_isAttributeGlobal( dataSetTest: vtkMultiBlockDataSet, attributeName: str, - onpoints: bool, + piece: Piece, expected: bool, ) -> None: """Test if the attribute is global or partial.""" multiBlockDataset: vtkMultiBlockDataSet = dataSetTest( "multiblock" ) - obtained: bool = arrayHelpers.isAttributeGlobal( multiBlockDataset, attributeName, onpoints ) + obtained: bool = arrayHelpers.isAttributeGlobal( multiBlockDataset, attributeName, piece ) assert obtained == expected -@pytest.mark.parametrize( "arrayExpected, onpoints", [ - ( "PORO", False ), - ( "PERM", False ), - ( "PointAttribute", True ), +@pytest.mark.parametrize( "arrayExpected, piece", [ + ( "PORO", Piece.CELLS ), + ( "PERM", Piece.CELLS ), + ( "PointAttribute", Piece.POINTS ), ], indirect=[ "arrayExpected" ] ) def test_getArrayInObject( request: pytest.FixtureRequest, arrayExpected: npt.NDArray[ np.float64 ], - dataSetTest: vtkDataSet, onpoints: bool ) -> None: + dataSetTest: vtkDataSet, piece: Piece ) -> None: """Test getting numpy array of an attribute from dataset.""" vtkDataSetTest: vtkDataSet = dataSetTest( "dataset" ) params = request.node.callspec.params attributeName: str = params[ "arrayExpected" ] - obtained: npt.NDArray[ np.float64 ] = arrayHelpers.getArrayInObject( vtkDataSetTest, attributeName, onpoints ) + obtained: npt.NDArray[ np.float64 ] = arrayHelpers.getArrayInObject( vtkDataSetTest, attributeName, piece ) expected: npt.NDArray[ np.float64 ] = arrayExpected assert ( obtained == expected ).all() -@pytest.mark.parametrize( "attributeName, vtkDataType, onPoints", [ - ( "CellAttribute", 11, False ), - ( "PointAttribute", 11, True ), - ( "collocated_nodes", 12, True ), +@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, - onPoints: bool ) -> None: + 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, onPoints ) + vtkDataTypeTest: int = arrayHelpers.getVtkArrayTypeInMultiBlock( multiBlockDataSet, attributeName, piece ) assert ( vtkDataTypeTest == vtkDataType ) -@pytest.mark.parametrize( "attributeName, onPoints", [ - ( "CellAttribute", False ), - ( "PointAttribute", True ), +@pytest.mark.parametrize( "attributeName, piece", [ + ( "CellAttribute", Piece.CELLS ), + ( "PointAttribute", Piece.POINTS ), ] ) -def test_getVtkArrayTypeInObject( dataSetTest: vtkDataSet, attributeName: str, onPoints: bool ) -> None: +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, onPoints ) + obtained: int = arrayHelpers.getVtkArrayTypeInObject( vtkDataSetTest, attributeName, piece ) expected: int = 11 assert ( obtained == expected ) -@pytest.mark.parametrize( "arrayExpected, onpoints", [ - ( "PORO", False ), - ( "PointAttribute", True ), +@pytest.mark.parametrize( "arrayExpected, piece", [ + ( "PORO", Piece.CELLS ), + ( "PointAttribute", Piece.POINTS ), ], indirect=[ "arrayExpected" ] ) def test_getVtkArrayInObject( request: pytest.FixtureRequest, arrayExpected: npt.NDArray[ np.float64 ], - dataSetTest: vtkDataSet, onpoints: bool ) -> None: + dataSetTest: vtkDataSet, piece: Piece ) -> None: """Test getting Vtk Array from a dataset.""" vtkDataSetTest: vtkDataSet = dataSetTest( "dataset" ) params = request.node.callspec.params attributeName: str = params[ 'arrayExpected' ] - obtained: vtkDoubleArray = arrayHelpers.getVtkArrayInObject( vtkDataSetTest, attributeName, onpoints ) + obtained: vtkDoubleArray = arrayHelpers.getVtkArrayInObject( vtkDataSetTest, attributeName, piece ) obtained_as_np: npt.NDArray[ np.float64 ] = vnp.vtk_to_numpy( obtained ) assert ( obtained_as_np == arrayExpected ).all() -@pytest.mark.parametrize( "attributeName, onpoints, expected", [ - ( "PORO", False, 1 ), - ( "PERM", False, 3 ), - ( "PointAttribute", True, 3 ), +@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, - onpoints: bool, + 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, onpoints ) + obtained: int = arrayHelpers.getNumberOfComponentsDataSet( vtkDataSetTest, attributeName, piece ) assert obtained == expected -@pytest.mark.parametrize( "attributeName, onpoints, expected", [ - ( "PORO", False, 1 ), - ( "PERM", False, 3 ), - ( "PointAttribute", True, 3 ), +@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, - onpoints: bool, + 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, onpoints ) + obtained: int = arrayHelpers.getNumberOfComponentsMultiBlock( vtkMultiBlockDataSetTest, attributeName, piece ) assert obtained == expected -@pytest.mark.parametrize( "attributeName, onpoints, expected", [ - ( "PERM", False, ( "AX1", "AX2", "AX3" ) ), - ( "PORO", False, () ), +@pytest.mark.parametrize( "attributeName, piece, expected", [ + ( "PERM", Piece.CELLS, ( "AX1", "AX2", "AX3" ) ), + ( "PORO", Piece.CELLS, () ), ] ) -def test_getComponentNamesDataSet( dataSetTest: vtkDataSet, attributeName: str, onpoints: bool, +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, onpoints ) + obtained: tuple[ str, ...] = arrayHelpers.getComponentNamesDataSet( vtkDataSetTest, attributeName, piece ) assert obtained == expected -@pytest.mark.parametrize( "attributeName, onpoints, expected", [ - ( "PERM", False, ( "AX1", "AX2", "AX3" ) ), - ( "PORO", False, () ), +@pytest.mark.parametrize( "attributeName, piece, expected", [ + ( "PERM", Piece.CELLS, ( "AX1", "AX2", "AX3" ) ), + ( "PORO", Piece.CELLS, () ), ] ) def test_getComponentNamesMultiBlock( dataSetTest: vtkMultiBlockDataSet, attributeName: str, - onpoints: bool, + 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, - onpoints ) + piece ) assert obtained == expected -@pytest.mark.parametrize( "attributeNames, onPoints, expected_columns", [ - ( ( "collocated_nodes", ), True, ( "collocated_nodes_0", "collocated_nodes_1" ) ), +@pytest.mark.parametrize( "attributeNames, piece, expected_columns", [ + ( ( "collocated_nodes", ), Piece.POINTS, ( "collocated_nodes_0", "collocated_nodes_1" ) ), ] ) -def test_getAttributeValuesAsDF( dataSetTest: vtkPolyData, attributeNames: Tuple[ str, ...], onPoints: bool, +def test_getAttributeValuesAsDF( dataSetTest: vtkPolyData, attributeNames: Tuple[ str, ...], piece: Piece, expected_columns: Tuple[ str, ...] ) -> None: """Test getting an attribute from a polydata as a dataframe.""" polydataset: vtkPolyData = vtkPolyData.SafeDownCast( dataSetTest( "polydata" ) ) - data: pd.DataFrame = arrayHelpers.getAttributeValuesAsDF( polydataset, attributeNames, onPoints ) + data: pd.DataFrame = arrayHelpers.getAttributeValuesAsDF( polydataset, attributeNames, piece ) obtained_columns = data.columns.values.tolist() assert obtained_columns == list( expected_columns ) diff --git a/geos-mesh/tests/test_arrayModifiers.py b/geos-mesh/tests/test_arrayModifiers.py index 0b2528d8c..7bd2c6f2a 100644 --- a/geos-mesh/tests/test_arrayModifiers.py +++ b/geos-mesh/tests/test_arrayModifiers.py @@ -20,6 +20,7 @@ VTK_UNSIGNED_CHAR, VTK_UNSIGNED_SHORT, VTK_UNSIGNED_INT, VTK_UNSIGNED_LONG_LONG, VTK_CHAR, VTK_SIGNED_CHAR, VTK_SHORT, VTK_INT, VTK_LONG_LONG, VTK_ID_TYPE, VTK_FLOAT, VTK_DOUBLE, ) +from geos.utils.pieceEnum import Piece # Information : # https://github.com/Kitware/VTK/blob/master/Wrapping/Python/vtkmodules/util/numpy_support.py @@ -47,24 +48,26 @@ @pytest.mark.parametrize( - "idBlock, attributeName, nbComponentsTest, componentNamesTest, onPoints, listValues, listValuesTest, vtkDataTypeTest", + "idBlock, attributeName, nbComponentsTest, componentNamesTest, piece, listValues, listValuesTest, vtkDataTypeTest", [ # Test fill an attribute on point and on cell. - ( 3, "PointAttribute", 3, - ( "AX1", "AX2", "AX3" ), True, None, [ np.float64( - np.nan ), np.float64( np.nan ), np.float64( np.nan ) ], VTK_DOUBLE ), - ( 3, "CellAttribute", 3, - ( "AX1", "AX2", "AX3" ), False, None, [ np.float64( - np.nan ), np.float64( np.nan ), np.float64( np.nan ) ], VTK_DOUBLE ), + ( 3, "PointAttribute", 3, ( "AX1", "AX2", "AX3" ), Piece.POINTS, None, + [ np.float64( np.nan ), np.float64( np.nan ), + np.float64( np.nan ) ], VTK_DOUBLE ), + ( 3, "CellAttribute", 3, ( "AX1", "AX2", "AX3" ), Piece.CELLS, None, + [ np.float64( np.nan ), np.float64( np.nan ), + np.float64( np.nan ) ], VTK_DOUBLE ), # Test fill attributes with different number of component with or without component names. - ( 3, "PORO", 1, (), False, None, [ np.float32( np.nan ) ], VTK_FLOAT ), - ( 1, "collocated_nodes", 2, ( None, None ), True, None, [ np.int64( -1 ), np.int64( -1 ) ], VTK_ID_TYPE ), + ( 3, "PORO", 1, (), Piece.CELLS, None, [ np.float32( np.nan ) ], VTK_FLOAT ), + ( 1, "collocated_nodes", 2, + ( None, None ), Piece.POINTS, None, [ np.int64( -1 ), np.int64( -1 ) ], VTK_ID_TYPE ), # Test fill an attribute with different type of value. - ( 3, "FAULT", 1, (), False, None, [ np.int32( -1 ) ], VTK_INT ), - ( 3, "FAULT", 1, (), False, [ 4 ], [ np.int32( 4 ) ], VTK_INT ), - ( 3, "PORO", 1, (), False, [ 4 ], [ np.float32( 4 ) ], VTK_FLOAT ), - ( 1, "collocated_nodes", 2, ( None, None ), True, [ 4, 4 ], [ np.int64( 4 ), np.int64( 4 ) ], VTK_ID_TYPE ), - ( 3, "CellAttribute", 3, ( "AX1", "AX2", "AX3" ), False, [ 4, 4, 4 ], + ( 3, "FAULT", 1, (), Piece.CELLS, None, [ np.int32( -1 ) ], VTK_INT ), + ( 3, "FAULT", 1, (), Piece.CELLS, [ 4 ], [ np.int32( 4 ) ], VTK_INT ), + ( 3, "PORO", 1, (), Piece.CELLS, [ 4 ], [ np.float32( 4 ) ], VTK_FLOAT ), + ( 1, "collocated_nodes", 2, + ( None, None ), Piece.POINTS, [ 4, 4 ], [ np.int64( 4 ), np.int64( 4 ) ], VTK_ID_TYPE ), + ( 3, "CellAttribute", 3, ( "AX1", "AX2", "AX3" ), Piece.CELLS, [ 4, 4, 4 ], [ np.float64( 4 ), np.float64( 4 ), np.float64( 4 ) ], VTK_DOUBLE ), ] ) def test_fillPartialAttributes( @@ -73,7 +76,7 @@ def test_fillPartialAttributes( attributeName: str, nbComponentsTest: int, componentNamesTest: tuple[ str, ...], - onPoints: bool, + piece: Piece, listValues: Union[ list[ Any ], None ], listValuesTest: list[ Any ], vtkDataTypeTest: int, @@ -83,7 +86,7 @@ def test_fillPartialAttributes( # Fill the attribute in the multiBlockDataSet. assert arrayModifiers.fillPartialAttributes( multiBlockDataSetTest, attributeName, - onPoints=onPoints, + piece=piece, listValues=listValues ) # Get the dataSet where the attribute has been filled. @@ -92,7 +95,7 @@ def test_fillPartialAttributes( # Get the filled attribute. data: Union[ vtkPointData, vtkCellData ] nbElements: int - if onPoints: + if piece == Piece.POINTS: nbElements = dataSet.GetNumberOfPoints() data = dataSet.GetPointData() else: @@ -171,89 +174,80 @@ def test_createEmptyAttribute( @pytest.mark.parametrize( - "attributeName, onPoints", + "attributeName, piece", [ # Test to create a new attribute on points and on cells. - ( "newAttribute", False ), - ( "newAttribute", True ), - # Test to create a new attribute when an attribute with the same name already exist on the opposite piece. - ( "PORO", True ), # Partial attribute on cells already exist. - ( "GLOBAL_IDS_CELLS", True ), # Global attribute on cells already exist. + ( "newAttribute", Piece.CELLS ), + ( "newAttribute", Piece.POINTS ), ] ) def test_createConstantAttributeMultiBlock( dataSetTest: vtkMultiBlockDataSet, attributeName: str, - onPoints: bool, + piece: Piece, ) -> None: """Test creation of constant attribute in multiblock dataset.""" multiBlockDataSetTest: vtkMultiBlockDataSet = dataSetTest( "multiblock" ) values: list[ float ] = [ np.nan ] - assert arrayModifiers.createConstantAttributeMultiBlock( multiBlockDataSetTest, - values, - attributeName, - onPoints=onPoints ) + assert arrayModifiers.createConstantAttributeMultiBlock( multiBlockDataSetTest, values, attributeName, piece=piece ) elementaryBlockIndexes: list[ int ] = getBlockElementIndexesFlatten( multiBlockDataSetTest ) for blockIndex in elementaryBlockIndexes: dataSet: vtkDataSet = vtkDataSet.SafeDownCast( multiBlockDataSetTest.GetDataSet( blockIndex ) ) data: Union[ vtkPointData, vtkCellData ] - data = dataSet.GetPointData() if onPoints else dataSet.GetCellData() + data = dataSet.GetPointData() if piece == Piece.POINTS else dataSet.GetCellData() attributeWellCreated: int = data.HasArray( attributeName ) assert attributeWellCreated == 1 @pytest.mark.parametrize( - "listValues, componentNames, componentNamesTest, onPoints, vtkDataType, vtkDataTypeTest, attributeName", + "listValues, componentNames, componentNamesTest, piece, vtkDataType, vtkDataTypeTest, attributeName", [ # Test attribute names. - ## Test with an attributeName already existing on opposite piece. - ( [ np.float64( 42 ) ], (), (), True, VTK_DOUBLE, VTK_DOUBLE, "CellAttribute" ), - ( [ np.float64( 42 ) ], (), (), False, VTK_DOUBLE, VTK_DOUBLE, "PointAttribute" ), ## Test with a new attributeName on cells and on points. - ( [ np.float32( 42 ) ], (), (), True, VTK_FLOAT, VTK_FLOAT, "newAttribute" ), - ( [ np.float32( 42 ) ], (), (), False, VTK_FLOAT, VTK_FLOAT, "newAttribute" ), + ( [ np.float32( 42 ) ], (), (), Piece.POINTS, VTK_FLOAT, VTK_FLOAT, "newAttribute" ), + ( [ np.float32( 42 ) ], (), (), Piece.CELLS, VTK_FLOAT, VTK_FLOAT, "newAttribute" ), # Test the number of components and their names. - ( [ np.float32( 42 ) ], ( "X" ), (), True, VTK_FLOAT, VTK_FLOAT, "newAttribute" ), + ( [ np.float32( 42 ) ], ( "X" ), (), Piece.POINTS, VTK_FLOAT, VTK_FLOAT, "newAttribute" ), ( [ np.float32( 42 ), np.float32( 42 ) ], ( "X", "Y" ), - ( "X", "Y" ), True, VTK_FLOAT, VTK_FLOAT, "newAttribute" ), + ( "X", "Y" ), Piece.POINTS, VTK_FLOAT, VTK_FLOAT, "newAttribute" ), ( [ np.float32( 42 ), np.float32( 42 ) ], ( "X", "Y", "Z" ), - ( "X", "Y" ), True, VTK_FLOAT, VTK_FLOAT, "newAttribute" ), + ( "X", "Y" ), Piece.POINTS, VTK_FLOAT, VTK_FLOAT, "newAttribute" ), ( [ np.float32( 42 ), np.float32( 42 ) ], (), - ( "Component0", "Component1" ), True, VTK_FLOAT, VTK_FLOAT, "newAttribute" ), + ( "Component0", "Component1" ), Piece.POINTS, VTK_FLOAT, VTK_FLOAT, "newAttribute" ), # Test the type of the values. ## With numpy scalar type. - ( [ np.int8( 42 ) ], (), (), True, None, VTK_SIGNED_CHAR, "newAttribute" ), - ( [ np.int8( 42 ) ], (), (), True, VTK_SIGNED_CHAR, VTK_SIGNED_CHAR, "newAttribute" ), - ( [ np.int16( 42 ) ], (), (), True, None, VTK_SHORT, "newAttribute" ), - ( [ np.int16( 42 ) ], (), (), True, VTK_SHORT, VTK_SHORT, "newAttribute" ), - ( [ np.int32( 42 ) ], (), (), True, None, VTK_INT, "newAttribute" ), - ( [ np.int32( 42 ) ], (), (), True, VTK_INT, VTK_INT, "newAttribute" ), - ( [ np.int64( 42 ) ], (), (), True, None, VTK_LONG_LONG, "newAttribute" ), - ( [ np.int64( 42 ) ], (), (), True, VTK_LONG_LONG, VTK_LONG_LONG, "newAttribute" ), - ( [ np.uint8( 42 ) ], (), (), True, None, VTK_UNSIGNED_CHAR, "newAttribute" ), - ( [ np.uint8( 42 ) ], (), (), True, VTK_UNSIGNED_CHAR, VTK_UNSIGNED_CHAR, "newAttribute" ), - ( [ np.uint16( 42 ) ], (), (), True, None, VTK_UNSIGNED_SHORT, "newAttribute" ), - ( [ np.uint16( 42 ) ], (), (), True, VTK_UNSIGNED_SHORT, VTK_UNSIGNED_SHORT, "newAttribute" ), - ( [ np.uint32( 42 ) ], (), (), True, None, VTK_UNSIGNED_INT, "newAttribute" ), - ( [ np.uint32( 42 ) ], (), (), True, VTK_UNSIGNED_INT, VTK_UNSIGNED_INT, "newAttribute" ), - ( [ np.uint64( 42 ) ], (), (), True, None, VTK_UNSIGNED_LONG_LONG, "newAttribute" ), - ( [ np.uint64( 42 ) ], (), (), True, VTK_UNSIGNED_LONG_LONG, VTK_UNSIGNED_LONG_LONG, "newAttribute" ), - ( [ np.float32( 42 ) ], (), (), True, None, VTK_FLOAT, "newAttribute" ), - ( [ np.float64( 42 ) ], (), (), True, None, VTK_DOUBLE, "newAttribute" ), - ( [ np.float64( 42 ) ], (), (), True, VTK_DOUBLE, VTK_DOUBLE, "newAttribute" ), + ( [ np.int8( 42 ) ], (), (), Piece.POINTS, None, VTK_SIGNED_CHAR, "newAttribute" ), + ( [ np.int8( 42 ) ], (), (), Piece.POINTS, VTK_SIGNED_CHAR, VTK_SIGNED_CHAR, "newAttribute" ), + ( [ np.int16( 42 ) ], (), (), Piece.POINTS, None, VTK_SHORT, "newAttribute" ), + ( [ np.int16( 42 ) ], (), (), Piece.POINTS, VTK_SHORT, VTK_SHORT, "newAttribute" ), + ( [ np.int32( 42 ) ], (), (), Piece.POINTS, None, VTK_INT, "newAttribute" ), + ( [ np.int32( 42 ) ], (), (), Piece.POINTS, VTK_INT, VTK_INT, "newAttribute" ), + ( [ np.int64( 42 ) ], (), (), Piece.POINTS, None, VTK_LONG_LONG, "newAttribute" ), + ( [ np.int64( 42 ) ], (), (), Piece.POINTS, VTK_LONG_LONG, VTK_LONG_LONG, "newAttribute" ), + ( [ np.uint8( 42 ) ], (), (), Piece.POINTS, None, VTK_UNSIGNED_CHAR, "newAttribute" ), + ( [ np.uint8( 42 ) ], (), (), Piece.POINTS, VTK_UNSIGNED_CHAR, VTK_UNSIGNED_CHAR, "newAttribute" ), + ( [ np.uint16( 42 ) ], (), (), Piece.POINTS, None, VTK_UNSIGNED_SHORT, "newAttribute" ), + ( [ np.uint16( 42 ) ], (), (), Piece.POINTS, VTK_UNSIGNED_SHORT, VTK_UNSIGNED_SHORT, "newAttribute" ), + ( [ np.uint32( 42 ) ], (), (), Piece.POINTS, None, VTK_UNSIGNED_INT, "newAttribute" ), + ( [ np.uint32( 42 ) ], (), (), Piece.POINTS, VTK_UNSIGNED_INT, VTK_UNSIGNED_INT, "newAttribute" ), + ( [ np.uint64( 42 ) ], (), (), Piece.POINTS, None, VTK_UNSIGNED_LONG_LONG, "newAttribute" ), + ( [ np.uint64( 42 ) ], (), (), Piece.POINTS, VTK_UNSIGNED_LONG_LONG, VTK_UNSIGNED_LONG_LONG, "newAttribute" ), + ( [ np.float32( 42 ) ], (), (), Piece.POINTS, None, VTK_FLOAT, "newAttribute" ), + ( [ np.float64( 42 ) ], (), (), Piece.POINTS, None, VTK_DOUBLE, "newAttribute" ), + ( [ np.float64( 42 ) ], (), (), Piece.POINTS, VTK_DOUBLE, VTK_DOUBLE, "newAttribute" ), ## With python scalar type. - ( [ 42 ], (), (), True, None, VTK_LONG_LONG, "newAttribute" ), - ( [ 42 ], (), (), True, VTK_LONG_LONG, VTK_LONG_LONG, "newAttribute" ), - ( [ 42. ], (), (), True, None, VTK_DOUBLE, "newAttribute" ), - ( [ 42. ], (), (), True, VTK_DOUBLE, VTK_DOUBLE, "newAttribute" ), + ( [ 42 ], (), (), Piece.POINTS, None, VTK_LONG_LONG, "newAttribute" ), + ( [ 42 ], (), (), Piece.POINTS, VTK_LONG_LONG, VTK_LONG_LONG, "newAttribute" ), + ( [ 42. ], (), (), Piece.POINTS, None, VTK_DOUBLE, "newAttribute" ), + ( [ 42. ], (), (), Piece.POINTS, VTK_DOUBLE, VTK_DOUBLE, "newAttribute" ), ] ) def test_createConstantAttributeDataSet( dataSetTest: vtkDataSet, listValues: list[ Any ], componentNames: tuple[ str, ...], componentNamesTest: tuple[ str, ...], - onPoints: bool, + piece: Piece, vtkDataType: Union[ int, Any ], vtkDataTypeTest: int, attributeName: str, @@ -262,13 +256,13 @@ def test_createConstantAttributeDataSet( dataSet: vtkDataSet = dataSetTest( "dataset" ) # Create the new constant attribute in the dataSet. - assert arrayModifiers.createConstantAttributeDataSet( dataSet, listValues, attributeName, componentNames, onPoints, + assert arrayModifiers.createConstantAttributeDataSet( dataSet, listValues, attributeName, componentNames, piece, vtkDataType ) # Get the created attribute. data: Union[ vtkPointData, vtkCellData ] nbElements: int - if onPoints: + if piece == Piece.POINTS: data = dataSet.GetPointData() nbElements = dataSet.GetNumberOfPoints() else: @@ -302,53 +296,53 @@ def test_createConstantAttributeDataSet( @pytest.mark.parametrize( - "componentNames, componentNamesTest, onPoints, vtkDataType, vtkDataTypeTest, valueType, attributeName", + "componentNames, componentNamesTest, piece, vtkDataType, vtkDataTypeTest, valueType, attributeName", [ # Test attribute names. - ## Test with an attributeName already existing on opposite piece. - ( (), (), True, VTK_DOUBLE, VTK_DOUBLE, "float64", "CellAttribute" ), - ( (), (), False, VTK_DOUBLE, VTK_DOUBLE, "float64", "PointAttribute" ), ## Test with a new attributeName on cells and on points. - ( (), (), True, VTK_FLOAT, VTK_FLOAT, "float32", "newAttribute" ), - ( (), (), False, VTK_FLOAT, VTK_FLOAT, "float32", "newAttribute" ), + ( (), (), Piece.POINTS, VTK_FLOAT, VTK_FLOAT, "float32", "newAttribute" ), + ( (), (), Piece.CELLS, VTK_FLOAT, VTK_FLOAT, "float32", "newAttribute" ), + ## Test with an attributeName already existing on opposite piece. + ( (), (), Piece.POINTS, VTK_DOUBLE, VTK_DOUBLE, "float64", "CellAttribute" ), + ( (), (), Piece.CELLS, VTK_DOUBLE, VTK_DOUBLE, "float64", "PointAttribute" ), # Test the number of components and their names. - ( ( "X" ), (), True, VTK_FLOAT, VTK_FLOAT, "float32", "newAttribute" ), - ( ( "X", "Y" ), ( "X", "Y" ), True, VTK_FLOAT, VTK_FLOAT, "float32", "newAttribute" ), - ( ( "X", "Y", "Z" ), ( "X", "Y" ), True, VTK_FLOAT, VTK_FLOAT, "float32", "newAttribute" ), - ( (), ( "Component0", "Component1" ), True, VTK_FLOAT, VTK_FLOAT, "float32", "newAttribute" ), + ( ( "X" ), (), Piece.POINTS, VTK_FLOAT, VTK_FLOAT, "float32", "newAttribute" ), + ( ( "X", "Y" ), ( "X", "Y" ), Piece.POINTS, VTK_FLOAT, VTK_FLOAT, "float32", "newAttribute" ), + ( ( "X", "Y", "Z" ), ( "X", "Y" ), Piece.POINTS, VTK_FLOAT, VTK_FLOAT, "float32", "newAttribute" ), + ( (), ( "Component0", "Component1" ), Piece.POINTS, VTK_FLOAT, VTK_FLOAT, "float32", "newAttribute" ), # Test the type of the values. ## With numpy scalar type. - ( (), (), True, None, VTK_SIGNED_CHAR, "int8", "newAttribute" ), - ( (), (), True, VTK_SIGNED_CHAR, VTK_SIGNED_CHAR, "int8", "newAttribute" ), - ( (), (), True, None, VTK_SHORT, "int16", "newAttribute" ), - ( (), (), True, VTK_SHORT, VTK_SHORT, "int16", "newAttribute" ), - ( (), (), True, None, VTK_INT, "int32", "newAttribute" ), - ( (), (), True, VTK_INT, VTK_INT, "int32", "newAttribute" ), - ( (), (), True, None, VTK_LONG_LONG, "int64", "newAttribute" ), - ( (), (), True, VTK_LONG_LONG, VTK_LONG_LONG, "int64", "newAttribute" ), - ( (), (), True, None, VTK_UNSIGNED_CHAR, "uint8", "newAttribute" ), - ( (), (), True, VTK_UNSIGNED_CHAR, VTK_UNSIGNED_CHAR, "uint8", "newAttribute" ), - ( (), (), True, None, VTK_UNSIGNED_SHORT, "uint16", "newAttribute" ), - ( (), (), True, VTK_UNSIGNED_SHORT, VTK_UNSIGNED_SHORT, "uint16", "newAttribute" ), - ( (), (), True, None, VTK_UNSIGNED_INT, "uint32", "newAttribute" ), - ( (), (), True, VTK_UNSIGNED_INT, VTK_UNSIGNED_INT, "uint32", "newAttribute" ), - ( (), (), True, None, VTK_UNSIGNED_LONG_LONG, "uint64", "newAttribute" ), - ( (), (), True, VTK_UNSIGNED_LONG_LONG, VTK_UNSIGNED_LONG_LONG, "uint64", "newAttribute" ), - ( (), (), True, None, VTK_FLOAT, "float32", "newAttribute" ), - ( (), (), True, None, VTK_DOUBLE, "float64", "newAttribute" ), - ( (), (), True, VTK_DOUBLE, VTK_DOUBLE, "float64", "newAttribute" ), + ( (), (), Piece.POINTS, None, VTK_SIGNED_CHAR, "int8", "newAttribute" ), + ( (), (), Piece.POINTS, VTK_SIGNED_CHAR, VTK_SIGNED_CHAR, "int8", "newAttribute" ), + ( (), (), Piece.POINTS, None, VTK_SHORT, "int16", "newAttribute" ), + ( (), (), Piece.POINTS, VTK_SHORT, VTK_SHORT, "int16", "newAttribute" ), + ( (), (), Piece.POINTS, None, VTK_INT, "int32", "newAttribute" ), + ( (), (), Piece.POINTS, VTK_INT, VTK_INT, "int32", "newAttribute" ), + ( (), (), Piece.POINTS, None, VTK_LONG_LONG, "int64", "newAttribute" ), + ( (), (), Piece.POINTS, VTK_LONG_LONG, VTK_LONG_LONG, "int64", "newAttribute" ), + ( (), (), Piece.POINTS, None, VTK_UNSIGNED_CHAR, "uint8", "newAttribute" ), + ( (), (), Piece.POINTS, VTK_UNSIGNED_CHAR, VTK_UNSIGNED_CHAR, "uint8", "newAttribute" ), + ( (), (), Piece.POINTS, None, VTK_UNSIGNED_SHORT, "uint16", "newAttribute" ), + ( (), (), Piece.POINTS, VTK_UNSIGNED_SHORT, VTK_UNSIGNED_SHORT, "uint16", "newAttribute" ), + ( (), (), Piece.POINTS, None, VTK_UNSIGNED_INT, "uint32", "newAttribute" ), + ( (), (), Piece.POINTS, VTK_UNSIGNED_INT, VTK_UNSIGNED_INT, "uint32", "newAttribute" ), + ( (), (), Piece.POINTS, None, VTK_UNSIGNED_LONG_LONG, "uint64", "newAttribute" ), + ( (), (), Piece.POINTS, VTK_UNSIGNED_LONG_LONG, VTK_UNSIGNED_LONG_LONG, "uint64", "newAttribute" ), + ( (), (), Piece.POINTS, None, VTK_FLOAT, "float32", "newAttribute" ), + ( (), (), Piece.POINTS, None, VTK_DOUBLE, "float64", "newAttribute" ), + ( (), (), Piece.POINTS, VTK_DOUBLE, VTK_DOUBLE, "float64", "newAttribute" ), ## With python scalar type. - ( (), (), True, None, VTK_LONG_LONG, "int", "newAttribute" ), - ( (), (), True, VTK_LONG_LONG, VTK_LONG_LONG, "int", "newAttribute" ), - ( (), (), True, None, VTK_DOUBLE, "float", "newAttribute" ), - ( (), (), True, VTK_DOUBLE, VTK_DOUBLE, "float", "newAttribute" ), + ( (), (), Piece.POINTS, None, VTK_LONG_LONG, "int", "newAttribute" ), + ( (), (), Piece.POINTS, VTK_LONG_LONG, VTK_LONG_LONG, "int", "newAttribute" ), + ( (), (), Piece.POINTS, None, VTK_DOUBLE, "float", "newAttribute" ), + ( (), (), Piece.POINTS, VTK_DOUBLE, VTK_DOUBLE, "float", "newAttribute" ), ] ) def test_createAttribute( dataSetTest: vtkDataSet, getArrayWithSpeTypeValue: npt.NDArray[ Any ], componentNames: tuple[ str, ...], componentNamesTest: tuple[ str, ...], - onPoints: bool, + piece: Piece, vtkDataType: int, vtkDataTypeTest: int, valueType: str, @@ -358,16 +352,16 @@ def test_createAttribute( dataSet: vtkDataSet = dataSetTest( "dataset" ) # Get a array with random values of a given type. - nbElements: int = dataSet.GetNumberOfPoints() if onPoints else dataSet.GetNumberOfCells() + nbElements: int = dataSet.GetNumberOfPoints() if piece == Piece.POINTS else dataSet.GetNumberOfCells() nbComponentsTest: int = 1 if len( componentNamesTest ) == 0 else len( componentNamesTest ) npArrayTest: npt.NDArray[ Any ] = getArrayWithSpeTypeValue( nbComponentsTest, nbElements, valueType ) # Create the new attribute in the dataSet. - assert arrayModifiers.createAttribute( dataSet, npArrayTest, attributeName, componentNames, onPoints, vtkDataType ) + assert arrayModifiers.createAttribute( dataSet, npArrayTest, attributeName, componentNames, piece, vtkDataType ) # Get the created attribute. data: Union[ vtkPointData, vtkCellData ] - data = dataSet.GetPointData() if onPoints else dataSet.GetCellData() + data = dataSet.GetPointData() if piece == Piece.POINTS else dataSet.GetCellData() attributeCreated: vtkDataArray = data.GetArray( attributeName ) # Test the number of components and their names if multiple. @@ -388,20 +382,20 @@ def test_createAttribute( @pytest.mark.parametrize( - "attributeNameFrom, attributeNameTo, onPoints", + "attributeNameFrom, attributeNameTo, piece", [ # Test with global attributes. - ( "GLOBAL_IDS_POINTS", "GLOBAL_IDS_POINTS_To", True ), - ( "GLOBAL_IDS_CELLS", 'GLOBAL_IDS_CELLS_To', False ), + ( "GLOBAL_IDS_POINTS", "GLOBAL_IDS_POINTS_To", Piece.POINTS ), + ( "GLOBAL_IDS_CELLS", 'GLOBAL_IDS_CELLS_To', Piece.CELLS ), # Test with partial attributes. - ( "CellAttribute", "CellAttributeTo", False ), - ( "PointAttribute", "PointAttributeTo", True ), + ( "CellAttribute", "CellAttributeTo", Piece.CELLS ), + ( "PointAttribute", "PointAttributeTo", Piece.POINTS ), ] ) def test_copyAttribute( dataSetTest: vtkMultiBlockDataSet, attributeNameFrom: str, attributeNameTo: str, - onPoints: bool, + piece: Piece, ) -> None: """Test copy of cell attribute from one multiblock to another.""" multiBlockDataSetFrom: vtkMultiBlockDataSet = dataSetTest( "multiblock" ) @@ -409,7 +403,7 @@ def test_copyAttribute( # Copy the attribute from the multiBlockDataSetFrom to the multiBlockDataSetTo. assert arrayModifiers.copyAttribute( multiBlockDataSetFrom, multiBlockDataSetTo, attributeNameFrom, attributeNameTo, - onPoints ) + piece ) # Parse the two multiBlockDataSet and test if the attribute has been copied. elementaryBlockIndexes: list[ int ] = getBlockElementIndexesFlatten( multiBlockDataSetFrom ) @@ -418,7 +412,7 @@ def test_copyAttribute( dataSetTo: vtkDataSet = vtkDataSet.SafeDownCast( multiBlockDataSetTo.GetDataSet( blockIndex ) ) dataFrom: Union[ vtkPointData, vtkCellData ] dataTo: Union[ vtkPointData, vtkCellData ] - if onPoints: + if piece == Piece.POINTS: dataFrom = dataSetFrom.GetPointData() dataTo = dataSetTo.GetPointData() else: @@ -430,27 +424,27 @@ def test_copyAttribute( assert attributeExistCopied == attributeExistTest -@pytest.mark.parametrize( "attributeNameFrom, attributeNameTo, onPoints", [ - ( "CellAttribute", "CellAttributeTo", False ), - ( "PointAttribute", "PointAttributeTo", True ), +@pytest.mark.parametrize( "attributeNameFrom, attributeNameTo, piece", [ + ( "CellAttribute", "CellAttributeTo", Piece.CELLS ), + ( "PointAttribute", "PointAttributeTo", Piece.POINTS ), ] ) def test_copyAttributeDataSet( dataSetTest: vtkDataSet, attributeNameFrom: str, attributeNameTo: str, - onPoints: bool, + piece: Piece, ) -> None: """Test copy of an attribute from one dataset to another.""" dataSetFrom: vtkDataSet = dataSetTest( "dataset" ) dataSetTo: vtkDataSet = dataSetTest( "emptydataset" ) # Copy the attribute from the dataSetFrom to the dataSetTo. - assert arrayModifiers.copyAttributeDataSet( dataSetFrom, dataSetTo, attributeNameFrom, attributeNameTo, onPoints ) + assert arrayModifiers.copyAttributeDataSet( dataSetFrom, dataSetTo, attributeNameFrom, attributeNameTo, piece ) # Get the tested attribute and its copy. dataFrom: Union[ vtkPointData, vtkCellData ] dataTo: Union[ vtkPointData, vtkCellData ] - if onPoints: + if piece == Piece.POINTS: dataFrom = dataSetFrom.GetPointData() dataTo = dataSetTo.GetPointData() else: @@ -481,12 +475,12 @@ def test_copyAttributeDataSet( assert vtkDataTypeCopied == vtkDataTypeTest -@pytest.mark.parametrize( "meshFromName, meshToName, attributeName, onPoints, defaultValueTest", [ - ( "fracture", "emptyFracture", "collocated_nodes", True, [ -1, -1 ] ), - ( "multiblock", "emptyFracture", "FAULT", False, -1 ), - ( "multiblock", "emptymultiblock", "FAULT", False, -1 ), - ( "dataset", "emptymultiblock", "FAULT", False, -1 ), - ( "dataset", "emptydataset", "FAULT", False, -1 ), +@pytest.mark.parametrize( "meshFromName, meshToName, attributeName, piece, defaultValueTest", [ + ( "fracture", "emptyFracture", "collocated_nodes", Piece.POINTS, [ -1, -1 ] ), + ( "multiblock", "emptyFracture", "FAULT", Piece.CELLS, -1 ), + ( "multiblock", "emptymultiblock", "FAULT", Piece.CELLS, -1 ), + ( "dataset", "emptymultiblock", "FAULT", Piece.CELLS, -1 ), + ( "dataset", "emptydataset", "FAULT", Piece.CELLS, -1 ), ] ) def test_transferAttributeWithElementMap( dataSetTest: Any, @@ -494,7 +488,7 @@ def test_transferAttributeWithElementMap( meshFromName: str, meshToName: str, attributeName: str, - onPoints: bool, + piece: Piece, defaultValueTest: Any, ) -> None: """Test to transfer attributes from the source mesh to the final mesh using a map of points/cells.""" @@ -503,17 +497,17 @@ def test_transferAttributeWithElementMap( arrayModifiers.fillAllPartialAttributes( meshFrom ) meshTo: Union[ vtkMultiBlockDataSet, vtkDataSet ] = dataSetTest( meshToName ) - elementMap: dict[ int, npt.NDArray[ np.int64 ] ] = getElementMap( meshFromName, meshToName, onPoints ) + elementMap: dict[ int, npt.NDArray[ np.int64 ] ] = getElementMap( meshFromName, meshToName, piece ) - assert arrayModifiers.transferAttributeWithElementMap( meshFrom, meshTo, elementMap, attributeName, onPoints ) + assert arrayModifiers.transferAttributeWithElementMap( meshFrom, meshTo, elementMap, attributeName, piece ) for flatIdDataSetTo in elementMap: dataTo: Union[ vtkPointData, vtkCellData ] if isinstance( meshTo, vtkDataSet ): - dataTo = meshTo.GetPointData() if onPoints else meshTo.GetCellData() + dataTo = meshTo.GetPointData() if piece == Piece.POINTS else meshTo.GetCellData() elif isinstance( meshTo, vtkMultiBlockDataSet ): dataSetTo: vtkDataSet = vtkDataSet.SafeDownCast( meshTo.GetDataSet( flatIdDataSetTo ) ) - dataTo = dataSetTo.GetPointData() if onPoints else dataSetTo.GetCellData() + dataTo = dataSetTo.GetPointData() if piece == Piece.POINTS else dataSetTo.GetCellData() arrayTo: npt.NDArray[ Any ] = vnp.vtk_to_numpy( dataTo.GetArray( attributeName ) ) for idElementTo in range( len( arrayTo ) ): @@ -524,24 +518,24 @@ def test_transferAttributeWithElementMap( else: dataFrom: Union[ vtkPointData, vtkCellData ] if isinstance( meshFrom, vtkDataSet ): - dataFrom = meshFrom.GetPointData() if onPoints else meshFrom.GetCellData() + dataFrom = meshFrom.GetPointData() if piece == Piece.POINTS else meshFrom.GetCellData() elif isinstance( meshFrom, vtkMultiBlockDataSet ): flatIdDataSetFrom: int = int( elementMap[ flatIdDataSetTo ][ idElementTo ][ 0 ] ) dataSetFrom: vtkDataSet = vtkDataSet.SafeDownCast( meshFrom.GetDataSet( flatIdDataSetFrom ) ) - dataFrom = dataSetFrom.GetPointData() if onPoints else dataSetFrom.GetCellData() + dataFrom = dataSetFrom.GetPointData() if piece == Piece.POINTS else dataSetFrom.GetCellData() arrayFrom: npt.NDArray[ Any ] = vnp.vtk_to_numpy( dataFrom.GetArray( attributeName ) ) assert np.all( arrayTo[ idElementTo ] == arrayFrom[ idElementFrom ] ) -@pytest.mark.parametrize( "attributeName, onPoints", [ - ( "CellAttribute", False ), - ( "PointAttribute", True ), +@pytest.mark.parametrize( "attributeName, piece", [ + ( "CellAttribute", Piece.CELLS ), + ( "PointAttribute", Piece.POINTS ), ] ) def test_renameAttributeMultiblock( dataSetTest: vtkMultiBlockDataSet, attributeName: str, - onPoints: bool, + piece: Piece, ) -> None: """Test renaming attribute in a multiblock dataset.""" vtkMultiBlockDataSetTest: vtkMultiBlockDataSet = dataSetTest( "multiblock" ) @@ -550,11 +544,11 @@ def test_renameAttributeMultiblock( vtkMultiBlockDataSetTest, attributeName, newAttributeName, - onPoints, + piece, ) block: vtkDataSet = vtkDataSet.SafeDownCast( vtkMultiBlockDataSetTest.GetDataSet( 1 ) ) data: Union[ vtkPointData, vtkCellData ] - if onPoints: + if piece == Piece.POINTS: data = block.GetPointData() assert data.HasArray( attributeName ) == 0 assert data.HasArray( newAttributeName ) == 1 @@ -565,11 +559,12 @@ def test_renameAttributeMultiblock( assert data.HasArray( newAttributeName ) == 1 -@pytest.mark.parametrize( "attributeName, onPoints", [ ( "CellAttribute", False ), ( "PointAttribute", True ) ] ) +@pytest.mark.parametrize( "attributeName, piece", [ ( "CellAttribute", Piece.CELLS ), + ( "PointAttribute", Piece.POINTS ) ] ) def test_renameAttributeDataSet( dataSetTest: vtkDataSet, attributeName: str, - onPoints: bool, + piece: Piece, ) -> None: """Test renaming an attribute in a dataset.""" vtkDataSetTest: vtkDataSet = dataSetTest( "dataset" ) @@ -577,8 +572,8 @@ def test_renameAttributeDataSet( arrayModifiers.renameAttribute( object=vtkDataSetTest, attributeName=attributeName, newAttributeName=newAttributeName, - onPoints=onPoints ) - if onPoints: + piece=piece ) + if piece == Piece.POINTS: assert vtkDataSetTest.GetPointData().HasArray( attributeName ) == 0 assert vtkDataSetTest.GetPointData().HasArray( newAttributeName ) == 1 diff --git a/geos-processing/src/geos/processing/generic_processing_tools/AttributeMapping.py b/geos-processing/src/geos/processing/generic_processing_tools/AttributeMapping.py index 598eedc0a..4fc389c85 100644 --- a/geos-processing/src/geos/processing/generic_processing_tools/AttributeMapping.py +++ b/geos-processing/src/geos/processing/generic_processing_tools/AttributeMapping.py @@ -10,6 +10,7 @@ from geos.mesh.utils.arrayModifiers import transferAttributeWithElementMap from geos.mesh.utils.arrayHelpers import ( computeElementMapping, getAttributeSet, isAttributeGlobal ) from geos.utils.Logger import ( Logger, getLogger ) +from geos.utils.pieceEnum import Piece __doc__ = """ AttributeMapping is a vtk filter that transfers global attributes from a source mesh to a final mesh with same @@ -41,7 +42,7 @@ meshTo: Union[ vtkDataSet, vtkMultiBlockDataSet ] attributeNames: set[ str ] # Optional inputs. - onPoints: bool # defaults to False + piece: Piece # defaults to Piece.CELLS speHandler: bool # defaults to False # Instantiate the filter @@ -49,7 +50,7 @@ meshFrom, meshTo, attributeNames, - onPoints, + piece, speHandler, ) @@ -77,7 +78,7 @@ def __init__( meshFrom: Union[ vtkDataSet, vtkMultiBlockDataSet ], meshTo: Union[ vtkDataSet, vtkMultiBlockDataSet ], attributeNames: set[ str ], - onPoints: bool = False, + piece: Piece = Piece.CELLS, speHandler: bool = False, ) -> None: """Transfer global attributes from a source mesh to a final mesh. @@ -88,22 +89,20 @@ def __init__( meshFrom (Union[vtkDataSet, vtkMultiBlockDataSet]): The source mesh with attributes to transfer. meshTo (Union[vtkDataSet, vtkMultiBlockDataSet]): The final mesh where to transfer attributes. attributeNames (set[str]): Names of the attributes to transfer. - onPoints (bool): True if attributes are on points, False if they are on cells. - Defaults to False. + piece (Piece): The piece of the attribute. + Defaults to Piece.CELLS. speHandler (bool, optional): True to use a specific handler, False to use the internal handler. Defaults to False. """ self.meshFrom: Union[ vtkDataSet, vtkMultiBlockDataSet ] = meshFrom self.meshTo: Union[ vtkDataSet, vtkMultiBlockDataSet ] = meshTo self.attributeNames: set[ str ] = attributeNames - self.onPoints: bool = onPoints - # TODO/refact (@RomainBaville) make it an enum - self.piece: str = "points" if self.onPoints else "cells" + self.piece: Piece = piece - # cell map + # Element map self.ElementMap: dict[ int, npt.NDArray[ np.int64 ] ] = {} - # Logger. + # Logger self.logger: Logger if not speHandler: self.logger = getLogger( loggerTitle, True ) @@ -149,43 +148,42 @@ def applyFilter( self: Self ) -> None: self.logger.info( f"Apply filter { self.logger.name }." ) if len( self.attributeNames ) == 0: - raise ValueError( f"Please enter at least one { self.piece } attribute to transfer." ) + raise ValueError( "Please enter at least one attribute to transfer." ) - attributesInMeshFrom: set[ str ] = getAttributeSet( self.meshFrom, self.onPoints ) + attributesInMeshFrom: set[ str ] = getAttributeSet( self.meshFrom, self.piece ) wrongAttributeNames: set[ str ] = self.attributeNames.difference( attributesInMeshFrom ) if len( wrongAttributeNames ) > 0: - raise AttributeError( - f"The { self.piece } attributes { wrongAttributeNames } are not present in the source mesh." ) + raise AttributeError( f"The attributes { wrongAttributeNames } are not present in the source mesh." ) - attributesInMeshTo: set[ str ] = getAttributeSet( self.meshTo, self.onPoints ) + attributesInMeshTo: set[ str ] = getAttributeSet( self.meshTo, self.piece ) attributesAlreadyInMeshTo: set[ str ] = self.attributeNames.intersection( attributesInMeshTo ) if len( attributesAlreadyInMeshTo ) > 0: raise AttributeError( - f"The { self.piece } attributes { attributesAlreadyInMeshTo } are already present in the final mesh." ) + f"The attributes { attributesAlreadyInMeshTo } are already present in the final mesh." ) if isinstance( self.meshFrom, vtkMultiBlockDataSet ): partialAttributes: list[ str ] = [] for attributeName in self.attributeNames: - if not isAttributeGlobal( self.meshFrom, attributeName, self.onPoints ): + if not isAttributeGlobal( self.meshFrom, attributeName, self.piece ): partialAttributes.append( attributeName ) if len( partialAttributes ) > 0: raise AttributeError( - f"All { self.piece } attributes to transfer must be global, { partialAttributes } are partials." ) + f"All attributes to transfer must be global, { partialAttributes } are partials." ) - self.ElementMap = computeElementMapping( self.meshFrom, self.meshTo, self.onPoints ) + self.ElementMap = computeElementMapping( self.meshFrom, self.meshTo, self.piece ) sharedElement: bool = False for key in self.ElementMap: if np.any( self.ElementMap[ key ] > -1 ): sharedElement = True if not sharedElement: - raise ValueError( f"The two meshes do not have any shared { self.piece }." ) + raise ValueError( f"The two meshes do not have any shared { self.piece.value }." ) for attributeName in self.attributeNames: # TODO:: Modify arrayModifiers function to raise error. if not transferAttributeWithElementMap( self.meshFrom, self.meshTo, self.ElementMap, attributeName, - self.onPoints, self.logger ): + self.piece, self.logger ): raise ValueError( f"Fail to transfer the attribute { attributeName }." ) # Log the output message. @@ -197,5 +195,5 @@ def _logOutputMessage( self: Self ) -> None: """Create and log result messages of the filter.""" self.logger.info( f"The filter { self.logger.name } succeeded." ) self.logger.info( - f"The { self.piece } attributes { self.attributeNames } have been transferred from the source mesh to the final mesh with the { self.piece } mapping." + f"The attributes { self.attributeNames } have been transferred from the source mesh to the final mesh with the { self.piece.value } mapping." ) 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 aa3dd5e0c..4dca5cd89 100644 --- a/geos-processing/src/geos/processing/generic_processing_tools/CreateConstantAttributePerRegion.py +++ b/geos-processing/src/geos/processing/generic_processing_tools/CreateConstantAttributePerRegion.py @@ -11,6 +11,7 @@ import vtkmodules.util.numpy_support as vnp from vtkmodules.vtkCommonDataModel import vtkMultiBlockDataSet, vtkDataSet +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, @@ -116,9 +117,7 @@ def __init__( # Region attribute settings. self.regionName: str = regionName self.dictRegionValues: dict[ Any, Any ] = dictRegionValues - self.onPoints: Union[ None, bool ] - self.onBoth: bool - self.onPoints, self.onBoth = getAttributePieceInfo( self.mesh, self.regionName ) + self.piece: Piece = getAttributePieceInfo( self.mesh, self.regionName ) # Check if the new component have default values (information for the output message). self.useDefaultValue: bool = False @@ -165,15 +164,15 @@ def applyFilter( self: Self ) -> None: self.logger.addHandler( self.counter ) # Check the validity of the attribute region. - if self.onPoints is None: + if self.piece == Piece.NONE: raise AttributeError( f"The attribute { self.regionName } is not in the mesh." ) - if self.onBoth: + if self.piece == Piece.BOTH: raise AttributeError( f"There are two attributes named { self.regionName }, one on points and the other on cells. The region attribute must be unique." ) - nbComponentsRegion: int = getNumberOfComponents( self.mesh, self.regionName, self.onPoints ) + nbComponentsRegion: int = getNumberOfComponents( self.mesh, self.regionName, self.piece ) if nbComponentsRegion != 1: raise AttributeError( f"The region attribute { self.regionName } has to many components, one is requires." ) @@ -192,11 +191,11 @@ def applyFilter( self: Self ) -> None: newArray: npt.NDArray[ Any ] if isinstance( self.mesh, vtkMultiBlockDataSet ): # Check if the attribute region is global. - if not isAttributeGlobal( self.mesh, self.regionName, self.onPoints ): + 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.onPoints ) + self.piece ) if len( validIndexes ) == 0: if len( self.dictRegionValues ) == 0: self.logger.warning( "No region index entered." ) @@ -208,7 +207,7 @@ def applyFilter( self: Self ) -> None: self.defaultValue, self.newAttributeName, componentNames=self.componentNames, - onPoints=self.onPoints, + piece=self.piece, logger=self.logger ): raise ValueError( f"Something went wrong with the creation of the attribute { self.newAttributeName }." ) @@ -223,20 +222,20 @@ def applyFilter( self: Self ) -> None: for flatIdDataSet in listFlatIdDataSet: dataSet: vtkDataSet = vtkDataSet.SafeDownCast( self.mesh.GetDataSet( flatIdDataSet ) ) - regionArray = getArrayInObject( dataSet, self.regionName, self.onPoints ) + regionArray = getArrayInObject( dataSet, self.regionName, self.piece ) newArray = self._createArrayFromRegionArrayWithValueMap( regionArray ) if not createAttribute( dataSet, newArray, self.newAttributeName, componentNames=self.componentNames, - onPoints=self.onPoints, + piece=self.piece, logger=self.logger ): raise ValueError( f"Something went wrong with the creation of the attribute { self.newAttributeName }." ) else: validIndexes, invalidIndexes = checkValidValuesInDataSet( self.mesh, self.regionName, listIndexes, - self.onPoints ) + self.piece ) if len( validIndexes ) == 0: if len( self.dictRegionValues ) == 0: self.logger.warning( "No region index entered." ) @@ -248,7 +247,7 @@ def applyFilter( self: Self ) -> None: self.defaultValue, self.newAttributeName, componentNames=self.componentNames, - onPoints=self.onPoints, + piece=self.piece, logger=self.logger ): raise ValueError( f"Something went wrong with the creation of the attribute { self.newAttributeName }." ) @@ -258,13 +257,13 @@ def applyFilter( self: Self ) -> None: self.logger.warning( f"The region indexes { invalidIndexes } are not in the region attribute { self.regionName }." ) - regionArray = getArrayInObject( self.mesh, self.regionName, self.onPoints ) + regionArray = getArrayInObject( self.mesh, self.regionName, self.piece ) newArray = self._createArrayFromRegionArrayWithValueMap( regionArray ) if not createAttribute( self.mesh, newArray, self.newAttributeName, componentNames=self.componentNames, - onPoints=self.onPoints, + piece=self.piece, logger=self.logger ): raise ValueError( f"Something went wrong with the creation of the attribute { self.newAttributeName }." ) @@ -282,7 +281,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.onPoints ) + regionVtkType: int = getVtkDataTypeInObject( self.mesh, self.regionName, self.piece ) regionNpType: type = dictType[ regionVtkType ] # Set the correct type of values and region index. @@ -356,11 +355,10 @@ def _logOutputMessage( self: Self, trueIndexes: list[ Any ] ) -> None: # Info about the created attribute. # The piece where the attribute is created. - piece: str = "points" if self.onPoints else "cells" - self.logger.info( f"The new attribute { self.newAttributeName } is created on { piece }." ) + self.logger.info( f"The new attribute { self.newAttributeName } is created on { self.piece.value }." ) # The number of component and they names if multiple. - componentNamesCreated: tuple[ str, ...] = getComponentNames( self.mesh, self.newAttributeName, self.onPoints ) + componentNamesCreated: tuple[ str, ...] = getComponentNames( self.mesh, self.newAttributeName, self.piece ) if self.nbComponents > 1: messComponent: str = ( f"The new attribute { self.newAttributeName } has { self.nbComponents } components" f" named { componentNamesCreated }." ) diff --git a/geos-processing/src/geos/processing/generic_processing_tools/FillPartialArrays.py b/geos-processing/src/geos/processing/generic_processing_tools/FillPartialArrays.py index 2851d0337..5c5925482 100644 --- a/geos-processing/src/geos/processing/generic_processing_tools/FillPartialArrays.py +++ b/geos-processing/src/geos/processing/generic_processing_tools/FillPartialArrays.py @@ -5,6 +5,7 @@ from typing_extensions import Self from typing import Union, Any +from geos.utils.pieceEnum import Piece from geos.utils.Logger import ( Logger, getLogger ) from geos.mesh.utils.arrayModifiers import fillPartialAttributes from geos.mesh.utils.arrayHelpers import getAttributePieceInfo @@ -120,22 +121,19 @@ def applyFilter( self: Self ) -> None: ValueError: Error during the filling of the attribute. """ self.logger.info( f"Apply filter { self.logger.name }." ) - - onPoints: Union[ None, bool ] - onBoth: bool + piece: Piece for attributeName in self.dictAttributesValues: - onPoints, onBoth = getAttributePieceInfo( self.multiBlockDataSet, attributeName ) - if onPoints is None: + piece = getAttributePieceInfo( self.multiBlockDataSet, attributeName ) + if piece == Piece.NONE: raise AttributeError( f"The attribute { attributeName } is not in the mesh." ) - - if onBoth: + elif piece == Piece.BOTH: raise AttributeError( f"There is two attribute named { attributeName }, one on points and the other on cells. The attribute name must be unique." ) if not fillPartialAttributes( self.multiBlockDataSet, attributeName, - onPoints=onPoints, + piece=piece, listValues=self.dictAttributesValues[ attributeName ], logger=self.logger ): raise ValueError( "Something went wrong with the filling of partial attributes" ) diff --git a/geos-processing/src/geos/processing/post_processing/GeomechanicsCalculator.py b/geos-processing/src/geos/processing/post_processing/GeomechanicsCalculator.py index ff9a0d88d..6e4c36dc4 100644 --- a/geos-processing/src/geos/processing/post_processing/GeomechanicsCalculator.py +++ b/geos-processing/src/geos/processing/post_processing/GeomechanicsCalculator.py @@ -15,6 +15,7 @@ from geos.mesh.utils.arrayModifiers import createAttribute from geos.mesh.utils.arrayHelpers import ( getArrayInObject, isAttributeInObject ) +from geos.utils.pieceEnum import Piece from geos.utils.Logger import ( Logger, getLogger ) from geos.utils.GeosOutputsConstants import ( AttributeEnum, ComponentNameEnum, GeosMeshOutputsEnum, PostProcessingOutputsEnum ) @@ -729,7 +730,7 @@ def applyFilter( self: Self ) -> None: # Create an attribute on the mesh for each geomechanics properties computed: for attribute in self._attributesToCreate: attributeName: str = attribute.attributeName - onPoints: bool = attribute.isOnPoints + piece: Piece = attribute.piece array: npt.NDArray[ np.float64 ] | None if attribute in ELASTIC_MODULI: array = self._elasticModuli.getElasticModulusValue( attributeName ) @@ -741,12 +742,8 @@ def applyFilter( self: Self ) -> None: if attribute.nbComponent == 6: componentNames = ComponentNameEnum.XYZ.value - if not createAttribute( self.output, - array, - attributeName, - componentNames=componentNames, - onPoints=onPoints, - logger=self.logger ): + if not createAttribute( + self.output, array, attributeName, componentNames=componentNames, piece=piece, logger=self.logger ): raise ValueError( f"Something went wrong during the creation of the attribute { attributeName }." ) self.logger.info( "All the geomechanics properties have been added to the mesh." ) @@ -805,11 +802,11 @@ def _checkMandatoryProperties( self: Self ) -> None: mess: str for elasticModulus in ELASTIC_MODULI: elasticModulusName: str = elasticModulus.attributeName - elasticModulusOnPoints: bool = elasticModulus.isOnPoints - if isAttributeInObject( self.output, elasticModulusName, elasticModulusOnPoints ): + elasticModulusPiece: Piece = elasticModulus.piece + if isAttributeInObject( self.output, elasticModulusName, elasticModulusPiece ): self._elasticModuli.setElasticModulusValue( elasticModulus.attributeName, - getArrayInObject( self.output, elasticModulusName, elasticModulusOnPoints ) ) + getArrayInObject( self.output, elasticModulusName, elasticModulusPiece ) ) # Check the presence of the elastic moduli at the current time. self.computeYoungPoisson: bool @@ -854,14 +851,14 @@ def _checkMandatoryProperties( self: Self ) -> None: # Check the presence of the other mandatory properties for mandatoryAttribute in MANDATORY_PROPERTIES: mandatoryAttributeName: str = mandatoryAttribute.attributeName - mandatoryAttributeOnPoints: bool = mandatoryAttribute.isOnPoints - if not isAttributeInObject( self.output, mandatoryAttributeName, mandatoryAttributeOnPoints ): + mandatoryAttributePiece: Piece = mandatoryAttribute.piece + if not isAttributeInObject( self.output, mandatoryAttributeName, mandatoryAttributePiece ): mess = f"The mandatory property { mandatoryAttributeName } is missing to compute geomechanical properties." raise AttributeError( mess ) else: self._mandatoryProperties.setMandatoryPropertyValue( mandatoryAttributeName, - getArrayInObject( self.output, mandatoryAttributeName, mandatoryAttributeOnPoints ) ) + getArrayInObject( self.output, mandatoryAttributeName, mandatoryAttributePiece ) ) return @@ -892,13 +889,13 @@ def _computeAdvancedProperties( self: Self ) -> None: def _computeBiotCoefficient( self: Self ) -> None: """Compute the Biot coefficient from default and grain bulk modulus.""" - if not isAttributeInObject( self.output, BIOT_COEFFICIENT.attributeName, BIOT_COEFFICIENT.isOnPoints ): + if not isAttributeInObject( self.output, BIOT_COEFFICIENT.attributeName, BIOT_COEFFICIENT.piece ): self._basicProperties.biotCoefficient = fcts.biotCoefficient( self.physicalConstants.grainBulkModulus, self._elasticModuli.bulkModulus ) self._attributesToCreate.append( BIOT_COEFFICIENT ) else: self._basicProperties.biotCoefficient = getArrayInObject( self.output, BIOT_COEFFICIENT.attributeName, - BIOT_COEFFICIENT.isOnPoints ) + BIOT_COEFFICIENT.piece ) self.logger.warning( f"{ BIOT_COEFFICIENT.attributeName } is already on the mesh, it has not been computed by the filter." ) @@ -907,7 +904,7 @@ def _computeBiotCoefficient( self: Self ) -> None: def _computeCompressibilityCoefficient( self: Self ) -> None: """Compute the normal, the oedometric and the real compressibility coefficient from Poisson's ratio, bulk modulus, Biot coefficient and Porosity.""" # normal compressibility - if not isAttributeInObject( self.output, COMPRESSIBILITY.attributeName, COMPRESSIBILITY.isOnPoints ): + if not isAttributeInObject( self.output, COMPRESSIBILITY.attributeName, COMPRESSIBILITY.piece ): self._basicProperties.compressibility = fcts.compressibility( self._elasticModuli.poissonRatio, self._elasticModuli.bulkModulus, self._basicProperties.biotCoefficient, @@ -915,25 +912,25 @@ def _computeCompressibilityCoefficient( self: Self ) -> None: self._attributesToCreate.append( COMPRESSIBILITY ) else: self._basicProperties.compressibility = getArrayInObject( self.output, COMPRESSIBILITY.attributeName, - COMPRESSIBILITY.isOnPoints ) + COMPRESSIBILITY.piece ) self.logger.warning( f"{ COMPRESSIBILITY.attributeName } is already on the mesh, it has not been computed by the filter." ) # oedometric compressibility - if not isAttributeInObject( self.output, COMPRESSIBILITY_OED.attributeName, COMPRESSIBILITY_OED.isOnPoints ): + if not isAttributeInObject( self.output, COMPRESSIBILITY_OED.attributeName, COMPRESSIBILITY_OED.piece ): self._basicProperties.compressibilityOed = fcts.compressibilityOed( self._elasticModuli.shearModulus, self._elasticModuli.bulkModulus, self._mandatoryProperties.porosity ) self._attributesToCreate.append( COMPRESSIBILITY_OED ) else: self._basicProperties.compressibilityOed = getArrayInObject( self.output, COMPRESSIBILITY_OED.attributeName, - COMPRESSIBILITY_OED.isOnPoints ) + COMPRESSIBILITY_OED.piece ) self.logger.warning( f"{ COMPRESSIBILITY_OED.attributeName } is already on the mesh, it has not been computed by the filter." ) # real compressibility - if not isAttributeInObject( self.output, COMPRESSIBILITY_REAL.attributeName, COMPRESSIBILITY_REAL.isOnPoints ): + if not isAttributeInObject( self.output, COMPRESSIBILITY_REAL.attributeName, COMPRESSIBILITY_REAL.piece ): self._basicProperties.compressibilityReal = fcts.compressibilityReal( self._mandatoryProperties.deltaPressure, self._mandatoryProperties.porosity, self._mandatoryProperties.porosityInitial ) @@ -941,7 +938,7 @@ def _computeCompressibilityCoefficient( self: Self ) -> None: else: self._basicProperties.compressibilityReal = getArrayInObject( self.output, COMPRESSIBILITY_REAL.attributeName, - COMPRESSIBILITY_REAL.isOnPoints ) + COMPRESSIBILITY_REAL.piece ) self.logger.warning( f"{ COMPRESSIBILITY_REAL.attributeName } is already on the mesh, it has not been computed by the filter." ) @@ -950,13 +947,13 @@ def _computeCompressibilityCoefficient( self: Self ) -> None: def _computeSpecificGravity( self: Self ) -> None: """Compute the specific gravity from rock density and specific density.""" - if not isAttributeInObject( self.output, SPECIFIC_GRAVITY.attributeName, SPECIFIC_GRAVITY.isOnPoints ): + if not isAttributeInObject( self.output, SPECIFIC_GRAVITY.attributeName, SPECIFIC_GRAVITY.piece ): self._basicProperties.specificGravity = fcts.specificGravity( self._mandatoryProperties.density, self.physicalConstants.specificDensity ) self._attributesToCreate.append( SPECIFIC_GRAVITY ) else: self._basicProperties.specificGravity = getArrayInObject( self.output, SPECIFIC_GRAVITY.attributeName, - SPECIFIC_GRAVITY.isOnPoints ) + SPECIFIC_GRAVITY.piece ) self.logger.warning( f"{ SPECIFIC_GRAVITY.attributeName } is already on the mesh, it has not been computed by the filter." ) @@ -981,11 +978,11 @@ def _doComputeRatio( horizontalStress: npt.NDArray[ np.float64 ] = np.min( array[ :, :2 ], axis=1 ) ratio: npt.NDArray[ np.float64 ] - if not isAttributeInObject( self.output, geomechanicProperty.attributeName, geomechanicProperty.isOnPoints ): + if not isAttributeInObject( self.output, geomechanicProperty.attributeName, geomechanicProperty.piece ): ratio = fcts.stressRatio( horizontalStress, verticalStress ) self._attributesToCreate.append( geomechanicProperty ) else: - ratio = getArrayInObject( self.output, geomechanicProperty.attributeName, geomechanicProperty.isOnPoints ) + ratio = getArrayInObject( self.output, geomechanicProperty.attributeName, geomechanicProperty.piece ) self.logger.warning( f"{ geomechanicProperty.attributeName } is already on the mesh, it has not been computed by the filter." ) @@ -1019,7 +1016,7 @@ def _doComputeTotalStress( npt.NDArray[ np.float64 ]: The array with the totalStress computed. """ totalStress: npt.NDArray[ np.float64 ] - if not isAttributeInObject( self.output, geomechanicProperty.attributeName, geomechanicProperty.isOnPoints ): + if not isAttributeInObject( self.output, geomechanicProperty.attributeName, geomechanicProperty.piece ): if pressure is None: totalStress = np.copy( effectiveStress ) self.logger.warning( "There is no pressure, the total stress is equal to the effective stress." ) @@ -1032,8 +1029,7 @@ def _doComputeTotalStress( totalStress = fcts.totalStress( effectiveStress, biotCoefficient, pressure ) self._attributesToCreate.append( geomechanicProperty ) else: - totalStress = getArrayInObject( self.output, geomechanicProperty.attributeName, - geomechanicProperty.isOnPoints ) + totalStress = getArrayInObject( self.output, geomechanicProperty.attributeName, geomechanicProperty.piece ) self.logger.warning( f"{ geomechanicProperty.attributeName } is already on the mesh, it has not been computed by the filter." ) @@ -1090,15 +1086,15 @@ def _computeTotalStresses( self: Self ) -> None: # TODO: Lithostatic stress calculation is deactivated until the formula is not fixed # def _computeLithostaticStress( self: Self ) -> None: # """Compute the lithostatic stress.""" - # if not isAttributeInObject( self.output, LITHOSTATIC_STRESS.attributeName, LITHOSTATIC_STRESS.isOnPoints ): + # if not isAttributeInObject( self.output, LITHOSTATIC_STRESS.attributeName, LITHOSTATIC_STRESS.piece ): # depth: npt.NDArray[ np.float64 ] = self._doComputeDepthAlongLine( - # ) if LITHOSTATIC_STRESS.isOnPoints else self._doComputeDepthInMesh() + # ) if LITHOSTATIC_STRESS.piece else self._doComputeDepthInMesh() # self._basicProperties.lithostaticStress = fcts.lithostaticStress( depth, self._mandatoryProperties.density, # GRAVITY ) # self._attributesToCreate.append( LITHOSTATIC_STRESS ) # else: # self._basicProperties.lithostaticStress = getArrayInObject( self.output, LITHOSTATIC_STRESS.attributeName, - # LITHOSTATIC_STRESS.isOnPoints ) + # LITHOSTATIC_STRESS.piece ) # self.logger.warning( # f"{ LITHOSTATIC_STRESS.attributeName } is already on the mesh, it has not been computed by the filter." # ) @@ -1134,47 +1130,49 @@ def _computeTotalStresses( self: Self ) -> None: # depth: npt.NDArray[ np.float64 ] = -1.0 * zCoord # return depth - # def _getZcoordinates( self: Self, onPoints: bool ) -> npt.NDArray[ np.float64 ]: + # def _getZcoordinates( self: Self, piece: Piece ) -> npt.NDArray[ np.float64 ]: # """Get z coordinates from self.output. # Args: - # onPoints (bool): True if the attribute is on points, False if it is on cells. + # piece (Piece): The piece of the attribute. # Returns: # npt.NDArray[np.float64]: 1D array with depth property # """ # # get z coordinate # zCoord: npt.NDArray[ np.float64 ] - # pointCoords: npt.NDArray[ np.float64 ] = self._getPointCoordinates( onPoints ) + # pointCoords: npt.NDArray[ np.float64 ] = self._getPointCoordinates( piece ) # assert pointCoords is not None, "Point coordinates are undefined." # assert pointCoords.shape[ 1 ] == 2, "Point coordinates are undefined." # zCoord = pointCoords[ :, 2 ] # return zCoord - # def _getPointCoordinates( self: Self, onPoints: bool ) -> npt.NDArray[ np.float64 ]: + # def _getPointCoordinates( self: Self, piece: Piece ) -> npt.NDArray[ np.float64 ]: # """Get the coordinates of Points or Cell center. # Args: - # onPoints (bool): True if the attribute is on points, False if it is on cells. + # piece (Piece): The piece of the attribute. # Returns: # npt.NDArray[np.float64]: points/cell center coordinates # """ - # if onPoints: + # if piece == Piece.POINTS: # return self.output.GetPoints() # type: ignore[no-any-return] - # else: + # elif piece == Piece.CELLS: # # Find cell centers # filter = vtkCellCenters() # filter.SetInputDataObject( self.output ) # filter.Update() # return filter.GetOutput().GetPoints() # type: ignore[no-any-return] + # else: + # raise ValueError( "The piece attribute must be cell or point." ) def _computeElasticStrain( self: Self ) -> None: """Compute the elastic strain from the effective stress and the elastic modulus.""" if self._mandatoryProperties.effectiveStress is not None and self._mandatoryProperties.effectiveStressT0 is not None: deltaEffectiveStress = self._mandatoryProperties.effectiveStress - self._mandatoryProperties.effectiveStressT0 - if not isAttributeInObject( self.output, STRAIN_ELASTIC.attributeName, STRAIN_ELASTIC.isOnPoints ): + if not isAttributeInObject( self.output, STRAIN_ELASTIC.attributeName, STRAIN_ELASTIC.piece ): if self.computeYoungPoisson: self._basicProperties.elasticStrain = fcts.elasticStrainFromBulkShear( deltaEffectiveStress, self._elasticModuli.bulkModulus, self._elasticModuli.shearModulus ) @@ -1184,7 +1182,7 @@ def _computeElasticStrain( self: Self ) -> None: self._attributesToCreate.append( STRAIN_ELASTIC ) else: self._basicProperties.totalStressT0 = getArrayInObject( self.output, STRAIN_ELASTIC.attributeName, - STRAIN_ELASTIC.isOnPoints ) + STRAIN_ELASTIC.piece ) self.logger.warning( f"{ STRAIN_ELASTIC.attributeName } is already on the mesh, it has not been computed by the filter." ) @@ -1198,7 +1196,7 @@ def _computeReservoirStressPathReal( self: Self ) -> None: AttributeError: A mandatory attribute is missing. """ # create delta stress attribute for QC - if not isAttributeInObject( self.output, STRESS_TOTAL_DELTA.attributeName, STRESS_TOTAL_DELTA.isOnPoints ): + if not isAttributeInObject( self.output, STRESS_TOTAL_DELTA.attributeName, STRESS_TOTAL_DELTA.piece ): if self._basicProperties.totalStress is not None and self._basicProperties.totalStressT0 is not None: self._basicProperties.deltaTotalStress = self._basicProperties.totalStress - self._basicProperties.totalStressT0 self._attributesToCreate.append( STRESS_TOTAL_DELTA ) @@ -1207,17 +1205,17 @@ def _computeReservoirStressPathReal( self: Self ) -> None: raise AttributeError( mess ) else: self._basicProperties.deltaTotalStress = getArrayInObject( self.output, STRESS_TOTAL_DELTA.attributeName, - STRESS_TOTAL_DELTA.isOnPoints ) + STRESS_TOTAL_DELTA.piece ) self.logger.warning( f"{ STRESS_TOTAL_DELTA.attributeName } is already on the mesh, it has not been computed by the filter." ) - if not isAttributeInObject( self.output, RSP_REAL.attributeName, RSP_REAL.isOnPoints ): + if not isAttributeInObject( self.output, RSP_REAL.attributeName, RSP_REAL.piece ): self._basicProperties.rspReal = fcts.reservoirStressPathReal( self._basicProperties.deltaTotalStress, self._mandatoryProperties.deltaPressure ) self._attributesToCreate.append( RSP_REAL ) else: - self._basicProperties.rspReal = getArrayInObject( self.output, RSP_REAL.attributeName, RSP_REAL.isOnPoints ) + self._basicProperties.rspReal = getArrayInObject( self.output, RSP_REAL.attributeName, RSP_REAL.piece ) self.logger.warning( f"{ RSP_REAL.attributeName } is already on the mesh, it has not been computed by the filter." ) @@ -1225,12 +1223,12 @@ def _computeReservoirStressPathReal( self: Self ) -> None: def _computeReservoirStressPathOed( self: Self ) -> None: """Compute Reservoir Stress Path in oedometric conditions.""" - if not isAttributeInObject( self.output, RSP_OED.attributeName, RSP_OED.isOnPoints ): + if not isAttributeInObject( self.output, RSP_OED.attributeName, RSP_OED.piece ): self._basicProperties.rspOed = fcts.reservoirStressPathOed( self._basicProperties.biotCoefficient, self._elasticModuli.poissonRatio ) self._attributesToCreate.append( RSP_OED ) else: - self._basicProperties.rspOed = getArrayInObject( self.output, RSP_OED.attributeName, RSP_OED.isOnPoints ) + self._basicProperties.rspOed = getArrayInObject( self.output, RSP_OED.attributeName, RSP_OED.piece ) self.logger.warning( f"{ RSP_OED.attributeName } is already on the mesh, it has not been computed by the filter." ) @@ -1239,14 +1237,14 @@ def _computeReservoirStressPathOed( self: Self ) -> None: def _computeEffectiveStressRatioOed( self: Self ) -> None: """Compute the effective stress ratio in oedometric conditions.""" if not isAttributeInObject( self.output, STRESS_EFFECTIVE_RATIO_OED.attributeName, - STRESS_EFFECTIVE_RATIO_OED.isOnPoints ): + STRESS_EFFECTIVE_RATIO_OED.piece ): self._basicProperties.effectiveStressRatioOed = fcts.deviatoricStressPathOed( self._elasticModuli.poissonRatio ) self._attributesToCreate.append( STRESS_EFFECTIVE_RATIO_OED ) else: self._basicProperties.effectiveStressRatioOed = getArrayInObject( self.output, STRESS_EFFECTIVE_RATIO_OED.attributeName, - STRESS_EFFECTIVE_RATIO_OED.isOnPoints ) + STRESS_EFFECTIVE_RATIO_OED.piece ) self.logger.warning( f"{ STRESS_EFFECTIVE_RATIO_OED.attributeName } is already on the mesh, it has not been computed by the filter." ) @@ -1261,7 +1259,7 @@ def _computeCriticalTotalStressRatio( self: Self ) -> None: """ mess: str if not isAttributeInObject( self.output, CRITICAL_TOTAL_STRESS_RATIO.attributeName, - CRITICAL_TOTAL_STRESS_RATIO.isOnPoints ): + CRITICAL_TOTAL_STRESS_RATIO.piece ): if self._basicProperties.totalStress is not None: verticalStress: npt.NDArray[ np.float64 ] = self._basicProperties.totalStress[ :, 2 ] self._advancedProperties.criticalTotalStressRatio = fcts.criticalTotalStressRatio( @@ -1272,13 +1270,13 @@ def _computeCriticalTotalStressRatio( self: Self ) -> None: raise AttributeError( mess ) else: self._advancedProperties.criticalTotalStressRatio = getArrayInObject( - self.output, CRITICAL_TOTAL_STRESS_RATIO.attributeName, CRITICAL_TOTAL_STRESS_RATIO.isOnPoints ) + self.output, CRITICAL_TOTAL_STRESS_RATIO.attributeName, CRITICAL_TOTAL_STRESS_RATIO.piece ) self.logger.warning( f"{ CRITICAL_TOTAL_STRESS_RATIO.attributeName } is already on the mesh, it has not been computed by the filter." ) if not isAttributeInObject( self.output, TOTAL_STRESS_RATIO_THRESHOLD.attributeName, - TOTAL_STRESS_RATIO_THRESHOLD.isOnPoints ): + TOTAL_STRESS_RATIO_THRESHOLD.piece ): if self._basicProperties.totalStress is not None: mask: npt.NDArray[ np.bool_ ] = np.argmin( np.abs( self._basicProperties.totalStress[ :, :2 ] ), axis=1 ) @@ -1292,7 +1290,7 @@ def _computeCriticalTotalStressRatio( self: Self ) -> None: raise AttributeError( mess ) else: self._advancedProperties.stressRatioThreshold = getArrayInObject( - self.output, TOTAL_STRESS_RATIO_THRESHOLD.attributeName, TOTAL_STRESS_RATIO_THRESHOLD.isOnPoints ) + self.output, TOTAL_STRESS_RATIO_THRESHOLD.attributeName, TOTAL_STRESS_RATIO_THRESHOLD.piece ) self.logger.warning( f"{ TOTAL_STRESS_RATIO_THRESHOLD.attributeName } is already on the mesh, it has not been computed by the filter." ) @@ -1305,8 +1303,7 @@ def _computeCriticalPorePressure( self: Self ) -> None: Raises: AttributeError: A mandatory attribute is missing. """ - if not isAttributeInObject( self.output, CRITICAL_PORE_PRESSURE.attributeName, - CRITICAL_PORE_PRESSURE.isOnPoints ): + if not isAttributeInObject( self.output, CRITICAL_PORE_PRESSURE.attributeName, CRITICAL_PORE_PRESSURE.piece ): if self._basicProperties.totalStress is not None: self._advancedProperties.criticalPorePressure = fcts.criticalPorePressure( -1.0 * self._basicProperties.totalStress, self.physicalConstants.rockCohesion, @@ -1319,21 +1316,20 @@ def _computeCriticalPorePressure( self: Self ) -> None: else: self._advancedProperties.criticalPorePressure = getArrayInObject( self.output, CRITICAL_PORE_PRESSURE.attributeName, - CRITICAL_PORE_PRESSURE.isOnPoints ) + CRITICAL_PORE_PRESSURE.piece ) self.logger.warning( f"{ CRITICAL_PORE_PRESSURE.attributeName } is already on the mesh, it has not been computed by the filter." ) # Add critical pore pressure index (i.e., ratio between pressure and criticalPorePressure) if not isAttributeInObject( self.output, CRITICAL_PORE_PRESSURE_THRESHOLD.attributeName, - CRITICAL_PORE_PRESSURE_THRESHOLD.isOnPoints ): + CRITICAL_PORE_PRESSURE_THRESHOLD.piece ): self._advancedProperties.criticalPorePressureIndex = fcts.criticalPorePressureThreshold( self._mandatoryProperties.pressure, self._advancedProperties.criticalPorePressure ) self._attributesToCreate.append( CRITICAL_PORE_PRESSURE_THRESHOLD ) else: self._advancedProperties.criticalPorePressureIndex = getArrayInObject( - self.output, CRITICAL_PORE_PRESSURE_THRESHOLD.attributeName, - CRITICAL_PORE_PRESSURE_THRESHOLD.isOnPoints ) + self.output, CRITICAL_PORE_PRESSURE_THRESHOLD.attributeName, CRITICAL_PORE_PRESSURE_THRESHOLD.piece ) self.logger.warning( f"{ CRITICAL_PORE_PRESSURE_THRESHOLD.attributeName } is already on the mesh, it has not been computed by the filter." ) diff --git a/geos-processing/src/geos/processing/post_processing/GeosBlockMerge.py b/geos-processing/src/geos/processing/post_processing/GeosBlockMerge.py index 7caab5a88..f19e0d06e 100644 --- a/geos-processing/src/geos/processing/post_processing/GeosBlockMerge.py +++ b/geos-processing/src/geos/processing/post_processing/GeosBlockMerge.py @@ -7,6 +7,7 @@ from vtkmodules.vtkCommonDataModel import vtkCompositeDataSet, vtkMultiBlockDataSet, vtkPolyData, vtkUnstructuredGrid +from geos.utils.pieceEnum import Piece from geos.utils.Logger import ( Logger, getLogger ) from geos.utils.GeosOutputsConstants import ( PHASE_SEP, PhaseTypeEnum, FluidPrefixEnum, PostProcessingOutputsEnum, getRockSuffixRenaming ) @@ -165,7 +166,7 @@ def applyFilter( self: Self ) -> None: # Create index attribute keeping the index in initial mesh if not createConstantAttribute( volumeMesh, [ blockIndex ], PostProcessingOutputsEnum.BLOCK_INDEX.attributeName, - onPoints=False, + piece=Piece.CELLS, logger=self.logger ): raise ValueError( f"Something went wrong during the creation of the attribute { PostProcessingOutputsEnum.BLOCK_INDEX.attributeName }." @@ -200,23 +201,23 @@ def renameAttributes( mesh (vtkUnstructuredGrid): The mesh with the attribute to rename. """ # All the attributes to rename are on cells - for attributeName in getAttributeSet( mesh, False ): + for attributeName in getAttributeSet( mesh, piece=Piece.CELLS ): for suffix, newName in getRockSuffixRenaming().items(): if suffix in attributeName: # Fluid and Rock density attribute have the same suffix, only the rock density need to be renamed if suffix == "_density": for phaseName in self.phaseNameDict[ PhaseTypeEnum.ROCK.type ]: if phaseName in attributeName: - renameAttribute( mesh, attributeName, newName, False ) + renameAttribute( mesh, attributeName, newName, piece=Piece.CELLS ) else: - renameAttribute( mesh, attributeName, newName, False ) + renameAttribute( mesh, attributeName, newName, piece=Piece.CELLS ) return def computePhaseNames( self: Self ) -> None: """Get the names of the phases in the mesh from Cell attributes.""" # All the phase attributes are on cells - for name in getAttributeSet( self.inputMesh, False ): + for name in getAttributeSet( self.inputMesh, piece=Piece.CELLS ): if PHASE_SEP in name and "dofIndex" not in name: phaseName: str suffixName: str diff --git a/geos-processing/src/geos/processing/post_processing/SurfaceGeomechanics.py b/geos-processing/src/geos/processing/post_processing/SurfaceGeomechanics.py index 349237028..c590e79fe 100644 --- a/geos-processing/src/geos/processing/post_processing/SurfaceGeomechanics.py +++ b/geos-processing/src/geos/processing/post_processing/SurfaceGeomechanics.py @@ -15,6 +15,7 @@ from geos.mesh.utils.arrayHelpers import ( getArrayInObject, getAttributeSet, isAttributeInObject ) from geos.mesh.utils.genericHelpers import ( getLocalBasisVectors, convertAttributeFromLocalToXYZForOneCell ) import geos.geomechanics.processing.geomechanicsCalculatorFunctions as fcts +from geos.utils.pieceEnum import Piece from geos.utils.Logger import ( Logger, getLogger ) from geos.utils.PhysicalConstants import ( DEFAULT_FRICTION_ANGLE_RAD, DEFAULT_ROCK_COHESION ) from geos.utils.GeosOutputsConstants import ( ComponentNameEnum, GeosMeshOutputsEnum, PostProcessingOutputsEnum ) @@ -127,7 +128,7 @@ def __init__( self: Self, surfacicMesh: vtkPolyData, speHandler: bool = False ) } # Attributes are either on points or on cells - self.attributeOnPoints: bool = False + self.attributePiece: Piece = Piece.CELLS # Rock cohesion (Pa) self.rockCohesion: float = DEFAULT_ROCK_COHESION # Friction angle (rad) @@ -279,14 +280,14 @@ def convertAttributesFromLocalToXYZBasis( self: Self ) -> None: attrNameXYZ: str = f"{attrNameLocal}_{ComponentNameEnum.XYZ.name}" # Skip attribute if it is already in the object - if isAttributeInObject( self.outputMesh, attrNameXYZ, self.attributeOnPoints ): + if isAttributeInObject( self.outputMesh, attrNameXYZ, self.attributePiece ): continue - if self.attributeOnPoints: + if self.attributePiece != Piece.CELLS: raise AttributeError( "This filter can only convert cell attributes from local to XYZ basis, not point attributes." ) localArray: npt.NDArray[ np.float64 ] = getArrayInObject( self.outputMesh, attrNameLocal, - self.attributeOnPoints ) + self.attributePiece ) arrayXYZ: npt.NDArray[ np.float64 ] = self.__computeXYZCoordinates( localArray ) @@ -295,7 +296,7 @@ def convertAttributesFromLocalToXYZBasis( self: Self ) -> None: arrayXYZ, attrNameXYZ, ComponentNameEnum.XYZ.value, - onPoints=self.attributeOnPoints, + piece=self.attributePiece, logger=self.logger ): self.logger.info( f"Attribute {attrNameXYZ} added to the output mesh." ) self.newAttributeNames.add( attrNameXYZ ) @@ -313,7 +314,7 @@ def __filterAttributesToConvert( self: Self ) -> set[ str ]: attributesFiltered: set[ str ] = set() if len( self.attributesToConvert ) != 0: - attributeSet: set[ str ] = getAttributeSet( self.outputMesh, False ) + attributeSet: set[ str ] = getAttributeSet( self.outputMesh, Piece.CELLS ) for attrName in self.attributesToConvert: if attrName in attributeSet: attr: vtkDataArray = self.outputMesh.GetCellData().GetArray( attrName ) @@ -374,11 +375,11 @@ def computeShearCapacityUtilization( self: Self ) -> None: """ SCUAttributeName: str = PostProcessingOutputsEnum.SCU.attributeName - if not isAttributeInObject( self.outputMesh, SCUAttributeName, self.attributeOnPoints ): + if not isAttributeInObject( self.outputMesh, SCUAttributeName, self.attributePiece ): # Get the traction to compute the SCU tractionAttributeName: str = GeosMeshOutputsEnum.TRACTION.attributeName traction: npt.NDArray[ np.float64 ] = getArrayInObject( self.outputMesh, tractionAttributeName, - self.attributeOnPoints ) + self.attributePiece ) # Computation of the shear capacity utilization (SCU) # TODO: better handling of errors in shearCapacityUtilization @@ -387,7 +388,8 @@ def computeShearCapacityUtilization( self: Self ) -> None: # Create attribute if not createAttribute( - self.outputMesh, scuAttribute, SCUAttributeName, (), self.attributeOnPoints, logger=self.logger ): + self.outputMesh, scuAttribute, SCUAttributeName, (), self.attributePiece, logger=self.logger ): + self.logger.error( f"Failed to create attribute {SCUAttributeName}." ) raise ValueError( f"Failed to create attribute {SCUAttributeName}." ) else: self.logger.info( "SCU computed and added to the output mesh." ) diff --git a/geos-processing/src/geos/processing/pre_processing/MeshQualityEnhanced.py b/geos-processing/src/geos/processing/pre_processing/MeshQualityEnhanced.py index de5fb1d8c..930c64c41 100644 --- a/geos-processing/src/geos/processing/pre_processing/MeshQualityEnhanced.py +++ b/geos-processing/src/geos/processing/pre_processing/MeshQualityEnhanced.py @@ -29,6 +29,7 @@ import geos.utils.geometryFunctions as geom from geos.utils.Logger import ( Logger, getLogger ) +from geos.utils.pieceEnum import Piece __doc__ = """ MeshQualityEnhanced module is a vtk filter that computes mesh quality stats. @@ -354,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, False ): + if arrayName in getAttributesFromDataSet( 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_AttributeMapping.py b/geos-processing/tests/test_AttributeMapping.py index 3fbffe27a..8312b2eea 100644 --- a/geos-processing/tests/test_AttributeMapping.py +++ b/geos-processing/tests/test_AttributeMapping.py @@ -7,21 +7,22 @@ from geos.mesh.utils.arrayModifiers import fillAllPartialAttributes from geos.processing.generic_processing_tools.AttributeMapping import AttributeMapping from vtkmodules.vtkCommonDataModel import vtkMultiBlockDataSet, vtkDataSet +from geos.utils.pieceEnum import Piece -@pytest.mark.parametrize( "meshFromName, meshToName, attributeNames, onPoints", [ - ( "fracture", "emptyFracture", { "collocatedNodes" }, True ), - ( "multiblock", "emptyFracture", { "FAULT" }, False ), - ( "multiblock", "emptymultiblock", { "FAULT" }, False ), - ( "dataset", "emptymultiblock", { "FAULT" }, False ), - ( "dataset", "emptydataset", { "FAULT" }, False ), +@pytest.mark.parametrize( "meshFromName, meshToName, attributeNames, piece", [ + ( "fracture", "emptyFracture", { "collocatedNodes" }, Piece.POINTS ), + ( "multiblock", "emptyFracture", { "FAULT" }, Piece.CELLS ), + ( "multiblock", "emptymultiblock", { "FAULT" }, Piece.CELLS ), + ( "dataset", "emptymultiblock", { "FAULT" }, Piece.CELLS ), + ( "dataset", "emptydataset", { "FAULT" }, Piece.CELLS ), ] ) def test_AttributeMapping( dataSetTest: Any, meshFromName: str, meshToName: str, attributeNames: set[ str ], - onPoints: bool, + piece: Piece, ) -> None: """Test mapping an attribute between two meshes.""" meshFrom: Union[ vtkDataSet, vtkMultiBlockDataSet ] = dataSetTest( meshFromName ) @@ -29,50 +30,47 @@ def test_AttributeMapping( if isinstance( meshFrom, vtkMultiBlockDataSet ): fillAllPartialAttributes( meshFrom ) - attributeMappingFilter: AttributeMapping = AttributeMapping( meshFrom, meshTo, attributeNames, onPoints ) + attributeMappingFilter: AttributeMapping = AttributeMapping( meshFrom, meshTo, attributeNames, piece ) attributeMappingFilter.applyFilter() @pytest.mark.parametrize( - "meshFromName, meshToName, attributeNames, onPoints", + "meshFromName, meshToName, attributeNames", [ - ( "dataset", "emptydataset", { "Fault" }, False ), # Attribute not in the mesh from - ( "dataset", "dataset", { "GLOBAL_IDS_CELLS" }, False ), # Attribute on both meshes - ( "multiblock", "emptymultiblock", { "FAULT" }, False ), # Partial attribute in the mesh from + ( "dataset", "emptydataset", { "Fault" } ), # Attribute not in the mesh from + ( "dataset", "dataset", { "GLOBAL_IDS_CELLS" } ), # Attribute on both meshes + ( "multiblock", "emptymultiblock", { "FAULT" } ), # Partial attribute in the mesh from ] ) def test_AttributeMappingRaisesAttributeError( dataSetTest: Any, meshFromName: str, meshToName: str, attributeNames: set[ str ], - onPoints: bool, ) -> None: """Test the fails of the filter with attributes issues.""" meshFrom: Union[ vtkDataSet, vtkMultiBlockDataSet ] = dataSetTest( meshFromName ) meshTo: Union[ vtkDataSet, vtkMultiBlockDataSet ] = dataSetTest( meshToName ) - attributeMappingFilter: AttributeMapping = AttributeMapping( meshFrom, meshTo, attributeNames, onPoints ) + attributeMappingFilter: AttributeMapping = AttributeMapping( meshFrom, meshTo, attributeNames, Piece.CELLS ) with pytest.raises( AttributeError ): attributeMappingFilter.applyFilter() @pytest.mark.parametrize( - "meshFromName, meshToName, attributeNames, onPoints", + "meshToName, attributeNames", [ - ( "dataset", "emptydataset", {}, False ), # No attribute to map - ( "dataset", "multiblockGeosOutput", { "FAULT" }, False ), # Meshes with no common cells + ( "emptydataset", {} ), # No attribute to map + ( "multiblockGeosOutput", { "FAULT" } ), # Meshes with no common cells ] ) def test_AttributeMappingRaisesValueError( dataSetTest: Any, - meshFromName: str, meshToName: str, attributeNames: set[ str ], - onPoints: bool, ) -> None: """Test the fails of the filter with input value issue.""" - meshFrom: Union[ vtkDataSet, vtkMultiBlockDataSet ] = dataSetTest( meshFromName ) + meshFrom: Union[ vtkDataSet, vtkMultiBlockDataSet ] = dataSetTest( "dataset" ) meshTo: Union[ vtkDataSet, vtkMultiBlockDataSet ] = dataSetTest( meshToName ) - attributeMappingFilter: AttributeMapping = AttributeMapping( meshFrom, meshTo, attributeNames, onPoints ) + attributeMappingFilter: AttributeMapping = AttributeMapping( meshFrom, meshTo, attributeNames, Piece.CELLS ) with pytest.raises( ValueError ): attributeMappingFilter.applyFilter() diff --git a/geos-processing/tests/test_CreateConstantAttributePerRegion.py b/geos-processing/tests/test_CreateConstantAttributePerRegion.py index 388fee0c6..d3a910882 100644 --- a/geos-processing/tests/test_CreateConstantAttributePerRegion.py +++ b/geos-processing/tests/test_CreateConstantAttributePerRegion.py @@ -15,7 +15,7 @@ @pytest.mark.parametrize( "meshType, newAttributeName, regionName, dictRegionValues, componentNames, componentNamesTest, valueNpType", [ - # Test the name of the new attribute (new on the mesh, one present on the other piece). + # Test the name of the new attribute. ## For vtkDataSet. ( "dataset", "newAttribute", "GLOBAL_IDS_POINTS", {}, (), (), np.float32 ), ( "dataset", "CellAttribute", "GLOBAL_IDS_POINTS", {}, (), (), np.float32 ), @@ -103,35 +103,24 @@ def test_CreateConstantAttributePerRegion( @pytest.mark.parametrize( - "meshType, newAttributeName, regionName, dictRegionValues, componentNames, componentNamesTest, valueNpType", + "meshType, regionName", [ - ( "dataset", "newAttribute", "PERM", {}, (), (), np.float32 ), # Region attribute has too many components - ( "multiblock", "newAttribute", "FAULT", {}, (), (), np.float32 ), # Region attribute is partial. + ( "dataset", "PERM" ), # Region attribute has too many components + ( "multiblock", "FAULT" ), # Region attribute is partial. ] ) def test_CreateConstantAttributePerRegionRaisesAttributeError( dataSetTest: Union[ vtkMultiBlockDataSet, vtkDataSet ], meshType: str, - newAttributeName: str, regionName: str, - dictRegionValues: dict[ Any, Any ], - componentNames: tuple[ str, ...], - componentNamesTest: tuple[ str, ...], - valueNpType: int, ) -> None: """Test tes fails of CreateConstantAttributePerRegion with attributes issues.""" mesh: Union[ vtkMultiBlockDataSet, vtkDataSet ] = dataSetTest( meshType ) - nbComponents: int = len( componentNamesTest ) - if nbComponents == 0: # If the attribute has one component, the component has no name. - nbComponents += 1 createConstantAttributePerRegionFilter: CreateConstantAttributePerRegion = CreateConstantAttributePerRegion( mesh, regionName, - dictRegionValues, - newAttributeName, - valueNpType=valueNpType, - nbComponents=nbComponents, - componentNames=componentNames, + {}, + "newAttribute", ) with pytest.raises( AttributeError ): @@ -139,44 +128,39 @@ def test_CreateConstantAttributePerRegionRaisesAttributeError( @pytest.mark.parametrize( - "meshType, newAttributeName, regionName, dictRegionValues, componentNames, componentNamesTest, valueNpType", + "newAttributeName, dictRegionValues, componentNames", [ - ( "dataset", "newAttribute", "FAULT", { + ( "newAttribute", { 0: [ 0 ], 100: [ 1, 1 ], - }, (), (), np.float32 ), # Number of value inconsistent. - ( "dataset", "newAttribute", "FAULT", { + }, () ), # Number of value inconsistent. + ( "newAttribute", { 0: [ 0, 0 ], 100: [ 1, 1 ], - }, (), (), np.float32 ), # More values than components. - ( "dataset", "newAttribute", "FAULT", { + }, () ), # More values than components. + ( "newAttribute", { 0: [ 0 ], 100: [ 1 ], - }, ( "X", "Y" ), ( "X", "Y" ), np.float32 ), # More components than value. - ( "dataset", "PERM", "FAULT", {}, (), (), np.float32 ), # The attribute name already exist in the mesh. + }, ( "X", "Y" ) ), # More components than value. + ( "PERM", {}, () ), # The attribute name already exist on the mesh on the same piece. ] ) def test_CreateConstantAttributePerRegionRaisesValueError( - dataSetTest: Union[ vtkMultiBlockDataSet, vtkDataSet ], - meshType: str, + dataSetTest: vtkDataSet, newAttributeName: str, - regionName: str, dictRegionValues: dict[ Any, Any ], componentNames: tuple[ str, ...], - componentNamesTest: tuple[ str, ...], - valueNpType: int, ) -> None: """Test the fails of CreateConstantAttributePerRegion with inputs value issues.""" - mesh: Union[ vtkMultiBlockDataSet, vtkDataSet ] = dataSetTest( meshType ) - nbComponents: int = len( componentNamesTest ) + mesh: vtkDataSet = dataSetTest( "dataset" ) + nbComponents: int = len( componentNames ) if nbComponents == 0: # If the attribute has one component, the component has no name. nbComponents += 1 createConstantAttributePerRegionFilter: CreateConstantAttributePerRegion = CreateConstantAttributePerRegion( mesh, - regionName, + "FAULT", dictRegionValues, newAttributeName, - valueNpType=valueNpType, nbComponents=nbComponents, componentNames=componentNames, ) diff --git a/geos-pv/src/geos/pv/plugins/generic_processing/PVAttributeMapping.py b/geos-pv/src/geos/pv/plugins/generic_processing/PVAttributeMapping.py index 76a8f62e5..96c10685a 100644 --- a/geos-pv/src/geos/pv/plugins/generic_processing/PVAttributeMapping.py +++ b/geos-pv/src/geos/pv/plugins/generic_processing/PVAttributeMapping.py @@ -26,6 +26,7 @@ from vtkmodules.vtkCommonDataModel import vtkCompositeDataSet, vtkDataSet, vtkMultiBlockDataSet from geos.pv.utils.details import FilterCategory +from geos.utils.pieceEnum import Piece __doc__ = f""" AttributeMapping is a paraview plugin that transfers global attributes from a source mesh to a final mesh with same point/cell coordinates. @@ -45,7 +46,7 @@ * Select the mesh to transfer the global attributes (meshTo) * Select the filter: Filters > { FilterCategory.GENERIC_PROCESSING.value } > Attribute Mapping * Select the source mesh with global attributes to transfer (meshFrom) -* Select on which element (onPoints/onCells) the attributes to transfer are +* Select on which element ({ Piece.POINTS.value }/{ Piece.CELLS.value }) the attributes to transfer are * Select the global attributes to transfer from the source mesh to the final mesh * Apply @@ -70,7 +71,7 @@ def __init__( self: Self ) -> None: """Map attributes of the source mesh (meshFrom) to the final mesh (meshTo).""" super().__init__( nInputPorts=2, nOutputPorts=1, inputType="vtkObject", outputType="vtkObject" ) - self.onPoints: bool = False + self.piece: Piece = Piece.CELLS self.clearAttributeNames = True self.attributeNames: list[ str ] = [] @@ -92,7 +93,7 @@ def setAttributePiece( self: Self, piece: int ) -> None: Args: piece (int): 0 if on points, 1 if on cells. """ - self.onPoints = not bool( piece ) + self.piece = Piece.POINTS if piece == 0 else Piece.CELLS self.Modified() @smproperty.stringvector( @@ -184,7 +185,7 @@ def RequestData( outData.ShallowCopy( meshTo ) attributeMappingFilter: AttributeMapping = AttributeMapping( meshFrom, outData, set( self.attributeNames ), - self.onPoints, True ) + self.piece, True ) if len( attributeMappingFilter.logger.handlers ) == 0: attributeMappingFilter.setLoggerHandler( VTKHandler() ) diff --git a/geos-pv/src/geos/pv/plugins/post_processing/PVGeosBlockExtractAndMerge.py b/geos-pv/src/geos/pv/plugins/post_processing/PVGeosBlockExtractAndMerge.py index 0193d5cef..85e473dcf 100644 --- a/geos-pv/src/geos/pv/plugins/post_processing/PVGeosBlockExtractAndMerge.py +++ b/geos-pv/src/geos/pv/plugins/post_processing/PVGeosBlockExtractAndMerge.py @@ -22,6 +22,7 @@ from geos.mesh.utils.multiblockHelpers import getBlockNames from geos.utils.Errors import VTKError +from geos.utils.pieceEnum import Piece from geos.utils.GeosOutputsConstants import ( GeosMeshOutputsEnum, GeosDomainNameEnum, getAttributeToTransferFromInitialTime ) @@ -298,10 +299,10 @@ def RequestData( self.extractWell ) # Copy attributes from the initial time step - meshAttributes: set[ str ] = getAttributeSet( self.outputCellsT0, False ) + meshAttributes: set[ str ] = getAttributeSet( self.outputCellsT0, piece=Piece.CELLS ) for ( attributeName, attributeNewName ) in getAttributeToTransferFromInitialTime().items(): if attributeName in meshAttributes: - copyAttribute( self.outputCellsT0, outputCells, attributeName, attributeNewName, False, + copyAttribute( self.outputCellsT0, outputCells, attributeName, attributeNewName, Piece.CELLS, self.logger ) # Create elementCenter attribute in the volume mesh if needed diff --git a/geos-pv/src/geos/pv/plugins/post_processing/PVMohrCirclePlot.py b/geos-pv/src/geos/pv/plugins/post_processing/PVMohrCirclePlot.py index 067d36f83..49423dca6 100644 --- a/geos-pv/src/geos/pv/plugins/post_processing/PVMohrCirclePlot.py +++ b/geos-pv/src/geos/pv/plugins/post_processing/PVMohrCirclePlot.py @@ -31,6 +31,7 @@ update_paths() from geos.geomechanics.model.MohrCircle import MohrCircle +from geos.utils.pieceEnum import Piece from geos.utils.enumUnits import Pressure, enumerationDomainUnit from geos.utils.GeosOutputsConstants import ( FAILURE_ENVELOPE, GeosMeshOutputsEnum ) from geos.utils.Logger import CustomLoggerFormatter @@ -799,7 +800,7 @@ def _createMohrCirclesAtTimeStep( # Get effective stress array stressArray: npt.NDArray[ np.float64 ] = getArrayInObject( mesh, GeosMeshOutputsEnum.STRESS_EFFECTIVE.attributeName, - False ) + Piece.CELLS ) # Get stress convention stressConvention = StressConventionEnum.GEOS_STRESS_CONVENTION if self.useGeosStressConvention else StressConventionEnum.COMMON_STRESS_CONVENTION diff --git a/geos-utils/src/geos/utils/GeosOutputsConstants.py b/geos-utils/src/geos/utils/GeosOutputsConstants.py index 0dc0e6917..dc2aba8d1 100644 --- a/geos-utils/src/geos/utils/GeosOutputsConstants.py +++ b/geos-utils/src/geos/utils/GeosOutputsConstants.py @@ -1,9 +1,10 @@ # SPDX-License-Identifier: Apache-2.0 # SPDX-FileCopyrightText: Copyright 2023-2024 TotalEnergies. -# SPDX-FileContributor: Martin Lemay +# SPDX-FileContributor: Martin Lemay, Romain Baville from enum import Enum from typing_extensions import Self +from geos.utils.pieceEnum import Piece __doc__ = """ GeosOutputsConstants module defines useful constant names such as attribute @@ -26,19 +27,17 @@ class AttributeEnum( Enum ): - def __init__( self: Self, attributeName: str, nbComponent: int, onPoints: bool ) -> None: + def __init__( self: Self, attributeName: str, nbComponent: int, piece: Piece ) -> None: """Define the enumeration to store attribute properties. Args: - attributeName (str): name of the attribute - nbComponent (int): number of component: 1 is scalar attribute, >1 is - vectorial attribute - onPoints (bool): location of the attribute: on Points (True) or on Cells - (False) + attributeName (str): name of the attribute. + nbComponent (int): number of component: 1 is scalar attribute, >1 is vectorial attribute. + piece (Piece): The piece of the attribute. """ self.attributeName: str = attributeName self.nbComponent: int = nbComponent - self.isOnPoints: bool = onPoints + self.piece: Piece = piece def __repr__( self: Self ) -> str: """Get the string of AttributeEnum. @@ -131,38 +130,38 @@ class GeosMeshOutputsEnum( AttributeEnum ): """Attribute names that come from Geos. Define the names of Geos outputs, the number of components - for vectorial attributes, and the location (Point or Cell) in the mesh + for vectorial attributes, and the location (Points or Cells) in the mesh. """ # IDs - POINTS_ID = ( "Point ID", 1, True ) - CELL_ID = ( "Cell ID", 1, False ) - VTK_ORIGINAL_CELL_ID = ( "vtkOriginalCellIds", 1, False ) + POINTS_ID = ( "Point ID", 1, Piece.POINTS ) + CELL_ID = ( "Cell ID", 1, Piece.CELLS ) + VTK_ORIGINAL_CELL_ID = ( "vtkOriginalCellIds", 1, Piece.CELLS ) # geometry attributes - POINT = ( "Points", 3, True ) - ELEMENT_CENTER = ( "elementCenter", 1, False ) + POINT = ( "Points", 3, Piece.POINTS ) + ELEMENT_CENTER = ( "elementCenter", 1, Piece.CELLS ) # flow attributes - WATER_DENSITY = ( "water_density", 1, False ) - PRESSURE = ( "pressure", 1, False ) - DELTA_PRESSURE = ( "deltaPressure", 1, False ) - MASS = ( "mass", 1, False ) + WATER_DENSITY = ( "water_density", 1, Piece.CELLS ) + PRESSURE = ( "pressure", 1, Piece.CELLS ) + DELTA_PRESSURE = ( "deltaPressure", 1, Piece.CELLS ) + MASS = ( "mass", 1, Piece.CELLS ) # geomechanics attributes - ROCK_DENSITY = ( "density", 1, False ) - PERMEABILITY = ( "permeability", 1, False ) - POROSITY = ( "porosity", 1, False ) - POROSITY_INI = ( "porosityInitial", 1, False ) + ROCK_DENSITY = ( "density", 1, Piece.CELLS ) + PERMEABILITY = ( "permeability", 1, Piece.CELLS ) + POROSITY = ( "porosity", 1, Piece.CELLS ) + POROSITY_INI = ( "porosityInitial", 1, Piece.CELLS ) - BULK_MODULUS = ( "bulkModulus", 1, False ) - GRAIN_BULK_MODULUS = ( "bulkModulusGrains", 1, False ) - SHEAR_MODULUS = ( "shearModulus", 1, False ) - STRESS_EFFECTIVE = ( "stressEffective", 6, False ) - TOTAL_DISPLACEMENT = ( "totalDisplacement", 4, True ) + BULK_MODULUS = ( "bulkModulus", 1, Piece.CELLS ) + GRAIN_BULK_MODULUS = ( "bulkModulusGrains", 1, Piece.CELLS ) + SHEAR_MODULUS = ( "shearModulus", 1, Piece.CELLS ) + STRESS_EFFECTIVE = ( "stressEffective", 6, Piece.CELLS ) + TOTAL_DISPLACEMENT = ( "totalDisplacement", 4, Piece.POINTS ) - TRACTION = ( "traction", 3, False ) - DISPLACEMENT_JUMP = ( "displacementJump", 3, False ) + TRACTION = ( "traction", 3, Piece.CELLS ) + DISPLACEMENT_JUMP = ( "displacementJump", 3, Piece.CELLS ) ################################################################################ @@ -178,43 +177,43 @@ class PostProcessingOutputsEnum( AttributeEnum ): """ # general outputs - BLOCK_INDEX = ( "blockIndex", 1, False ) - ADJACENT_CELL_SIDE = ( "SurfaceAdjacentCells", 1, False ) + BLOCK_INDEX = ( "blockIndex", 1, Piece.CELLS ) + ADJACENT_CELL_SIDE = ( "SurfaceAdjacentCells", 1, Piece.CELLS ) # basic geomechanical outputs - BULK_MODULUS_INITIAL = ( "bulkModulusInitial", 1, False ) - SHEAR_MODULUS_INITIAL = ( "shearModulusInitial", 1, False ) - YOUNG_MODULUS = ( "youngModulus", 1, False ) - YOUNG_MODULUS_INITIAL = ( "youngModulusInitial", 1, False ) - POISSON_RATIO = ( "poissonRatio", 1, False ) - POISSON_RATIO_INITIAL = ( "poissonRatioInitial", 1, False ) - OEDOMETRIC_MODULUS = ( "oedometricModulus", 1, False ) - BIOT_COEFFICIENT = ( "biotCoefficient", 1, False ) - BIOT_COEFFICIENT_INITIAL = ( "biotCoefficientInitial", 1, False ) - COMPRESSIBILITY = ( "compressibilityCoefficient", 1, False ) - COMPRESSIBILITY_REAL = ( "compressibilityCoefficient_real", 1, False ) - COMPRESSIBILITY_OED = ( "compressibilityCoefficient_oed", 1, False ) - SPECIFIC_GRAVITY = ( "specificGravity", 1, False ) - LITHOSTATIC_STRESS = ( "stressLithostatic", 1, False ) - STRESS_EFFECTIVE_INITIAL = ( "stressEffectiveInitial", 6, False ) - STRESS_EFFECTIVE_RATIO_REAL = ( "stressEffectiveRatio_real", 1, False ) - STRESS_EFFECTIVE_RATIO_OED = ( "stressEffectiveRatio_oed", 1, False ) - STRESS_TOTAL = ( "stressTotal", 6, False ) - STRESS_TOTAL_INITIAL = ( "stressTotalInitial", 6, False ) - STRESS_TOTAL_RATIO_REAL = ( "stressTotalRatio_real", 1, False ) - STRESS_TOTAL_DELTA = ( "deltaStressTotal", 6, False ) - STRAIN_ELASTIC = ( "strainElastic", 6, False ) - RSP_OED = ( "rsp_oed", 1, False ) - RSP_REAL = ( "rsp_real", 6, False ) + BULK_MODULUS_INITIAL = ( "bulkModulusInitial", 1, Piece.CELLS ) + SHEAR_MODULUS_INITIAL = ( "shearModulusInitial", 1, Piece.CELLS ) + YOUNG_MODULUS = ( "youngModulus", 1, Piece.CELLS ) + YOUNG_MODULUS_INITIAL = ( "youngModulusInitial", 1, Piece.CELLS ) + POISSON_RATIO = ( "poissonRatio", 1, Piece.CELLS ) + POISSON_RATIO_INITIAL = ( "poissonRatioInitial", 1, Piece.CELLS ) + OEDOMETRIC_MODULUS = ( "oedometricModulus", 1, Piece.CELLS ) + BIOT_COEFFICIENT = ( "biotCoefficient", 1, Piece.CELLS ) + BIOT_COEFFICIENT_INITIAL = ( "biotCoefficientInitial", 1, Piece.CELLS ) + COMPRESSIBILITY = ( "compressibilityCoefficient", 1, Piece.CELLS ) + COMPRESSIBILITY_REAL = ( "compressibilityCoefficient_real", 1, Piece.CELLS ) + COMPRESSIBILITY_OED = ( "compressibilityCoefficient_oed", 1, Piece.CELLS ) + SPECIFIC_GRAVITY = ( "specificGravity", 1, Piece.CELLS ) + LITHOSTATIC_STRESS = ( "stressLithostatic", 1, Piece.CELLS ) + STRESS_EFFECTIVE_INITIAL = ( "stressEffectiveInitial", 6, Piece.CELLS ) + STRESS_EFFECTIVE_RATIO_REAL = ( "stressEffectiveRatio_real", 1, Piece.CELLS ) + STRESS_EFFECTIVE_RATIO_OED = ( "stressEffectiveRatio_oed", 1, Piece.CELLS ) + STRESS_TOTAL = ( "stressTotal", 6, Piece.CELLS ) + STRESS_TOTAL_INITIAL = ( "stressTotalInitial", 6, Piece.CELLS ) + STRESS_TOTAL_RATIO_REAL = ( "stressTotalRatio_real", 1, Piece.CELLS ) + STRESS_TOTAL_DELTA = ( "deltaStressTotal", 6, Piece.CELLS ) + STRAIN_ELASTIC = ( "strainElastic", 6, Piece.CELLS ) + RSP_OED = ( "rsp_oed", 1, Piece.CELLS ) + RSP_REAL = ( "rsp_real", 6, Piece.CELLS ) # advanced geomechanical outputs - CRITICAL_TOTAL_STRESS_RATIO = ( "totalStressRatioCritical_real", 1, False ) - TOTAL_STRESS_RATIO_THRESHOLD = ( "totalStressRatioThreshold_real", 1, False ) - CRITICAL_PORE_PRESSURE = ( "porePressureCritical_real", 1, False ) - CRITICAL_PORE_PRESSURE_THRESHOLD = ( "porePressureThreshold_real", 1, False ) + CRITICAL_TOTAL_STRESS_RATIO = ( "totalStressRatioCritical_real", 1, Piece.CELLS ) + TOTAL_STRESS_RATIO_THRESHOLD = ( "totalStressRatioThreshold_real", 1, Piece.CELLS ) + CRITICAL_PORE_PRESSURE = ( "porePressureCritical_real", 1, Piece.CELLS ) + CRITICAL_PORE_PRESSURE_THRESHOLD = ( "porePressureThreshold_real", 1, Piece.CELLS ) # surface outputs - SCU = ( "SCU", 1, False ) + SCU = ( "SCU", 1, Piece.CELLS ) class PhaseTypeEnum( Enum ): diff --git a/geos-utils/src/geos/utils/pieceEnum.py b/geos-utils/src/geos/utils/pieceEnum.py new file mode 100644 index 000000000..15b0284b6 --- /dev/null +++ b/geos-utils/src/geos/utils/pieceEnum.py @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: Apache-2.0 +# SPDX-FileCopyrightText: Copyright 2023-2024 TotalEnergies. +# SPDX-FileContributor: Romain Baville +from enum import Enum + + +class Piece( str, Enum ): + """String Enum of a vtkDataObject pieces.""" + POINTS = "points" + CELLS = "cells" + BOTH = "cells and points" + FIELD = "field" + NONE = "none" diff --git a/mesh-doctor/src/geos/mesh_doctor/actions/generateCube.py b/mesh-doctor/src/geos/mesh_doctor/actions/generateCube.py index 9af53ddbc..887bf1a07 100644 --- a/mesh-doctor/src/geos/mesh_doctor/actions/generateCube.py +++ b/mesh-doctor/src/geos/mesh_doctor/actions/generateCube.py @@ -13,6 +13,7 @@ from geos.mesh.utils.arrayModifiers import createConstantAttributeDataSet from geos.mesh_doctor.actions.generateGlobalIds import buildGlobalIds from geos.mesh_doctor.parsing.cliParsing import setupLogger +from geos.utils.pieceEnum import Piece @dataclass( frozen=True ) @@ -180,14 +181,14 @@ def addFields( mesh: vtkUnstructuredGrid, fields: Iterable[ FieldInfo ] ) -> vtk vtkUnstructuredGrid: The mesh with added fields. """ for fieldInfo in fields: - onPoints = fieldInfo.support == "POINTS" + piece: Piece = Piece.POINTS if fieldInfo.support == "POINTS" else Piece.CELLS # Create list of values (all 1.0) for each component listValues = [ 1.0 ] * fieldInfo.dimension # Use the robust createConstantAttributeDataSet function success = createConstantAttributeDataSet( dataSet=mesh, listValues=listValues, attributeName=fieldInfo.name, - onPoints=onPoints, + piece=piece, logger=setupLogger ) if not success: setupLogger.warning( f"Failed to create field {fieldInfo.name}" )