From 02ff32b80060e2006083fa214cf14e75e6619118 Mon Sep 17 00:00:00 2001 From: Romain Baville Date: Wed, 10 Dec 2025 10:48:24 +0100 Subject: [PATCH 1/4] Fix plugin's categorie --- .../src/geos/pv/plugins/post_processing/PVMohrCirclePlot.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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..3203323fc 100644 --- a/geos-pv/src/geos/pv/plugins/post_processing/PVMohrCirclePlot.py +++ b/geos-pv/src/geos/pv/plugins/post_processing/PVMohrCirclePlot.py @@ -73,7 +73,7 @@ * Extract a few number of cells with the `ExtractSelection` ParaView Filter, then use the `MergeBlocks` ParaView Filter * Select the resulting mesh in the pipeline -* Select the filter: Filters > { FilterCategory.GENERIC_PROCESSING.value } > Plot Mohr's Circle +* Select the filter: Filters > { FilterCategory.GEOS_POST_PROCESSING.value } > Plot Mohr's Circle * Select the cell Ids and time steps you want * (Optional) Set rock cohesion and/or friction angle * Apply @@ -89,7 +89,7 @@ @smproxy.filter( name="PVMohrCirclePlot", label="Plot Mohr's Circles" ) @smhint.xml( f""" - + """ ) @smproperty.input( name="Input", port_index=0 ) From afcf70fa73a73b35995584f3710727b373215349 Mon Sep 17 00:00:00 2001 From: Romain Baville Date: Wed, 10 Dec 2025 13:30:54 +0100 Subject: [PATCH 2/4] sort the morh circle by cell indexes --- .../plugins/post_processing/PVMohrCirclePlot.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) 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 3203323fc..a845a8d4a 100644 --- a/geos-pv/src/geos/pv/plugins/post_processing/PVMohrCirclePlot.py +++ b/geos-pv/src/geos/pv/plugins/post_processing/PVMohrCirclePlot.py @@ -766,6 +766,7 @@ def RequestData( assert self.pythonView is not None, "No Python View was found." self._defineCurvesAspect() mohrCircles: list[ MohrCircle ] = self._filterMohrCircles() + print( mohrCircles ) self.pythonView.Script = mcf.buildPythonViewScript( geos_pv_path, @@ -812,12 +813,21 @@ def _createMohrCirclesAtTimeStep( def _filterMohrCircles( self: Self ) -> list[ MohrCircle ]: """Filter the list of all MohrCircle to get those to plot. + Mohr circles are sort by cell indexes first then by timesteps. + Returns: list[MohrCircle]: list of MohrCircle to plot. """ # Circle ids to plot circleIds: list[ str ] = self._getCircleIds() - return [ mohrCircle for mohrCircle in self.mohrCircles if mohrCircle.getCircleId() in circleIds ] + mohrCircleToPlot: list[ MohrCircle ] = [ MohrCircle( "-1" ) for i in range( len( circleIds ) ) ] + for mohrCircle in self.mohrCircles: + try: + mohrCircleToPlot[ circleIds.index( str( mohrCircle.getCircleId() ) ) ] = mohrCircle + except ValueError: + continue + + return mohrCircleToPlot def _updateRequestedTimeSteps( self: Self ) -> None: """Update the requestedTimeStepsIndexes attribute from user choice.""" @@ -842,13 +852,15 @@ def _getUserChoices( self: Self ) -> dict[ str, Any ]: def _getCircleIds( self: Self ) -> list[ str ]: """Get circle ids to plot. + This list of circle indexes is sort by cell indexes first then by timesteps + Returns: list[str]: list of circle ids to plot. """ cellIds: list[ str ] = pvt.getArrayChoices( self.a01GetCellIdsDAS() ) timeSteps: list[ str ] = pvt.getArrayChoices( self.a02GetTimestepsToPlot() ) - return [ mcf.getMohrCircleId( cellId, timeStep ) for timeStep in timeSteps for cellId in cellIds ] + return [ mcf.getMohrCircleId( cellId, timeStep ) for cellId in cellIds for timeStep in timeSteps ] def _defineCurvesAspect( self: Self ) -> None: """Add curve aspect parameters according to user choices.""" From 81edf23c6060a4504414a309be19dc63cdded6c0 Mon Sep 17 00:00:00 2001 From: Romain Baville Date: Wed, 10 Dec 2025 19:24:17 +0100 Subject: [PATCH 3/4] add the cell id anotation on paraview --- .../post_processing/PVMohrCirclePlot.py | 75 +++++++++++++++++-- 1 file changed, 68 insertions(+), 7 deletions(-) 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 a845a8d4a..4e2992762 100644 --- a/geos-pv/src/geos/pv/plugins/post_processing/PVMohrCirclePlot.py +++ b/geos-pv/src/geos/pv/plugins/post_processing/PVMohrCirclePlot.py @@ -17,11 +17,11 @@ # source: https://github.com/Kitware/ParaView/blob/master/Wrapping/Python/paraview/util/vtkAlgorithm.py from paraview.detail.loghandler import VTKHandler # type: ignore[import-not-found] # source: https://github.com/Kitware/ParaView/blob/master/Wrapping/Python/paraview/detail/loghandler.py - +import vtk from typing_extensions import Self from vtkmodules.vtkCommonCore import vtkDataArraySelection as vtkDAS from vtkmodules.vtkCommonCore import vtkInformation, vtkInformationVector -from vtkmodules.vtkCommonDataModel import vtkUnstructuredGrid +from vtkmodules.vtkCommonDataModel import vtkUnstructuredGrid, vtkMultiBlockDataSet # Update sys.path to load all GEOS Python Package dependencies geos_pv_path: Path = Path( __file__ ).parent.parent.parent.parent.parent.parent @@ -104,7 +104,10 @@ def __init__( self: Self ) -> None: Mohr's circles are plotted using a Python View. """ - super().__init__( nInputPorts=1, nOutputPorts=1, outputType="vtkDataObject" ) + super().__init__( nInputPorts=1, + nOutputPorts=1, + inputType="vtkUnstructuredGrid", + outputType="vtkMultiBlockDataSet" ) # Create a new PythonView self.pythonView: Any = buildNewLayoutWithPythonView() @@ -719,9 +722,9 @@ def RequestDataObject( outData = self.GetOutputData( outInfoVec, 0 ) assert inData is not None - if ( outData is None ) or ( not outData.IsA( inData.GetClassName() ) ): - outData = inData.NewInstance() - outInfoVec.GetInformationObject( 0 ).Set( outData.DATA_OBJECT(), outData ) + if outData is None or ( not outData.IsA( "vtkMultiBlockDataSet" ) ): + outData = vtk.vtkMultiBlockDataSet() + outInfoVec.GetInformationObject( 0 ).Set( outData.DATA_OBJECT(), outData ) # type: ignore return super().RequestDataObject( request, inInfoVec, outInfoVec ) # type: ignore[no-any-return] def RequestData( @@ -766,7 +769,6 @@ def RequestData( assert self.pythonView is not None, "No Python View was found." self._defineCurvesAspect() mohrCircles: list[ MohrCircle ] = self._filterMohrCircles() - print( mohrCircles ) self.pythonView.Script = mcf.buildPythonViewScript( geos_pv_path, @@ -775,8 +777,67 @@ def RequestData( self.frictionAngle, self._getUserChoices(), ) + Render() + # Cell indexes annotation + nbCells = inputMesh.GetNumberOfCells() + inputData = inputMesh.NewInstance() + inputData.ShallowCopy( inputMesh ) + outputMesh: vtkMultiBlockDataSet = self.GetOutputData( outInfoVec, 0 ) + + cellId = vtk.vtkStringArray() + cellId.SetName( "cellId" ) + cellId.SetNumberOfValues( nbCells ) + + cellMask = vtk.vtkIntArray() + cellMask.SetName( "CellMask" ) + cellMask.SetNumberOfValues( nbCells ) + + selected_local = set() + originalCellIds = inputMesh.GetCellData().GetArray( "vtkOriginalCellIds" ) + for localCellId in range( nbCells ): + if str( originalCellIds.GetValue( localCellId ) ) in self.requestedCellIds: + selected_local.add( localCellId ) + cellId.SetValue( localCellId, f"{ originalCellIds.GetValue( localCellId ) }" ) + cellMask.SetValue( localCellId, 1 ) + else: + cellMask.SetValue( localCellId, 0 ) + + inputData.GetCellData().AddArray( cellId ) + inputData.GetCellData().AddArray( cellMask ) + + idBlock = 0 + for localCellId in selected_local: + globalCellId = f"{ originalCellIds.GetValue( localCellId ) }" + text = vtk.vtkVectorText() + text.SetText( globalCellId ) + text.Update() + + cellBounds = inputMesh.GetCell( localCellId ).GetBounds() + transformFilter = vtk.vtkTransform() + transformFilter.Translate( cellBounds[ 1 ], cellBounds[ 3 ], cellBounds[ 5 ] ) + + scaleX = ( cellBounds[ 1 ] - cellBounds[ 0 ] ) / 4 + scaleY = ( cellBounds[ 3 ] - cellBounds[ 2 ] ) / 4 + scaleZ = ( cellBounds[ 5 ] - cellBounds[ 4 ] ) / 4 + transformFilter.Scale( scaleX, scaleY, scaleZ ) + + transformFromPolyDataFilter = vtk.vtkTransformPolyDataFilter() + transformFromPolyDataFilter.SetTransform( transformFilter ) + transformFromPolyDataFilter.SetInputData( text.GetOutput() ) + transformFromPolyDataFilter.Update() + + meshText = vtk.vtkPolyData() + meshText.ShallowCopy( transformFromPolyDataFilter.GetOutput() ) + + outputMesh.SetBlock( idBlock, meshText ) + outputMesh.GetMetaData( idBlock ).Set( vtk.vtkCompositeDataSet.NAME(), f"Cell_{ globalCellId }" ) + idBlock += 1 + + outputMesh.SetBlock( idBlock, inputData ) + outputMesh.GetMetaData( idBlock ).Set( vtk.vtkCompositeDataSet.NAME(), "Input Data" ) + except Exception as e: self.logger.error( "Mohr circles cannot be plotted due to:" ) self.logger.error( e ) From 1e3661cf3cac3f9e0a4f5993785cbdca3fe4fc42 Mon Sep 17 00:00:00 2001 From: Romain Baville Date: Thu, 11 Dec 2025 17:04:43 +0100 Subject: [PATCH 4/4] Update vtk import --- .../post_processing/PVMohrCirclePlot.py | 29 ++++++++++--------- 1 file changed, 16 insertions(+), 13 deletions(-) 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 4e2992762..3c6f38aa6 100644 --- a/geos-pv/src/geos/pv/plugins/post_processing/PVMohrCirclePlot.py +++ b/geos-pv/src/geos/pv/plugins/post_processing/PVMohrCirclePlot.py @@ -7,6 +7,7 @@ from pathlib import Path from enum import Enum from typing import Any, Union, cast +from typing_extensions import Self import numpy as np import numpy.typing as npt @@ -17,11 +18,13 @@ # source: https://github.com/Kitware/ParaView/blob/master/Wrapping/Python/paraview/util/vtkAlgorithm.py from paraview.detail.loghandler import VTKHandler # type: ignore[import-not-found] # source: https://github.com/Kitware/ParaView/blob/master/Wrapping/Python/paraview/detail/loghandler.py -import vtk -from typing_extensions import Self + from vtkmodules.vtkCommonCore import vtkDataArraySelection as vtkDAS -from vtkmodules.vtkCommonCore import vtkInformation, vtkInformationVector -from vtkmodules.vtkCommonDataModel import vtkUnstructuredGrid, vtkMultiBlockDataSet +from vtkmodules.vtkCommonCore import vtkInformation, vtkInformationVector, vtkStringArray, vtkIntArray +from vtkmodules.vtkCommonDataModel import vtkUnstructuredGrid, vtkMultiBlockDataSet, vtkPolyData, vtkCompositeDataSet +from vtkmodules.vtkCommonTransforms import vtkTransform +from vtkmodules.vtkRenderingFreeType import vtkVectorText +from vtkmodules.vtkFiltersGeneral import vtkTransformPolyDataFilter # Update sys.path to load all GEOS Python Package dependencies geos_pv_path: Path = Path( __file__ ).parent.parent.parent.parent.parent.parent @@ -723,7 +726,7 @@ def RequestDataObject( assert inData is not None if outData is None or ( not outData.IsA( "vtkMultiBlockDataSet" ) ): - outData = vtk.vtkMultiBlockDataSet() + outData = vtkMultiBlockDataSet() outInfoVec.GetInformationObject( 0 ).Set( outData.DATA_OBJECT(), outData ) # type: ignore return super().RequestDataObject( request, inInfoVec, outInfoVec ) # type: ignore[no-any-return] @@ -786,11 +789,11 @@ def RequestData( inputData.ShallowCopy( inputMesh ) outputMesh: vtkMultiBlockDataSet = self.GetOutputData( outInfoVec, 0 ) - cellId = vtk.vtkStringArray() + cellId = vtkStringArray() cellId.SetName( "cellId" ) cellId.SetNumberOfValues( nbCells ) - cellMask = vtk.vtkIntArray() + cellMask = vtkIntArray() cellMask.SetName( "CellMask" ) cellMask.SetNumberOfValues( nbCells ) @@ -810,12 +813,12 @@ def RequestData( idBlock = 0 for localCellId in selected_local: globalCellId = f"{ originalCellIds.GetValue( localCellId ) }" - text = vtk.vtkVectorText() + text = vtkVectorText() text.SetText( globalCellId ) text.Update() cellBounds = inputMesh.GetCell( localCellId ).GetBounds() - transformFilter = vtk.vtkTransform() + transformFilter = vtkTransform() transformFilter.Translate( cellBounds[ 1 ], cellBounds[ 3 ], cellBounds[ 5 ] ) scaleX = ( cellBounds[ 1 ] - cellBounds[ 0 ] ) / 4 @@ -823,20 +826,20 @@ def RequestData( scaleZ = ( cellBounds[ 5 ] - cellBounds[ 4 ] ) / 4 transformFilter.Scale( scaleX, scaleY, scaleZ ) - transformFromPolyDataFilter = vtk.vtkTransformPolyDataFilter() + transformFromPolyDataFilter = vtkTransformPolyDataFilter() transformFromPolyDataFilter.SetTransform( transformFilter ) transformFromPolyDataFilter.SetInputData( text.GetOutput() ) transformFromPolyDataFilter.Update() - meshText = vtk.vtkPolyData() + meshText = vtkPolyData() meshText.ShallowCopy( transformFromPolyDataFilter.GetOutput() ) outputMesh.SetBlock( idBlock, meshText ) - outputMesh.GetMetaData( idBlock ).Set( vtk.vtkCompositeDataSet.NAME(), f"Cell_{ globalCellId }" ) + outputMesh.GetMetaData( idBlock ).Set( vtkCompositeDataSet.NAME(), f"Cell_{ globalCellId }" ) idBlock += 1 outputMesh.SetBlock( idBlock, inputData ) - outputMesh.GetMetaData( idBlock ).Set( vtk.vtkCompositeDataSet.NAME(), "Input Data" ) + outputMesh.GetMetaData( idBlock ).Set( vtkCompositeDataSet.NAME(), "Input Data" ) except Exception as e: self.logger.error( "Mohr circles cannot be plotted due to:" )