diff --git a/geos-mesh/src/geos/mesh/utils/arrayHelpers.py b/geos-mesh/src/geos/mesh/utils/arrayHelpers.py index 98388fd59..43f363714 100644 --- a/geos-mesh/src/geos/mesh/utils/arrayHelpers.py +++ b/geos-mesh/src/geos/mesh/utils/arrayHelpers.py @@ -11,10 +11,9 @@ from vtkmodules.util.numpy_support import vtk_to_numpy from vtkmodules.vtkCommonCore import vtkDataArray, vtkPoints from vtkmodules.vtkCommonDataModel import ( vtkUnstructuredGrid, vtkFieldData, vtkMultiBlockDataSet, vtkDataSet, - vtkCompositeDataSet, vtkDataObject, vtkPointData, vtkCellData, - vtkDataObjectTreeIterator, vtkPolyData ) + vtkCompositeDataSet, vtkDataObject, vtkPointData, vtkCellData, vtkPolyData ) from vtkmodules.vtkFiltersCore import vtkCellCenters -from geos.mesh.utils.multiblockHelpers import ( getBlockElementIndexesFlatten, getBlockFromFlatIndex ) +from geos.mesh.utils.multiblockHelpers import getBlockElementIndexesFlatten __doc__ = """ ArrayHelpers module contains several utilities methods to get information on arrays in VTK datasets. @@ -159,23 +158,23 @@ def getNumpyArrayByName( data: Union[ vtkCellData, vtkPointData ], return None -def getAttributeSet( object: Union[ vtkMultiBlockDataSet, vtkDataSet ], onPoints: bool ) -> set[ str ]: - """Get the set of all attributes from an object on points or on cells. +def getAttributeSet( mesh: Union[ vtkMultiBlockDataSet, vtkDataSet ], onPoints: bool ) -> set[ str ]: + """Get the set of all attributes from an mesh on points or on cells. Args: - object (Any): Object where to find the attributes. + mesh (Any): Mesh where to find the attributes. onPoints (bool): True if attributes are on points, False if they are on cells. Returns: - set[str]: Set of attribute names present in input object. + set[str]: Set of attribute names present in input mesh. """ attributes: dict[ str, int ] - if isinstance( object, vtkMultiBlockDataSet ): - attributes = getAttributesFromMultiBlockDataSet( object, onPoints ) - elif isinstance( object, vtkDataSet ): - attributes = getAttributesFromDataSet( object, onPoints ) + if isinstance( mesh, vtkMultiBlockDataSet ): + attributes = getAttributesFromMultiBlockDataSet( mesh, onPoints ) + elif isinstance( mesh, vtkDataSet ): + attributes = getAttributesFromDataSet( mesh, onPoints ) else: - raise TypeError( "Input object must be a vtkDataSet or vtkMultiBlockDataSet." ) + raise TypeError( "Input mesh must be a vtkDataSet or vtkMultiBlockDataSet." ) assert attributes is not None, "Attribute list is undefined." @@ -183,61 +182,56 @@ def getAttributeSet( object: Union[ vtkMultiBlockDataSet, vtkDataSet ], onPoints def getAttributesWithNumberOfComponents( - object: Union[ vtkMultiBlockDataSet, vtkCompositeDataSet, vtkDataSet, vtkDataObject ], + mesh: Union[ vtkMultiBlockDataSet, vtkCompositeDataSet, vtkDataSet, vtkDataObject ], onPoints: bool, ) -> dict[ str, int ]: """Get the dictionary of all attributes from object on points or cells. Args: - object (Any): Object where to find the attributes. + mesh (Any): Mesh where to find the attributes. onPoints (bool): True if attributes are on points, False if they are on cells. 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( object, ( vtkMultiBlockDataSet, vtkCompositeDataSet ) ): - attributes = getAttributesFromMultiBlockDataSet( object, onPoints ) - elif isinstance( object, vtkDataSet ): - attributes = getAttributesFromDataSet( object, onPoints ) + if isinstance( mesh, ( vtkMultiBlockDataSet, vtkCompositeDataSet ) ): + attributes = getAttributesFromMultiBlockDataSet( mesh, onPoints ) + elif isinstance( mesh, vtkDataSet ): + attributes = getAttributesFromDataSet( mesh, onPoints ) else: - raise TypeError( "Input object must be a vtkDataSet or vtkMultiBlockDataSet." ) + raise TypeError( "Input mesh must be a vtkDataSet or vtkMultiBlockDataSet." ) return attributes -def getAttributesFromMultiBlockDataSet( object: Union[ vtkMultiBlockDataSet, vtkCompositeDataSet ], +def getAttributesFromMultiBlockDataSet( multiBlockDataSet: Union[ vtkMultiBlockDataSet, vtkCompositeDataSet ], onPoints: bool ) -> dict[ str, int ]: """Get the dictionary of all attributes of object on points or on cells. Args: - object (vtkMultiBlockDataSet | vtkCompositeDataSet): Object where to find the attributes. + multiBlockDataSet (vtkMultiBlockDataSet | vtkCompositeDataSet): multiBlockDataSet where to find the attributes. onPoints (bool): True if attributes are on points, False if they are on cells. Returns: dict[str, int]: Dictionary of the names of the attributes as keys, and number of components as values. """ attributes: dict[ str, int ] = {} - # initialize data object tree iterator - iterator: vtkDataObjectTreeIterator = vtkDataObjectTreeIterator() - iterator.SetDataSet( object ) - iterator.VisitOnlyLeavesOn() - iterator.GoToFirstItem() - while iterator.GetCurrentDataObject() is not None: - dataSet: vtkDataSet = vtkDataSet.SafeDownCast( iterator.GetCurrentDataObject() ) + elementaryBlockIndexes: list[ int ] = getBlockElementIndexesFlatten( multiBlockDataSet ) + for blockIndex in elementaryBlockIndexes: + dataSet: vtkDataSet = vtkDataSet.SafeDownCast( multiBlockDataSet.GetDataSet( blockIndex ) ) blockAttributes: dict[ str, int ] = getAttributesFromDataSet( dataSet, onPoints ) for attributeName, nbComponents in blockAttributes.items(): if attributeName not in attributes: attributes[ attributeName ] = nbComponents - iterator.GoToNextItem() return attributes -def getAttributesFromDataSet( object: vtkDataSet, onPoints: bool ) -> dict[ str, int ]: +def getAttributesFromDataSet( dataSet: vtkDataSet, onPoints: bool ) -> dict[ str, int ]: """Get the dictionary of all attributes of a vtkDataSet on points or cells. Args: - object (vtkDataSet): Object where to find the attributes. + dataSet (vtkDataSet): DataSet where to find the attributes. onPoints (bool): True if attributes are on points, False if they are on cells. Returns: @@ -247,10 +241,10 @@ def getAttributesFromDataSet( object: vtkDataSet, onPoints: bool ) -> dict[ str, data: Union[ vtkPointData, vtkCellData ] sup: str = "" if onPoints: - data = object.GetPointData() + data = dataSet.GetPointData() sup = "Point" else: - data = object.GetCellData() + data = dataSet.GetCellData() sup = "Cell" assert data is not None, f"{sup} data was not recovered." @@ -264,54 +258,51 @@ def getAttributesFromDataSet( object: vtkDataSet, onPoints: bool ) -> dict[ str, return attributes -def isAttributeInObject( object: Union[ vtkMultiBlockDataSet, vtkDataSet ], attributeName: str, - onPoints: bool ) -> bool: +def isAttributeInObject( mesh: Union[ vtkMultiBlockDataSet, vtkDataSet ], attributeName: str, onPoints: bool ) -> bool: """Check if an attribute is in the input object. Args: - object (vtkMultiBlockDataSet | vtkDataSet): Input object. + 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. Returns: bool: True if the attribute is in the table, False otherwise. """ - if isinstance( object, vtkMultiBlockDataSet ): - return isAttributeInObjectMultiBlockDataSet( object, attributeName, onPoints ) - elif isinstance( object, vtkDataSet ): - return isAttributeInObjectDataSet( object, attributeName, onPoints ) + if isinstance( mesh, vtkMultiBlockDataSet ): + return isAttributeInObjectMultiBlockDataSet( mesh, attributeName, onPoints ) + elif isinstance( mesh, vtkDataSet ): + return isAttributeInObjectDataSet( mesh, attributeName, onPoints ) else: raise TypeError( "Input object must be a vtkDataSet or vtkMultiBlockDataSet." ) -def isAttributeInObjectMultiBlockDataSet( object: vtkMultiBlockDataSet, attributeName: str, onPoints: bool ) -> bool: +def isAttributeInObjectMultiBlockDataSet( multiBlockDataSet: vtkMultiBlockDataSet, attributeName: str, + onPoints: bool ) -> bool: """Check if an attribute is in the input object. Args: - object (vtkMultiBlockDataSet): Input multiBlockDataSet. + multiBlockDataSet (vtkMultiBlockDataSet): Input multiBlockDataSet. attributeName (str): Name of the attribute. onPoints (bool): True if attributes are on points, False if they are on cells. Returns: bool: True if the attribute is in the table, False otherwise. """ - iterator: vtkDataObjectTreeIterator = vtkDataObjectTreeIterator() - iterator.SetDataSet( object ) - iterator.VisitOnlyLeavesOn() - iterator.GoToFirstItem() - while iterator.GetCurrentDataObject() is not None: - dataSet: vtkDataSet = vtkDataSet.SafeDownCast( iterator.GetCurrentDataObject() ) + elementaryBlockIndexes: list[ int ] = getBlockElementIndexesFlatten( multiBlockDataSet ) + for blockIndex in elementaryBlockIndexes: + dataSet: vtkDataSet = vtkDataSet.SafeDownCast( multiBlockDataSet.GetDataSet( blockIndex ) ) if isAttributeInObjectDataSet( dataSet, attributeName, onPoints ): return True - iterator.GoToNextItem() + return False -def isAttributeInObjectDataSet( object: vtkDataSet, attributeName: str, onPoints: bool ) -> bool: +def isAttributeInObjectDataSet( dataSet: vtkDataSet, attributeName: str, onPoints: bool ) -> bool: """Check if an attribute is in the input object. Args: - object (vtkDataSet): Input object. + dataSet (vtkDataSet): Input dataSet. attributeName (str): Name of the attribute. onPoints (bool): True if attributes are on points, False if they are on cells. @@ -321,65 +312,63 @@ def isAttributeInObjectDataSet( object: vtkDataSet, attributeName: str, onPoints data: Union[ vtkPointData, vtkCellData ] sup: str = "" if onPoints: - data = object.GetPointData() + data = dataSet.GetPointData() sup = "Point" else: - data = object.GetCellData() + data = dataSet.GetCellData() sup = "Cell" assert data is not None, f"{ sup } data was not recovered." return bool( data.HasArray( attributeName ) ) -def isAttributeGlobal( object: vtkMultiBlockDataSet, attributeName: str, onPoints: bool ) -> bool: +def isAttributeGlobal( multiBlockDataSet: vtkMultiBlockDataSet, attributeName: str, onPoints: bool ) -> bool: """Check if an attribute is global in the input multiBlockDataSet. Args: - object (vtkMultiBlockDataSet): Input object. + multiBlockDataSet (vtkMultiBlockDataSet): Input multiBlockDataSet. attributeName (str): Name of the attribute. onPoints (bool): True if attributes are on points, False if they are on cells. Returns: bool: True if the attribute is global, False if not. """ - isOnBlock: bool - nbBlock: int = object.GetNumberOfBlocks() - for idBlock in range( nbBlock ): - block: vtkDataSet = vtkDataSet.SafeDownCast( object.GetBlock( idBlock ) ) - isOnBlock = isAttributeInObjectDataSet( block, attributeName, onPoints ) - if not isOnBlock: + elementaryBlockIndexes: list[ int ] = getBlockElementIndexesFlatten( multiBlockDataSet ) + for blockIndex in elementaryBlockIndexes: + dataSet: vtkDataSet = vtkDataSet.SafeDownCast( multiBlockDataSet.GetDataSet( blockIndex ) ) + if not isAttributeInObjectDataSet( dataSet, attributeName, onPoints ): return False return True -def getArrayInObject( object: vtkDataSet, attributeName: str, onPoints: bool ) -> npt.NDArray[ Any ]: +def getArrayInObject( dataSet: vtkDataSet, attributeName: str, onPoints: bool ) -> npt.NDArray[ Any ]: """Return the numpy array corresponding to input attribute name in table. Args: - object (PointSet or UnstructuredGrid): Input object. + dataSet (vtkDataSet): Input dataSet. attributeName (str): Name of the attribute. onPoints (bool): True if attributes are on points, False if they are on cells. Returns: ArrayLike[Any]: The numpy array corresponding to input attribute name. """ - vtkArray: vtkDataArray = getVtkArrayInObject( object, attributeName, onPoints ) + vtkArray: vtkDataArray = getVtkArrayInObject( dataSet, attributeName, onPoints ) npArray: npt.NDArray[ Any ] = vnp.vtk_to_numpy( vtkArray ) # type: ignore[no-untyped-call] return npArray -def getVtkArrayTypeInObject( object: vtkDataSet, attributeName: str, onPoints: bool ) -> int: +def getVtkArrayTypeInObject( dataSet: vtkDataSet, attributeName: str, onPoints: bool ) -> int: """Return VTK type of requested array from dataset input. Args: - object (PointSet or UnstructuredGrid): Input object. + dataSet (vtkDataSet): Input dataSet. attributeName (str): Name of the attribute. onPoints (bool): True if attributes are on points, False if they are on cells. Returns: int: The type of the vtk array corresponding to input attribute name. """ - array: vtkDataArray = getVtkArrayInObject( object, attributeName, onPoints ) + array: vtkDataArray = getVtkArrayInObject( dataSet, attributeName, onPoints ) vtkArrayType: int = array.GetDataType() return vtkArrayType @@ -389,58 +378,58 @@ def getVtkArrayTypeInMultiBlock( multiBlockDataSet: vtkMultiBlockDataSet, attrib """Return VTK type of requested array from multiblock dataset input, if existing. Args: - multiBlockDataSet (vtkMultiBlockDataSet): Input object. + multiBlockDataSet (vtkMultiBlockDataSet): Input multiBlockDataSet. attributeName (str): Name of the attribute. onPoints (bool): True if attributes are on points, False if they are on cells. Returns: int: Type of the requested vtk array if existing in input multiblock dataset. """ - nbBlocks = multiBlockDataSet.GetNumberOfBlocks() - for idBlock in range( nbBlocks ): - object: vtkDataSet = vtkDataSet.SafeDownCast( multiBlockDataSet.GetBlock( idBlock ) ) - listAttributes: set[ str ] = getAttributeSet( object, onPoints ) + elementaryBlockIndexes: list[ int ] = getBlockElementIndexesFlatten( multiBlockDataSet ) + for blockIndex in elementaryBlockIndexes: + dataSet: vtkDataSet = vtkDataSet.SafeDownCast( multiBlockDataSet.GetDataSet( blockIndex ) ) + listAttributes: set[ str ] = getAttributeSet( dataSet, onPoints ) if attributeName in listAttributes: - return getVtkArrayTypeInObject( object, attributeName, onPoints ) + return getVtkArrayTypeInObject( dataSet, attributeName, onPoints ) raise AssertionError( "The vtkMultiBlockDataSet has no attribute with the name " + attributeName + "." ) -def getVtkArrayInObject( object: vtkDataSet, attributeName: str, onPoints: bool ) -> vtkDataArray: +def getVtkArrayInObject( dataSet: vtkDataSet, attributeName: str, onPoints: bool ) -> vtkDataArray: """Return the array corresponding to input attribute name in table. Args: - object (PointSet or UnstructuredGrid): Input object. + dataSet (vtkDataSet): Input dataSet. attributeName (str): Name of the attribute. onPoints (bool): True if attributes are on points, False if they are on cells. Returns: vtkDataArray: The vtk array corresponding to input attribute name. """ - assert isAttributeInObject( object, attributeName, onPoints ), f"{attributeName} is not in input object." - return object.GetPointData().GetArray( attributeName ) if onPoints else object.GetCellData().GetArray( + assert isAttributeInObject( dataSet, attributeName, onPoints ), f"{attributeName} is not in input mesh." + return dataSet.GetPointData().GetArray( attributeName ) if onPoints else dataSet.GetCellData().GetArray( attributeName ) def getNumberOfComponents( - dataSet: Union[ vtkMultiBlockDataSet, vtkCompositeDataSet, vtkDataSet ], + mesh: Union[ vtkMultiBlockDataSet, vtkCompositeDataSet, vtkDataSet ], attributeName: str, onPoints: bool, ) -> int: """Get the number of components of attribute attributeName in dataSet. Args: - dataSet (vtkMultiBlockDataSet | vtkCompositeDataSet | vtkDataSet): DataSet where the attribute is. + 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. Returns: int: Number of components. """ - if isinstance( dataSet, vtkDataSet ): - return getNumberOfComponentsDataSet( dataSet, attributeName, onPoints ) - elif isinstance( dataSet, ( vtkMultiBlockDataSet, vtkCompositeDataSet ) ): - return getNumberOfComponentsMultiBlock( dataSet, attributeName, onPoints ) + if isinstance( mesh, vtkDataSet ): + return getNumberOfComponentsDataSet( mesh, attributeName, onPoints ) + elif isinstance( mesh, ( vtkMultiBlockDataSet, vtkCompositeDataSet ) ): + return getNumberOfComponentsMultiBlock( mesh, attributeName, onPoints ) else: raise AssertionError( "Object type is not managed." ) @@ -461,50 +450,50 @@ def getNumberOfComponentsDataSet( dataSet: vtkDataSet, attributeName: str, onPoi def getNumberOfComponentsMultiBlock( - dataSet: Union[ vtkMultiBlockDataSet, vtkCompositeDataSet ], + multiBlockDataSet: Union[ vtkMultiBlockDataSet, vtkCompositeDataSet ], attributeName: str, onPoints: bool, ) -> int: """Get the number of components of attribute attributeName in dataSet. Args: - dataSet (vtkMultiBlockDataSet | vtkCompositeDataSet): multi block data Set where the attribute is. + 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. Returns: int: Number of components. """ - elementaryBlockIndexes: list[ int ] = getBlockElementIndexesFlatten( dataSet ) + elementaryBlockIndexes: list[ int ] = getBlockElementIndexesFlatten( multiBlockDataSet ) for blockIndex in elementaryBlockIndexes: - block: vtkDataSet = vtkDataSet.SafeDownCast( getBlockFromFlatIndex( dataSet, blockIndex ) ) - if isAttributeInObject( block, attributeName, onPoints ): - array: vtkDataArray = getVtkArrayInObject( block, attributeName, onPoints ) + dataSet: vtkDataSet = vtkDataSet.SafeDownCast( multiBlockDataSet.GetDataSet( blockIndex ) ) + if isAttributeInObject( dataSet, attributeName, onPoints ): + array: vtkDataArray = getVtkArrayInObject( dataSet, attributeName, onPoints ) return array.GetNumberOfComponents() return 0 def getComponentNames( - dataSet: Union[ vtkMultiBlockDataSet, vtkCompositeDataSet, vtkDataSet, vtkDataObject ], + mesh: Union[ vtkMultiBlockDataSet, vtkCompositeDataSet, vtkDataSet, vtkDataObject ], attributeName: str, onPoints: bool, ) -> tuple[ str, ...]: """Get the name of the components of attribute attributeName in dataSet. Args: - dataSet (vtkDataSet | vtkMultiBlockDataSet | vtkCompositeDataSet | vtkDataObject): DataSet where the attribute is. + 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. Returns: tuple[str,...]: Names of the components. """ - if isinstance( dataSet, vtkDataSet ): - return getComponentNamesDataSet( dataSet, attributeName, onPoints ) - elif isinstance( dataSet, ( vtkMultiBlockDataSet, vtkCompositeDataSet ) ): - return getComponentNamesMultiBlock( dataSet, attributeName, onPoints ) + if isinstance( mesh, vtkDataSet ): + return getComponentNamesDataSet( mesh, attributeName, onPoints ) + elif isinstance( mesh, ( vtkMultiBlockDataSet, vtkCompositeDataSet ) ): + return getComponentNamesMultiBlock( mesh, attributeName, onPoints ) else: - raise AssertionError( "Object type is not managed." ) + raise AssertionError( "Mesh type is not managed." ) def getComponentNamesDataSet( dataSet: vtkDataSet, attributeName: str, onPoints: bool ) -> tuple[ str, ...]: @@ -527,25 +516,25 @@ def getComponentNamesDataSet( dataSet: vtkDataSet, attributeName: str, onPoints: def getComponentNamesMultiBlock( - dataSet: Union[ vtkMultiBlockDataSet, vtkCompositeDataSet ], + multiBlockDataSet: Union[ vtkMultiBlockDataSet, vtkCompositeDataSet ], attributeName: str, onPoints: bool, ) -> tuple[ str, ...]: """Get the name of the components of attribute in MultiBlockDataSet. Args: - dataSet (vtkMultiBlockDataSet | vtkCompositeDataSet): DataSet where the attribute is. + 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. Returns: tuple[str,...]: Names of the components. """ - elementaryBlockIndexes: list[ int ] = getBlockElementIndexesFlatten( dataSet ) + elementaryBlockIndexes: list[ int ] = getBlockElementIndexesFlatten( multiBlockDataSet ) for blockIndex in elementaryBlockIndexes: - block: vtkDataSet = vtkDataSet.SafeDownCast( getBlockFromFlatIndex( dataSet, blockIndex ) ) - if isAttributeInObject( block, attributeName, onPoints ): - return getComponentNamesDataSet( block, attributeName, onPoints ) + dataSet: vtkDataSet = vtkDataSet.SafeDownCast( multiBlockDataSet.GetDataSet( blockIndex ) ) + if isAttributeInObject( dataSet, attributeName, onPoints ): + return getComponentNamesDataSet( dataSet, attributeName, onPoints ) return () diff --git a/geos-mesh/src/geos/mesh/utils/arrayModifiers.py b/geos-mesh/src/geos/mesh/utils/arrayModifiers.py index e5c8b0a6a..e14ac2d94 100644 --- a/geos-mesh/src/geos/mesh/utils/arrayModifiers.py +++ b/geos-mesh/src/geos/mesh/utils/arrayModifiers.py @@ -17,7 +17,6 @@ vtkPointSet, vtkCompositeDataSet, vtkDataObject, - vtkDataObjectTreeIterator, vtkPointData, vtkCellData, ) @@ -43,10 +42,7 @@ getVtkArrayTypeInMultiBlock, getNumberOfComponentsMultiBlock, ) -from geos.mesh.utils.multiblockHelpers import ( - getBlockElementIndexesFlatten, - getBlockFromFlatIndex, -) +from geos.mesh.utils.multiblockHelpers import getBlockElementIndexesFlatten __doc__ = """ ArrayModifiers contains utilities to process VTK Arrays objects. @@ -148,18 +144,13 @@ def fillPartialAttributes( ) # Parse the multiBlockDataSet to create and fill the attribute on blocks where it is not. - iterator: vtkDataObjectTreeIterator = vtkDataObjectTreeIterator() - iterator.SetDataSet( multiBlockDataSet ) - iterator.VisitOnlyLeavesOn() - iterator.GoToFirstItem() - while iterator.GetCurrentDataObject() is not None: - dataSet: vtkDataSet = vtkDataSet.SafeDownCast( iterator.GetCurrentDataObject() ) + 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 ): return False - iterator.GoToNextItem() - return True @@ -224,7 +215,7 @@ def createEmptyAttribute( def createConstantAttribute( - object: Union[ vtkMultiBlockDataSet, vtkCompositeDataSet, vtkDataObject ], + mesh: Union[ vtkMultiBlockDataSet, vtkCompositeDataSet, vtkDataSet ], listValues: list[ Any ], attributeName: str, componentNames: tuple[ str, ...] = (), # noqa: C408 @@ -232,10 +223,10 @@ def createConstantAttribute( vtkDataType: Union[ int, None ] = None, logger: Union[ Logger, None ] = None, ) -> bool: - """Create a new attribute with a constant value in the object. + """Create a new attribute with a constant value in the mesh. Args: - object (vtkDataObject): Object (vtkMultiBlockDataSet, vtkDataSet) where to create the attribute. + mesh (Union[vtkMultiBlockDataSet, vtkDataSet]): Mesh where to create the attribute. listValues (list[Any]): List of values of the attribute for each components. It is recommended to use numpy scalar type for the values. attributeName (str): Name of the attribute. componentNames (tuple[str,...], optional): Name of the components for vectorial attributes. If one component, gives an empty tuple. @@ -260,20 +251,15 @@ def createConstantAttribute( logger = getLogger( "createConstantAttribute", True ) # Deals with multiBlocksDataSets. - if isinstance( object, ( vtkMultiBlockDataSet, vtkCompositeDataSet ) ): - return createConstantAttributeMultiBlock( object, listValues, attributeName, componentNames, onPoints, + if isinstance( mesh, ( vtkMultiBlockDataSet, vtkCompositeDataSet ) ): + return createConstantAttributeMultiBlock( mesh, listValues, attributeName, componentNames, onPoints, vtkDataType, logger ) # Deals with dataSets. - elif isinstance( object, vtkDataSet ): - return createConstantAttributeDataSet( object, listValues, attributeName, componentNames, onPoints, vtkDataType, + elif isinstance( mesh, vtkDataSet ): + return createConstantAttributeDataSet( mesh, listValues, attributeName, componentNames, onPoints, vtkDataType, logger ) - else: - logger.error( "The mesh has to be inherited from a vtkMultiBlockDataSet or a vtkDataSet" ) - logger.error( f"The constant attribute { attributeName } has not been created into the mesh." ) - return False - def createConstantAttributeMultiBlock( multiBlockDataSet: Union[ vtkMultiBlockDataSet, vtkCompositeDataSet ], @@ -287,7 +273,7 @@ def createConstantAttributeMultiBlock( """Create a new attribute with a constant value per component on every block of the multiBlockDataSet. Args: - multiBlockDataSet (vtkMultiBlockDataSet | vtkCompositeDataSet): MultiBlockDataSet where to create the attribute. + multiBlockDataSet (Union[vtkMultiBlockDataSet, vtkCompositeDataSet]): MultiBlockDataSet where to create the attribute. listValues (list[Any]): List of values of the attribute for each components. It is recommended to use numpy scalar type for the values. attributeName (str): Name of the attribute. componentNames (tuple[str,...], optional): Name of the components for vectorial attributes. If one component, gives an empty tuple. @@ -334,18 +320,13 @@ def createConstantAttributeMultiBlock( ) # Parse the multiBlockDataSet to create the constant attribute on each blocks. - iterator: vtkDataObjectTreeIterator = vtkDataObjectTreeIterator() - iterator.SetDataSet( multiBlockDataSet ) - iterator.VisitOnlyLeavesOn() - iterator.GoToFirstItem() - while iterator.GetCurrentDataObject() is not None: - dataSet: vtkDataSet = vtkDataSet.SafeDownCast( iterator.GetCurrentDataObject() ) + 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 ): return False - iterator.GoToNextItem() - return True @@ -613,13 +594,13 @@ def copyAttribute( # Parse blocks of the two mesh to copy the attribute. for idBlock in elementaryBlockIndexesTo: - dataSetFrom: vtkDataSet = vtkDataSet.SafeDownCast( getBlockFromFlatIndex( multiBlockDataSetFrom, idBlock ) ) + dataSetFrom: vtkDataSet = vtkDataSet.SafeDownCast( multiBlockDataSetFrom.GetDataSet( idBlock ) ) if dataSetFrom is None: logger.error( f"Block { idBlock } of multiBlockDataSetFrom is null." ) # type: ignore[unreachable] logger.error( f"The attribute { attributeNameFrom } has not been copied." ) return False - dataSetTo: vtkDataSet = vtkDataSet.SafeDownCast( getBlockFromFlatIndex( multiBlockDataSetTo, idBlock ) ) + dataSetTo: vtkDataSet = vtkDataSet.SafeDownCast( multiBlockDataSetTo.GetDataSet( idBlock ) ) if dataSetTo is None: logger.error( f"Block { idBlock } of multiBlockDataSetTo is null." ) # type: ignore[unreachable] logger.error( f"The attribute { attributeNameFrom } has not been copied." ) @@ -735,15 +716,10 @@ def createCellCenterAttribute( mesh: Union[ vtkMultiBlockDataSet, vtkDataSet ], """ ret: int = 1 if isinstance( mesh, vtkMultiBlockDataSet ): - # initialize data object tree iterator - iterator: vtkDataObjectTreeIterator = vtkDataObjectTreeIterator() - iterator.SetDataSet( mesh ) - iterator.VisitOnlyLeavesOn() - iterator.GoToFirstItem() - while iterator.GetCurrentDataObject() is not None: - block: vtkDataSet = vtkDataSet.SafeDownCast( iterator.GetCurrentDataObject() ) - ret *= int( doCreateCellCenterAttribute( block, cellCenterAttributeName ) ) - iterator.GoToNextItem() + elementaryBlockIndexes: list[ int ] = getBlockElementIndexesFlatten( mesh ) + for blockIndex in elementaryBlockIndexes: + dataSet: vtkDataSet = vtkDataSet.SafeDownCast( mesh.GetDataSet( blockIndex ) ) + ret *= int( doCreateCellCenterAttribute( dataSet, cellCenterAttributeName ) ) elif isinstance( mesh, vtkDataSet ): ret = int( doCreateCellCenterAttribute( mesh, cellCenterAttributeName ) ) else: diff --git a/geos-mesh/src/geos/mesh/utils/multiblockHelpers.py b/geos-mesh/src/geos/mesh/utils/multiblockHelpers.py index ac060f5b7..8a6aea5e9 100644 --- a/geos-mesh/src/geos/mesh/utils/multiblockHelpers.py +++ b/geos-mesh/src/geos/mesh/utils/multiblockHelpers.py @@ -1,7 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 # SPDX-FileCopyrightText: Copyright 2023-2024 TotalEnergies. -# SPDX-FileContributor: Martin Lemay -from typing import Union, cast +# SPDX-FileContributor: Martin Lemay, Romain Baville +from typing import Union from vtkmodules.vtkCommonDataModel import ( vtkCompositeDataSet, vtkDataObject, vtkDataObjectTreeIterator, vtkMultiBlockDataSet ) from vtkmodules.vtkFiltersExtraction import vtkExtractBlock @@ -15,216 +15,202 @@ """ -def getBlockName( input: Union[ vtkMultiBlockDataSet, vtkCompositeDataSet ] ) -> str: - """Get the name of input block. - - If input is a vtkMultiBlockDataSet or vtkCompositeDataSet, returns the name - of the lowest level unique child block. +def getBlockNames( multiBlockDataSet: Union[ vtkMultiBlockDataSet, vtkCompositeDataSet ] ) -> list[ str ]: + """Get the name of all blocks of the multiBlockDataSet. Args: - input (vtkMultiBlockDataSet | vtkCompositeDataSet): input multi block object. + multiBlockDataSet (Union[vtkMultiBlockDataSet, vtkCompositeDataSet]): MultiBlockDataSet with the block names to get. Returns: - str: name of the block in the tree. + list[str]: list of the names of the block in the multiBlockDataSet. """ - iter: vtkDataObjectTreeIterator = vtkDataObjectTreeIterator() - iter.SetDataSet( input ) - iter.VisitOnlyLeavesOff() - iter.GoToFirstItem() - blockName: str = "Block" - while iter.GetCurrentDataObject() is not None: - blockName = iter.GetCurrentMetaData().Get( vtkMultiBlockDataSet.NAME() ) - block: vtkDataObject = iter.GetCurrentDataObject() - nbBlocks: int = 99 - if isinstance( block, vtkMultiBlockDataSet ): - block1: vtkMultiBlockDataSet = cast( vtkMultiBlockDataSet, block ) - nbBlocks = block1.GetNumberOfBlocks() - - # stop if multiple children - if nbBlocks > 1: - break - - iter.GoToNextItem() - return blockName - - -def getBlockNameFromIndex( input: Union[ vtkMultiBlockDataSet, vtkCompositeDataSet ], index: int ) -> str: - """Get the name of a block from input multiblock and block flat index. + listBlockNames: list[ str ] = [] + iterator: vtkDataObjectTreeIterator = vtkDataObjectTreeIterator() + iterator.SetDataSet( multiBlockDataSet ) + iterator.VisitOnlyLeavesOff() + iterator.GoToFirstItem() + while iterator.GetCurrentDataObject() is not None: + listBlockNames.append( iterator.GetCurrentMetaData().Get( vtkMultiBlockDataSet.NAME() ) ) + iterator.GoToNextItem() + return listBlockNames + + +def getBlockNameFromIndex( multiBlockDataSet: Union[ vtkMultiBlockDataSet, vtkCompositeDataSet ], index: int ) -> str: + """Get the name of a multiBlockDataSet block with its flat index. Args: - input (vtkMultiBlockDataSet | vtkCompositeDataSet): input multi block object. - index (int): flat index of the block to get the name + multiBlockDataSet (Union[vtkMultiBlockDataSet, vtkCompositeDataSet]): MultiBlockDataSet with the block to get the name. + index (int): Flat index of the block to get the name. Returns: str: name of the block in the tree. """ - iter: vtkDataObjectTreeIterator = vtkDataObjectTreeIterator() - iter.SetDataSet( input ) - iter.VisitOnlyLeavesOff() - iter.GoToFirstItem() - blockName: str = "Block" - while iter.GetCurrentDataObject() is not None: - blockName = iter.GetCurrentMetaData().Get( vtkMultiBlockDataSet.NAME() ) - if iter.GetCurrentFlatIndex() == index: - break - iter.GoToNextItem() - return blockName - - -def getBlockIndexFromName( input: Union[ vtkMultiBlockDataSet, vtkCompositeDataSet ], name: str ) -> int: - """Get block flat index from name of node in the vtkMultiBlockDataSet tree. + iterator: vtkDataObjectTreeIterator = vtkDataObjectTreeIterator() + iterator.SetDataSet( multiBlockDataSet ) + iterator.VisitOnlyLeavesOff() + iterator.GoToFirstItem() + while iterator.GetCurrentDataObject() is not None: + if iterator.GetCurrentFlatIndex() == index: + return iterator.GetCurrentMetaData().Get( vtkMultiBlockDataSet.NAME() ) + iterator.GoToNextItem() + + raise ValueError( "The block index is not an index of a block in the mesh" ) + + +def getBlockIndexFromName( multiBlockDataSet: Union[ vtkMultiBlockDataSet, vtkCompositeDataSet ], + blockName: str ) -> int: + """Get flat index of a multiBlockDataSet block with its name. Args: - input (vtkMultiBlockDataSet | vtkCompositeDataSet): input multi block object. - name (str): name of the block to get the index in the tree. + multiBlockDataSet (Union[vtkMultiBlockDataSet, vtkCompositeDataSet]): MultiBlockDataSet with the block to get the index. + blockName (str): Name of the block to get the flat index. Returns: - int: index of the block if found, -1 otherwise. + int: Flat index of the block if found, -1 otherwise. """ blockIndex: int = -1 # initialize data object tree iterator - iter: vtkDataObjectTreeIterator = vtkDataObjectTreeIterator() - iter.SetDataSet( input ) - iter.VisitOnlyLeavesOff() - iter.GoToFirstItem() - found: bool = False - while iter.GetCurrentDataObject() is not None: - blockName: str = iter.GetCurrentMetaData().Get( vtkMultiBlockDataSet.NAME() ) - blockIndex = iter.GetCurrentFlatIndex() - if blockName.lower() == name.lower(): - found = True - break - iter.GoToNextItem() - return blockIndex if found else -1 - - -def getElementaryCompositeBlockIndexes( input: Union[ vtkMultiBlockDataSet, vtkCompositeDataSet ] ) -> dict[ str, int ]: - """Get indexes of composite block that contains elementrary blocks. + iterator: vtkDataObjectTreeIterator = vtkDataObjectTreeIterator() + iterator.SetDataSet( multiBlockDataSet ) + iterator.VisitOnlyLeavesOff() + iterator.GoToFirstItem() + while iterator.GetCurrentDataObject() is not None: + currentBlockName: str = iterator.GetCurrentMetaData().Get( vtkMultiBlockDataSet.NAME() ) + blockIndex = iterator.GetCurrentFlatIndex() + if currentBlockName == blockName: + return blockIndex + iterator.GoToNextItem() + return -1 + + +def getElementaryCompositeBlockIndexes( + multiBlockDataSet: Union[ vtkMultiBlockDataSet, vtkCompositeDataSet ] ) -> dict[ str, int ]: + """Get indexes of composite block of the multiBlockDataSet that contains elementary blocks. Args: - input (vtkMultiBlockDataSet | vtkCompositeDataSet): input multi block object. + multiBlockDataSet (Union[vtkMultiBlockDataSet, vtkCompositeDataSet]): MultiBlockDataSet. Returns: - dict[str, int]: dictionary that contains names as keys and flat indices + dict[str, int]: Dictionary that contains names as keys and flat indices as values of the parent composite blocks of elementary blocks. """ # initialize data object tree iterator - iter: vtkDataObjectTreeIterator = vtkDataObjectTreeIterator() - iter.SetDataSet( input ) - iter.VisitOnlyLeavesOff() - iter.GoToFirstItem() - - elementaryBlockIndexes: dict[ str, int ] = {} - while iter.GetCurrentDataObject() is not None: - curIndex: int = iter.GetCurrentFlatIndex() - curName: str = iter.GetCurrentMetaData().Get( vtkMultiBlockDataSet.NAME() ) - curIsComposite = iter.GetCurrentDataObject().IsA( "vtkMultiBlockDataSet" ) - iter.GoToNextItem() - nextIsNotNone = iter.GetCurrentDataObject() is not None - if ( curIsComposite and nextIsNotNone and ( not iter.GetCurrentDataObject().IsA( "vtkMultiBlockDataSet" ) ) ): - elementaryBlockIndexes[ curName ] = curIndex - - return elementaryBlockIndexes - - -def getBlockElementIndexesFlatten( input: Union[ vtkMultiBlockDataSet, vtkCompositeDataSet ] ) -> list[ int ]: + iterator: vtkDataObjectTreeIterator = vtkDataObjectTreeIterator() + iterator.SetDataSet( multiBlockDataSet ) + iterator.VisitOnlyLeavesOff() + iterator.GoToFirstItem() + + dictCompositeBlocks: dict[ str, int ] = {} + while iterator.GetCurrentDataObject() is not None: + curIndex: int = iterator.GetCurrentFlatIndex() + curName: str = iterator.GetCurrentMetaData().Get( vtkMultiBlockDataSet.NAME() ) + curIsComposite = iterator.GetCurrentDataObject().IsA( "vtkMultiBlockDataSet" ) + iterator.GoToNextItem() + nextIsNotNone = iterator.GetCurrentDataObject() is not None + if ( curIsComposite and nextIsNotNone + and ( not iterator.GetCurrentDataObject().IsA( "vtkMultiBlockDataSet" ) ) ): + dictCompositeBlocks[ curName ] = curIndex + + return dictCompositeBlocks + + +def getBlockElementIndexesFlatten( + multiBlockDataSet: Union[ vtkMultiBlockDataSet, vtkCompositeDataSet ] ) -> list[ int ]: """Get a flatten list that contains flat indexes of elementary blocks. Args: - input (vtkMultiBlockDataSet | vtkCompositeDataSet): input multi block object. + multiBlockDataSet (Union[vtkMultiBlockDataSet, vtkCompositeDataSet]): MultiBlockDataSet with the block flat indexes to get. Returns: - list[int]: list of flat indexes + list[int]: List of flat indexes. """ - return [ i for li in getBlockElementIndexes( input ) for i in li ] + return [ i for li in getBlockElementIndexes( multiBlockDataSet ) for i in li ] -def getBlockElementIndexes( input: Union[ vtkMultiBlockDataSet, vtkCompositeDataSet ] ) -> list[ list[ int ] ]: +def getBlockElementIndexes( + multiBlockDataSet: Union[ vtkMultiBlockDataSet, vtkCompositeDataSet ] ) -> list[ list[ int ] ]: """Get a list of list that contains flat indexes of elementary blocks. Each sublist contains the indexes of elementary blocks that belongs to a same parent node. Args: - input (vtkMultiBlockDataSet | vtkCompositeDataSet): input multi block object. + multiBlockDataSet (Union[vtkMultiBlockDataSet, vtkCompositeDataSet]): MultiBlockDataSet with the block indexes to get. Returns: - list[list[int]]: list of list of flat indexes + list[list[int]]: List of list of flat indexes. """ # initialize data object tree iterator - iter: vtkDataObjectTreeIterator = vtkDataObjectTreeIterator() - iter.SetDataSet( input ) - iter.VisitOnlyLeavesOff() - iter.GoToFirstItem() + iterator: vtkDataObjectTreeIterator = vtkDataObjectTreeIterator() + iterator.SetDataSet( multiBlockDataSet ) + iterator.VisitOnlyLeavesOff() + iterator.GoToFirstItem() blockElementIndexes: list[ list[ int ] ] = [] indexes: list[ int ] = [] - while iter.GetCurrentDataObject() is not None: - curIndex: int = iter.GetCurrentFlatIndex() - if iter.GetCurrentDataObject().IsA( "vtkMultiBlockDataSet" ): + while iterator.GetCurrentDataObject() is not None: + curIndex: int = iterator.GetCurrentFlatIndex() + if iterator.GetCurrentDataObject().IsA( "vtkMultiBlockDataSet" ): # change of parent node, then add the indexes of the previous # vtkMultiBlockDataSet if needed if len( indexes ) > 0: - blockElementIndexes += [ indexes ] + blockElementIndexes.append( indexes ) # reinitialize the list of indexes of included blocks indexes = [] else: - indexes += [ curIndex ] - iter.GoToNextItem() + indexes.append( curIndex ) + iterator.GoToNextItem() # add the indexes of the last vtkMultiBlockDataSet if needed if len( indexes ) > 0: - blockElementIndexes += [ indexes ] + blockElementIndexes.append( indexes ) return blockElementIndexes -def getBlockFromFlatIndex( multiBlock: Union[ vtkMultiBlockDataSet, vtkCompositeDataSet ], - blockIndex: int ) -> vtkDataObject: - """Get the block with blockIndex from input vtkMultiBlockDataSet. +def getBlockFromFlatIndex( multiBlockDataSet: Union[ vtkMultiBlockDataSet, vtkCompositeDataSet ], + blockIndex: int ) -> Union[ None, vtkDataObject ]: + """Get the block with blockIndex from the vtkMultiBlockDataSet. Args: - multiBlock (vtkMultiBlockDataSet | vtkCompositeDataSet): input multi block - blockIndex (int): block index + multiBlockDataSet (Union[vtkMultiBlockDataSet, vtkCompositeDataSet]): MultiBlockDataSet with the block to get. + blockIndex (int): The block index og the block to get. Returns: - vtkMultiBlockDataSet: block if it exists, None otherwise + Union[None, vtkDataObject]: The block with the flat index if it exists, None otherwise """ - block: vtkDataObject # initialize data object tree iterator - iter: vtkDataObjectTreeIterator = vtkDataObjectTreeIterator() - iter.SetDataSet( multiBlock ) - iter.VisitOnlyLeavesOff() - iter.GoToFirstItem() - while iter.GetCurrentDataObject() is not None: - if iter.GetCurrentFlatIndex() == blockIndex: - block = iter.GetCurrentDataObject() - break - iter.GoToNextItem() - return block + iterator: vtkDataObjectTreeIterator = vtkDataObjectTreeIterator() + iterator.SetDataSet( multiBlockDataSet ) + iterator.VisitOnlyLeavesOff() + iterator.GoToFirstItem() + while iterator.GetCurrentDataObject() is not None: + if iterator.GetCurrentFlatIndex() == blockIndex: + return iterator.GetCurrentDataObject() + iterator.GoToNextItem() + return None -def getBlockFromName( multiBlock: Union[ vtkMultiBlockDataSet, vtkCompositeDataSet ], blockName: str ) -> vtkDataObject: - """Get the block named blockName from input vtkMultiBlockDataSet. +def getBlockFromName( multiBlockDataSet: Union[ vtkMultiBlockDataSet, vtkCompositeDataSet ], + blockName: str ) -> Union[ None, vtkDataObject ]: + """Get the block named blockName from the vtkMultiBlockDataSet. Args: - multiBlock (vtkMultiBlockDataSet | vtkCompositeDataSet): input multi block - blockName (str): block name + multiBlockDataSet (vtkMultiBlockDataSet | vtkCompositeDataSet): MultiBlockDataSet with the block to get. + blockName (str): The name of the block to get. Returns: - vtkDataObject: block if it exists, None otherwise + Union[None, vtkDataObject]: The block name blockName if it exists, None otherwise """ - block: vtkDataObject # initialize data object tree iterator - iter: vtkDataObjectTreeIterator = vtkDataObjectTreeIterator() - iter.SetDataSet( multiBlock ) - iter.VisitOnlyLeavesOff() - iter.GoToFirstItem() - while iter.GetCurrentDataObject() is not None: - if iter.GetCurrentMetaData().Get( vtkMultiBlockDataSet.NAME() ) == blockName: - block = vtkMultiBlockDataSet.SafeDownCast( iter.GetCurrentDataObject() ) - break - iter.GoToNextItem() - return block + iterator: vtkDataObjectTreeIterator = vtkDataObjectTreeIterator() + iterator.SetDataSet( multiBlockDataSet ) + iterator.VisitOnlyLeavesOff() + iterator.GoToFirstItem() + while iterator.GetCurrentDataObject() is not None: + if iterator.GetCurrentMetaData().Get( vtkMultiBlockDataSet.NAME() ) == blockName: + return iterator.GetCurrentDataObject() + iterator.GoToNextItem() + return None def extractBlock( multiBlockDataSet: vtkMultiBlockDataSet, blockIndex: int ) -> vtkMultiBlockDataSet: diff --git a/geos-mesh/tests/data/displacedFault.vtm b/geos-mesh/tests/data/displacedFault.vtm index 2cf49998a..cb28f0e8d 100644 --- a/geos-mesh/tests/data/displacedFault.vtm +++ b/geos-mesh/tests/data/displacedFault.vtm @@ -2,6 +2,8 @@ - + + + diff --git a/geos-mesh/tests/data/displacedFaultempty.vtm b/geos-mesh/tests/data/displacedFaultempty.vtm index 20ff57fb3..bea56fc6b 100644 --- a/geos-mesh/tests/data/displacedFaultempty.vtm +++ b/geos-mesh/tests/data/displacedFaultempty.vtm @@ -2,6 +2,8 @@ - + + + diff --git a/geos-mesh/tests/test_arrayModifiers.py b/geos-mesh/tests/test_arrayModifiers.py index 91ecc423e..f4446de6f 100644 --- a/geos-mesh/tests/test_arrayModifiers.py +++ b/geos-mesh/tests/test_arrayModifiers.py @@ -14,6 +14,8 @@ from vtkmodules.vtkCommonCore import vtkDataArray from vtkmodules.vtkCommonDataModel import ( vtkDataSet, vtkMultiBlockDataSet, vtkPointData, vtkCellData ) +from geos.mesh.utils.multiblockHelpers import getBlockElementIndexesFlatten + from vtk import ( # type: ignore[import-untyped] 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, @@ -48,21 +50,21 @@ "idBlock, attributeName, nbComponentsTest, componentNamesTest, onPoints, listValues, listValuesTest, vtkDataTypeTest", [ # Test fill an attribute on point and on cell. - ( 1, "PointAttribute", 3, + ( 3, "PointAttribute", 3, ( "AX1", "AX2", "AX3" ), True, None, [ np.float64( np.nan ), np.float64( np.nan ), np.float64( np.nan ) ], VTK_DOUBLE ), - ( 1, "CellAttribute", 3, + ( 3, "CellAttribute", 3, ( "AX1", "AX2", "AX3" ), False, 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. - ( 1, "PORO", 1, (), False, None, [ np.float32( np.nan ) ], VTK_FLOAT ), - ( 0, "collocated_nodes", 2, ( None, None ), True, None, [ np.int64( -1 ), np.int64( -1 ) ], VTK_ID_TYPE ), + ( 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 ), # Test fill an attribute with different type of value. - ( 1, "FAULT", 1, (), False, None, [ np.int32( -1 ) ], VTK_INT ), - ( 1, "FAULT", 1, (), False, [ 4 ], [ np.int32( 4 ) ], VTK_INT ), - ( 1, "PORO", 1, (), False, [ 4 ], [ np.float32( 4 ) ], VTK_FLOAT ), - ( 0, "collocated_nodes", 2, ( None, None ), True, [ 4, 4 ], [ np.int64( 4 ), np.int64( 4 ) ], VTK_ID_TYPE ), - ( 1, "CellAttribute", 3, ( "AX1", "AX2", "AX3" ), False, [ 4, 4, 4 ], + ( 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 ], [ np.float64( 4 ), np.float64( 4 ), np.float64( 4 ) ], VTK_DOUBLE ), ] ) def test_fillPartialAttributes( @@ -85,7 +87,7 @@ def test_fillPartialAttributes( listValues=listValues ) # Get the dataSet where the attribute has been filled. - dataSet: vtkDataSet = vtkDataSet.SafeDownCast( multiBlockDataSetTest.GetBlock( idBlock ) ) + dataSet: vtkDataSet = vtkDataSet.SafeDownCast( multiBlockDataSetTest.GetDataSet( idBlock ) ) # Get the filled attribute. data: Union[ vtkPointData, vtkCellData ] @@ -134,9 +136,9 @@ def test_FillAllPartialAttributes( multiBlockDataSetTest: vtkMultiBlockDataSet = dataSetTest( multiBlockDataSetName ) assert arrayModifiers.fillAllPartialAttributes( multiBlockDataSetTest ) - nbBlock: int = multiBlockDataSetTest.GetNumberOfBlocks() - for idBlock in range( nbBlock ): - dataSet: vtkDataSet = vtkDataSet.SafeDownCast( multiBlockDataSetTest.GetBlock( idBlock ) ) + elementaryBlockIndexes: list[ int ] = getBlockElementIndexesFlatten( multiBlockDataSetTest ) + for blockIndex in elementaryBlockIndexes: + dataSet: vtkDataSet = vtkDataSet.SafeDownCast( multiBlockDataSetTest.GetDataSet( blockIndex ) ) attributeExist: int for attributeNameOnPoint in [ "PointAttribute", "collocated_nodes" ]: attributeExist = dataSet.GetPointData().HasArray( attributeNameOnPoint ) @@ -191,9 +193,9 @@ def test_createConstantAttributeMultiBlock( attributeName, onPoints=onPoints ) - nbBlock = multiBlockDataSetTest.GetNumberOfBlocks() - for idBlock in range( nbBlock ): - dataSet: vtkDataSet = vtkDataSet.SafeDownCast( multiBlockDataSetTest.GetBlock( idBlock ) ) + 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() @@ -410,10 +412,10 @@ def test_copyAttribute( onPoints ) # Parse the two multiBlockDataSet and test if the attribute has been copied. - nbBlocks: int = multiBlockDataSetFrom.GetNumberOfBlocks() - for idBlock in range( nbBlocks ): - dataSetFrom: vtkDataSet = vtkDataSet.SafeDownCast( multiBlockDataSetFrom.GetBlock( idBlock ) ) - dataSetTo: vtkDataSet = vtkDataSet.SafeDownCast( multiBlockDataSetTo.GetBlock( idBlock ) ) + elementaryBlockIndexes: list[ int ] = getBlockElementIndexesFlatten( multiBlockDataSetFrom ) + for blockIndex in elementaryBlockIndexes: + dataSetFrom: vtkDataSet = vtkDataSet.SafeDownCast( multiBlockDataSetFrom.GetDataSet( blockIndex ) ) + dataSetTo: vtkDataSet = vtkDataSet.SafeDownCast( multiBlockDataSetTo.GetDataSet( blockIndex ) ) dataFrom: Union[ vtkPointData, vtkCellData ] dataTo: Union[ vtkPointData, vtkCellData ] if onPoints: @@ -497,7 +499,7 @@ def test_renameAttributeMultiblock( newAttributeName, onPoints, ) - block: vtkDataSet = vtkDataSet.SafeDownCast( vtkMultiBlockDataSetTest.GetBlock( 0 ) ) + block: vtkDataSet = vtkDataSet.SafeDownCast( vtkMultiBlockDataSetTest.GetDataSet( 1 ) ) data: Union[ vtkPointData, vtkCellData ] if onPoints: data = block.GetPointData() diff --git a/geos-mesh/tests/test_multiblockHelpers.py b/geos-mesh/tests/test_multiblockHelpers.py new file mode 100644 index 000000000..7dd5409c0 --- /dev/null +++ b/geos-mesh/tests/test_multiblockHelpers.py @@ -0,0 +1,97 @@ +# SPDX-License-Identifier: Apache-2.0 +# SPDX-FileCopyrightText: Copyright 2023-2024 TotalEnergies. +# SPDX-FileContributor: Romain Baville +# SPDX-License-Identifier: Apache 2.0 +# ruff: noqa: E402 # disable Module level import not at top of file +# mypy: disable-error-code="operator" +import pytest +from vtkmodules.vtkCommonDataModel import vtkMultiBlockDataSet + +from geos.mesh.utils import multiblockHelpers + + +@pytest.mark.parametrize( "listBlockNamesTest", [ + ( [ "main", "Fracture", "fracture" ] ), +] ) +def test_getBlockNames( + dataSetTest: vtkMultiBlockDataSet, + listBlockNamesTest: list[ str ], +) -> None: + """Test getting the name of all blocks in a multiBlockDataSet.""" + multiBlockDataSet: vtkMultiBlockDataSet = dataSetTest( "multiblock" ) + listBlockName: list[ str ] = multiblockHelpers.getBlockNames( multiBlockDataSet ) + assert listBlockName == listBlockNamesTest + + +@pytest.mark.parametrize( "idBlock, blockNameTest", [ + ( 1, "main" ), + ( 2, "Fracture" ), + ( 3, "fracture" ), +] ) +def test_getBlockNameFromIndex( + dataSetTest: vtkMultiBlockDataSet, + idBlock: int, + blockNameTest: str, +) -> None: + """Test getting the name of the block with the idBlock index.""" + multiBlockDataSet: vtkMultiBlockDataSet = dataSetTest( "multiblock" ) + blockName: str = multiblockHelpers.getBlockNameFromIndex( multiBlockDataSet, idBlock ) + assert blockName == blockNameTest + + +@pytest.mark.parametrize( "idBlockTest, blockName", [ + ( 1, "main" ), + ( 2, "Fracture" ), + ( 3, "fracture" ), + ( -1, "NotABlock" ), +] ) +def test_getBlockIndexFromName( + dataSetTest: vtkMultiBlockDataSet, + idBlockTest: int, + blockName: str, +) -> None: + """Test getting the flat index of a block with its name.""" + multiBlockDataSet: vtkMultiBlockDataSet = dataSetTest( "multiblock" ) + idBlock: str = multiblockHelpers.getBlockIndexFromName( multiBlockDataSet, blockName ) + assert idBlock == idBlockTest + + +@pytest.mark.parametrize( "dictCompositeBlocksTest", [ + ( { + "Fracture": 2 + } ), +] ) +def test_getElementaryCompositeBlockIndexes( + dataSetTest: vtkMultiBlockDataSet, + dictCompositeBlocksTest: dict[ str, int ], +) -> None: + """Test getting the name of all blocks in a multiBlockDataSet.""" + multiBlockDataSet: vtkMultiBlockDataSet = dataSetTest( "multiblock" ) + dictCompositeBlocks: dict[ str, int ] = multiblockHelpers.getElementaryCompositeBlockIndexes( multiBlockDataSet ) + assert dictCompositeBlocks == dictCompositeBlocksTest + + +@pytest.mark.parametrize( "blockElementFlatIndexesTest", [ + ( [ 1, 3 ] ), +] ) +def test_getBlockElementIndexesFlatten( + dataSetTest: vtkMultiBlockDataSet, + blockElementFlatIndexesTest: list[ int ], +) -> None: + """Test getting a flatten list that contains flat indexes of elementary blocks.""" + multiBlockDataSet: vtkMultiBlockDataSet = dataSetTest( "multiblock" ) + blockElementFlatIndexes: list[ int ] = multiblockHelpers.getBlockElementIndexesFlatten( multiBlockDataSet ) + assert blockElementFlatIndexes == blockElementFlatIndexesTest + + +@pytest.mark.parametrize( "blockElementIndexesTest", [ + ( [ [ 1 ], [ 3 ] ] ), +] ) +def test_getBlockElementIndexes( + dataSetTest: vtkMultiBlockDataSet, + blockElementIndexesTest: list[ list[ int ] ], +) -> None: + """Test getting a list of list that contains flat indexes of elementary blocks.""" + multiBlockDataSet: vtkMultiBlockDataSet = dataSetTest( "multiblock" ) + blockElementIndexes: list[ list[ int ] ] = multiblockHelpers.getBlockElementIndexes( multiBlockDataSet ) + assert blockElementIndexes == blockElementIndexesTest