Skip to content

Commit 3ead124

Browse files
authored
feat: Create the PV plugin wrapping ClipToMainFrame (#137)
* Trick to get both Unstructured and MBDS * Ensure compat w PV12.X and python <3.10
1 parent 70b631e commit 3ead124

File tree

5 files changed

+135
-15
lines changed

5 files changed

+135
-15
lines changed

docs/geos_pv_docs/processing.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,9 @@ PVSplitMesh
1818
----------------------------------
1919

2020
.. automodule:: geos.pv.plugins.PVSplitMesh
21+
22+
23+
PVClipToMainFrame
24+
----------------------------------
25+
26+
.. automodule:: geos.pv.plugins.PVClipToMainFrame

geos-mesh/src/geos/mesh/processing/ClipToMainFrame.py

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
# SPDX-License-Identifier: Apache 2.0
22
# SPDX-FileCopyrightText: Copyright 2023-2025 TotalEnergies
33
# SPDX-FileContributor: Jacques Franc
4+
from typing import Tuple
5+
import logging
6+
7+
import numpy as np
8+
import numpy.typing as npt
49

510
from vtkmodules.numpy_interface import dataset_adapter as dsa
611
from vtkmodules.vtkCommonCore import vtkPoints
@@ -11,15 +16,9 @@
1116
from vtkmodules.vtkCommonTransforms import vtkLandmarkTransform
1217
from vtkmodules.vtkFiltersGeneral import vtkTransformFilter
1318

14-
from geos.utils.Logger import logging, Logger, getLogger
15-
19+
from geos.utils.Logger import ( Logger, getLogger )
1620
from geos.mesh.utils.genericHelpers import getMultiBlockBounds
1721

18-
import numpy as np
19-
import numpy.typing as npt
20-
21-
from typing import Tuple
22-
2322
__doc__ = """
2423
Module to clip a mesh to the main frame using rigid body transformation.
2524
@@ -241,13 +240,17 @@ def ComputeTransform( self ) -> None:
241240
# dispatch to ClipToMainFrame depending on input type
242241
if isinstance( self.GetInput(), vtkMultiBlockDataSet ):
243242
#locate reference point
243+
self.logger.info(
244+
"Processing MultiblockDataSet.\n Please make sure your MultiblockDataSet is owning a vtkUnstructured grid as a leaf."
245+
)
244246
try:
245247
idBlock = self.__locate_reference_point( self.GetInput() )
246248
except IndexError:
247249
self.logger.error( "Reference point is not in the domain" )
248250

249251
clip = ClipToMainFrameElement( self.GetInput().GetDataSet( idBlock ) )
250252
else:
253+
self.logger.info( "Processing untructuredGrid" )
251254
clip = ClipToMainFrameElement( self.GetInput() )
252255

253256
clip.Update()

geos-mesh/src/geos/mesh/utils/genericHelpers.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ def to_vtk_id_list( data: List[ int ] ) -> vtkIdList:
3636
return result
3737

3838

39-
def vtk_iter( vtkContainer: vtkIdList | vtkCellTypes ) -> Iterator[ Any ]:
39+
def vtk_iter( vtkContainer: Union[ vtkIdList, vtkCellTypes ] ) -> Iterator[ Any ]:
4040
"""Utility function transforming a vtk "container" into an iterable.
4141
4242
Args:

geos-mesh/tests/test_clipToMainFrame.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,14 @@
66
import pytest
77
import itertools
88
from dataclasses import dataclass
9-
from typing import Generator, Tuple
9+
from typing import Generator, Tuple, List
1010
from vtkmodules.vtkCommonCore import vtkIdList, vtkPoints
1111
from vtkmodules.vtkCommonDataModel import vtkUnstructuredGrid, vtkHexahedron, vtkMultiBlockDataSet
1212
from vtkmodules.numpy_interface import dataset_adapter as dsa
1313
import numpy as np
1414
import numpy.typing as npt
1515
from vtkmodules.util.vtkConstants import VTK_HEXAHEDRON
1616

17-
from typing import List
18-
1917
from geos.mesh.processing.ClipToMainFrame import ClipToMainFrame
2018

2119
Lx, Ly, Lz = 5, 2, 8
@@ -76,8 +74,9 @@ def __build_test_mesh( mxx: Tuple[ int, ...] ) -> Generator[ Expected, None, Non
7674

7775
# Creating multiple meshes, each time with a different angles
7876
mesh = vtkUnstructuredGrid()
79-
( vtps := vtkPoints() ).SetData( dsa.numpy_support.numpy_to_vtk( pts ) )
80-
mesh.SetPoints( vtps )
77+
vpts = vtkPoints()
78+
vpts.SetData( dsa.numpy_support.numpy_to_vtk( pts ) )
79+
mesh.SetPoints( vpts )
8180

8281
ids = vtkIdList()
8382
for i in range( nx - 1 ):
@@ -103,7 +102,8 @@ def __build_test_mesh( mxx: Tuple[ int, ...] ) -> Generator[ Expected, None, Non
103102
"expected", [ item for t in list( itertools.product( [ -1, 1 ], repeat=3 ) ) for item in __build_test_mesh( t ) ] )
104103
def test_clipToMainFrame_polyhedron( expected: Expected ) -> None:
105104
"""Test the ClipToMainFrameFilter on a rotated and translated box hexa mesh."""
106-
( filter := ClipToMainFrame() ).SetInputData( expected.mesh )
105+
filter = ClipToMainFrame()
106+
filter.SetInputData( expected.mesh )
107107
filter.ComputeTransform()
108108
filter.Update()
109109
output_mesh: vtkUnstructuredGrid = filter.GetOutput()
@@ -133,10 +133,12 @@ def test_clipToMainFrame_polyhedron( expected: Expected ) -> None:
133133
def test_clipToMainFrame_generic( dataSetTest: vtkMultiBlockDataSet ) -> None:
134134
"""Test the ClipToMainFrameFilter on a MultiBlockDataSet."""
135135
multiBlockDataSet: vtkMultiBlockDataSet = dataSetTest( "multiblock" )
136-
( filter := ClipToMainFrame() ).SetInputData( multiBlockDataSet )
136+
filter = ClipToMainFrame()
137+
filter.SetInputData( multiBlockDataSet )
137138
filter.ComputeTransform()
138139
filter.Update()
139140
print( filter.GetTransform() )
140141
output_mesh: vtkMultiBlockDataSet = filter.GetOutputDataObject( 0 )
141142
assert output_mesh.GetNumberOfPoints() == multiBlockDataSet.GetNumberOfPoints()
142143
assert output_mesh.GetNumberOfCells() == multiBlockDataSet.GetNumberOfCells()
144+
assert output_mesh.IsA( 'vtkMultiBlockDataSet' )
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
# SPDX-FileCopyrightText: Copyright 2023-2024 TotalEnergies.
3+
# SPDX-FileContributor: Jacques Franc
4+
# ruff: noqa: E402 # disable Module level import not at top of file
5+
import sys
6+
from pathlib import Path
7+
from typing import Union
8+
9+
from paraview.util.vtkAlgorithm import ( # type: ignore[import-not-found]
10+
VTKPythonAlgorithmBase, smdomain, smhint, smproperty, smproxy,
11+
) # source: https://github.com/Kitware/ParaView/blob/master/Wrapping/Python/paraview/util/vtkAlgorithm.py
12+
from paraview.detail.loghandler import ( # type: ignore[import-not-found]
13+
VTKHandler,
14+
) # source: https://github.com/Kitware/ParaView/blob/master/Wrapping/Python/paraview/detail/loghandler.py
15+
16+
from vtkmodules.vtkCommonDataModel import (
17+
vtkMultiBlockDataSet,
18+
vtkUnstructuredGrid,
19+
)
20+
21+
from vtkmodules.vtkCommonCore import (
22+
vtkInformation,
23+
vtkInformationVector,
24+
)
25+
26+
# update sys.path to load all GEOS Python Package dependencies
27+
geos_pv_path: Path = Path( __file__ ).parent.parent.parent.parent.parent
28+
sys.path.insert( 0, str( geos_pv_path / "src" ) )
29+
from geos.pv.utils.config import update_paths
30+
31+
update_paths()
32+
33+
from geos.mesh.processing.ClipToMainFrame import ClipToMainFrame
34+
35+
__doc__ = """
36+
Clip the input mesh to the main frame applying the correct LandmarkTransform
37+
38+
To use it:
39+
40+
* Load the module in Paraview: Tools>Manage Plugins...>Load new>PVClipToMainFrame.
41+
* Apply.
42+
43+
"""
44+
45+
46+
@smproxy.filter( name="PVClipToMainFrame", label="Clip to the main frame" )
47+
@smhint.xml( '<ShowInMenu category="4- Geos Utils"/>' )
48+
@smproperty.input( name="Input", port_index=0 )
49+
@smdomain.datatype(
50+
dataTypes=[ "vtkMultiBlockDataSet", "vtkUnstructuredGrid" ],
51+
composite_data_supported=True,
52+
)
53+
class PVClipToMainFrame( VTKPythonAlgorithmBase ):
54+
55+
def __init__( self ) -> None:
56+
"""Init motherclass, filter and logger."""
57+
VTKPythonAlgorithmBase.__init__( self,
58+
nInputPorts=1,
59+
nOutputPorts=1,
60+
inputType="vtkDataObject",
61+
outputType="vtkDataObject" )
62+
63+
self._realFilter = ClipToMainFrame( speHandler=True )
64+
if not self._realFilter.logger.hasHandlers():
65+
self._realFilter.SetLoggerHandler( VTKHandler() )
66+
67+
#ensure I/O consistency
68+
def RequestDataObject( self, request: vtkInformation, inInfoVec: list[ vtkInformationVector ],
69+
outInfoVec: vtkInformationVector ) -> int:
70+
"""Inherited from VTKPythonAlgorithmBase::RequestDataObject.
71+
72+
Args:
73+
request (vtkInformation): request
74+
inInfoVec (list[vtkInformationVector]): input objects
75+
outInfoVec (vtkInformationVector): output objects
76+
77+
Returns:
78+
int: 1 if calculation successfully ended, 0 otherwise.
79+
"""
80+
inData = self.GetInputData( inInfoVec, 0, 0 )
81+
outData = self.GetOutputData( outInfoVec, 0 )
82+
assert inData is not None
83+
if outData is None or ( not outData.IsA( inData.GetClassName() ) ):
84+
outData = inData.NewInstance()
85+
outInfoVec.GetInformationObject( 0 ).Set( outData.DATA_OBJECT(), outData )
86+
return super().RequestDataObject( request, inInfoVec, outInfoVec ) # type: ignore[no-any-return]
87+
88+
def RequestData( self, request: vtkInformation, inInfo: list[ vtkInformationVector ],
89+
outInfo: vtkInformationVector ) -> int:
90+
"""Inherited from VTKPythonAlgorithmBase::RequestData. Apply ClipToMainFrame filter.
91+
92+
Args:
93+
request (vtkInformation): Request
94+
inInfo (list[vtkInformationVector]): Input objects
95+
outInfo (vtkInformationVector): Output objects
96+
97+
Returns:
98+
int: 1 if calculation successfully ended, 0 otherwise.
99+
"""
100+
inputMesh: Union[ vtkMultiBlockDataSet, vtkUnstructuredGrid ] = self.GetInputData( inInfo, 0, 0 )
101+
outputMesh: Union[ vtkMultiBlockDataSet, vtkUnstructuredGrid ] = self.GetOutputData( outInfo, 0 )
102+
103+
# struct
104+
self._realFilter.SetInputData( inputMesh )
105+
self._realFilter.ComputeTransform()
106+
self._realFilter.Update()
107+
outputMesh.ShallowCopy( self._realFilter.GetOutputDataObject( 0 ) )
108+
109+
return 1

0 commit comments

Comments
 (0)