diff --git a/src/coreComponents/python/modules/geosx_mesh_doctor/mesh_doctor-pvplugin.py b/src/coreComponents/python/modules/geosx_mesh_doctor/mesh_doctor-pvplugin.py new file mode 100644 index 00000000000..9f1e24025c3 --- /dev/null +++ b/src/coreComponents/python/modules/geosx_mesh_doctor/mesh_doctor-pvplugin.py @@ -0,0 +1,62 @@ +from paraview.util.vtkAlgorithm import * +from paraview.selection import * + + +@smproxy.filter(name="Mesh Doctor(GEOS)") +@smproperty.input(name="Input") +@smdomain.datatype(dataTypes=["vtkUnstructuredGrid"], composite_data_supported=False) +class ElementVolumesFilter(VTKPythonAlgorithmBase): + """ + Example portage meshDoctor in PV Python plugins + """ + def __init__(self): + super().__init__(outputType='vtkUnstructuredGrid') + from checks import element_volumes + self.opt = element_volumes.Options(0) + + def RequestData(self, request, inInfo, outInfo): + inData = self.GetInputData(inInfo, 0, 0) + outData = self.GetOutputData(outInfo, 0) + assert inData is not None + if outData is None or (not outData.IsA(inData.GetClassName())): + outData = inData.NewInstance() + extracted = self._Process(inData) + outData.DeepCopy( extracted.GetOutput() ) + outInfo.GetInformationObject(0).Set(outData.DATA_OBJECT(), extracted.GetOutput()) + + print("1> There are {} cells under {} m3 vol".format(outData.GetNumberOfCells(), self.opt)) + return 1 + + def _Process(self,mesh): + from checks import element_volumes + from paraview.vtk import vtkIdTypeArray, vtkSelectionNode, vtkSelection, vtkCollection + from vtk import vtkExtractSelection + res = element_volumes.check(mesh, self.opt) + ids = vtkIdTypeArray() + ids.SetNumberOfComponents(1) + for val in res.element_volumes: + ids.InsertNextValue(val[0]) + + + selectionNode = vtkSelectionNode() + selectionNode.SetFieldType(vtkSelectionNode.CELL) + selectionNode.SetContentType(vtkSelectionNode.INDICES) + selectionNode.SetSelectionList(ids) + selection = vtkSelection() + selection.AddNode(selectionNode) + + extracted = vtkExtractSelection() + extracted.SetInputDataObject(0, mesh) + extracted.SetInputData(1, selection) + extracted.Update() + print("There are {} cells under {} m3 vol".format(extracted.GetOutput().GetNumberOfCells(), self.opt)) + print("There are {} arrays of cell data".format(extracted.GetOutput().GetCellData().GetNumberOfArrays(), self.opt)) + + return extracted + + @smproperty.doublevector(name="Vol Threshold", default_values=["0.0"]) + def SetValue(self, val): + from checks import element_volumes + self.opt = element_volumes.Options(val) + # print("settings value:", self.opt) + self.Modified() diff --git a/src/docs/sphinx/pythonTools/mesh_doctor.rst b/src/docs/sphinx/pythonTools/mesh_doctor.rst index d9de402e15f..ed6f48b46d7 100644 --- a/src/docs/sphinx/pythonTools/mesh_doctor.rst +++ b/src/docs/sphinx/pythonTools/mesh_doctor.rst @@ -122,3 +122,75 @@ It will also verify that the ``VTK_POLYHEDRON`` cells can effectively get conver .. command-output:: python mesh_doctor.py supported_elements --help :cwd: ../../../coreComponents/python/modules/geosx_mesh_doctor + +``Using mesh_doctor in paraview`` +"""""""""""""""""""""""""""""""""" + +Using mesh_doctor as a programmable filter +____________________________________________ + +To use ``mesh_doctor`` in Paraview as a python programmable filter, a python package install is required first in Paraview python resolved +path. Paraview is storing its python ressources under its *lib/pythonX.X* depending on the paraview version, *e.g* Paraview 5.11 is working +with python 3.9. As a results the following command will install ``mesh_doctor`` package into Paraview resolved path. + +.. command-output:: python3 -m pip install --index-url https://test.pypi.org/simple/ --no-deps --upgrade --target /path/to/Paraview/lib/python3.9/ mesh_doctor + +.. note:: + ``pip`` is installing the ``mesh_doctor`` package from the test.pypi repo, which is intended to test package deployment. + Once stabilized and ``mesh_doctor`` uploaded onto the main package repo, this should be dropped out. + +Once the installation done, the */path/to/Paraview/lib/pythonX.X* should holds ``mesh_doctor`` package content, *i.e.* ``checks`` and ``parsing``. +Then launching ``Paraview`` and loading our *mesh.vtu*, as an example, we will design a *Programmable python filter* relying on *element_volumes* from +``mesh_doctor``. Add such a filter pipelined after the mesh reader, in the script section paste the following, + +.. code-block:: python + :linenos: + + mesh = inputs[0].VTKObject + tol = 1.2e-6 + + from checks import element_volumes + import vtk + + res = element_volumes.__check(mesh, element_volumes.Options(tol)) + #print(res) + ids = vtk.vtkIdTypeArray() + ids.SetNumberOfComponents(1) + for cell_index, volume in res.element_volumes: + ids.InsertNextValue(cell_index) + + selectionNode = vtk.vtkSelectionNode() + selectionNode.SetFieldType(vtk.vtkSelectionNode.CELL) + selectionNode.SetContentType(vtk.vtkSelectionNode.INDICES) + selectionNode.SetSelectionList(ids) + selection = vtk.vtkSelection() + selection.AddNode(selectionNode) + extracted = vtk.vtkExtractSelection() + extracted.SetInputDataObject(0, mesh) + extracted.SetInputData(1, selection) + extracted.Update() + print("There are {} cells under {} m3 vol".format(extracted.GetOutput().GetNumberOfCells(), tol)) + output.ShallowCopy(extracted.GetOutput()) + +Here we rely on ``pyvtk`` interface more than on Paraview adaptation, for legacy and reusability reasons. This is the reason +for the full ``import vtk`` instead of ``from paraview import vtk``, the `vtkSelectionNode` being fully wrapped in paraview +and not accessible otherwise. + +On line 7, we leverage ``mesh_doctor`` package to provide us with pairs of `(index,volumes)` of cells with volumes lower +than tolerance `tol`. As input of *Programmable Python Filter* is wrapped in a `dataset_adapter.UnstructuredGrid`, we rely on +the copy of the inital VTKObject `inputs[0].VTKObject` to ensure consistency with our ``pyvtk`` workflow. + +What follows is ``pyvtk`` steps in oder to convert into input struct and extract from the original mesh this list of cells. +Eventually, the `extracted` selection is shallow-copied to the output and then accessible in ``Paraview``. An helper print +is left and should be reported in *Output Message* of ``Paraview`` (and in launching terminal if exist). + +Using mesh_doctor as a paraview plugins +____________________________________________ + +Another way of leveraging ``mesh_doctor`` in ``Paraview`` is to wrap it in a python plugin that would be loadable through the +``Paraview`` interface under **Tools | Manage Plugins/Extensions** and **Load New** looking for ``mesh_doctor-pvplugin.py``. +(see `Paraview How To `_ for more details). + +The file ``mesh_doctor-pvplugin.py`` is located under the ``geosx_mesh_doctor`` module in GEOS. Once the plugin loaded and a mesh opened, +it should appear in filter list as *Mesh Doctor(GEOS)*. It displays a parameter value box allowing the user to enter the volume he wants as +threshold to select cells based on ``element_volumes`` capability. Once applied, it extracts selected set of cells as a new unstructured grid. \ No newline at end of file