diff --git a/docs/geos-mesh.rst b/docs/geos-mesh.rst
index 061f596db..cb8a5264f 100644
--- a/docs/geos-mesh.rst
+++ b/docs/geos-mesh.rst
@@ -15,8 +15,6 @@ GEOS Mesh tools
./geos_mesh_docs/model
- ./geos_mesh_docs/processing
-
./geos_mesh_docs/stats
./geos_mesh_docs/utils
diff --git a/docs/geos_mesh_docs/processing.rst b/docs/geos_mesh_docs/processing.rst
deleted file mode 100644
index fc8f3ca26..000000000
--- a/docs/geos_mesh_docs/processing.rst
+++ /dev/null
@@ -1,64 +0,0 @@
-Processing filters
-^^^^^^^^^^^^^^^^^^^
-
-The `processing` module of `geos-mesh` package contains filters to process meshes.
-
-geos.mesh.processing.AttributeMapping filter
----------------------------------------------
-
-.. automodule:: geos.mesh.processing.AttributeMapping
- :members:
- :undoc-members:
- :show-inheritance:
-
-geos.mesh.processing.CreateConstantAttributePerRegion filter
--------------------------------------------------------------
-
-.. automodule:: geos.mesh.processing.CreateConstantAttributePerRegion
- :members:
- :undoc-members:
- :show-inheritance:
-
-geos.mesh.processing.FillPartialArrays filter
-----------------------------------------------
-
-.. automodule:: geos.mesh.processing.FillPartialArrays
- :members:
- :undoc-members:
- :show-inheritance:
-
-
-geos.mesh.processing.meshQualityMetricHelpers module
------------------------------------------------------
-
-.. automodule:: geos.mesh.processing.meshQualityMetricHelpers
- :members:
- :undoc-members:
- :show-inheritance:
-
-
-geos.mesh.processing.SplitMesh filter
---------------------------------------
-
-.. automodule:: geos.mesh.processing.SplitMesh
- :members:
- :undoc-members:
- :show-inheritance:
-
-
-geos.mesh.processing.MergeBlockEnhanced filter
-------------------------------------------------
-
-.. automodule:: geos.mesh.processing.MergeBlockEnhanced
- :members:
- :undoc-members:
- :show-inheritance:
-
-
-geos.mesh.processing.ClipToMainFrame filter
---------------------------------------------
-
-.. automodule:: geos.mesh.processing.ClipToMainFrame
- :members:
- :undoc-members:
- :show-inheritance:
diff --git a/docs/geos_mesh_docs/stats.rst b/docs/geos_mesh_docs/stats.rst
index 77e9eee60..d5d06b2c0 100644
--- a/docs/geos_mesh_docs/stats.rst
+++ b/docs/geos_mesh_docs/stats.rst
@@ -1,21 +1,13 @@
Mesh stats tools
^^^^^^^^^^^^^^^^
-The `stats` module of `geos-mesh` package contains filter to compute statistics on meshes.
+The `stats` module of `geos-mesh` package contains module to compute statistics on meshes.
-geos.mesh.stats.CellTypeCounterEnhanced filter
+geos.mesh.stats.meshQualityMetricHelpers module
-----------------------------------------------
-.. automodule:: geos.mesh.stats.CellTypeCounterEnhanced
+.. automodule:: geos.mesh.stats.meshQualityMetricHelpers
:members:
:undoc-members:
:show-inheritance:
-
-geos.mesh.stats.MeshQualityEnhanced filter
--------------------------------------------
-
-.. automodule:: geos.mesh.stats.MeshQualityEnhanced
- :members:
- :undoc-members:
- :show-inheritance:
\ No newline at end of file
diff --git a/docs/geos_processing_docs/generic_processing_tools.rst b/docs/geos_processing_docs/generic_processing_tools.rst
index 4fdb32fcb..66bd22d02 100644
--- a/docs/geos_processing_docs/generic_processing_tools.rst
+++ b/docs/geos_processing_docs/generic_processing_tools.rst
@@ -1,4 +1,58 @@
Generic processing filters
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-In progress..
\ No newline at end of file
+The `generic_processing_tools` module of `geos-processing` package contains filters to process meshes.
+
+
+geos.processing.generic_processing_tools.AttributeMapping filter
+----------------------------------------------------------------
+
+.. automodule:: geos.processing.generic_processing_tools.AttributeMapping
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+
+geos.processing.generic_processing_tools.CreateConstantAttributePerRegion filter
+--------------------------------------------------------------------------------
+
+.. automodule:: geos.processing.generic_processing_tools.CreateConstantAttributePerRegion
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+
+geos.processing.generic_processing_tools.FillPartialArrays filter
+-----------------------------------------------------------------
+
+.. automodule:: geos.processing.generic_processing_tools.FillPartialArrays
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+
+geos.processing.generic_processing_tools.SplitMesh filter
+---------------------------------------------------------
+
+.. automodule:: geos.processing.generic_processing_tools.SplitMesh
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+
+geos.processing.generic_processing_tools.MergeBlockEnhanced filter
+------------------------------------------------------------------
+
+.. automodule:: geos.processing.generic_processing_tools.MergeBlockEnhanced
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+
+geos.processing.generic_processing_tools.ClipToMainFrame filter
+---------------------------------------------------------------
+
+.. automodule:: geos.processing.generic_processing_tools.ClipToMainFrame
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/geos_processing_docs/pre_processing.rst b/docs/geos_processing_docs/pre_processing.rst
index 859730930..6a943c57b 100644
--- a/docs/geos_processing_docs/pre_processing.rst
+++ b/docs/geos_processing_docs/pre_processing.rst
@@ -1,4 +1,20 @@
Pre-processing filters
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-In progress..
\ No newline at end of file
+The `pre_processing` module of `geos-processing` package contains filters to pre-process meshes for GEOS simulation.
+
+geos.processing.pre_processing.CellTypeCounterEnhanced filter
+-------------------------------------------------------------
+
+.. automodule:: geos.processing.pre_processing.CellTypeCounterEnhanced
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+geos.processing.pre_processing.MeshQualityEnhanced filter
+---------------------------------------------------------
+
+.. automodule:: geos.processing.pre_processing.MeshQualityEnhanced
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/geos-mesh/src/geos/mesh/model/QualityMetricSummary.py b/geos-mesh/src/geos/mesh/model/QualityMetricSummary.py
index 05e7d73d6..e21d86e72 100644
--- a/geos-mesh/src/geos/mesh/model/QualityMetricSummary.py
+++ b/geos-mesh/src/geos/mesh/model/QualityMetricSummary.py
@@ -17,11 +17,11 @@
from matplotlib.patches import Patch
from vtkmodules.vtkCommonDataModel import ( vtkCellTypes, VTK_TRIANGLE, VTK_QUAD, VTK_TETRA, VTK_PYRAMID,
VTK_HEXAHEDRON, VTK_WEDGE, VTK_POLYGON, VTK_POLYHEDRON )
-from geos.mesh.processing.meshQualityMetricHelpers import ( QUALITY_METRIC_OTHER_START_INDEX, getAllCellTypesExtended,
- getQualityMeasureNameFromIndex, getQualityMetricFromIndex,
- MeshQualityMetricEnum, CellQualityMetricEnum,
- VtkCellQualityMetricEnum, CellQualityMetricAdditionalEnum,
- QualityMetricOtherEnum, QualityRange )
+from geos.mesh.stats.meshQualityMetricHelpers import ( QUALITY_METRIC_OTHER_START_INDEX, getAllCellTypesExtended,
+ getQualityMeasureNameFromIndex, getQualityMetricFromIndex,
+ MeshQualityMetricEnum, CellQualityMetricEnum,
+ VtkCellQualityMetricEnum, CellQualityMetricAdditionalEnum,
+ QualityMetricOtherEnum, QualityRange )
from geos.mesh.model.CellTypeCounts import CellTypeCounts
from packaging.version import Version
diff --git a/geos-mesh/src/geos/mesh/processing/meshQualityMetricHelpers.py b/geos-mesh/src/geos/mesh/stats/meshQualityMetricHelpers.py
similarity index 100%
rename from geos-mesh/src/geos/mesh/processing/meshQualityMetricHelpers.py
rename to geos-mesh/src/geos/mesh/stats/meshQualityMetricHelpers.py
diff --git a/geos-mesh/tests/test_meshQualityHelpers.py b/geos-mesh/tests/test_meshQualityHelpers.py
index f961b32b3..2b077d96f 100644
--- a/geos-mesh/tests/test_meshQualityHelpers.py
+++ b/geos-mesh/tests/test_meshQualityHelpers.py
@@ -10,7 +10,7 @@
from vtkmodules.vtkCommonDataModel import ( VTK_TRIANGLE, VTK_QUAD, VTK_TETRA, VTK_PYRAMID, VTK_WEDGE, VTK_HEXAHEDRON,
VTK_POLYGON, VTK_POLYHEDRON )
-from geos.mesh.processing.meshQualityMetricHelpers import (
+from geos.mesh.stats.meshQualityMetricHelpers import (
VtkCellQualityMetricEnum,
CellQualityMetricAdditionalEnum,
QualityRange,
diff --git a/geos-mesh/src/geos/mesh/processing/AttributeMapping.py b/geos-processing/src/geos/processing/generic_processing_tools/AttributeMapping.py
similarity index 71%
rename from geos-mesh/src/geos/mesh/processing/AttributeMapping.py
rename to geos-processing/src/geos/processing/generic_processing_tools/AttributeMapping.py
index 465f986b5..9eb7aa6fe 100644
--- a/geos-mesh/src/geos/mesh/processing/AttributeMapping.py
+++ b/geos-processing/src/geos/processing/generic_processing_tools/AttributeMapping.py
@@ -5,60 +5,59 @@
import numpy as np
import numpy.typing as npt
import logging
-
-from geos.utils.Logger import ( Logger, getLogger )
-from typing_extensions import Self, Union, Set, List, Dict
-
-from vtkmodules.vtkCommonDataModel import (
- vtkDataSet,
- vtkMultiBlockDataSet,
-)
-
+from typing_extensions import Self, Union
+from vtkmodules.vtkCommonDataModel import vtkDataSet, vtkMultiBlockDataSet
from geos.mesh.utils.arrayModifiers import transferAttributeWithElementMap
from geos.mesh.utils.arrayHelpers import ( computeElementMapping, getAttributeSet, isAttributeGlobal )
+from geos.utils.Logger import ( Logger, getLogger )
__doc__ = """
-AttributeMapping is a vtk filter that transfers global attributes from a source mesh to a final mesh with same point/cell coordinates. The final mesh is updated directly, without creation of a copy.
+AttributeMapping is a vtk filter that transfers global attributes from a source mesh to a final mesh with same
+point/cell coordinates. The final mesh is updated directly, without creation of a copy.
Input meshes can be vtkDataSet or vtkMultiBlockDataSet.
.. Warning::
- For one application of the filter, the attributes to transfer should all be located on the same piece (all on points or all on cells).
+ For one application of the filter, the attributes to transfer should all be located on the same piece
+ (all on points or all on cells).
.. Note::
For cell, the coordinates of the points in the cell are compared.
- If one of the two meshes is a surface and the other a volume, all the points of the surface must be points of the volume.
+ If one of the two meshes is a surface and the other a volume,
+ all the points of the surface must be points of the volume.
-To use a logger handler of yours, set the variable 'speHandler' to True and add it using the member function setLoggerHandler.
+To use a logger handler of yours, set the variable 'speHandler' to True
+and add it using the member function setLoggerHandler.
To use the filter:
.. code-block:: python
- from geos.mesh.processing.AttributeMapping import AttributeMapping
+ from geos.processing.generic_processing_tools.AttributeMapping import AttributeMapping
# Filter inputs.
meshFrom: Union[ vtkDataSet, vtkMultiBlockDataSet ]
meshTo: Union[ vtkDataSet, vtkMultiBlockDataSet ]
- attributeNames: Set[ str ]
+ attributeNames: set[ str ]
# Optional inputs.
onPoints: bool # defaults to False
speHandler: bool # defaults to False
# Instantiate the filter
- filter: AttributeMapping = AttributeMapping( meshFrom,
- meshTo,
- attributeNames,
- onPoints,
- speHandler,
+ attributeMappingFilter: AttributeMapping = AttributeMapping(
+ meshFrom,
+ meshTo,
+ attributeNames,
+ onPoints,
+ speHandler,
)
# Set the handler of yours (only if speHandler is True).
yourHandler: logging.Handler
- filter.setLoggerHandler( yourHandler )
+ attributeMappingFilter.setLoggerHandler( yourHandler )
# Do calculations.
- filter.applyFilter()
+ attributeMappingFilter.applyFilter()
"""
loggerTitle: str = "Attribute Mapping"
@@ -70,16 +69,18 @@ def __init__(
self: Self,
meshFrom: Union[ vtkDataSet, vtkMultiBlockDataSet ],
meshTo: Union[ vtkDataSet, vtkMultiBlockDataSet ],
- attributeNames: Set[ str ],
+ attributeNames: set[ str ],
onPoints: bool = False,
speHandler: bool = False,
) -> None:
- """Transfer global attributes from a source mesh to a final mesh, mapping the piece of the attributes to transfer.
+ """Transfer global attributes from a source mesh to a final mesh.
+
+ Mapping the piece of the attributes to transfer.
Args:
- 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.
+ 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.
speHandler (bool, optional): True to use a specific handler, False to use the internal handler.
@@ -87,13 +88,13 @@ def __init__(
"""
self.meshFrom: Union[ vtkDataSet, vtkMultiBlockDataSet ] = meshFrom
self.meshTo: Union[ vtkDataSet, vtkMultiBlockDataSet ] = meshTo
- self.attributeNames: Set[ str ] = attributeNames
+ self.attributeNames: set[ str ] = attributeNames
self.onPoints: bool = onPoints
- #TODO/refact (@RomainBaville) make it an enum
+ # TODO/refact (@RomainBaville) make it an enum
self.piece: str = "points" if self.onPoints else "cells"
# cell map
- self.ElementMap: Dict[ int, npt.NDArray[ np.int64 ] ] = {}
+ self.ElementMap: dict[ int, npt.NDArray[ np.int64 ] ] = {}
# Logger.
self.logger: Logger
@@ -106,7 +107,8 @@ def __init__(
def setLoggerHandler( self: Self, handler: logging.Handler ) -> None:
"""Set a specific handler for the filter logger.
- In this filter 4 log levels are use, .info, .error, .warning and .critical, be sure to have at least the same 4 levels.
+ In this filter 4 log levels are use, .info, .error, .warning and .critical,
+ be sure to have at least the same 4 levels.
Args:
handler (logging.Handler): The handler to add.
@@ -114,22 +116,23 @@ def setLoggerHandler( self: Self, handler: logging.Handler ) -> None:
if not self.logger.hasHandlers():
self.logger.addHandler( handler )
else:
- self.logger.warning(
- "The logger already has an handler, to use yours set the argument 'speHandler' to True during the filter initialization."
- )
+ self.logger.warning( "The logger already has an handler, to use yours set the argument 'speHandler'"
+ " to True during the filter initialization." )
- def getElementMap( self: Self ) -> Dict[ int, npt.NDArray[ np.int64 ] ]:
+ def getElementMap( self: Self ) -> dict[ int, npt.NDArray[ np.int64 ] ]:
"""Getter of the element mapping dictionary.
If attribute to transfer are on points it will be a pointMap, else it will be a cellMap.
Returns:
- self.elementMap (Dict[int, npt.NDArray[np.int64]]): The element mapping dictionary.
+ self.elementMap (dict[int, npt.NDArray[np.int64]]): The element mapping dictionary.
"""
return self.ElementMap
def applyFilter( self: Self ) -> bool:
- """Transfer global attributes from a source mesh to a final mesh, mapping the piece of the attributes to transfer.
+ """Transfer global attributes from a source mesh to a final mesh.
+
+ Mapping the piece of the attributes to transfer.
Returns:
boolean (bool): True if calculation successfully ended, False otherwise.
@@ -141,16 +144,16 @@ def applyFilter( self: Self ) -> bool:
self.logger.warning( f"The filter { self.logger.name } has not been used." )
return False
- attributesInMeshFrom: Set[ str ] = getAttributeSet( self.meshFrom, self.onPoints )
- wrongAttributeNames: Set[ str ] = self.attributeNames.difference( attributesInMeshFrom )
+ attributesInMeshFrom: set[ str ] = getAttributeSet( self.meshFrom, self.onPoints )
+ wrongAttributeNames: set[ str ] = self.attributeNames.difference( attributesInMeshFrom )
if len( wrongAttributeNames ) > 0:
self.logger.error(
f"The { self.piece } attributes { wrongAttributeNames } are not present in the source mesh." )
self.logger.error( f"The filter { self.logger.name } failed." )
return False
- attributesInMeshTo: Set[ str ] = getAttributeSet( self.meshTo, self.onPoints )
- attributesAlreadyInMeshTo: Set[ str ] = self.attributeNames.intersection( attributesInMeshTo )
+ attributesInMeshTo: set[ str ] = getAttributeSet( self.meshTo, self.onPoints )
+ attributesAlreadyInMeshTo: set[ str ] = self.attributeNames.intersection( attributesInMeshTo )
if len( attributesAlreadyInMeshTo ) > 0:
self.logger.error(
f"The { self.piece } attributes { attributesAlreadyInMeshTo } are already present in the final mesh." )
@@ -158,7 +161,7 @@ def applyFilter( self: Self ) -> bool:
return False
if isinstance( self.meshFrom, vtkMultiBlockDataSet ):
- partialAttributes: List[ str ] = []
+ partialAttributes: list[ str ] = []
for attributeName in self.attributeNames:
if not isAttributeGlobal( self.meshFrom, attributeName, self.onPoints ):
partialAttributes.append( attributeName )
@@ -194,6 +197,5 @@ def applyFilter( self: Self ) -> bool:
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."
- )
+ 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." )
diff --git a/geos-mesh/src/geos/mesh/processing/ClipToMainFrame.py b/geos-processing/src/geos/processing/generic_processing_tools/ClipToMainFrame.py
similarity index 86%
rename from geos-mesh/src/geos/mesh/processing/ClipToMainFrame.py
rename to geos-processing/src/geos/processing/generic_processing_tools/ClipToMainFrame.py
index bc24b0349..6b95fbbae 100644
--- a/geos-mesh/src/geos/mesh/processing/ClipToMainFrame.py
+++ b/geos-processing/src/geos/processing/generic_processing_tools/ClipToMainFrame.py
@@ -1,7 +1,6 @@
# SPDX-License-Identifier: Apache 2.0
# SPDX-FileCopyrightText: Copyright 2023-2025 TotalEnergies
# SPDX-FileContributor: Jacques Franc
-from typing import Tuple
import logging
import numpy as np
@@ -12,7 +11,8 @@
from vtkmodules.vtkCommonMath import vtkMatrix4x4
from vtkmodules.vtkFiltersGeneral import vtkOBBTree
from vtkmodules.vtkFiltersGeometry import vtkDataSetSurfaceFilter
-from vtkmodules.vtkCommonDataModel import vtkUnstructuredGrid, vtkMultiBlockDataSet, vtkDataObjectTreeIterator, vtkPolyData
+from vtkmodules.vtkCommonDataModel import ( vtkUnstructuredGrid, vtkMultiBlockDataSet, vtkDataObjectTreeIterator,
+ vtkPolyData )
from vtkmodules.vtkCommonTransforms import vtkLandmarkTransform
from vtkmodules.vtkFiltersGeneral import vtkTransformFilter
@@ -30,7 +30,7 @@
.. code-block:: python
- from geos.mesh.processing.ClipToMainFrame import ClipToMainFrame
+ from geos.processing.generic_processing_tools.ClipToMainFrame import ClipToMainFrame
# Filter inputs.
multiBlockDataSet: vtkMultiBlockDataSet
@@ -38,17 +38,17 @@
speHandler : bool
# Instantiate the filter.
- filter: ClipToMainFrame = ClipToMainFrame()
- filter.SetInputData( multiBlockDataSet )
+ clipToMainFrameFilter: ClipToMainFrame = ClipToMainFrame()
+ clipToMainFrameFilter.SetInputData( multiBlockDataSet )
# Set the handler of yours (only if speHandler is True).
yourHandler: logging.Handler
- filter.setLoggerHandler( yourHandler )
+ clipToMainFrameFilter.setLoggerHandler( yourHandler )
# Do calculations.
- filter.ComputeTransform()
- filter.Update()
- output: vtkMultiBlockDataSet = filter.GetOutput()
+ clipToMainFrameFilter.ComputeTransform()
+ clipToMainFrameFilter.Update()
+ output: vtkMultiBlockDataSet = clipToMainFrameFilter.GetOutput()
"""
@@ -79,9 +79,9 @@ def Update( self ) -> None:
def __str__( self ) -> str:
"""String representation of the transformation."""
return super().__str__() + f"\nSource points: {self.sourcePts}" \
- + f"\nTarget points: {self.targetPts}" \
- + f"\nAngle-Axis: {self.__getAngleAxis()}" \
- + f"\nTranslation: {self.__getTranslation()}"
+ + f"\nTarget points: {self.targetPts}" \
+ + f"\nAngle-Axis: {self.__getAngleAxis()}" \
+ + f"\nTranslation: {self.__getTranslation()}"
def __getAngleAxis( self ) -> tuple[ float, npt.NDArray[ np.double ] ]:
"""Get the angle and axis of the rotation.
@@ -163,7 +163,7 @@ def __getFramePoints( self, vpts: vtkPoints ) -> tuple[ vtkPoints, vtkPoints ]:
tuple[vtkPoints, vtkPoints]: Source and target points for the transformation.
"""
pts: npt.NDArray[ np.double ] = dsa.numpy_support.vtk_to_numpy( vpts.GetData() )
- #translate pts so they always lie on the -z,-y,-x quadrant
+ # translate pts so they always lie on the -z,-y,-x quadrant
off: npt.NDArray[ np.double ] = np.asarray( [
-2 * np.amax( np.abs( pts[ :, 0 ] ) ), -2 * np.amax( np.abs( pts[ :, 1 ] ) ),
-2 * np.amax( np.abs( pts[ :, 2 ] ) )
@@ -190,7 +190,7 @@ def __getFramePoints( self, vpts: vtkPoints ) -> tuple[ vtkPoints, vtkPoints ]:
v3: npt.NDArray[ np.double ] = np.cross( v1, v2 )
v3 /= np.linalg.norm( v3 )
- #reorder axis if v3 points downward
+ # reorder axis if v3 points downward
if v3[ 2 ] < 0:
v3 = -v3
v1, v2 = v2, v1
@@ -239,10 +239,9 @@ def ComputeTransform( self ) -> None:
"""Update the transformation."""
# dispatch to ClipToMainFrame depending on input type
if isinstance( self.GetInput(), vtkMultiBlockDataSet ):
- #locate reference point
- self.logger.info(
- "Processing MultiblockDataSet.\n Please make sure your MultiblockDataSet is owning a vtkUnstructured grid as a leaf."
- )
+ # locate reference point
+ self.logger.info( "Processing MultiblockDataSet.\n Please make sure your MultiblockDataSet is owning"
+ " a vtkUnstructured grid as a leaf." )
try:
idBlock = self.__locate_reference_point( self.GetInput() )
except IndexError:
@@ -250,14 +249,17 @@ def ComputeTransform( self ) -> None:
clip = ClipToMainFrameElement( self.GetInput().GetDataSet( idBlock ) )
else:
- self.logger.info( "Processing untructuredGrid" )
+ self.logger.info( "Processing unstructuredGrid" )
clip = ClipToMainFrameElement( self.GetInput() )
clip.Update()
self.SetTransform( clip )
def SetLoggerHandler( self, handler: logging.Handler ) -> None:
- """Set a specific handler for the filter logger. In this filter 4 log levels are use, .info, .error, .warning and .critical, be sure to have at least the same 4 levels.
+ """Set a specific handler for the filter logger.
+
+ In this filter 4 log levels are use, .info, .error, .warning and .critical,
+ be sure to have at least the same 4 levels.
Args:
handler (logging.Handler): The handler to add.
@@ -265,9 +267,8 @@ def SetLoggerHandler( self, handler: logging.Handler ) -> None:
if not self.logger.hasHandlers():
self.logger.addHandler( handler )
else:
- self.logger.warning(
- "The logger already has an handler, to use yours set the argument 'speHandler' to True during the filter initialization."
- )
+ self.logger.warning( "The logger already has an handler, to use yours set the argument 'speHandler' to True"
+ " during the filter initialization." )
def __locate_reference_point( self, multiBlockDataSet: vtkMultiBlockDataSet ) -> int:
"""Locate the block to use as reference for the transformation.
@@ -303,8 +304,8 @@ def __inside( pt: npt.NDArray[ np.double ], bounds: tuple[ float, float, float,
xmin, _, ymin, _, zmin, _ = getMultiBlockBounds( multiBlockDataSet )
while DOIterator.GetCurrentDataObject() is not None:
dataSet: vtkUnstructuredGrid = vtkUnstructuredGrid.SafeDownCast( DOIterator.GetCurrentDataObject() )
- bounds: Tuple[ float, float, float, float, float, float ] = dataSet.GetBounds()
- #use the furthest bounds corner as reference point in the all negs quadrant
+ bounds: tuple[ float, float, float, float, float, float ] = dataSet.GetBounds()
+ # use the furthest bounds corner as reference point in the all negs quadrant
if __inside( np.asarray( [ xmin, ymin, zmin ] ), bounds ):
self.logger.info( f"Using block {DOIterator.GetCurrentFlatIndex()} as reference for transformation" )
return DOIterator.GetCurrentFlatIndex()
diff --git a/geos-mesh/src/geos/mesh/processing/CreateConstantAttributePerRegion.py b/geos-processing/src/geos/processing/generic_processing_tools/CreateConstantAttributePerRegion.py
similarity index 79%
rename from geos-mesh/src/geos/mesh/processing/CreateConstantAttributePerRegion.py
rename to geos-processing/src/geos/processing/generic_processing_tools/CreateConstantAttributePerRegion.py
index 29ec103ae..85e1fc74b 100644
--- a/geos-mesh/src/geos/mesh/processing/CreateConstantAttributePerRegion.py
+++ b/geos-processing/src/geos/processing/generic_processing_tools/CreateConstantAttributePerRegion.py
@@ -28,7 +28,8 @@
If other region indexes exist values are set to nan for float type, -1 for int type or 0 for uint type.
Input mesh is either vtkMultiBlockDataSet or vtkDataSet and the region attribute must have one component.
-The relation index/values is given by a dictionary. Its keys are the indexes and its items are the list of values for each component.
+The relation index/values is given by a dictionary.
+Its keys are the indexes and its items are the list of values for each component.
To use a handler of yours, set the variable 'speHandler' to True and add it using the member function addLoggerHandler.
By default, the value type is set to float32, their is one component and no name and the logger use an intern handler.
@@ -37,7 +38,7 @@
.. code-block:: python
- from geos.mesh.processing.CreateConstantAttributePerRegion import CreateConstantAttributePerRegion
+ from geos.processing.generic_processing_tools.CreateConstantAttributePerRegion import CreateConstantAttributePerRegion
# Filter inputs.
mesh: Union[vtkMultiBlockDataSet, vtkDataSet]
@@ -52,22 +53,23 @@
speHandler: bool
# Instantiate the filter
- filter: CreateConstantAttributePerRegion = CreateConstantAttributePerRegion( mesh,
- regionName,
- dictRegionValues,
- newAttributeName,
- valueNpType,
- nbComponents,
- componentNames,
- speHandler,
- )
+ createConstantAttributePerRegionFilter: CreateConstantAttributePerRegion = CreateConstantAttributePerRegion(
+ mesh,
+ regionName,
+ dictRegionValues,
+ newAttributeName,
+ valueNpType,
+ nbComponents,
+ componentNames,
+ speHandler,
+ )
# Set your handler (only if speHandler is True).
yourHandler: logging.Handler
- filter.addLoggerHandler( yourHandler )
+ createConstantAttributePerRegionFilter.addLoggerHandler( yourHandler )
# Do calculations.
- filter.applyFilter()
+ createConstantAttributePerRegionFilter.applyFilter()
"""
loggerTitle: str = "Create Constant Attribute Per Region"
@@ -89,15 +91,16 @@ def __init__(
"""Create an attribute with constant value per region.
Args:
- mesh (Union[ vtkDataSet, vtkMultiBlockDataSet ]): The mesh where to create the constant attribute per region.
- regionName (str): The name of the attribute with the region indexes.
- dictRegionValues (dict[ Any, Any ]): The dictionary with the region indexes as keys and the list of values as items.
- newAttributeName (str): The name of the new attribute to create.
- valueNpType (type, optional): The numpy scalar type for values.
+ mesh (Union[ vtkDataSet, vtkMultiBlockDataSet ]): Mesh where to create the constant attribute per region.
+ regionName (str): Name of the attribute with the region indexes.
+ dictRegionValues (dict[ Any, Any ]): Dictionary with the region ids as keys and the list of values as items.
+ newAttributeName (str): Name of the new attribute to create.
+ valueNpType (type, optional): Numpy scalar type for values.
Defaults to numpy.float32.
nbComponents (int, optional): Number of components for the new attribute.
Defaults to 1.
- componentNames (tuple[str,...], optional): Name of the components for vectorial attributes. If one component, gives an empty tuple.
+ componentNames (tuple[str,...], optional): Name of the components for vectorial attributes.
+ If one component, gives an empty tuple.
Defaults to an empty tuple.
speHandler (bool, optional): True to use a specific handler, False to use the internal handler.
Defaults to False.
@@ -117,7 +120,8 @@ def __init__(
self.onBoth: bool
self.onPoints, self.onBoth = getAttributePieceInfo( self.mesh, self.regionName )
- self.useDefaultValue: bool = False # Check if the new component have default values (information for the output message).
+ # Check if the new component have default values (information for the output message).
+ self.useDefaultValue: bool = False
# Warnings counter.
self.counter: CountWarningHandler = CountWarningHandler()
@@ -144,9 +148,8 @@ def setLoggerHandler( self: Self, handler: logging.Handler ) -> None:
self.logger.addHandler( handler )
else:
# This warning does not count for the number of warning created during the application of the filter.
- self.logger.warning(
- "The logger already has an handler, to use yours set the argument 'speHandler' to True during the filter initialization."
- )
+ self.logger.warning( "The logger already has an handler, to use yours set the argument 'speHandler' to True"
+ " during the filter initialization." )
def applyFilter( self: Self ) -> bool:
"""Create a constant attribute per region in the mesh.
@@ -167,9 +170,8 @@ def applyFilter( self: Self ) -> bool:
return False
if self.onBoth:
- self.logger.error(
- f"There are two attributes named { self.regionName }, one on points and the other on cells. The region attribute must be unique."
- )
+ self.logger.error( f"There are two attributes named { self.regionName }, one on points"
+ "and the other on cells. The region attribute must be unique." )
self.logger.error( f"The new attribute { self.newAttributeName } has not been added." )
self.logger.error( f"The filter { self.logger.name } failed." )
return False
@@ -185,9 +187,8 @@ def applyFilter( self: Self ) -> bool:
# Check if the number of components and number of values for the region indexes are coherent.
for index in self.dictRegionValues:
if len( self.dictRegionValues[ index ] ) != self.nbComponents:
- self.logger.error(
- f"The number of value given for the region index { index } is not correct. You must set a value for each component, in this case { self.nbComponents }."
- )
+ self.logger.error( f"The number of value given for the region index { index } is not correct."
+ f" You must set a value for each component, in this case { self.nbComponents }." )
return False
listIndexes: list[ Any ] = list( self.dictRegionValues.keys() )
@@ -303,21 +304,24 @@ def _setInfoRegion( self: Self ) -> None:
# Set the list of default value for each component depending of the type.
self.defaultValue: list[ Any ]
- ## Default value for float types is nan.
+ # Default value for float types is nan.
if self.valueNpType in ( np.float32, np.float64 ):
self.defaultValue = [ self.valueNpType( np.nan ) for _ in range( self.nbComponents ) ]
- ## Default value for int types is -1.
+ # Default value for int types is -1.
elif self.valueNpType in ( np.int8, np.int16, np.int32, np.int64 ):
self.defaultValue = [ self.valueNpType( -1 ) for _ in range( self.nbComponents ) ]
- ## Default value for uint types is 0.
+ # Default value for uint types is 0.
elif self.valueNpType in ( np.uint8, np.uint16, np.uint32, np.uint64 ):
self.defaultValue = [ self.valueNpType( 0 ) for _ in range( self.nbComponents ) ]
def _createArrayFromRegionArrayWithValueMap( self: Self, regionArray: npt.NDArray[ Any ] ) -> npt.NDArray[ Any ]:
- """Create the array from the regionArray and the valueMap (self.valueMap) giving the relation between the values of the regionArray and the new one.
+ """Create the array from the regionArray and the valueMap (self.valueMap).
+
+ Giving the relation between the values of the regionArray and the new one.
For each element (idElement) of the regionArray:
- - If the value (regionArray[idElement]) is mapped (a keys of the valueMap), valueArray[idElement] = self.valueMap[value].
+ - If the value (regionArray[idElement]) is mapped (a keys of the valueMap),
+ valueArray[idElement] = self.valueMap[value].
- If not, valueArray[idElement] = self.defaultValue.
Args:
@@ -360,44 +364,48 @@ def _logOutputMessage( self: Self, trueIndexes: list[ Any ] ) -> None:
self.logger.info( f"The filter { self.logger.name } succeeded." )
# Info about the created attribute.
- ## The piece where the attribute is created.
+ # 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 }." )
- ## The number of component and they names if multiple.
+ # The number of component and they names if multiple.
componentNamesCreated: tuple[ str, ...] = getComponentNames( self.mesh, self.newAttributeName, self.onPoints )
if self.nbComponents > 1:
- messComponent: str = f"The new attribute { self.newAttributeName } has { self.nbComponents } components named { componentNamesCreated }."
+ messComponent: str = ( f"The new attribute { self.newAttributeName } has { self.nbComponents } components"
+ f" named { componentNamesCreated }." )
if componentNamesCreated != self.componentNames:
- ### Warn the user because other component names than those given have been used.
+ # Warn the user because other component names than those given have been used.
self.logger.warning( messComponent )
else:
self.logger.info( messComponent )
- ## The values of the attribute.
+ # The values of the attribute.
messValue: str = f"The new attribute { self.newAttributeName } is constant"
if len( trueIndexes ) == 0:
- ### Create the message to have the value of each component.
+ # Create the message to have the value of each component.
messValue = f"{ messValue } with"
if self.nbComponents > 1:
for idComponent in range( self.nbComponents ):
- messValue = f"{ messValue } the value { self.defaultValue[ idComponent ] } for the component { componentNamesCreated[ idComponent ] },"
+ messValue = ( f"{ messValue } the value { self.defaultValue[ idComponent ] } for the component"
+ f" { componentNamesCreated[ idComponent ] }," )
messValue = f"{ messValue[:-1] }."
else:
messValue = f"{ messValue } the value { self.defaultValue[ 0 ] }."
- ### Warn the user because no region index has been used.
+ # Warn the user because no region index has been used.
self.logger.warning( messValue )
else:
- ### Create the message to have for each component the value of the region index.
+ # Create the message to have for each component the value of the region index.
messValue = f"{ messValue } per region indexes with:\n"
for index in trueIndexes:
messValue = f"{ messValue }\tThe value { self.dictRegionValues[ index ][ 0 ] } for the"
if self.nbComponents > 1:
messValue = f"{ messValue } component { componentNamesCreated[ 0 ] },"
for idComponent in range( 1, self.nbComponents - 1 ):
- messValue = f"{ messValue } the value { self.dictRegionValues[ index ][ idComponent ] } for the component { componentNamesCreated[ idComponent ] },"
- messValue = f"{ messValue[ : -1 ] } and the value { self.dictRegionValues[ index ][ -1 ] } for the component { componentNamesCreated[ -1 ] } for the index { index }.\n"
+ messValue = ( f"{ messValue } the value { self.dictRegionValues[ index ][ idComponent ] }"
+ f" for the component { componentNamesCreated[ idComponent ] }," )
+ messValue = ( f"{ messValue[ : -1 ] } and the value { self.dictRegionValues[ index ][ -1 ] }"
+ f" for the component { componentNamesCreated[ -1 ] } for the index { index }.\n" )
else:
messValue = f"{ messValue } index { index }.\n"
@@ -406,15 +414,17 @@ def _logOutputMessage( self: Self, trueIndexes: list[ Any ] ) -> None:
if self.nbComponents > 1:
messValue = f"{ messValue } component { componentNamesCreated[ 0 ] },"
for idComponent in range( 1, self.nbComponents - 1 ):
- messValue = f"{ messValue } the value { self.defaultValue[ idComponent ] } for the component { componentNamesCreated[ idComponent ] },"
- messValue = f"{ messValue[ : -1 ] } and the value { self.defaultValue[ -1 ] } for the component { componentNamesCreated[ -1 ] } for the other indexes."
+ messValue = ( f"{ messValue } the value { self.defaultValue[ idComponent ] }"
+ f" for the component { componentNamesCreated[ idComponent ] }," )
+ messValue = ( f"{ messValue[ : -1 ] } and the value { self.defaultValue[ -1 ] }"
+ f" for the component { componentNamesCreated[ -1 ] } for the other indexes." )
else:
messValue = f"{ messValue } other indexes."
- ### Warn the user because a default value has been used.
+ # Warn the user because a default value has been used.
self.logger.warning( messValue )
else:
if self.counter.warningCount > 0:
- ### Warn the user because other component names than those given have been used.
+ # Warn the user because other component names than those given have been used.
self.logger.warning( messValue )
else:
self.logger.info( messValue )
diff --git a/geos-mesh/src/geos/mesh/processing/FillPartialArrays.py b/geos-processing/src/geos/processing/generic_processing_tools/FillPartialArrays.py
similarity index 79%
rename from geos-mesh/src/geos/mesh/processing/FillPartialArrays.py
rename to geos-processing/src/geos/processing/generic_processing_tools/FillPartialArrays.py
index 1810bc735..feb561984 100644
--- a/geos-mesh/src/geos/mesh/processing/FillPartialArrays.py
+++ b/geos-processing/src/geos/processing/generic_processing_tools/FillPartialArrays.py
@@ -19,7 +19,7 @@
The list of filling values per attribute is given by a dictionary.
Its keys are the attribute names and its items are the list of filling values for each component.
-If the list of filling value is None, attributes are filled with the same constant value for each component;
+If the list of filling value is None, attributes are filled with the same constant value for each component:
0 for uint data, -1 for int data and nan for float data.
To use a handler of yours for the logger, set the variable 'speHandler' to True and add it to the filter
@@ -29,7 +29,7 @@
.. code-block:: python
- from geos.mesh.processing.FillPartialArrays import FillPartialArrays
+ from geos.processing.generic_processing_tools.FillPartialArrays import FillPartialArrays
# Filter inputs.
multiBlockDataSet: vtkMultiBlockDataSet
@@ -38,14 +38,18 @@
speHandler: bool
# Instantiate the filter.
- filter: FillPartialArrays = FillPartialArrays( multiBlockDataSet, dictAttributesValues, speHandler )
+ fillPartialArraysFilter: FillPartialArrays = FillPartialArrays(
+ multiBlockDataSet,
+ dictAttributesValues,
+ speHandler
+ )
# Set the handler of yours (only if speHandler is True).
yourHandler: logging.Handler
- filter.setLoggerHandler( yourHandler )
+ fillPartialArraysFilter.setLoggerHandler( yourHandler )
# Do calculations.
- filter.applyFilter()
+ fillPartialArraysFilter.applyFilter()
"""
loggerTitle: str = "Fill Partial Attribute"
@@ -61,14 +65,17 @@ def __init__(
) -> None:
"""Fill partial attributes with constant value per component.
- If the list of filling values for an attribute is None, it will filled with the default value for each component:
- 0 for uint data.
- -1 for int data.
- nan for float data.
+ If the list of filling values for an attribute is None,
+ it will be filled with the default value for each component:
+
+ - 0 for uint data.
+ - -1 for int data.
+ - nan for float data.
Args:
multiBlockDataSet (vtkMultiBlockDataSet): The mesh where to fill the attribute.
- dictAttributesValues (dict[str, Any]): The dictionary with the attribute to fill as keys and the list of filling values as items.
+ dictAttributesValues (dict[str, Any]): The dictionary with the attribute to fill as keys
+ and the list of filling values as values.
speHandler (bool, optional): True to use a specific handler, False to use the internal handler.
Defaults to False.
"""
@@ -86,7 +93,8 @@ def __init__(
def setLoggerHandler( self: Self, handler: logging.Handler ) -> None:
"""Set a specific handler for the filter logger.
- In this filter 4 log levels are use, .info, .error, .warning and .critical, be sure to have at least the same 4 levels.
+ In this filter 4 log levels are use, .info, .error, .warning and .critical,
+ be sure to have at least the same 4 levels.
Args:
handler (logging.Handler): The handler to add.
@@ -94,9 +102,8 @@ def setLoggerHandler( self: Self, handler: logging.Handler ) -> None:
if not self.logger.hasHandlers():
self.logger.addHandler( handler )
else:
- self.logger.warning(
- "The logger already has an handler, to use yours set the argument 'speHandler' to True during the filter initialization."
- )
+ self.logger.warning( "The logger already has an handler, to use yours set the argument 'speHandler' to True"
+ " during the filter initialization." )
def applyFilter( self: Self ) -> bool:
"""Create a constant attribute per region in the mesh.
@@ -117,9 +124,8 @@ def applyFilter( self: Self ) -> bool:
return False
if onBoth:
- self.logger.error(
- f"Their is two attribute named { attributeName }, one on points and the other on cells. The attribute must be unique."
- )
+ self.logger.error( f"There is two attribute named { attributeName },"
+ " one on points and the other on cells. The attribute must be unique." )
self.logger.error( f"The attribute { attributeName } has not been filled." )
self.logger.error( f"The filter { self.logger.name } failed." )
return False
diff --git a/geos-mesh/src/geos/mesh/processing/MergeBlockEnhanced.py b/geos-processing/src/geos/processing/generic_processing_tools/MergeBlockEnhanced.py
similarity index 85%
rename from geos-mesh/src/geos/mesh/processing/MergeBlockEnhanced.py
rename to geos-processing/src/geos/processing/generic_processing_tools/MergeBlockEnhanced.py
index 3d0b87b50..9bcfa5736 100644
--- a/geos-mesh/src/geos/mesh/processing/MergeBlockEnhanced.py
+++ b/geos-processing/src/geos/processing/generic_processing_tools/MergeBlockEnhanced.py
@@ -15,7 +15,8 @@
)
__doc__ = """
-Merge Blocks Keeping Partial Attributes is a filter that allows to merge blocks from a multiblock dataset while keeping partial attributes.
+Merge Blocks Keeping Partial Attributes is a filter that allows to merge blocks from a multiblock dataset
+while keeping partial attributes.
Input is a vtkMultiBlockDataSet and output is a vtkUnstructuredGrid.
@@ -31,7 +32,7 @@
.. code-block:: python
- from geos.mesh.processing.MergeBlockEnhanced import MergeBlockEnhanced
+ from geos.processing.generic_processing_tools.MergeBlockEnhanced import MergeBlockEnhanced
import logging
from geos.utils.Errors import VTKError
@@ -40,20 +41,20 @@
speHandler: bool # optional
# Instantiate the filter
- filter: MergeBlockEnhanced = MergeBlockEnhanced( multiblockdataset, speHandler )
+ mergeBlockEnhancedFilter: MergeBlockEnhanced = MergeBlockEnhanced( multiblockdataset, speHandler )
# Use your own handler (if speHandler is True)
yourHandler: logging.Handler
- filter.setLoggerHandler( yourHandler )
+ mergeBlockEnhancedFilter.setLoggerHandler( yourHandler )
# Do calculations
try:
- filter.applyFilter()
+ mergeBlockEnhancedFilter.applyFilter()
except VTKError:
logging.error("Something went wrong in VTK")
# Get the merged mesh
- filter.getOutput()
+ mergeBlockEnhancedFilter.getOutput()
"""
loggerTitle: str = "Merge Block Enhanced"
@@ -100,9 +101,8 @@ def setLoggerHandler( self: Self, handler: logging.Handler ) -> None:
if not self.logger.hasHandlers():
self.logger.addHandler( handler )
else:
- self.logger.warning(
- "The logger already has an handler, to use yours set the argument 'speHandler' to True during the filter initialization."
- )
+ self.logger.warning( "The logger already has an handler, to use yours set the argument 'speHandler' to True"
+ " during the filter initialization." )
def applyFilter( self: Self ) -> None:
"""Merge the blocks of a multiblock dataset mesh.
diff --git a/geos-mesh/src/geos/mesh/processing/SplitMesh.py b/geos-processing/src/geos/processing/generic_processing_tools/SplitMesh.py
similarity index 87%
rename from geos-mesh/src/geos/mesh/processing/SplitMesh.py
rename to geos-processing/src/geos/processing/generic_processing_tools/SplitMesh.py
index 0275774ea..f4a7a6bd7 100644
--- a/geos-mesh/src/geos/mesh/processing/SplitMesh.py
+++ b/geos-processing/src/geos/processing/generic_processing_tools/SplitMesh.py
@@ -30,7 +30,7 @@
from vtkmodules.util.numpy_support import ( numpy_to_vtk, vtk_to_numpy )
-from geos.mesh.stats.CellTypeCounterEnhanced import CellTypeCounterEnhanced
+from geos.processing.pre_processing.CellTypeCounterEnhanced import CellTypeCounterEnhanced
from geos.mesh.model.CellTypeCounts import CellTypeCounts
__doc__ = """
@@ -42,19 +42,22 @@
.. code-block:: python
- from geos.mesh.processing.SplitMesh import SplitMesh
+ from geos.processing.generic_processing_tools.SplitMesh import SplitMesh
- # filter inputs
- input :vtkUnstructuredGrid
+ # Filter inputs
+ input: vtkUnstructuredGrid
- # instanciate the filter
- filter :SplitMesh = SplitMesh()
- # set input data object
- filter.SetInputDataObject(input)
- # do calculations
- filter.Update()
- # get output object
- output :vtkUnstructuredGrid = filter.GetOutputDataObject(0)
+ # Instantiate the filter
+ splitMeshFilter: SplitMesh = SplitMesh()
+
+ # Set input data object
+ splitMeshFilter.SetInputDataObject( input )
+
+ # Do calculations
+ splitMeshFilter.Update()
+
+ # Get output object
+ output :vtkUnstructuredGrid = splitMeshFilter.GetOutputDataObject( 0 )
"""
@@ -130,20 +133,21 @@ def RequestData(
assert self.inData is not None, "Input mesh is undefined."
assert output is not None, "Output mesh is undefined."
- nb_cells: int = self.inData.GetNumberOfCells()
- counts: CellTypeCounts = self._get_cell_counts()
- nb_tet: int = counts.getTypeCount( VTK_TETRA )
- nb_pyr: int = counts.getTypeCount( VTK_PYRAMID )
- nb_hex: int = counts.getTypeCount( VTK_HEXAHEDRON )
- nb_triangles: int = counts.getTypeCount( VTK_TRIANGLE )
- nb_quad: int = counts.getTypeCount( VTK_QUAD )
- nb_polygon = counts.getTypeCount( VTK_POLYGON )
- nb_polyhedra = counts.getTypeCount( VTK_POLYHEDRON )
+ nbCells: int = self.inData.GetNumberOfCells()
+ counts: CellTypeCounts = self._getCellCounts()
+ nbTet: int = counts.getTypeCount( VTK_TETRA )
+ nbPyr: int = counts.getTypeCount( VTK_PYRAMID )
+ nbHex: int = counts.getTypeCount( VTK_HEXAHEDRON )
+ nbTriangles: int = counts.getTypeCount( VTK_TRIANGLE )
+ nbQuad: int = counts.getTypeCount( VTK_QUAD )
+ nbPolygon: int = counts.getTypeCount( VTK_POLYGON )
+ nbPolyhedra: int = counts.getTypeCount( VTK_POLYHEDRON )
assert counts.getTypeCount( VTK_WEDGE ) == 0, "Input mesh contains wedges that are not currently supported."
- assert nb_polyhedra * nb_polygon == 0, "Input mesh is composed of both polygons and polyhedra, but it must contains only one of the two."
+ assert nbPolyhedra * nbPolygon == 0, ( "Input mesh is composed of both polygons and polyhedra,"
+ " but it must contains only one of the two." )
nbNewPoints: int = 0
- nbNewPoints = nb_hex * 19 + nb_tet * 6 + nb_pyr * 9 if nb_polyhedra > 0 else nb_triangles * 3 + nb_quad * 5
- nbNewCells: int = nb_hex * 8 + nb_tet * 8 + nb_pyr * 10 * nb_triangles * 4 + nb_quad * 4
+ nbNewPoints = nbHex * 19 + nbTet * 6 + nbPyr * 9 if nbPolyhedra > 0 else nbTriangles * 3 + nbQuad * 5
+ nbNewCells: int = nbHex * 8 + nbTet * 8 + nbPyr * 10 * nbTriangles * 4 + nbQuad * 4
self.points = vtkPoints()
self.points.DeepCopy( self.inData.GetPoints() )
@@ -155,19 +159,19 @@ def RequestData(
self.originalId.SetName( "OriginalID" )
self.originalId.Allocate( nbNewCells )
self.cellTypes = []
- for c in range( nb_cells ):
+ for c in range( nbCells ):
cell: vtkCell = self.inData.GetCell( c )
cellType: int = cell.GetCellType()
if cellType == VTK_HEXAHEDRON:
- self._split_hexahedron( cell, c )
+ self._splitHexahedron( cell, c )
elif cellType == VTK_TETRA:
- self._split_tetrahedron( cell, c )
+ self._splitTetrahedron( cell, c )
elif cellType == VTK_PYRAMID:
- self._split_pyramid( cell, c )
+ self._splitPyramid( cell, c )
elif cellType == VTK_TRIANGLE:
- self._split_triangle( cell, c )
+ self._splitTriangle( cell, c )
elif cellType == VTK_QUAD:
- self._split_quad( cell, c )
+ self._splitQuad( cell, c )
else:
raise TypeError( f"Cell type {vtkCellTypes.GetClassNameFromTypeId(cellType)} is not supported." )
# add points and cells
@@ -181,16 +185,16 @@ def RequestData(
self._transferCellArrays( output )
return 1
- def _get_cell_counts( self: Self ) -> CellTypeCounts:
+ def _getCellCounts( self: Self ) -> CellTypeCounts:
"""Get the number of cells of each type.
Returns:
CellTypeCounts: cell type counts
"""
- filter: CellTypeCounterEnhanced = CellTypeCounterEnhanced()
- filter.SetInputDataObject( self.inData )
- filter.Update()
- return filter.GetCellTypeCountsObject()
+ cellTypeCounterEnhancedFilter: CellTypeCounterEnhanced = CellTypeCounterEnhanced()
+ cellTypeCounterEnhancedFilter.SetInputDataObject( self.inData )
+ cellTypeCounterEnhancedFilter.Update()
+ return cellTypeCounterEnhancedFilter.GetCellTypeCountsObject()
def _addMidPoint( self: Self, ptA: int, ptB: int ) -> int:
"""Add a point at the center of the edge defined by input point ids.
@@ -207,7 +211,7 @@ def _addMidPoint( self: Self, ptA: int, ptB: int ) -> int:
center: npt.NDArray[ np.float64 ] = ( ptACoor + ptBCoor ) / 2.
return self.points.InsertNextPoint( center[ 0 ], center[ 1 ], center[ 2 ] )
- def _split_tetrahedron( self: Self, cell: vtkCell, index: int ) -> None:
+ def _splitTetrahedron( self: Self, cell: vtkCell, index: int ) -> None:
r"""Split a tetrahedron.
Let's suppose an input tetrahedron composed of nodes (0, 1, 2, 3),
@@ -253,7 +257,7 @@ def _split_tetrahedron( self: Self, cell: vtkCell, index: int ) -> None:
self.originalId.InsertNextValue( index )
self.cellTypes.extend( [ VTK_TETRA ] * 8 )
- def _split_pyramid( self: Self, cell: vtkCell, index: int ) -> None:
+ def _splitPyramid( self: Self, cell: vtkCell, index: int ) -> None:
r"""Split a pyramid.
Let's suppose an input pyramid composed of nodes (0, 1, 2, 3, 4),
@@ -308,7 +312,7 @@ def _split_pyramid( self: Self, cell: vtkCell, index: int ) -> None:
self.originalId.InsertNextValue( index )
self.cellTypes.extend( [ VTK_PYRAMID ] * 8 )
- def _split_hexahedron( self: Self, cell: vtkCell, index: int ) -> None:
+ def _splitHexahedron( self: Self, cell: vtkCell, index: int ) -> None:
r"""Split a hexahedron.
Let's suppose an input hexahedron composed of nodes (0, 1, 2, 3, 4, 5, 6, 7),
@@ -370,7 +374,7 @@ def _split_hexahedron( self: Self, cell: vtkCell, index: int ) -> None:
self.originalId.InsertNextValue( index )
self.cellTypes.extend( [ VTK_HEXAHEDRON ] * 8 )
- def _split_triangle( self: Self, cell: vtkCell, index: int ) -> None:
+ def _splitTriangle( self: Self, cell: vtkCell, index: int ) -> None:
r"""Split a triangle.
Let's suppose an input triangle composed of nodes (0, 1, 2),
@@ -403,7 +407,7 @@ def _split_triangle( self: Self, cell: vtkCell, index: int ) -> None:
self.originalId.InsertNextValue( index )
self.cellTypes.extend( [ VTK_TRIANGLE ] * 4 )
- def _split_quad( self: Self, cell: vtkCell, index: int ) -> None:
+ def _splitQuad( self: Self, cell: vtkCell, index: int ) -> None:
r"""Split a quad.
Let's suppose an input quad composed of nodes (0, 1, 2, 3),
diff --git a/geos-mesh/src/geos/mesh/processing/__init__.py b/geos-processing/src/geos/processing/generic_processing_tools/__init__.py
similarity index 100%
rename from geos-mesh/src/geos/mesh/processing/__init__.py
rename to geos-processing/src/geos/processing/generic_processing_tools/__init__.py
diff --git a/geos-processing/src/geos/processing/post_processing/__init__.py b/geos-processing/src/geos/processing/post_processing/__init__.py
new file mode 100644
index 000000000..b7db25411
--- /dev/null
+++ b/geos-processing/src/geos/processing/post_processing/__init__.py
@@ -0,0 +1 @@
+# Empty
diff --git a/geos-mesh/src/geos/mesh/stats/CellTypeCounterEnhanced.py b/geos-processing/src/geos/processing/pre_processing/CellTypeCounterEnhanced.py
similarity index 85%
rename from geos-mesh/src/geos/mesh/stats/CellTypeCounterEnhanced.py
rename to geos-processing/src/geos/processing/pre_processing/CellTypeCounterEnhanced.py
index 8ed7500b3..c8f02e8b7 100644
--- a/geos-mesh/src/geos/mesh/stats/CellTypeCounterEnhanced.py
+++ b/geos-processing/src/geos/processing/pre_processing/CellTypeCounterEnhanced.py
@@ -11,7 +11,7 @@
from vtkmodules.vtkCommonDataModel import ( vtkUnstructuredGrid, vtkCell, vtkTable, vtkCellTypes, VTK_VERTEX )
from geos.mesh.model.CellTypeCounts import CellTypeCounts
-from geos.mesh.processing.meshQualityMetricHelpers import getAllCellTypes
+from geos.mesh.stats.meshQualityMetricHelpers import getAllCellTypes
__doc__ = """
CellTypeCounterEnhanced module is a vtk filter that computes cell type counts.
@@ -22,19 +22,22 @@
.. code-block:: python
- from geos.mesh.stats.CellTypeCounterEnhanced import CellTypeCounterEnhanced
+ from geos.processing.pre_processing.CellTypeCounterEnhanced import CellTypeCounterEnhanced
- # filter inputs
- input :vtkUnstructuredGrid
+ # Filter inputs
+ input: vtkUnstructuredGrid
- # instantiate the filter
- filter :CellTypeCounterEnhanced = CellTypeCounterEnhanced()
- # set input data object
- filter.SetInputDataObject(input)
- # do calculations
- filter.Update()
- # get counts
- counts :CellTypeCounts = filter.GetCellTypeCountsObject()
+ # Instantiate the filter
+ cellTypeCounterEnhancedFilter: CellTypeCounterEnhanced = CellTypeCounterEnhanced()
+
+ # Set input data object
+ cellTypeCounterEnhancedFilter.SetInputDataObject(input)
+
+ # Do calculations
+ cellTypeCounterEnhancedFilter.Update()
+
+ # Get counts
+ counts: CellTypeCounts = cellTypeCounterEnhancedFilter.GetCellTypeCountsObject()
"""
diff --git a/geos-mesh/src/geos/mesh/stats/MeshQualityEnhanced.py b/geos-processing/src/geos/processing/pre_processing/MeshQualityEnhanced.py
similarity index 95%
rename from geos-mesh/src/geos/mesh/stats/MeshQualityEnhanced.py
rename to geos-processing/src/geos/processing/pre_processing/MeshQualityEnhanced.py
index b1b7f5d0c..fc8c662b2 100644
--- a/geos-mesh/src/geos/mesh/stats/MeshQualityEnhanced.py
+++ b/geos-processing/src/geos/processing/pre_processing/MeshQualityEnhanced.py
@@ -25,11 +25,11 @@
VTK_POLYHEDRON )
from vtkmodules.util.numpy_support import vtk_to_numpy, numpy_to_vtk
-from geos.mesh.stats.CellTypeCounterEnhanced import CellTypeCounterEnhanced
+from geos.processing.pre_processing.CellTypeCounterEnhanced import CellTypeCounterEnhanced
from geos.mesh.model.CellTypeCounts import CellTypeCounts
from geos.mesh.model.QualityMetricSummary import QualityMetricSummary, StatTypes
from geos.mesh.utils.arrayHelpers import getAttributesFromDataSet
-from geos.mesh.processing.meshQualityMetricHelpers import (
+from geos.mesh.stats.meshQualityMetricHelpers import (
getQualityMeasureNameFromIndex,
getQualityMetricFromIndex,
VtkCellQualityMetricEnum,
@@ -57,28 +57,32 @@
.. code-block:: python
- from geos.mesh.stats.MeshQualityEnhanced import MeshQualityEnhanced
+ from geos.processing.pre_processing.MeshQualityEnhanced import MeshQualityEnhanced
# Filter inputs
- input :vtkUnstructuredGrid
+ input: vtkUnstructuredGrid
+
+ # Instantiate the filter
+ meshQualityEnhancedFilter: MeshQualityEnhanced = MeshQualityEnhanced()
- # Instanciate the filter
- filter :MeshQualityEnhanced = MeshQualityEnhanced()
# Set input data object
- filter.SetInputDataObject(input)
+ meshQualityEnhancedFilter.SetInputDataObject(input)
+
# Set metrics to use
- filter.SetTriangleMetrics(triangleQualityMetrics)
- filter.SetQuadMetrics(quadQualityMetrics)
- filter.SetTetraMetrics(tetraQualityMetrics)
- filter.SetPyramidMetrics(pyramidQualityMetrics)
- filter.SetWedgeMetrics(wedgeQualityMetrics)
- filter.SetHexaMetrics(hexaQualityMetrics)
- filter.SetOtherMeshQualityMetrics(otherQualityMetrics)
+ meshQualityEnhancedFilter.SetTriangleMetrics(triangleQualityMetrics)
+ meshQualityEnhancedFilter.SetQuadMetrics(quadQualityMetrics)
+ meshQualityEnhancedFilter.SetTetraMetrics(tetraQualityMetrics)
+ meshQualityEnhancedFilter.SetPyramidMetrics(pyramidQualityMetrics)
+ meshQualityEnhancedFilter.SetWedgeMetrics(wedgeQualityMetrics)
+ meshQualityEnhancedFilter.SetHexaMetrics(hexaQualityMetrics)
+ meshQualityEnhancedFilter.SetOtherMeshQualityMetrics(otherQualityMetrics)
+
# Do calculations
- filter.Update()
+ meshQualityEnhancedFilter.Update()
+
# Get output mesh quality report
- outputMesh: vtkUnstructuredGrid = filter.GetOutputDataObject(0)
- outputStats: QualityMetricSummary = filter.GetQualityMetricSummary()
+ outputMesh: vtkUnstructuredGrid = meshQualityEnhancedFilter.GetOutputDataObject(0)
+ outputStats: QualityMetricSummary = meshQualityEnhancedFilter.GetQualityMetricSummary()
"""
#: name of output quality array from vtkMeshQuality filter
@@ -329,10 +333,10 @@ def RequestData(
def _computeCellTypeCounts( self: Self ) -> None:
"""Compute cell type counts."""
- filter: CellTypeCounterEnhanced = CellTypeCounterEnhanced()
- filter.SetInputDataObject( self._outputMesh )
- filter.Update()
- counts: CellTypeCounts = filter.GetCellTypeCountsObject()
+ cellTypeCounterEnhancedFilter: CellTypeCounterEnhanced = CellTypeCounterEnhanced()
+ cellTypeCounterEnhancedFilter.SetInputDataObject( self._outputMesh )
+ cellTypeCounterEnhancedFilter.Update()
+ counts: CellTypeCounts = cellTypeCounterEnhancedFilter.GetCellTypeCountsObject()
assert counts is not None, "CellTypeCounts is undefined"
self._qualityMetricSummary.setCellTypeCounts( counts )
@@ -391,7 +395,8 @@ def _evaluateCellQuality( self: Self, metricIndex: int ) -> None:
assert output is not None, "Output mesh from mesh quality calculation is undefined."
# Transfer output cell array to input mesh
- # TODO: to test if Shallow copy of vtkMeshQualityFilter result and rename "Quality" array is more efficient than what is done here
+ # TODO: to test if Shallow copy of vtkMeshQualityFilter result
+ # and rename "Quality" array is more efficient than what is done here
self._transferCellAttribute( output, QUALITY_ARRAY_NAME, arrayName, metric )
def _applyMeshQualityFilter( self: Self, metric: int, cellTypes: list[ int ] ) -> vtkUnstructuredGrid:
diff --git a/geos-processing/src/geos/processing/pre_processing/__init__.py b/geos-processing/src/geos/processing/pre_processing/__init__.py
new file mode 100644
index 000000000..b7db25411
--- /dev/null
+++ b/geos-processing/src/geos/processing/pre_processing/__init__.py
@@ -0,0 +1 @@
+# Empty
diff --git a/geos-processing/tests/conftest.py b/geos-processing/tests/conftest.py
index 097713cf4..8a1767df6 100644
--- a/geos-processing/tests/conftest.py
+++ b/geos-processing/tests/conftest.py
@@ -29,7 +29,22 @@ def _get_dataset( datasetType: str ) -> Union[ vtkMultiBlockDataSet, vtkPolyData
(vtkMultiBlockDataSet, vtkPolyData, vtkDataSet): The vtk object.
"""
reader: vtkXMLGenericDataObjectReader = vtkXMLGenericDataObjectReader()
- if datasetType == "meshGeosExtractBlockTmp":
+ if datasetType == "multiblock":
+ vtkFilename = "data/displacedFault.vtm"
+ elif datasetType == "emptymultiblock":
+ vtkFilename = "data/displacedFaultempty.vtm"
+ elif datasetType == "multiblockGeosOutput":
+ # adapted from example GEOS/inputFiles/compositionalMultiphaseWell/simpleCo2InjTutorial_smoke.xml
+ vtkFilename = "data/simpleReservoirViz_small_000478.vtm"
+ elif datasetType == "fracture":
+ vtkFilename = "data/fracture_res5_id.vtu"
+ elif datasetType == "emptyFracture":
+ vtkFilename = "data/fracture_res5_id_empty.vtu"
+ elif datasetType == "dataset":
+ vtkFilename = "data/domain_res5_id.vtu"
+ elif datasetType == "emptydataset":
+ vtkFilename = "data/domain_res5_id_empty.vtu"
+ elif datasetType == "meshGeosExtractBlockTmp":
vtkFilename = "data/meshGeosExtractBlockTmp.vtm"
datapath: str = os.path.join( os.path.dirname( os.path.realpath( __file__ ) ), vtkFilename )
diff --git a/geos-processing/tests/data/displacedFault.vtm b/geos-processing/tests/data/displacedFault.vtm
new file mode 100644
index 000000000..cb28f0e8d
--- /dev/null
+++ b/geos-processing/tests/data/displacedFault.vtm
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/geos-processing/tests/data/displacedFaultempty.vtm b/geos-processing/tests/data/displacedFaultempty.vtm
new file mode 100644
index 000000000..bea56fc6b
--- /dev/null
+++ b/geos-processing/tests/data/displacedFaultempty.vtm
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/geos-processing/tests/data/hexa_cell.csv b/geos-processing/tests/data/hexa_cell.csv
new file mode 100644
index 000000000..741fa4f78
--- /dev/null
+++ b/geos-processing/tests/data/hexa_cell.csv
@@ -0,0 +1,8 @@
+0.0, 0.0, 0.0
+1.0, 0.0, 0.0
+1.0, 1.0, 0.0
+0.0, 1.0, 0.0
+0.0, 0.0, 1.0
+1.0, 0.0, 1.0
+1.0, 1.0, 1.0
+0.0, 1.0, 1.0
\ No newline at end of file
diff --git a/geos-processing/tests/data/hexa_mesh.csv b/geos-processing/tests/data/hexa_mesh.csv
new file mode 100644
index 000000000..cc55f5626
--- /dev/null
+++ b/geos-processing/tests/data/hexa_mesh.csv
@@ -0,0 +1,64 @@
+0.0,0.0,0.5
+0.5,0.0,0.5
+0.5,0.5,0.5
+0.0,0.5,0.5
+0.0,0.0,1.0
+0.5,0.0,1.0
+0.5,0.5,1.0
+0.0,0.5,1.0
+0.5,0.0,0.5
+1.0,0.0,0.5
+1.0,0.5,0.5
+0.5,0.5,0.5
+0.5,0.0,1.0
+1.0,0.0,1.0
+1.0,0.5,1.0
+0.5,0.5,1.0
+0.0,0.0,0.0
+0.5,0.0,0.0
+0.5,0.5,0.0
+0.0,0.5,0.0
+0.0,0.0,0.5
+0.5,0.0,0.5
+0.5,0.5,0.5
+0.0,0.5,0.5
+0.5,0.0,0.0
+1.0,0.0,0.0
+1.0,0.5,0.0
+0.5,0.5,0.0
+0.5,0.0,0.5
+1.0,0.0,0.5
+1.0,0.5,0.5
+0.5,0.5,0.5
+0.0,0.5,0.5
+0.5,0.5,0.5
+0.5,1.0,0.5
+0.0,1.0,0.5
+0.0,0.5,1.0
+0.5,0.5,1.0
+0.5,1.0,1.0
+0.0,1.0,1.0
+0.5,0.5,0.5
+1.0,0.5,0.5
+1.0,1.0,0.5
+0.5,1.0,0.5
+0.5,0.5,1.0
+1.0,0.5,1.0
+1.0,1.0,1.0
+0.5,1.0,1.0
+0.0,0.5,0.0
+0.5,0.5,0.0
+0.5,1.0,0.0
+0.0,1.0,0.0
+0.0,0.5,0.5
+0.5,0.5,0.5
+0.5,1.0,0.5
+0.0,1.0,0.5
+0.5,0.5,0.0
+1.0,0.5,0.0
+1.0,1.0,0.0
+0.5,1.0,0.0
+0.5,0.5,0.5
+1.0,0.5,0.5
+1.0,1.0,0.5
+0.5,1.0,0.5
diff --git a/geos-processing/tests/data/pyramid_cell.csv b/geos-processing/tests/data/pyramid_cell.csv
new file mode 100644
index 000000000..864deaf4f
--- /dev/null
+++ b/geos-processing/tests/data/pyramid_cell.csv
@@ -0,0 +1,5 @@
+0.0, 0.0, 0.0
+1.0, 0.0, 0.0
+1.0, 1.0, 0.0
+0.0, 1.0, 0.0
+0.5, 0.5, 1.0
\ No newline at end of file
diff --git a/geos-processing/tests/data/pyramid_mesh.csv b/geos-processing/tests/data/pyramid_mesh.csv
new file mode 100644
index 000000000..c435d2e49
--- /dev/null
+++ b/geos-processing/tests/data/pyramid_mesh.csv
@@ -0,0 +1,46 @@
+0.5,0.0,0.0
+1.0,0.0,0.0
+1.0,0.5,0.0
+0.5,0.5,0.0
+0.8,0.2,0.5
+0.5,0.5,0.0
+1.0,0.5,0.0
+1.0,1.0,0.0
+0.5,1.0,0.0
+0.8,0.8,0.5
+0.0,1.0,0.0
+0.0,0.5,0.0
+0.5,0.5,0.0
+0.5,1.0,0.0
+0.2,0.8,0.5
+0.0,0.5,0.0
+0.0,0.0,0.0
+0.5,0.0,0.0
+0.5,0.5,0.0
+0.2,0.2,0.5
+0.2,0.8,0.5
+0.2,0.2,0.5
+0.8,0.2,0.5
+0.8,0.8,0.5
+0.5,0.5,1.0
+0.8,0.8,0.5
+0.8,0.2,0.5
+0.2,0.2,0.5
+0.2,0.8,0.5
+0.5,0.5,0.0
+0.2,0.2,0.5
+0.8,0.2,0.5
+0.5,0.0,0.0
+0.5,0.5,0.0
+0.8,0.2,0.5
+0.8,0.8,0.5
+1.0,0.5,0.0
+0.5,0.5,0.0
+0.8,0.8,0.5
+0.2,0.8,0.5
+0.5,1.0,0.0
+0.5,0.5,0.0
+0.2,0.8,0.5
+0.2,0.2,0.5
+0.0,0.5,0.0
+0.5,0.5,0.0
diff --git a/geos-processing/tests/data/quad_cell.csv b/geos-processing/tests/data/quad_cell.csv
new file mode 100644
index 000000000..ffca9522e
--- /dev/null
+++ b/geos-processing/tests/data/quad_cell.csv
@@ -0,0 +1,4 @@
+0.0, 0.0, 0.0
+1.0, 0.0, 0.0
+1.0, 1.0, 0.0
+0.0, 1.0, 0.0
\ No newline at end of file
diff --git a/geos-processing/tests/data/simpleReservoirViz_small_000478.vtm b/geos-processing/tests/data/simpleReservoirViz_small_000478.vtm
new file mode 100755
index 000000000..834339547
--- /dev/null
+++ b/geos-processing/tests/data/simpleReservoirViz_small_000478.vtm
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/geos-processing/tests/data/simpleReservoirViz_small_000478/cartesianMesh/Level0/reservoir/rank_0.vtu b/geos-processing/tests/data/simpleReservoirViz_small_000478/cartesianMesh/Level0/reservoir/rank_0.vtu
new file mode 100755
index 000000000..3d0663682
--- /dev/null
+++ b/geos-processing/tests/data/simpleReservoirViz_small_000478/cartesianMesh/Level0/reservoir/rank_0.vtu
@@ -0,0 +1,255 @@
+
+
+
+
+
+ AQAAAACAAAAIAAAAEAAAAA==eJxjYGBg4M5e7QgAAwwBYw==
+
+
+
+
+
+ AQAAAACAAADACQAAGgIAAA==eJw11ulrCAAAxmH3tc055zD3NcPY2FCYoVxDuSnMUNgc5aYwVznmKNdQrqGwOQpzlZvCDIW5yk25hsLGB4/3y/MfvP0KFfq3wizCoizG4gxgIINYluVYnlVYldVYnTUYwrqsx/pswIZsxOYMZwu2ZCtGsB2jGcP27MCOjGVXxrEbu7MH+7Av49mP/TmAQziUwzicIziSCRzLRI7jeE5gEpM5hVM5jdM5m3M4l/M4nwuYwiVcymVczhVcw1Su5Tqu5wZu4VamcRu3cwf3cC/TuY/7eYAZzOQRHuUxHmcWT/MMz/Icz/Myr/Aqr/E6bzCbd5jDu7zH+8zlYz7hUz7jc77mG77lO77nB37hV+bxG7/zB/NZwD/8fzCFWYSlWJplGMBABrESg1mZVViV1ViboazDuqzH+mzKZgxjc4azBSMZxbZsx2jGsBM7swtj2ZVx7Mle7M0+7Mt4DuQgDuYQDuUwjuJojmECxzKREzmJk5nEZE7hDM7kLM7mHM7lQi7iYqZwCZdyJVdxNdcwlWu5kZu4mVu4lWncyV3czT3cy3Qe5CEeZgYzeYQneJKnmMXTPMMLvMhLvMwrvMqbvMXbzOYd5vABH/IRc/mYT/iCL/mKr/mGb/mRn/iZX/iVefzJX/zNfBbwD4sLmBIsyVIszTIszwqsyEoMZmWGsCZrsTZDWYeN2JhN2JTNGMYItmYbRjKKbfkXbteQsg==
+
+
+ AQAAAACAAADgBAAAHAAAAA==eJz79////39IGAb+jYqPio+Kj4oPcXEAQinajQ==
+
+
+
+
+ AQAAAACAAADQBwAAywAAAA==eJxjYEAGH+wZhhn/Xu1ei5KZBvZ5LU+uBf19R7F5BjnagT627vZrqsK31ARSbh5XcEGx4TZve4tf7sfLtSg3r/nQlykJ0TH2UlccuCakvKXYvMetO68FK2XYy7EVLL057w3F5olciw9K7m+yP/bFq7fN6BXF5jlwnU2wdGizv9fjvMJm7UuKzdNdsKD9ilSWvbnMhhWWtZT71yBkJzfniyJ7l+W/764/85pi86ZP0PfZtcnJ/seFJ+E+tZSnl1H+KH+UP3z4AGGm1Fg=
+
+
+ 0.8024706398
+
+
+ 1
+
+
+
+
+ AQAAAACAAADoAwAAFgAAAA==eJybNRMEVtrPGqVH6VF62NIAkycyIg==
+
+
+ AQAAAACAAADoAwAAHAMAAA==eJwd0H1MzHEcB/CLu7pUKiGnUo2wHmTuTtL4ViuppWLSg5um9EiergedbpdzYkaOkrTULN38vh3STLmeyOos2sjDUUyXdWyeItzpwfl8+uu192d7f/bZ54a75cONTpRc4PfXErCq4Kg6BHxpig8JA+kOg3Ez+MmRaIcdKRGkRV7Wg78kTYoP4MuSxakGsCbHL+UzGL/kW6fcgRJh85D4OFhjJeafwGyU3DgJNl8c8zgDrrYWqJfZU3LgW6CLF/ir/1jNcnBA1cFbCYo6Zq/xAa0qT2p67SiJTXIZQcMMC6gW9AhlPXkEuvo0DvSB+ZtuZWTZQt9TNYwePtfai35U24qzwfyl9YE5mK/KRqxtKLnWL4ubAw6oh7aio1xZGWqKUCWiVWp7W7U1JazSdlMjWOHqHIW56X7cNjRac9ob51ElgzkxXErqJtnp6BRvz0H0bF/mjMZRzl70e0D1zTFL2JtQfhcNDlbmouv1VcdQre+24R8gO7l0STmHEtm5SBtUN5cyF0CR1CYLtUv/mYQ+bctoErLhb947JGieMtogABdN8LxR6tDczgcPXwpa+HoW/GtUZdCBI/WVfPSrQuf2Cizu+LDzBZhcWtsgsYB7n2/PRlvcwwaLwFBdUeMRsFvUtqsA7LvjI3Zjwf2KQ57oHNN2iSvYwQsNcQHf94T48ED/loiM+/8Y8oX7zBnd8nhxYheY+fG6XSfoZeBkt4Ep0g3StGmGrPDcxEdLriXnpYJ589T+u8HUrw10F+i7zKPVcoohCivBPrRa7dTDATcUFZ9ngyyPBGoB6gaTWHSCIfLg2w8YkG1QxqLvy9ZKroNC86lcFfh7a23Klr8MiRNaCFB5Pm8sGjwrms5CzV6FzmjXpGZ4zMiQUwvnd6F+z1jVaPgBZQz6IpYmoP456cUVfxgy5Ti+H41wWxmDBpQXztgd/7cB1SgSV637Db0/b4To/DdrXNHod/JGdAXPV48mmqzGh8YZcqUp3IwaRS2r34KZ4bncd6Bv9dt+tFij7JX9ZIhUrx1Cb5XZBJSAoqBFZnSP5l6dHPwPxgTVXw==
+
+
+ AQAAAACAAADoAwAAGQAAAA==eJzr3ZnN+XPBSvveUXqUHqWHLQ0AVJ0Q7g==
+
+
+ AQAAAACAAADoAwAAdQMAAA==eJwV0XtME1YUBnCmGLQbVm2lPogaFKfW10TU+phHUdJSrVjcnG4Cm4ug3RQfRRaUSUsUVE4do6K1lhUfFBFYW1eYIlt5CRErispooUZQUECjDTLFuXruX7/c5Obc736nq/9xfIsdIdX91UEn6eG3DrjJsadCsoZUIgwfPPCvk5zjx383/2+EHO6KPQvJYfy8ygSSK8+LFlcjVPQkhR1pQuidWmw/UYHACfc3mch0ddyJ5zRPfbiwit+L8OymV1jXjPD9m+xFveUI+bo1aX3kpAfHDXK6H1qw7O1vbQjrOxX3zDcRMq2HueJrCJ+pnv4XQZZWqYT95HBPhr3hDsLZsK2h6lp6v1509NyfCP4q0ZiLJHfpT6LgqwjaH774ZibNCZYVjFWUIaxdYu74vxThV7OtwofOn6gfTdOQc+T2KH/6R7q0rra9ACGyemDe1zaELqH9dgw5KDz2cxdZW2Grz/4LoT9w80h9KkKN9nR56RWEiVrFljJSFh+iaiZv+bhkXZRjgmIB7lUiCIwREr6V8j40e5gxx7K6I0lL+aKTe6oQLqd2TcezCC1qQ9BuM4KtiFPEbBo6xJRFpq1Wmrspt/S69OQKDUL17B6RowShvT7Rlxk5ps11l5yrCH891YKwwzvbsOkPBOvi/SHCYoSfBRwO89NHhRtCyQOeHPuI36nHx5YS/SgNJKaIlemXEXYe+3EWM+7giEzmm2jl05AiBJ7FqH77CmG6ulPQeQnBXRNge0Je3S+JZZZlZKxsLUT40jfql41074bt/Psw6lEXcS+XGcRbO4rZ3KrJNJIDq5K3yJ4gHL/WOCUvH+F1saTBSO7K6RMwP5q1/OV9cm6dYTPeRuiQjcv0uYggzF4wj7lsmCTJewEh1hl0azKd9Xzr0CgHwsduzfiY85TrhaYxmpSWrpEwHS2CfdtIXmfjuL3Uj66823U9j/Z5tDKfKUo4FMdUpNx44SUlM43SlbSf94kOZ6ARYUaW1sJ0avzOMOvcW2s3kkbV82Y/mmfn1nAP5FIOa4k3mZzku7SbOTFB68glt+tehbVQn+sCU5Qu2jMGJKUw/9kX+h2zx9O3u50skccr+dS3JM7kt0SPMDpdGsBcxwuQM7/laHyADBblD9LT+9ssHXadDsGUBi7m6OVt4jOkWNGwwUDy7p9aP4XmfgAKwPAn
+
+
+ AQAAAACAAADQBwAAnAYAAA==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
+
+
+ 1248.3689347
+
+
+ 1299.9936807
+
+
+
+
+ AQAAAACAAADQBwAA5AAAAA==eJxjYEAGH+wZhhk/ZU9t7CP5VfaWKhq3GOPeUWyegOLMOgWptfbvc8V+xOpRbt6PnkWc5TvX2hteT+3PUKHcvLqmlt7QmRvsN+T7+1198xYu/x8M3pNsnvGuPf9rojbZ78rgSNiw5S3F7vvJPG8Pu+IO+0b7HI77v9+QbR7cP0a+X1dG77Q/EBl2sOsK+ebB+BLJz81NWzbZzxVmjqxcT7l/w5f7vZglusVeRPvbIp9a8s2D+TepRWBy867V9ru+nzsW7kJ5eqHUPeTKj/JJ41M7PAdb/FDqnsHmn4HiAwCsqwtG
+
+
+ 0.90637403877
+
+
+ 1
+
+
+
+
+ AQAAAACAAADQBwAAKAAAAA==eJxjYIAAYzC4bM8wzPizZoLASvtR80bNGzVvlD/KH+UPZz4AATZIOg==
+
+
+ 0.3
+
+
+ 0.30413812651
+
+
+
+
+ AQAAAACAAAC4CwAA6gcAAA==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
+
+
+ 7.6366451309e-15
+
+
+ 1.3110134231e-13
+
+
+
+
+ AQAAAACAAADQBwAAFwAAAA==eJxjYBgFo2AUjIJRMApGwVAHAAfQAAE=
+
+
+ 0
+
+
+ 0
+
+
+
+
+ AQAAAACAAADQBwAAZAMAAA==eJxV0H1QC3AcBvBCTkgqoabWkM2kVMtONR13bTWLtCuldEixMNS83DhdTeUSRqStEqXW20XLKSrkSN4mXc1rJWSMEmt1rqv81+/x5+ee793z3Pf6Ru7zqM45fg32+qb+VE+/8km8RjFYWM1UKcC/TAcVL8Epl9h2Hl3EcTqFqvY+8SC3tbcFzOQ4c36DDytzEpY3EcfPzg/MBps/TbupLyK+arL9yl9wa79rhuM1Yrv9Xu0h4BAT2osb4O7w/CXGNOJwp4ioMXBLUViIYzoxX7X9DwecYHGwIgks4Lm0vRURi4xqaifYpc28tQ+sKWoxnRpPPHfTRb472JObYpEpID7f1MfLBh/ZF0i5AK43Dp0pBCe/2bGyBqxelexm6Ua8Z07P4flgvZ/vRXRzAbvGAaxoN9DtwANRlr0SK+LHJQfWJIJNGQa6FBzZmPkOnS1nPtwGdhlP9Kg22Ew4tPm3+gZYMyStwHxx7rP/HHuUsRIdcPb+rYYO4uNrXeMawT9KG6i14Nmm6W/qwBtk60e14KwsykBuLXFy2gmuEuw/TaM9B5apKMsyweV1bEMGWON8d7NAQczw4JfwwH8/bHjoDfbRFccwwd7jQV1OYNH8tHXNUuJdqTrqA/D3YzZiNVg+c9xWCVZXDBUngG3P3qRZRsEeodkrc3Cc0oo1Gkl8+jUj5RN4nXWosgrsXB+7m84h3i8fZjiBM4INwVZgGfV1stGXmNI7bN0M/lLCapnhSMwL930wBcyyYSsMDsSl/svMtOCOSI5EAS5b/1V8e8x6wv3TBY/UYEmc9vxVsFdhv/AEmPLE3ZsPrutckefWTfxzekQtA7w3XpxhB95aH5032kWczSij3QFnnc5ZFH+PWBaQKNoBXs2bPBIBjj3wWMoF+yV1ps4FH3fLz99ZQKxRHsqJAVvTKWFbwFvlfT3BYG9PVnQg+FmuSxs9iZjp7169GOx59M5qGlhksdDHHsyqarKhgAtkkqWqaPi3gKorBj/Rm3cUgnXXpR/Q0UKnWRVgeXFlwWcO9Gl9Qr+AAwNqvvWA9UExib/A7R3i1EG8Zw08f7eA+MflNcPvwZIX7MqP4D8impcRnO5QZjLNgZhd7zVycsRqwrf4rmanwPNsLz3NAgvzpFNU4KCqsVkvwf8Ag5LBKw==
+
+
+ 0.00030569608784
+
+
+ 0.00030835264416
+
+
+
+
+ AQAAAACAAADQBwAAnAYAAA==eJwd03s81FkfB3AVqakopiHRa9ZjbS27iWhmE9+tVjNGbrXl8URK0aObyq1tjF1sZkbOL7NIclndKPcZDcuYcl9FVGJdtxRaysbailjP9/f8+X59z+uc7/mez9FwiD2ZyJHC8LuXR7qqCVy0pDrS0dH9XpHd6BRZvHE5epzZO92P5t/sP9yNXpVqI9OqIfDxie2cIVcKyxZMv+9G6z8o5wjMpWClzfy48R6BnjDDb/agL+l+fXoTml3w9Zpg9GLm1ZpgtPMxN3kKWtfzqi+vjkDYpO3vXWj1aMS2uCcEjOc35jbqS+G1eWH1RTUBK2UE7xGa4bQsNxdtudrd4A+0JCbw4hvsr8louI3BxP7P59UyXxNo8Rg+tgNdumQLZ5U5BR9vPPfQmieFQx+SOK9VBK672rktQeekucRO0i4UGLLR7I4LmZ64/89Jwlsb0RtvbZn6uY9AlsWPgfvRdv/U61mbURDSGeOmNSaBBMV5XV4lAdWQ5nfa6A3Rr2ac0Xsceo/qoctqoy3eofdZNfJN0ToTkurmRwR+2ZGf74C+v26cLzClgCUMr6rqloC6iSu99gsB6QoXUR1aJ5preBP92K5epxata3+W+2kFnucZfbkZnXzs232WDwhs+xie2onmSR/X+bMp4HgEaVo1SkCwueTFP2UEbJ71Wduhk0qUao1yAn47g5xoL415vpZCb2xSF3LR6z2rdy3D93h52SSXrj+6p/NIuIaC9ra+VwEKCbjXTVv/R0lgQWp062H0sEV16360qvv9ySD0fCc/hx70upTyYdoNamVT0l0CZ+NDVnqjfwPHgBRjCjrsPe55ZWE9+bKqrJTAsxD9INprko/6lKN96i31/o12PWIT3YkWuPv/3/c1elyHcR7Ce49r6PUiWP2H3IiCN9SBhRrxEmBlO/OZCgJtXKaIdsbvJRO0OeenbGekEvCNl424o39tqTw4i5arOCmnawk4ihZOrsD13YNe21sNKVgZks/zDUPHZJqeKiGgncIx80ErCxgFtL3ufOK1F/1kkVauDB3bknh6Fzrmm9CSEZx3RLhjuif6WsXgwmEWBSYpJ3cEH5BA3Zej3IdFBDxW7NE8jh5oCtOkvdm7dOUhtIdhX89jdLvwboUXev1Rp7/N5QTsX7WzPdG7bxxOnmNSkJE63b7eRQKKr8JtLAoJ3N+kPWKJjjJgMGgPOc+OfYL+7Hneblv0kqa6oeVo4cSl6uXFBIqLP3f7W4D5eikvStejIEJ4SpVpJ4EwES9UnE+gIi9iNg19Iv74F7RtTJpXydABkcsTaFvKzvCj0B98Q1/ZFBBIMEgs9UYvl2fHTI0TcIIjFiq2BNbFDBkM3SZg1xA1rwzdX89SDqLP3hSfzkdXhvP9aO+NKLqdii6XSLb25hHI6Ap6E4b+VnNX4l7cr35TqSyWIYFG5fXZbbcIjA61xkWh05zbs2g/sLlrewZtqr9Tj7ZgxeYpH3RnL5WQjb52nR1pjZ7efs7HdRDzbxIS99dfYrhQ2WZ2NYdAzr4rd8bQk4X85my0VPPp9gH0iUuTBrT749XGLeh5Xzi+fYpm+L5jXkNb/ZrpTVoJBFeF3NbuE8OAq1GCxk28vzIuez7aMsnOmnZsw5YL73vFYL+YHzF3g8DxsZ3mL9B+3aYt/8L6S8VMXwk6g6lYtOshgZJhk/HKejEw+qnV+6+jk3QqytAVY1SbL3qSl7u0GO1c5sKn7fDsjDwb3dJlEBKAdmvpCBCh9YfajM5gfiZO2FksKxRDqmqkp+oqgbV5+75koBulNTm0v18dE6eF5gZ/H0j7B7aR00yBGI6JGsfm0DqKoOJ3aGfLbMFW/D+fPuP+OZUshtmwh93G2QREuUtT3qMtZMly2gv8y+Ym0T2U9hXaL/wXqf5EN/b7N+xFf5aa6fsWnRX9plMb+/vcd6hdGCmGat16XWEWgVr9xc/PodMVRXPn0CO17uQsmq1pP0J7rGP8J9omwckPs9B3rMcbotD/TRvf1oX5VKapFbJDYnA1FoX2ZBDQPR7l8BOasCJEtGv8th9KRP8WYnuQNkuRUXUFPTIxeWoAXbc+KyMLXeR5JJSJ+VaPjuZtEoiBF5irvTmdwAFuQyIHzRILWLQFazdY26Pd9FmetD80ZWq6oP0YlAag35oMRHmjzbg589Px/lKTU+rDG8QQIH9RnZZGYKvBg92B6JxY6KHtN9O+9gR6pWMf7wr64B0ROxLNO9q8OxMtGQxzSUfrP031MMN+/wd4Hbvg
+
+
+ 1248.3689347
+
+
+ 1299.9936807
+
+
+
+
+ AQAAAACAAACgDwAASgcAAA==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
+
+
+ 1.3723365338
+
+
+ 1.4142135624
+
+
+
+
+ AQAAAACAAADoAwAA9wAAAA==eJwtyVtEAAAAA8AeSimllFJKKaWUUkoppZRSSimllFJKKaUUEREREREREREREREREREREREREREREVEf3X7OtoCA/wQznLFMZSgjGc905jOaicxkISuZzGwWs5rNzGUpa9nKXpaznu3s5zgb2clBTnKB3RzmNBe5ylHOcolr3OI8l7nObe5zhRvc4QFPuMldHvKUl9zjEc94xTse85zXvOczL3jDB77wg7d85Cs/+csnvvGLQYH/RvHd/s0QewxT+OMP0+OYxjxGMIEZLGAFk5jFIlaxiTksYQ1b2MMy1rGNfRxhAzs4wDFOsYtDnOAM5/gHDuoz+g==
+
+
+ AQAAAACAAADQBwAAYwcAAA==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
+
+
+ 20452165.799
+
+
+ 24060023.025
+
+
+
+
+ AQAAAACAAADQBwAAAAIAAA==eJyVlV0oQ2Ecxo/vr81HkXJFuaIwhCXeC+0OuVHmoyZXjFq4oEYRS7NcuEGhsMINRr5qKRQiX7ULkshaUhu7WNQ456idZb1Pnc05F6d+/d//c57/+7znHIYRrjDf3U38yIQDVwFHRdDcJqMZ9YqBE6NoHgU99SHL8/zHH8dAPwmnWQf1q0uh37Fedz7kWCNa3ah9OeVddL5r4HE5zV33nE9vz6grqyi3EKOlVD195xKdtwhYH0PzYwvv09PfNc5OL1mI7eHQaboI6DHQj343Yb+a4gVeUM1WM/tbZDX54fNpTFwP/e6G0fwWJ3BJR1aB27ZNBhwmb6sqoNd/7aXySUj/prgd9BX+vN8VZnmS2UqOe/IyB7VOUT9xwDbg/EiBc1LHCZd9QGru2TJNeUCP53nKD87fCyw7EvJ9PjCs6BU7xNKg0d4oXaJ6HLAC9DT+8zOSI693ZeyRk6O++sUf57/zVQEPxgq8/pJ7rDnZILcGq73o1SXqB/UfoT7M0tzV/Ra0H+dPhHozvI8TVxy1PlQemL8H/LXWeiX5w7oa+MztCZon6iGbgY1mTtJ8WG8EveiSL4rZEPOhvyGoz0TS/CNRbwW4kg2+P6HmVwLL5qTpYb0dvodp8D8K5Qe5EL6H1k6PJH/I8+Cv93aK6sfn43nE+iTk2XFq9K3/BYYK2L8=
+
+
+ 0.89007140992
+
+
+ 1
+
+
+
+
+ AQAAAACAAADQBwAAbAcAAA==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
+
+
+ 838.01741281
+
+
+ 984.23156391
+
+
+
+
+ AQAAAACAAADQBwAA6AMAAA==eJxN03tMk1cYBnAcptBwaYqTXqxCWxA+ubi1pTAs+jUotA7HTDYKGYVEh4M62iqEkrKaYVbMZG7ZtIyOWxUkzFZxDEszA2a0oKtEWIE5RgYtOqtQpyihXOeabOG833+/nCdPzvudc/z8/vtS8lRuD08s/J9+zaYA+1Pg+Mu0ynng2qHvqOQk5FNLo6u3gMkF7bkXuMi5hzzSOuA9K9U5A8BrBuOJOT4y1168WZaO7B61L+zhIOdQibXZwAd1M8fXwf4mT91I/VwiFj7+0KtULrXhmr8To3+yiDbWK9eash+8gfL9/uGMWeCUhcxAIujX64u3/fC2WJiBFXHTlL14fs0QPy4R9aVuiVk+uxvlZx5kFZ4Drk01fE8D/ay6CukroVjIquEVqPU/44XPbqsvhKC+xiCKhJOI8gEHyQoecJQLa2kEZnx8nP61QCwUTVzVvwp14MXh+7Jy5Zkb64+Mdv1EPJgnjBIxCTxWuzyenYCc1aAMvek7j4f0WKzHMYWvjwxjkuGMjfUXL19ero5DedtEW6kWOBmb180CRzldJLLvvD113OTNA14cj7j05rXp/Rvr461zLmwXypeFWIp2AbOfW+bSgf+UeJ0lvvmPxvAY0efXcM9bne8JylFfhfGjSEcsyvcNC4zQyYauEX8M+XB0Y5rAN689YC958Z4Tpzkz045dR/Om07ua1DEony9jk6qAhwyfhNcBv6vSBf/i+79ll+KtebLH+PTUnbETLNSXIBk8xN6J8h0nvUxotftHWgwwm6kxkHz7vz+wHvqCb8FDdP6SvQfQfYmrqPzrbhTKm9haKzSV1M0ZA34+83A0D/TnM29Rt6uQe4OLLOVs5C9N1RroiGMzd6HDts6lbgL9sQrpDWk+8tXS9j+2s5C/Pao5C233xu2H7oucrncDC34zrv3+AXLPk1nu7Ujkam2gexC4+2JQGbQr9KRrCxO5sPOIY/Uw8or2Xr8yArzPDKEaenm36pECeCG4NKkB+CvbUHMsjnyzinSGvgN5xPSNAPpaK6eNBiwXNsiSgddbg3k79yF3LtbLbAyw3ylmAvQZbWafFTibbFPYga8scQPfAfd/5QpBJd8GzpcgyoK21jRToAd6SpragN9/mjTuBX2bhN1mKh354he9Ouh/LIrT0B0VYj8xMLH/fOQieD+Ohi6WlYp8/cBnW6GPtDzzh8Y40XIncE7P7LwZ3E/5r+3mUgpyPe21Pug7xIl2aC2lQFkGvPrEVu4GfQs7AhTUcHDeREIVtDyXYILu4KecZgCLwpI8n4L5MUWayPo6svkcQQrNLJk0Q2vYQfxBYLVA3XLf1/8vRyi0lA==
+
+
+ 2683506.303
+
+
+ 3337786.1933
+
+
+
+
+ AQAAAACAAAD0AQAAFwAAAA==eJz79////39I+D8af1Rs+IkBABQD8bg=
+
+
+ AQAAAACAAADoAwAAagMAAA==eJwVzH1Q0wUcx3HYWBiF51iXkNyAeLgcJSlcOgPqC9syRA/PABHZ4QJxdyLjYdMDA3EPv99pECfjwQXiFFCih+sYOr0zJAjnlsAgsQOsU4L5UGBJKRTYZ3+9/njfvYukZex4AUtq3gn+MuRKjKt2qlgiteXhVRgyN+dRWciScMXgQuJGlvwjnXO5UN/EzemGkubahchNLAUosjSLcCktOKdzmaG0YWGbDTold7j85wwdKe9hDsGkJEV/lAdLilgmiD/A0ESdpyAUirIa5HvhlrEOTgu88ODTwKDr0EMQfaSKIeWrCaeOwQe2H2fPQmE9d8gJ+fl9neHVDB1wBeTd/oihl5+pgx7Bi2PxszNwXpjk4KQyVGsi1+vQuz3KLgpkKL9jV20svDfU4HDb+wl7SgbVOZbf4uBSXYDUNGUgqo4Jb4DtgubkVhjM9TO3wSsT2YNqmLCQnOnXaSCzv1PJhyXFx94XwMU315DbGNkOhbuPbBT6GYoM1NYatoeBZya8qsugTzs5yovcv5Kjl+CzLvkfHpsN9HPUaueS2EDVvpIVs/CGPfTAFCy2NoTdhfU9vrJKTwPJNNHsYSjWNzdmQ/ujS6IEeHHzW6VvQy2npWLRpqd0ccTgX3BdROr4LThpHv7zAkyZSVufDcu7YgtLa/QUmun4VgVvKnk1GfCd9GnTG9DyE6u88ZmeVg4sF3jt0lPTmhDx03Q9vWvzjpmEZwreq+uAvycOxu2Ej127K41BenrRanQy8GTNppH90GDcnxMN13f/+98PQj2FhLTLRS4dBbLeSiGctxUffz6jo7V5615ywMNBsmsK2FP11Gfgax1ZbHv7L8PSyS++Ow3zkm5z8mGyr2Z8/isdZTarf/1YoyN5+NTVDHitYv7DD+B216g9DJp8kv8eUuvIXtadz4vXkf90YfZynI5cvV25T+BJibjqDrzl1Scfhp6j4yVf8nQkWD3LPQ/VO7bzzHDLwuURI4zUqbbWQ+ta4fX0m1qyxLOmVPiKNHJbCnSkeO12e9cQeFQOpU96u16o01Ju+8GH3lA6+nk/F7buO/34NfhPVV9zKNxqvX/eukdLMk7j2Ssw+Jco8/ewcZ+rchqu6ok4yMvS0ljTN5z8MC15lI+pVHDDIc2GCpiYMXe8Ba48J7p/D/4PJVbH/g==
+
+
+ AQAAAACAAADoAwAAcAMAAA==eJwVz31M0gkcx3GSuJDL+ZSl6YEurit7Ih9mdh7zS8g8wmvVcm35UERhzjbDdAv4/fjx6wzzmA+nghluUkLZla1Cs9YzrhUqSjnX5kOntTPMh7q1isrzvvz1+uO9fbaPKkNT4TtBQynrj9Af1DQwxfUhKhRKHVMjaNzcHKNFQwOX7fbJgYbIdZ6539FyC1MxiIqb63xSEQ1R8tyyqG00zGfHKlxsGrIHuLZJ1CMeZQoCadCS9w0mVCqVd//GoUGeZuAJBvQw3LAoXITG55rzKDRzqC3gHnrRa4wRelBGeOJZsx6OLBedsaLeJ72zD1Guidn/Dg096vxL3KiHosko5cc8PSz9XMrj5Ouhc0g4y0I/cKU9cWhdE0wCusS+yfXraj0cbdtbtw+d6Df3+H1IVJw5hJYqHK9z0PmGqIxbMxRAVdKPnag9vFnmRGOZYdZu9Pbwfnc9KvLJ9m3uoMAa6TkiQI+X0OkJ6Jf10eA3SbJT7u/PUrhhNi0FtlZ+jh1tGV5c1YRy7NDTrPXvHaeG0M838mZ4YgpebFrhiUGrgsTsIPSpa1VRAFrSZeYzUNP9IEnL9xRIyhIrzGhqeXOjDnW9vRl/AO3cukG9A/2OJVxIsOugXSWzrEJzZJccXpsOurZZX1WjLb1X5P+16uDb4RMTCck6kHSaDvLQpuec2PdJOihqdyVXowVtoc8HEnUQY5x/KekmYUuKSLUeLasJLvjoJCH9JRlfi74wWDSvH5Hwd39HgHI3CWHFa89nofy4Y63B6NK1nietu0iQF37yPd1Jgkgku/vnBAFbQoKfqdE3tZPLfkF3uXOWD44T8E5opJgoGT0X4TpGQEGts+Ia+qFrD6FB3fXtrEi0ceW046diAn+/vcdaRMAd6WPNewYB1MKbul7U4r7QYECTIhqnRhe0UP+pcDizRgsC16sHW1H3SWUPH+WfVq30VWvhUuCpu2NogL3Da+JpYfXGkSVGdOqchUOhNf+W2JRoNnvcVIgW706rmmnXQAERkuxF11RmN42hJivb4fdRUCrjK1r5z0nldqEGXLLRwSy00p5yOgPN7EsbL0Gnow0/l6OmYs+Oq31qMC4WZNxA0+/ki5yooM/NDHSrIZbMGslEL6fmsyJz1cD4dnmciypmpxVp6KnrYxEEGiPZM8DMU8P/SNTC5g==
+
+
+ AQAAAACAAADoAwAAFwAAAA==eJxLSwMCpnKHtFF6lB6lhy0NABeoU2s=
+
+
+ AQAAAACAAADoAwAA5AAAAA==eJwtxSVCBAAAALBDEpawhCUsYQlLWMISlrCEJSxhCUtYwhKWsIQlLGEJS1jCHkBgKwsE/gU52CEOdZjDHeFIRznaMY51nOOd4EQnOdkpTnWa053hTGc52znOdZ7zXeBCF7nYJS51mctd4UpXudo1rnWd693gRje52S1udZvb3eFOd7nbPe51n/s94EEPedgjHvWYxz3hSU952jOe9ZznveBFL3nZK171mte94U1veds73vWe933gQx/52Cc+9ZnPfeFLX/naN771ne/94Ec/+dkvfvWb3/3hT3/52z/+9R+byzuT
+
+
+ AQAAAACAAADQBwAAbQcAAA==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
+
+
+ 20449339.815
+
+
+ 24059980.607
+
+
+
+
+ AQAAAACAAAC4CwAATgEAAA==eJx11bFtHDEURVEVsCU4UAEugcGmBqaEiRwTUORsADUwJbAENiBpFlABLIGBC5gSGFjyggmX5ycPuMkJ/9PT9/26/p/r6323t/t+/p7368u8//0z78/bvI9uhpvhZrgZboZb4Va4FW6FW+Fe3udu76Pb++j2Prq9j26AG+AGuAFugBvhRrgRboQb4Sa4CW6Cm+AmuAVugVvgFrgFboPb4Da4DW6D+/Nj7vY+ur2Pbu+j2/vornBXuCvcFe4Kd4e7w93h7nB3uAfcA+4B94B7wD3hnnBPuCfcE+6PY+72Prq9j27vo9v76C5wF7gL3AXuAneDu8Hd4G5wN7gZboab4Wa4GW6FW+FWuBVuhXu5zd3eH/7vbe72/vB/b3M3wA1wA9wAN8CNcCPcCDfCjXAT3AQ3wU1wE9wCt8AtcAvcArfBbXAb3Ab3q/8DP02+Wg==
+
+
+ 6543.323009
+
+
+ 7705.4186129
+
+
+
+
+ AQAAAACAAADQBwAAEgcAAA==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
+
+
+ 0.85978596808
+
+
+ 1
+
+
+
+
+ AQAAAACAAADoAwAAewAAAA==eJzdkTkKgDAQAMWjVtE0Hi8wPsJa//8IY/yCptggDAQEU5lmmGVhCKsS97ZxUcJG2GJeBJjDe7ADB+F5ubc+tMIDnsk+mcLrAEu4DfQM/O1/Y3dn2ScnOHsVut4NOp47XMu+Ro/zr13+9y9d3pd3PiN1K8zfdm/dah7g
+
+
+
+
+ AQAAAACAAACgDgAAvAIAAA==eJxN0EGKnEAYhuHe5hY5SyYDc6ycYtY5TkOChaIoimKhKIqi615lMvR0P7V6F8XPx3O5/H/x5fL9z+vlcv3x7LeXZ7/TV/pGf7xf334+7jz6486j3+krfaPve37/fe757Puez36nr/SNvu/5uvPo+56vO88/9I3+8knwSfBJ8EnwSfBJ8EnwSfBJ8EnwSfBJ8An4BHwCPgGfgE/AJ+AT8An4BHwCPgGfFJ8UnxSfFJ8UnxSfFJ8UnxSfFJ8UnxSfDJ8MnwyfDJ8MnwyfDJ8MnwyfDJ8MnwyfHJ8cnxyfHJ8cnxyfHJ8cnxyfHJ8cnxyfAp8CnwKfAp8CnwKfAp8CnwKfAp8CnwKfEp8SnxKfEp8SnxKfEp8SnxKfEp8SnxKfCp8KnwqfCp8KnwqfCp8KnwqfCp8KnwqfGp8anxqfGp8anxqfGp8anxqfGp8anxqfBp8GnwafBp8GnwafBp8GnwafBp8GnwafFp8WnxafFp8WnxafFp8WnxafFp8WnxafDp8Onw6fDp8Onw6fDp8Onw6fDp8Onw6fHp8enx6fHp8enx6fHp8enx6fHp8enx6fiE/EJ+IT8Yn4RHwiPhGfiE/EJ+IT8RnwGfAZ8BnwGfAZ8BnwGfAZ8BnwGfAZ8BnxGfEZ8RnxGfEZ8RnxGfEZ8RnxGfEZ8ZnwmfCZ8JnwmfCZ8JnwmfCZ8JnwmfCZ8JnxmfGZ8ZnxmfGZ8ZnxmfGZ8ZnxmfGZ8VnwWfBZ8FnwWfBZ8FnwWfBZ8FnwWfBZ8FnxWfFZ8VnxWfFZ8VnxWfFZ8VnxWfFZ8dnw2fDZ8Nnw2fDZ8Nnw2fDZ8Nnw2fDZ8Nnx2fHZ8dnx2fHZ8dnx2fHZ8dnx2fHZ8TnwOfA58DnwOfA58DnwOfA58DnwOfA58DnxOfE58TnxOfE58TnxOfE58TnxOfE5X/8BaRT7Dg==
+
+
+ 6515.558303
+
+
+ 7735.7934305
+
+
+
+
+
+
+ AQAAAACAAABAHwAAPQQAAA==eJyNmUXUFWQURXl0d3d3p53YoNiBgd1id4OF3YpiYIDdgYnd3S12K9jtwH0G76z1rfPfyR7tM9jTW6vW/1eBDWB92BQ2g21ga/Nqw4a2I685bGs78urARrYjrwVsZzvy6sLGtiOvJWxvO/LqwSa2I68V7GA7qU9H2An2gN3NK/WR1xn2tJ3UR14X2Mt2Uh95XWFv20l95HWDfWwn9ekL+8EhcLB5pT7y+sOhtpP6yBsAh9lO6iNvIBxuO6mPvEFwhO2kPiPhKDgBjjev1EfeaLiU7aQ+8sbApW0n9ZE3Fi5jO6mPvHFwWdtJfZaDy8NV4SrmlfrIWwFOtJ3UR96KcDXbSX3krQRXt53UR97KcA3bSX3WhGvB9eC65pX6yFsbTrGd1EfeOnB920l95E2CG9iOvFIfeZPhhraT+mwEN4ZT4RbmlfrI2wRuaTupj7xN4Va2k/rI2wxubTupj7zN4Ta2k/pMg9vCneFO5pX6yNsO7mI7qY+87eGutpP6yNsB7mY7qY+8HeHutjMNlvrsAfeE+8F9zSv1kbcX3N92Uh950+EBtpP6yNsbHmg7qY+8feBBtpP6HAwPgUfBI80r9ZF3KDzadlIfeYfBY2wn9ZF3ODzWdlIfeUfAGbaT+syEx8GT4SzzSn3kHQ9PsZ3UR94J8FTbSX3knQhPs53UR95J8HTbSX3OgGfC8+F55pX6yDsLXmA7qY+8s+GFtpP6yDsHzrad1EfeufAi20l9LoZz4BVwrnmlPvIugVfaTuoj71J4le2kPvIug1fbTuoj73I4z3ZSn/nwGngTvNG8Uh9518KbbSf1kXcdvMV2Uh9518NbbUdeqY+8G+BttpP63A7vgPfCe8wr9ZF3J7zPdlIfeXfB+20n9ZF3N3zAdlIfeQvgg7aT+iyED8En4OPmlfrIexg+aTupj7xH4FO2k/rIexQ+bTupj7zH4DO2sxCW+jwLn4OvwJfNK/WR9zx81XZSH3kvwNdsJ/WR9yJ83XZSH3kvwTdsJ/V5E74FP4Dvm1fqI+9t+KHtpD7y3oGLbCf1kfcu/Mh2Uh9578GPbSf1+QR+Cr+GX5lX6iPvM/iN7aQ+8j6H39pO6iPvC/id7aQ+8r6E39tO6vMDXAx/hb+YV+ojbwn8zXZSH3k/wt9tJ/WR9xP8w3ZSH3k/wz9tJ/X5C/4N6/DwqF2p9kp95P0D61aqd1Ifef/CepXqndRHnh419SvVO6mPvApsYDupT0PYCLaAzSvVXqmPvMawpe2kPvKawFa2k/rIawpb207qI68ZbGM7qU9b2A52gZ1r2Edee9jVdlIfeR1gN9tJfeR1hN1tJ/WR1wn2sJ3UpyfsBQfA/jXsI683HGg7qY+8PnCQ7aQ+8vrCwbaT+sjrB4fYTuozFA6DY+DoGvaRNxyOtZ3UR94IOM52Uh95I+F420l95I2CE2znPyQuuiI=
+
+
+ AQAAAACAAADoAwAAwgAAAA==eJwtxRFghAAAAMC2SRg+hmEYhmEYhmEYhmEYhmEYhmEYho+Pj4Pu5MLgEfnl2IlTZ85duHTl2o1bd+49ePTk2YtXb959+PTl229//HXw8xQ68suxE6fOnLtw6cq1G7fu3Hvw6MmzF6/evPvw6cu33/746+D3KXTkl2MnTp05d+HSlWs3bt259+DRk2cvXr159+HTl2+//fHXwd9T6Mgvx06cOnPuwqUr127cunPvwaMnz168evPuw6cv3377H1iHPNM=
+
+
+ AQAAAACAAAB9AAAADAAAAA==eJzj4RlAAABxsAXd
+
+
+
+
+
diff --git a/geos-processing/tests/data/simpleReservoirViz_small_000478/cartesianMesh/Level0/reservoir/rank_1.vtu b/geos-processing/tests/data/simpleReservoirViz_small_000478/cartesianMesh/Level0/reservoir/rank_1.vtu
new file mode 100755
index 000000000..9dc88b8e6
--- /dev/null
+++ b/geos-processing/tests/data/simpleReservoirViz_small_000478/cartesianMesh/Level0/reservoir/rank_1.vtu
@@ -0,0 +1,255 @@
+
+
+
+
+
+ AQAAAACAAAAIAAAAEAAAAA==eJxjYGBg4M5e7QgAAwwBYw==
+
+
+
+
+
+ AQAAAACAAADACQAAGQIAAA==eJwtxVloCAAAAFBmM+aae7Y55x7b3PdVjg3lmKOwOco1lJvC5ihsjnJT2BzlmKMcc5SbcmwozFVuyk1hruJj7/28oCKFijvYJVzSIQ51eVdwRVdyZUc40tVdwzVdy/XdwA3dyI0d7WZu7hZu6VZu7Y7u5M7u4q7u5l6Od4J7u4/7eqATPciDPcRDneRkj/Qoj/YYT/BEp3iSJ3uKZ3imZ3m253iuU53mhV7kxV7idGd4hVd6lVd7vTd4ozd5s7c401ne4Z3e5d3e72wf8EEf8mEfd45P+KRP+bTP+4Iv+pIv+4pvONd5vulbvu183/cDP/QjP/Zzv/BLv/Jrv/EHf/Qnf/YXf3WBf/qXf/uP/zqgaOHFHOggF3ewy7isyznU5V3BYa7mcEc40tUd5bqu5/pu4IaOcazj3MzN3cLt3N4d3NGd3Nnd3cM93cvxTnA/9/cAD3SiB3mYh3uEk5zskR7rcR7vCZ7oFE/1NE/3DM/0LM/zfC9wqtO80Eu9zMud7gyv8Bqv9Tqv9wZv9FZv83ZnOss7vMd7vc/7ne0DPuKjPubjzvEJn/FZn/N5X/BFX/U1X/cN5zrPd3zX95zv+37gJ37qZ37uF37pt37n9/7gj/7kb/7uHy7wT//yPxcJKKyoA1zMgQ5xKZd2GZd1OVd2FVd1mKs53LVc23Uc5bqu52g3cVPHONZxbu02but2bu8O/g/yB47S
+
+
+ AQAAAACAAADgBAAAHQAAAA==eJxjYGBg+A8E/9Aww6j4qPio+Kj4EBcHAKYTC10=
+
+
+
+
+ AQAAAACAAADQBwAARgIAAA==eJxjYEAGH+wZBhn/rPL+b/9Yp9pvrco/NLPmuX3+uy5h0XIne74vn1aur39HsnlHlNcG1VZU2N8+cn3OBLvX9n+77/IztQXYv7PpVvry/y3J5q38tEZk9ddCe8ElMm2sz1/bb3iyQ0RnYrB9Rs3pqCmXSTdP22vqQ4NPDfYbKrid8gpf2V/w/DdLgyXbPnxvtKRi3huSzSvuzozcsqPeXtU5dfKsua/sJzhILZR40Gg/afLUP5d9XpFsXo22hWP/7kL7jpi4v4VvX9t/ND/jXWVTYt9+xFTj7orXJJs3Wed4XcqHdvuJE968Ti55ab/jPGcN09dw+/SA1/EVM0kPP7VDXB95Fk21X5S4tml9/HN73hUBuW5sbvZT8hvu740hPb2kMuRqBDJ22zPevy23SOglxem5M/X4loTwLvsp09uu2am/tGe/e6P9SPF3O8fVdYybN70n2bySu5FTI19OtdfZVyCzKOg5xe6rXRp4OUt1mr2N6/2Ibe6UmyfuxH6n+tE0++1n64yPqVJuXmGIQ0f1zPn2Z+ZFblq17ynF5vU8d5Y5un2uPY96isl8tmcUm6fCF7Z925NJ9gw7uF6teEq5f28tW8OtuXuufd3910rSVHAf29sg+4uRC+x3pCYv2zGV8vBbYTo1f1vjQntG99OX6pwoNy/477k1/wyW2M/Vmvoxr/cJxeZN0NRezXFrhf0DT8Mt/4ofU2zepNKZMnf+LbZvkU5+JzuLcvfNP9tmf2y9v/372xln87hIL5/Q+QAqnWz4
+
+
+ 0.60984423369
+
+
+ 1
+
+
+
+
+ AQAAAACAAADoAwAAFgAAAA==eJybNRMEVtrPGqVH6VF62NIAkycyIg==
+
+
+ AQAAAACAAADoAwAAJwMAAA==eJwVzn0s1HEcB/AjGnduqhOj64Giy1hXkZW277luqJRpFVmeQkWepigV6kpX51YoD0lIevj9QoiW62SsJXQeEkrMiDudqK5kdKnP56/X3u+9/3jb+NxL28WhyZJeme8OsERT3i4Cnx9SJLiBjMTOFQKQyxeenVhMk7GaTBYqzdELUoGMmdsHP4NlT8R2I2Dc8+XM9EU0OdkS7I7y1+w/JwGnUyRmaWB+oYvJJbDhNzfOwZQmGkHjsD3I9A7fzAPV0TKBHZjA+1ptC5JX7sVtbJpEVjVltYK6VPnEGzC6squ0GbwZaWKD9itdVZEmNHG41KaNAL+vtVSifsnbt6H1bimNx0CXeFYdi0WTRVM5Sib4cMu63ZgVuqgvmImi+Bm6da7qYpkx/G2uGC8Hwy8Ym6G0Wk+NvWeIvAXVcVTRXkY0yfMwl3iDGvPZ0T1gQd/SNvRRxWU5Ov3aZ/3UQpoUhz/VfAfzZ0Nr0c4fdQVoh0lXIqrPmbHKNIR9NlOVBRYx5q+i79t356LakqWBKPuI1G6jAU0+MLcYbQIj57vZTqB01rkPdcyqbkBj6x0V7/RpsjIm3qgbDBBorHpApwT+UC94fvxbcB9oMc6iTurRpDS0MBbVFIRpE0Ee32P4NMg1FY0lgXeyY9TmDPiZFH4XTf7o2WMJDrwISFsG7rWsPcEFz9x9m1w3TxHtiKuFHEx9d+CtAjQ72xz7EpR+dXRrAEv7byUF/KVI7IjBzkAwTDqkDgJlZ8ZTQlCj806HQUm9arWejiK+4rEeBphb8JizAGRLJuoNQG7HCT9D0F9Gmu7NUaT1ivj4fbC4xIr9EPQ2jhA+Apst8irRgairFZ6zFLFvGbbeBQorr/uhI/LaUbRVxljjBfatdy+fnKFIftoe3jfQ9GdZBiqXmWej/FvdNagtQ8S98ZsiXrz0IvTYYGIhKil6cBxdVaKJQRt87Y9unabIpGvSnAuovfAyAxUt3heE6k5NC9EaJaNp9CdFfh2s3TYIDl770/QJLP+XIECrnfU5aNYqf2W6liLJ1r2hYnC/6O9kKtgfscEeleSu/JIC/gfRg+JN
+
+
+ AQAAAACAAADoAwAAGQAAAA==eJzr3ZnN+XPBSvveUXqUHqWHLQ0AVJ0Q7g==
+
+
+ AQAAAACAAADoAwAApQMAAA==eJwV03tM03cQAHCBSLcUXAniA1yAAYYKAVcJm0q2g8XSWgRFFFCMDPCx6lSgWGDAQEsAZ68oSYGCFih14zGQKIxOXt18jCAKwhArBR88Fai2ZGwYcde/Pvl9c7m7333ve7caTLvuI3T0LPQm/4mwHJSutvwDoVMyGaHXImy4+4b5lLyU9eC9mCWDEG2OlqtD+Nji04LDFM+YzdEc70Io6nvw7AsyzGF2a/hJBJ3zRLd3P0LXoryjQ4/wg+/uwsVOhLUiC6m8g/LxCwePVyCw5GNlYfcQ5LH/FcIAwqoPHpyRdgSJLsPd0IYgUj0yHLqGEGffmHub+lD3uL4q6kbY57XEGr2FwD+mPbKTtK0PdHORInyXNtCZX4twcy5sy9gdBFOMZ6XT75T3+m8X1RqEXUmO5XM/Ieh9ojLX5yEMfPT9hA3Vs8wW2XBaEULG/qpbQYpra5LXlSO86OGNs0oont86t53qlPraOYtbEFIyt4fGkPbN/i4vExFCZ9awa5oQVNMb+wZvI2x6WCWMbEbYkfReqrmJkLD325IDAvovVXiClvqoAtSbqM4O/TfTnBsIke523NXkrZaGmH3xCKml8svnHWQQva3tFI/qvGXz09Ip/7RLS8gZUmGQHUmIRZBF2EtyaX7PMxIbU6jevGuK9kkjQl7kG/de8lpydXZqAMKTLUWCjBkEJmOzE4fOay2HU7waELzi8w9uIpM8jC5GfwSNQ/C9WGsZKLMEPn6/IjR8+Y8kvx5hvNv/Uh4Zzqz7UeOLsCSKrr1gRJiIVtcH1SHYRNt6jtPc5cObJ81yPWsiVSyE/SY8FU/3/6GYeU5cg3DmwMOGQFIoVl4NIk9EhNq0U9wdY7bj2T6EFYnjh0d+pvhJ4YiStD/rU1ZBznd6NBl8aD+XjlZGjCIsWC2vK6a9eLT6s9ZlNYKB6zFt1munUcKyRijJlZtuUP+/XFQGx1UjJA58wjhECpvrCswuC/gLU4tSMOYPWXnT/Qz37+EtViFkjSZ83kbqVgbGmdXP2B1rei0FcekQr4vmNHu16rR3JYJrdkWcE7lgaSUy61zNLHZ7LIX9Q/N+aTSnV+yXiiIlwr+GwcfpZMFRYa/Zv3tsp4I1Uihbe0F7meYkcDNmTl1B8DvJyNGRVlHvDprtHzsR9fV9KZxvV00AvRMc3lgZQPu43iKds43ksrvfbSVTn1pzvjpH++1akWtL37qAlRblCtqHNkeGguQp2JpS8n94qe0m
+
+
+ AQAAAACAAADQBwAAuQYAAA==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
+
+
+ 1248.3635217
+
+
+ 1301.6668744
+
+
+
+
+ AQAAAACAAADQBwAAigIAAA==eJxjYEAGH+wZiOT/B4P3GPzHqbpOzCv67TO9vn+Kb3xPtHm4+HPzTl0Uytxvr7vp2NK7Qm/sGY8Vvq+NXGO/8DGHYobVO5LNW/zz7m+9U1vtzzi0KOxye2u/hi+y0L5/nb1o/isOHnHSzeMwObF7u9oW+/qfbRya1W/ts+YumFzpvt5e69vRtA5u0s27eOhTSfyS7fZLlycKlnC/tV/mVhmud3OTvc51AdNbS96SbN6fO19PvtfYbp/gcpDtkdRb+5/uGZunvd9uz/B9kiYvE+nm3d/9j3/Vh832rRoM+141vrVfmqkTJzpli/2ZIquQ2lzSzTvrJD1j3cud9sun/9E5deiNPXP/Ic3kf+vtBa4nn5VkID78YOlPJE/zqq7+fnvbS1GuUlJv7DmvvriUWrLGfn3RxUU7LUiPD8733w0c9uyyl2N6+LN8xRv7L1cyb4S99bTvfuq5quUn6ek766+doVnZLvsghRuWlhvf2Aed1U02yFhmr6V89mfNTNLdN/Fu2datQvvtfVUCPVfKvrFf3LTWMGXCdPvXk4vu1TiT7r5f+m83T5fcb88Y1cR5VuYNxfn3QgXnJMOY/fbPLuw7WylCuXn8Bt9MVjQctP9bfOjT1fmvyS6vYPJhb5pC/wodtH/tMn+Vw27izcPFv2/wschKc6/9k5sLN96Ioty/yeZrejl/HbBX/zRlTu1Byt1nsv2i+Lzmg/ZGk7irJEgIP1z8y34/mhKeHbT3fuN4P73tNcHwJsQ/bXF575vzh+zPGnZfYPHB7T5izXcSYwmb533EvuBXXZbE21cU+/fhurCF7+cfsncPWSXOEkG5+/6w3ay61rTGfmJ+0IxL5qTnf3Q+AGtXsU8=
+
+
+ 0.85625095466
+
+
+ 1
+
+
+
+
+ AQAAAACAAADQBwAATQAAAA==eJxjYIAAYzC4bM9AId/cNSdW6+wke2qZN2smCKy0x8UfNW/UPHqaF7Jx14wjy/wHrfsct5mU9pyeQzXzSNU/at6oeaPmDZx5ADPNtlI=
+
+
+ 0.3
+
+
+ 0.30413812651
+
+
+
+
+ AQAAAACAAAC4CwAA5wcAAA==eJxF1fk/FIgfx/HGzTjmcBtjXKPGkRzlmE+kthxJbI/EsoVKhVQokkRU5EpE2NxJjq9rcxRlSVQkFUlLKbkiJMewWj9857M/Pf+C9/sVKaTr55hOgcj/2yLaqsU7qgAhuQ597OOy6B+ckLwSBxUA966qu+F8qPN1U4k1zeLwz2znSFH2HJtrfXXGpPniGlDXmzQi2HDYXNPzK8bMa3ihi7Z96vtFXdRE8+jIxGMj4EmL+FP4pAga5qdq+eQ1FRiRwyo21yXQnlxt58BSGbhhqms1QlFDDzi1+rjQdGDwcDEnczsdXWdLWJ6vYgJh+F2SvdgMm+sFZ8v9HOoSu/Ty0AXPHjHg+pd6cVasmzTMmVF+FqRJot/2p68sDdMhXy9JQvcFAZ23+V2m9Z4IpAbtpFZfoqIe92YyKNaKwB538z43TkJ7PyTmmLjJwTxBdCVmjyAaRIhqOBpKBp/xiM3RRiz0WtmnUs+7+tCrLtAZcXkN+thI2GjHMyFoaTAcYv5PEJW0G9F0bSKDYLL/sZf1LLTZt0fCVdwA1jc1vfkySEfduxwY2iwNWFebM1Txghetl/LfF1MtBlav63vY1cqoT0PG1r5EFkSlxsdf2cWHPj/o2PM8QByC6pR2CY/S0HfPUjgtperA8pt3U+CloPVa3ymFfArAeyHL0zGXjhIO1MSGcZhw75bOG02GICo0PzjA2EcGctXajhgLaVT08q200XIG7NROKbYJoaDTTYPh0/cVYMXb4ir1PD/a8PLknTg6CZpOPPCtjPtP1cI0DbFuWQBhghNfuCraFxsWKbBVG+xYnN7Fbmm0LjPYw1RZGQ4Ht9unVDLRGJpzSLnABgC7Wrhju8jm6rNkrbOZwwP13RbVItlSqJjyKeFWIwbw16RX7DGjogJJo8Sf/TQQpQaMz0TRUcuOFN3Tw0x4yt5eIRbHQlNKqn6JHtMHe8V3oExWQxc1n7wvl9OBBI3c3LkfLLTItY4TaGQAHBF182dWUujphE0fyiaVYCCh7KZbKhEt8N6mb1UhCcaHPmRZhwujYzZ3FqqVqdAbOtrY2yyADir52udSydCwJ9hcJEkejQt1KRP8pgrVY9rk8reiqNCJwecROVIwpnVlS4kvES1VZk43XpcEj+fSF2uOiKDWcvbu0R1UIKbFZ5uMSaFXKjUXi3wZkGKqfjJUgoy69VavM0uRg2fe8zyBVvJo6jVjHvlqVdBrEg336iKjbWrUrdn35WHm6fJSgIkOapj6z7m3RRthooHPzm1sA+pBvzx3bcAEJMKzojxshNGrbkYF0QsU6JpOY436SqJ1x0Ye/l1AB0bMtGuK70ZUZl3ApfJX5tBm6H3oh5oYunctWbSmTwp4bRq9Mo4qohYLnbsNJZhQNyXIKjm4yOZ6dTZyIIzIC/154+cTZnjQnWfcGt56iYJlW74JwYqBjpcs9IT5rAXpfaFtV+pJKIPPTMeWJgf1ZPUzcp+paFpatR6zW3F1/3Nz0aKGaPvnk6c6E80gfVvOwtoyIdS/MqiOHrG6f9tfDYp6ZND+oM2ejz4qw/DptmtWUSTUWa/UebJdFpZYvg4VJDJ65tHtYOJNOWjaaCbrBQoo+eh6B9JxNfh4O0K967Akupuz3cg0jQ4dLo4qFaud46pPvKh/dbV3U0kuroaaFNRzQES001wB8rbwTnzX50P9ByM+TdiKw3Sfj2+ZvSA6ezDx120hZJjPCC733C+A1vxJexz7hAT9srv/VnWjo7cpy0PvWpmQ93H+sMsRAdR01Nj2lw4S9FTEJUq/JqLKAuMTpAFJEPEMVO1W4Efj0gwMGwslwKkyl9L1XgYNb+HE/jGkDBY7UgnNn0no4LGDPExHOUhSavcazpdHS3t6E3yWVaEgYyT/a4QRGhJw/Fy5hwV8usKM2damiN79Qjv6fS8THoo7Ve7PI6H0G/yx8XOyYNqxkB3YrYo6Gv6YqWrUhqnUEhrzpSxaqRee/D5DBV5lrwQZbxxjc/198bxC0Z3v7DeSU7FnLHmAq5nSyJ5KbyKcT7I8rtAhhrr63ktMcpYGWiuzI25GF2VpmRh2exnDIcJu3fhoUZRIYB8c95SCyLnqG+XKqmjLNNU9ukILZOR7Vm7z86AqBRbnzwoRIf3YfXsdLXF0Nn5nvUq2NLzOePhbciMFBa9M4QMqNNhzzXh8cpsMuqLlpVvpt9rPOx1EIXtR1H7lnVALe/W34g0mI9OE0HyvglOf/ShQ+9sYZ44hhz5tXs+ufasCqrPjkerF4qjc/Ak1GkEGEmqcTWqsxVAvkWZNkQUpULmb8GX7VkX0ZuhXrYAZdViXffuJgaES2r/wIHnYUwMaeB+xPjF+srm285AO3N0nCN+qah021C+wuVbuIK58juWBV60F720ypdBb3SFDgZsYkNldbFJ7nYpObOF9m+yqCE8qTcK/5P7na4Hij19NmOC+NFVv4MePRj3wj/OUJoGZYe0lKOVD+19IWbvwS8AzveyEs7uEUNkvgV/7TFb7f2vntFMYH3pkcmZU4C9xkHqVE7OiI4ja0c+ObvYgA6+TQuFVlip6kb8w5OVDLXCQMg1Y7qSjy3ZfHetpGuBwsVk+b1YePedOlQzepAaZ8v5ZHmokdFKj9ETyRllI1c+yETirgVYwa2oi0jfAJ0l2e06dMFooMSHHsaHCfFLLXp8pDptr7TdJgoMBH/wLNfIJdQ==
+
+
+ 5.9993165943e-15
+
+
+ 1.7958150475e-13
+
+
+
+
+ AQAAAACAAADQBwAAFwAAAA==eJxjYBgFo2AUjIJRMApGwVAHAAfQAAE=
+
+
+ 0
+
+
+ 0
+
+
+
+
+ AQAAAACAAADQBwAAcwMAAA==eJxN1VtMk2cAxnEZWhGttoKdE4hTDsK0QimBlRWoBDOVgwYbLdOImG5ShjLHoas4S2T9cBbBFQko0AZBiUUEMRG0Famhn2JSxrriiVnc1FXryiDEiQJld77P5e/if/VcPKPWVPl+u2+CcYXTNKriJwj3hb4UgK9aBgKHnxAnZzPDq8Hpn56IUIBFP/TV1JqIg0JKcivB4rYSHhfsuGS+6uolDhmlf7SBPSsPDZxpJrY23KC1YOdtDZ0G9mjJmvEDrw7z4THA+nLj4rNlxJSD4akA19tfpYvAX3bLr3DA0q6hcW/w2tQF+Yk5xJxG0Zu14OWTdS1e4NhOKtMlI2Z9cavwL3Auy9puSiFW3ldubANnGyP99WDb4zv/NYCbbzJbq8Di/AfPo8Ohz41jBIK7j/DvccF7q2syg8E71/M4q8BfFdDeSjbx5rqM9AawpMK9SQ1WOwXyMvCv3MKpn8AVZ+ke1YTPB/vrm4r6wc30EZ0BLAntkF0H//K1ebYLfKLpbZ9qiDh6LutPEzj+kF/KTfC8zDyuAXx0rvh1F/hYknRfXhfxCwW1uAb8pn3likqwVKkVnQJHpJnS1GCNbEY1U0scGWkMY58h/iOKdq0BNwZxCwRg0bgkOwb8uVMYnXaYeNC3/IUYfKmJJy0FS+9u92oFfyap338NHDHH7nl8F/Fqh2HiGHgO31NnAN/dUSRygAdbxOvcYN/hjzUaIXF1CZVRDv6tL5k7BH7ErqqYAr8UbrvBiiMu1buLDwQQJwU4YorB2t/5idfB3lNqix184eIz9Tj4GYPZu9699IOLdntQG8AKKsTyDZhnWyRXg5n6HGsdmMGr+qfNTvx8IP3BBfB7nnPsMXgrT3TeY4R4bFbWtgQcEtXKfthD/FG2ZMwNDgut9wu+Rdwcy8zaAC7oEeYngzvzeh2TWuLA+eGGSB1xre17cwxYG1bWkQRO3OxFbQHzH5U2Dh8lXvQudsQNjuqRVXkpiU/nfTeNVsqf/rsQvFteEEHtIebwM4o1YNaqw1nopHM5upPgg9ZOF5pDJ2R+Eg970X932+OILz/cYbCBv6WmlwyCBYXGLAt4tn6Z/EoAsc+W+PD3/sS3T04L7oNTGMGWfvDo3iKFGfx2sn2kY5pN/vadKrV/ilg3b525HPxzkGtCAV454u7MB/8P8p/GPw==
+
+
+ 0.00030569580986
+
+
+ 0.00030835344613
+
+
+
+
+ AQAAAACAAADQBwAAuQYAAA==eJwV1Hs81OkeB3BjYixZh+wmqRMNcinldkROX2E0LrW81rqkVaSilRQ6aROinZl4fk62IdGQpgsq5V7IiBhSiVr3klxyyJ3YcL7z5/v1fZ7f6/d5nu/zVS1kDFtu50HdTZhyeUFgF//6zDp0ZeN006lnBLSJ/pNeCx4s7ooUSlcTOP4y0L4IXRE38HO3iIDK2ReR2Wj15+MKneiwGU+vTh0emPn11y3qUtCQ6H3mLdpZFCNidRAY0krj8NHytHVcX/x+s5l2RzBabiSm7GgVgZcNjY/2o5Nfv/zwLzQ5q59qocqDp4OJJat1KBCkVr2wQocwH8mroS9eu2MiJ6nP8SsruwmYB7JODq7iwVmjn5LmnhJYjmb6t6PVwmiJ/EoCxc6ipBM0HrgGyjWYMCm4ZKy0ah86KW4iexv6jXiHmTn6yoH5JGghwIu31VqLVlrWNu6qIBDex4pahY7r+J05Vk5gu4buKPsLF3YmrT/srEXBhQzWZiv01ZL0CUd0VZiLLBMtbNQcThYTEHxQ0VJBuxss/KPnCYGLkx/n5dHsI6IAR3SkWEq3t4MLf3KpgkMbKHgex85rQbNl3/r5o0NLxq80o4tG95q8ryWwsn0kSYye9tmUtfYxAY+hnJpq9Pf5JQnCMgL/scsId6zjwjX+VGnUegr0HQIsrdHRjrMnz6EtNa4H2KFb5IL7V2K+jdRfDf9GS0eHrTQuJTDCUxm3Qru8r8+VQiccuVMcXMCF8bbzdqkaFFhwNq2IRXczdUzS0EbfbxkJR3exS0etMA+nO9nnFDrVSPmfp4sJKNEdH4Wiw89Z7fFB1zyr9LEScGGx8KtOvjoFIwe/6gWiNQNWnypEG9pxm3zR2UM6r1trCETc6djzK1rv1Y0gjyK87yJl7/1o25OLiWWFBHKyFbkdPC48VD/IbFCjoK82I4F+iQsr+jzHmtDzvezfpNDZQLqnMI9pCn1hCdfbd9sOGRcQsIjoq/qG9mQqs1TRwnzp3J0RXGiVy3Pq/5GCV/zlUW/0exlKPIhm/yCMcEd7WZYf3415zH6l2/yCntBjn4l8SIDpqtPphh7cUOx8Al2dZy3YfhDPZ/j0gUVVCu6qGVs7oJfrfdOW0DdDGLIe6N7fQx+EY77ebKGhP3pUM1zU/oDAXs0w0UH0RY9xZhOala/e3OnEBfn5Jx6qqyhgbTka9QFdnzgqkjg6c1GG5ox1xta1xri+0lehWgOdI90WbnCfwAblgWIm2sCfs08fzZWLid1pjv3plppvqEyBTI7shBW67AeHugOyFNSf8Oz1RwuinLaY3iMQM2OTFYu+bzEbx8kjUDr8rP4yuk9s/t8/0LdoXx3dNnDhnoj/zU6JglvBBj0u6IUwrxzeJN5/Y0JuDLrfS5i3Kxf3W+z5mo5W8FLc9CmHQHmqHyMPndK2dUDi2Dfh/1OR54LuvqO2+xUpGL5YX6eB9pgix/3x/fOGW9zY6OUUhdjTdwkEFUQ7HEKHeL+6b4Oe/ZRcHooOOi24vgutNXvElJrigF3WuoUIBQpU4lXE6ejayWj1iNcE4tffrSpBS4V+8u26TYDBOM96g14eCOoSoNtrctf2oFUjtlzLRN+nZU3d6eJAovOKx9R3OA9sveqy0YsLh7N+7sE8D6BVjJ6hL6ml3ML/Zd5WG0C/UdUqXRLifGVreY6jx1jaQxIvNtaF/FTLgeeGTZG3GBQs0dwUgtGp8fypAjx/nfevtbjo2wkCB7+bBG5C+EQGOrRFibEf3Wo06y1EHyvK5Ur81uJL3+N7HAjeKDX8VIaCMNPs7n70JOcd3RDfz9Zjl9I/o9ubXXfP3SAwoehmPoU+33NoWzk6oNI+YU5Sl7Hxk/iqQLqq6goHBMKYgTY6BXLnbUw60RFX3+2uwn46qV199iN65PqNEMMsAtMTVxok1ozO9FuL7rP/k9aPnpGmh0n8gFn70f8cB1xD0sYmaBSoreEbBaPd330xPYP9VOJB15D4s15fWrIA5+fnM7GB6Lmx1r8i0QGcggqJeYeDmiQOKrOqe3KIA9M1n6UVpSiolno1TdDXVvNEl7GfNCqs3f5AO22cPDeYQSDKvqTqAtrsN0ZMB7pvs21hDJru+fc+iXWYHcrdThwQ341tNlgisOaya8de9IWK7H7IJCDrXqRtik5o08nakU7A1uDjZX30GlqksSXaxuWYtS7aXk/893Y0i2+m5mzMgfLGeR/7bwTyZQ40p2zjgKJmZrwi1rscEx8eRbfvkKGlp+G88/NW8EZ/KFdnpKHpyd9tdkc7pOmVXUX/H6hMtB4=
+
+
+ 1248.3635217
+
+
+ 1301.6668744
+
+
+
+
+ AQAAAACAAACgDwAAqAcAAA==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
+
+
+ 1.3722248506
+
+
+ 1.4142135624
+
+
+
+
+ AQAAAACAAADoAwAA/AAAAA==eJwtylFEIAAQBNBKRERERERERERERERERERERBxHRJRSSimllFJKKaV0OqWUUkoppZRSSimllFKKiIhI1NufZ2a2JzDg51pYxypWcIx9bGMDazjHfxxgB5u4wQX+5xC7eMQtLnGKI7zhCXe4whm+8o5n3OMav/jGB17wgGFBvwbyXf/EK0bbwxnMD/sLE/QxjGAIP/2lyomMZSRDmcU0JjGOUcxnNtOZzHj+YQFzmMEUlvMvC5nLTDaykiUsYh672cxqlrKYo+xlK2tZxlmOs5/trOc65znBQXbykJtc5CSHecljbnOZ07znNU+5y1U+85G3POc+vwGJTEa6
+
+
+ AQAAAACAAADQBwAAjQcAAA==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
+
+
+ 18957397.195
+
+
+ 24060044.732
+
+
+
+
+ AQAAAACAAADQBwAAiQMAAA==eJyNlHtIU1EcxzcfaM4SCSdm2kuMntLLVVA/LTWzbNQWJZZsQg+dZeUjIRObMYRSy9I0F0jSw6TUbKbbbDanmK8yK//QfFSSuuuDWVg6vRHd7XQOLLp/XO6X8/t9zvf3u+f8WKw/z0ymkabpMWAkSzb393vcrJVWuHZj4ZrFaF5gzNGVrdnAFnIf50YhXiQ1jfET5uD5F21xvY3hSY++Ctl5QAvDj4bXxkr0kNYZXGpTWwY2dwTR9NcRc3xNAI3xOwn/aQwvKls1KSquhk1fMvo7miiQ5VzqyXd5CsLYVN3eGsST7p3FeLmOOG81w+vxDVOmtz+HeDVvqM12BPzL+L6jV5/C5cLMLZFPEG+yAPensMN5XgyvLrh5adWYCjyaIo32Ugr0wWOr3MMrIe/1/AL5RsQTcvD8dGtcuzO80KJ+482zKgjI9BK3XqcgS8dxyjisBp79RMRoPGWOlxP1ORP/25Hhyfxdv93XPIeizc5LOfYjcCTvQeJ0ShW4WmuuLR5HPAPR/1csXNsweu2X4qGwphfgV62qe+ZNwZyCK4qqFRWQ4HNwsPE2qrebOB9tNN5PNsObX9+7Zl2KFhZVtSniRHqIi7k34+NRDiX7K+iwbsQ7RPSvlY1rO4YXoRb4nhzUwE6X7VMGKwqE5co83X0+8MUJ+7g/0P6pRL1+RL0mf0ucBkRDJRrQXNC/kzpQEMkV77q8ugSCvIpUvNBRc3zBd7y+MQv1RpeJ0+ZlayGFkomSw/XgX7kx4WqzHCQfz8iL3FD8MgfcD3l/Tbwa9x2K8rtaaPVZflNwSG9ev8QZxPbnEvlGwt8soytDj99K+aCF1GU14aIQxAvqM2DxM0S+FcFnMfrCpz3jk9b10KIYtbXSDJvX+9X4/DJY8EPypB3cpK5sHfS5LfDa3YV4yhd4/F0L+aTOURU/TK94Cb199zo9bqB687fi9QqMOI+2wA9aHxzz6IYOco8lnnD5y18Dcd72WfBj+jL931PC0tmHAfXQzBfUvX+CeE2N+P6n6X/7M/XT+2Tu+oHGeijNGahsyEA83gQeP/c//WUlOnl6Ug1wJrYw+UcA4rUQ/SLvg6Xz0jtTaEcpG6HEXcIObB8yr78rw8+zmJifJj9kvcnVHO/MzgZIkqfGLwxB/j5PaTFeF/v/eG/XqDec/1kOktfnqDe1aD7JarswnoSYx2T/TPfnFx1wVos=
+
+
+ 0.82960658291
+
+
+ 1
+
+
+
+
+ AQAAAACAAADQBwAAiwcAAA==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
+
+
+ 779.00008161
+
+
+ 984.23194393
+
+
+
+
+ AQAAAACAAADQBwAA3QQAAA==eJxN1Xs01GkYB3C2VJQ6mTGTSxdjEcllQlMt83uZwWBoU6dtk5HktmYoHEsis6ValymmEim3bSs6YW1aTYgml8JZRaG7S0rNmjTa2jI7c3bPPO/vv895v89z3ved5zc/La3/nqGGx4I0Vw76n1rrqiiuri5gl4XK2oXO4Oe3OcsmncAjeiNuMsyjOmXCsiPggPiLrXJv8I+bSktssf5vZxc3N64BR1ZnXjupssIQZXqI9JD2Xy/FqRJ3dIwe99uzwHqipdwiNH2ztyZ/lh+e0eEL9UsvbJgVivVjh8bWEXQOqsjzsBAoZcQlw2zBsQY20j5wdHyb7Bahp/D7ZP7WS5NPLPlMcvCAevpAz6dfHcHTpNy6UQcOMvLJiHrcM0b03SuLzmV6Iguz85LTg+3EPRGb4dcO/a7ISne4b4D6LeyycR0HcHpTzHC2PQfdTqm/GXRCQbzeUot2ktmobQ4/PdbpOWHwLo86etFTkw8mi4YYDKhfq7OsRWwHnomRfF6jcl6BZ9Al9J6oMpOX+rmw0f16h5Bd96cJqX0ab0LB0uRtsmSUGWw/15VLDs9aDe6/nr9oyJaDeJk7Dlf+PkZ0PAjnniY8kUOEW2H461dEOe2OWKEL++t+3Ds3wx7qSysoRwpWgRPfUXKFKiMzWopH4wzxTVpWn9yThR6mGCiVrd2EnEKju4jh/vjVH38OXgv1X+wXNVXZgGtCA3mrVLaZ6Y54MzQfPep8/iKh2B1ZDzR39QVJiNdTciHHDuYlyd81uAw7X8bJJsbESnCJZevSXpVnTv1DfxOrjZxMdrwqm/bQrHvneA2WpkD+qEU1ay92vsmiSZbQCpzTv0uWrLKV1lBB6kJt9EjsqNOrw0JxqGs5lScgFlXkbD2CzYdEX5gjxc73YbKq2dYSe1/4bdE0ldu/smfOSVyAVub0nj0vctesP42fSE9Pgvz4d6nbyy2w37fuicndr8FCbobTHZXp0b583YcL0G6heKz3EPSbFcwLofAhzxizTNDG6o8nuEkTzMHk2n1f4lVm+j6Q2Izoo+SdTEpNFPQTtIVcuh8E+fK/NzdE0cDR+71Zppjrp0yeqU3nidK21ZIR6W6nzicfpFmvyuqrTMPe/yvcwBj5CrDVeF2AFPM8MzfybZUN9p97zzxEQtmxorEVP0E/+nr/7DECmw8/yb6S5dh9XX8yLMA8EOx8IFbl2o1/+JwZmYdmKwrr+2bgvFlF0q0sP8gv3qJ8eWIZuPDGtTlGmCMGF9upHWjZ4dVZQUJU9M7k+AHYny272iYau3+a0nR2myn4VJjj1RbML3ZvMGtV+eKUwcmDlYaIrBiMcrKEfh+b5obUW0O+61Z+ZrEJ2HZzshEf82rmQaT2+u1x6zzYVJSfWVQzf5jQrHPfJpM8sXkb5NTtszAGh+tHCamYvX+4cExt98vTIs6EMari5SSt2wT9jkpLGJHYfI2fsRL0LwGnRembt2B+Rj5orPYTUvaevOIVKHIvc8/xYTfNuvNUQO6AGeQDX67JT6KCK59yZTGYE7jyHrV/+eB72e5PYxTmf5Xh/z3sLyHSKj7MCPs+3jjXaEQB3/T6tpmK+ez89Hy18z+mDululBJ2X5jx7f3wfxd0gWc+ZQh5TmMb9xYZvEBsfaUF815nTqza/wJaERYf
+
+
+ 2096276.6389
+
+
+ 3346757.0206
+
+
+
+
+ AQAAAACAAAD0AQAAFQAAAA==eJz7/////39o+P+o2LAWAwAVk/G4
+
+
+ AQAAAACAAADoAwAAbAMAAA==eJwVzH1Q0wUcx/HZEQqsDhA2eXCGIQYIiKL40MyvmLrBjAMZd2B4cjcU5UExEVEQ2cNvRoNxsjlR4CIyQFh20UWUDR+Q7TzaTgeYRDiXqHOImpPD7lwf/3rd+5934OKaHsdBJb26E1KmhkFFqwesB5Tkc/bkaiH8+vdN1/3hmeEfWe418HTbcyfMj9l1NBqavEYK9IlKCvk2Z+A4DF227ft3WEra5/9dIRuy4/Zrit0MtWs9PNiws0uz1faGobBP0mrSBhlq2lu02B8Oxfe3fXODoVN+H1elwVnxvMb1cGnYdseWWoamrpSJQ+CnmduejagYUlWbA1phY96z6a9gtTjXvCGDoZN3n5dwYbnX2Sw/OOqpnZ7dwZC7ZSxwEnZ4cyZKQxlyaIKGUqGlXFUogeyoFFEGzNJ3ckTQMG9OU7ddQTtulmU8hPcfNf97HR6LMFy8DA8qzNO9cJCj9e3vVJBnS3rqxosKWnA+MDgC9llPOcKgwovHXwRb/e/08EoU1CD42VQHW1q50Qy8rV4eK4W/HPZ8rwLWG5Pqu9cq6MT+vJszMKNC+PgR7L0m9H0Ck1+PmW2wvkb9x1OWggyr5qbMn6OgK5UFOj4MvhHwUQ60Oi1ZWbBYGPc61CinzVXczyLhE74g4AQcPz2RYITulPy4cTjSa26rrpPTrLU/+yhUyb8U2KByu00Ur5aTjzMtMxuyXC0VLrGcJkN7ohxwJ+v8r0WZ+Ebu1vXAoA+tYWPQx3uFupQnp4fHY3bVQfWFzQfcsFI7SEmL5FTUnLxQAmu5fYXxkzLiNJ/5IB3+1Gf31kK3zXl3FM747kl0wcs8w8KJbhnZ9r2qugXvD3ZtidPLSHCbveILeE1eFquCCwrOle8+LCN7FId/AW59sfzqY+jxcu5ASKmMXnYMaGLgoc68dUl8fKJqOtrhKtdw1Q/wfZct0gjF03rJLSjiWl1L35XRX42mDRI4ZRnmlUJ3dvnwW5+KVs4cg7zxS6O8ISn9F672S4A+Fvs/K6Ehtqk7GibmmxKWwSO6PV25GinVCttT3zRISbIxec0UdBr/XvfgbR/Rtd2DugcztCRHSiXGF66pnVL6vD3AfgluMlUbz8HKe+HFDZBdG2PJiZBS3d71a/8Ml9JVHpN7COpHg/vSoSb3twQB/B9KK9HR
+
+
+ AQAAAACAAADoAwAAfgMAAA==eJwVyWtMUwcYgOGSKbZUNyS049IwcAYZRSlukI21ss/OzaIuzFrmagFdHLGIaA2deNrTnlMJEQmXgi1ys0AAEQj8GAZGMpFSQIRedIqdEHSIC6tSYKKZk8C+/Xry5uVsKepmaQ3w2h2a16UxQHBOwtBLwgDsKjpBiTbc3G2LQysf/MwIE6MVTUtsVLk943zybgOMsiay7WCA0Ob0oRqUF7O3K8LPAFkB107x0Y2xJ00lLAO0mtet46NtHaavGWhE0sEi1V0a6k7kbIlD7XG3mqwuGgo3CykV+iaVWS1Ht0V84/nxCg3zA3mpieie7/YuvqqkodjgDBxAqzMXF9pRQ+oPzrQMGuhHS2cTUIJVJRegD33NC0HommWSsx697sd9bIqkwWMKtp9GXUTxqXx0Y/T+A7movLONm432M33qxucpODSWJ/P1UjAzd/XlU2xNZH/7FKoqcC48REe4Zv/H3RT4WqQpGTcoCKrlhOxB++4Xer5AC1hhol1oY4C7W6Sl4LKkZ7QTtTS+z29BfysT7GhEf1H7bqpFjbfFxnExBfqTmWPcLymQkcl/bUB7B5P9/dB9/046GaixqMyxiU1Bf/yG/TvRAV32FQUaMhwYRaL3X7jk59Hpy+nL55r0cJERe7UMndCURwmb9dC3rV/pQFer7qX/g3aoLBLxx3r4+zrdI0BD2JwKxid68K+z1tSjXHdz5zLK8CS9jbLqYPyzE7IAtJfx6bnQQR1MSK2Ca+jOr1rFyyg38Hg4/1sdON7IbyrQ8AOFT4QHdbASU3rBhk4JKxOZUh3wYnMn65+QECOMhVk0Sz3CyfqDhNXB32/Mo94IR07UDAmESPf5ymkSrA9e+DxFbaXfF9eeIaG8Jfh4pIqEAvaS4jAqcCe8YqxpYVgWQ1xCS2aP5W9mkMCce++SGp2TFvGr0D8P2XNtJVqwybjS0lItZHnafRpQnmdQ6kA7ptPGZtDqHa3Pi8O00BtfQTI/0MKjhnZRNLras9zGR6dqMr3xqLDvWJemUwOvJeEftqDc+pHRZlSXlnjEhObcK1eaUa/AefidJA3wTCkNibs0cIcynwlC3cZf1cz/2yuQrIk0IBhbuHDRRcBs2bPnwQ4C+lI+GrbYCcgvX29Uoyu3JNOZaBDvSP3bowSE3f3p7GIaftG7Q1tRRVd87jMFAdFDeUoX+h9Q+ccG
+
+
+ AQAAAACAAADoAwAAFwAAAA==eJxLSwMCpnKHtFF6lB6lhy0NABeoU2s=
+
+
+ AQAAAACAAADoAwAA5AAAAA==eJwtxSVAAAAAACCPtaxlLWtZy1rWspa1rGUta1nLWtaylrWsZS1rWcta1rKW9RzCITDgX5CDHeJQhzncEY50lKMd41jHOd4JTnSSk53iVKc53RnOdJazneNc5znfBS50kYtd4lKXudwVrnSVq13jWte53g1udJOb3eJWt7ndHe50l7vd4173ud8DHvSQhz3iUY953BOe9JSnPeNZz3neC170kpe94lWved0b3vSWt73jXe953wc+9JGPfeJTn/ncF770la9941vf+d4PfvSTn/3iV7/53R/+9Je//eNf/wFqjj4E
+
+
+ AQAAAACAAADQBwAAjgcAAA==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
+
+
+ 18950081.249
+
+
+ 24060002.728
+
+
+
+
+ AQAAAACAAAC4CwAAUgEAAA==eJx11bFpJTEUhtFXgEvYEhxsAQpcwARbwJSgYAsYMAsGwzKGLUAlKHDq9bwOVIJKmBIU+BmjRNa5yQ9fcsJ7udzu55+Hz7k8PH7t9va1v57m/ffzvP/7O++vL/M+uhluhpvhZrgZboVb4Va4FW6Fe/d/7vY+ur2Pbu+j2/voBrgBboAb4Aa4EW6EG+FGuBFugpvgJrgJboJb4Ba4BW6BW+A2uA1ug9vgNrj373O399HtfXR7H93eR3eFu8Jd4a5wV7g73B3uDneHu8M94B5wD7gH3APuCfeEe8I94Z5wfxxzt/fR7X10ex/d3kd3gbvAXeAucBe4G9wN7gZ3g7vBzXAz3Aw3w81wK9wKt8KtcCvcu+vc7f3b/73O3d6//d/r3A1wA9wAN8ANcCPcCDfCjXAj3AQ3wU1wE9wEt8AtcAvcArfAbXAb3Aa3wb31D/j00eI=
+
+
+ 6566.2071244
+
+
+ 7750.7080967
+
+
+
+
+ AQAAAACAAADQBwAAaAcAAA==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
+
+
+ 0.8189999451
+
+
+ 1
+
+
+
+
+ AQAAAACAAADoAwAAlwAAAA==eJzdzz0LgkAAh/EQLShJU8QwHRrLCqRP4Kzf/0OYOVS7OTy3/CFQgoZu+XEv3HMXzoZRZ2WEO5kHaOMcV+ighYncs8cUt3jvh1FlZYcvNOsNWtJZynvM/gZDjGXdw5t0HthK19y/QFfeYX/ZfX7onjh/wSue8Yi+dLS7xmZkN+e86RcyP0zsjv3vv3TbH3e9id037pkfYA==
+
+
+
+
+ AQAAAACAAACgDgAAtwIAAA==eJxN0E2KnFAAhVGn2UDG2UEtotNQ26ht1ChLyX4SniiKoig+FEVRdJxRQuifM/tGl8tJkj8vSRJfkm+/XpPk6/fPvtF3+kE/6X87P758/9j56Bt9px/0k3778/P355//faPv9IN+0m9/3nc++kbf6Qf9pN99Aj4Bn4BPwCfgE/AJ+AR8Aj4Bn4BPwCfFJ8UnxSfFJ8UnxSfFJ8UnxSfFJ8UnxSfDJ8MnwyfDJ8MnwyfDJ8MnwyfDJ8MnwyfHJ8cnxyfHJ8cnxyfHJ8cnxyfHJ8cnx6fAp8CnwKfAp8CnwKfAp8CnwKfAp8CnwKfEp8SnxKfEp8SnxKfEp8SnxKfEp8SnxKfCp8KnwqfCp8KnwqfCp8KnwqfCp8KnwqfGp8anxqfGp8anxqfGp8anxqfGp8anxqfBp8GnwafBp8GnwafBp8GnwafBp8GnwafFp8WnxafFp8WnxafFp8WnxafFp8WnxafDp8Onw6fDp8Onw6fDp8Onw6fDp8Onw6fHp8enx6fHp8enx6fHp8enx6fHp8enx2fAZ8BnwGfAZ8BnwGfAZ8BnwGfAZ8BnwCfiE/GJ+ER8Ij4Rn4hPxCfiE/GJ+ER8RnxGfEZ8RnxGfEZ8RnxGfEZ8RnxGfEZ8JnwmfCZ8JnwmfCZ8JnwmfCZ8JnwmfCZ8ZnxmfGZ8ZnxmfGZ8ZnxmfGZ8ZnxmfGZ8FnwWfBZ8FnwWfBZ8FnwWfBZ8FnwWfBZ8VnxWfFZ8VnxWfFZ8VnxWfFZ8VnxWfFZ8Nnw2fDZ8Nnw2fDZ8Nnw2fDZ8Nnw2fDZ8dnx2fHZ8dnx2fHZ8dnx2fHZ8dnx2fHZ8DnwOfA58DnwOfA58DnwOfA58DnwOfA58TnxOfE58TnxOfE58TnxOfE58TnxOfE58LnwufC58LnwufC58LnwufC58LnwufK7Xv7ko1Ko=
+
+
+ 6534.71499
+
+
+ 7784.1184472
+
+
+
+
+
+
+ AQAAAACAAABAHwAAPQQAAA==eJyNmUXUFWQURXl0d3d3p53YoNiBgd1id4OF3YpiYIDdgYnd3S12K9jtwH0G76z1rfPfyR7tM9jTW6vW/1eBDWB92BQ2g21ga/Nqw4a2I685bGs78urARrYjrwVsZzvy6sLGtiOvJWxvO/LqwSa2I68V7GA7qU9H2An2gN3NK/WR1xn2tJ3UR14X2Mt2Uh95XWFv20l95HWDfWwn9ekL+8EhcLB5pT7y+sOhtpP6yBsAh9lO6iNvIBxuO6mPvEFwhO2kPiPhKDgBjjev1EfeaLiU7aQ+8sbApW0n9ZE3Fi5jO6mPvHFwWdtJfZaDy8NV4SrmlfrIWwFOtJ3UR96KcDXbSX3krQRXt53UR97KcA3bSX3WhGvB9eC65pX6yFsbTrGd1EfeOnB920l95E2CG9iOvFIfeZPhhraT+mwEN4ZT4RbmlfrI2wRuaTupj7xN4Va2k/rI2wxubTupj7zN4Ta2k/pMg9vCneFO5pX6yNsO7mI7qY+87eGutpP6yNsB7mY7qY+8HeHutjMNlvrsAfeE+8F9zSv1kbcX3N92Uh950+EBtpP6yNsbHmg7qY+8feBBtpP6HAwPgUfBI80r9ZF3KDzadlIfeYfBY2wn9ZF3ODzWdlIfeUfAGbaT+syEx8GT4SzzSn3kHQ9PsZ3UR94J8FTbSX3knQhPs53UR95J8HTbSX3OgGfC8+F55pX6yDsLXmA7qY+8s+GFtpP6yDsHzrad1EfeufAi20l9LoZz4BVwrnmlPvIugVfaTuoj71J4le2kPvIug1fbTuoj73I4z3ZSn/nwGngTvNG8Uh9518KbbSf1kXcdvMV2Uh9518NbbUdeqY+8G+BttpP63A7vgPfCe8wr9ZF3J7zPdlIfeXfB+20n9ZF3N3zAdlIfeQvgg7aT+iyED8En4OPmlfrIexg+aTupj7xH4FO2k/rIexQ+bTupj7zH4DO2sxCW+jwLn4OvwJfNK/WR9zx81XZSH3kvwNdsJ/WR9yJ83XZSH3kvwTdsJ/V5E74FP4Dvm1fqI+9t+KHtpD7y3oGLbCf1kfcu/Mh2Uh9578GPbSf1+QR+Cr+GX5lX6iPvM/iN7aQ+8j6H39pO6iPvC/id7aQ+8r6E39tO6vMDXAx/hb+YV+ojbwn8zXZSH3k/wt9tJ/WR9xP8w3ZSH3k/wz9tJ/X5C/4N6/DwqF2p9kp95P0D61aqd1Ifef/CepXqndRHnh419SvVO6mPvApsYDupT0PYCLaAzSvVXqmPvMawpe2kPvKawFa2k/rIawpb207qI68ZbGM7qU9b2A52gZ1r2Edee9jVdlIfeR1gN9tJfeR1hN1tJ/WR1wn2sJ3UpyfsBQfA/jXsI683HGg7qY+8PnCQ7aQ+8vrCwbaT+sjrB4fYTuozFA6DY+DoGvaRNxyOtZ3UR94IOM52Uh95I+F420l95I2CE2znPyQuuiI=
+
+
+ AQAAAACAAADoAwAAwgAAAA==eJwtxRFghAAAAMC2SRg+hmEYhmEYhmEYhmEYhmEYhmEYho+Pj4Pu5MLgEfnl2IlTZ85duHTl2o1bd+49ePTk2YtXb959+PTl229//HXw8xQ68suxE6fOnLtw6cq1G7fu3Hvw6MmzF6/evPvw6cu33/746+D3KXTkl2MnTp05d+HSlWs3bt259+DRk2cvXr159+HTl2+//fHXwd9T6Mgvx06cOnPuwqUr127cunPvwaMnz168evPuw6cv3377H1iHPNM=
+
+
+ AQAAAACAAAB9AAAADAAAAA==eJzj4RlAAABxsAXd
+
+
+
+
+
diff --git a/geos-processing/tests/data/simpleReservoirViz_small_000478/cartesianMesh/Level0/wellRegion/rank_1.vtu b/geos-processing/tests/data/simpleReservoirViz_small_000478/cartesianMesh/Level0/wellRegion/rank_1.vtu
new file mode 100755
index 000000000..de408e42a
--- /dev/null
+++ b/geos-processing/tests/data/simpleReservoirViz_small_000478/cartesianMesh/Level0/wellRegion/rank_1.vtu
@@ -0,0 +1,177 @@
+
+
+
+
+
+ AQAAAACAAAAIAAAAEAAAAA==eJxjYGBg4M5e7QgAAwwBYw==
+
+
+
+
+
+
+
+ AQAAAACAAAAQAAAAGAAAAA==eJyr11S2/MHV5XD3vZ+zuXCXAwA15QZC
+
+
+ AQAAAACAAAAgAAAAKQAAAA==eJyr11S2/MHV5RBS+SXl1N4+h7vv/ZzNhbscNHW/nm/e1+cAAOxhDuU=
+
+
+ 1289.2711608
+
+
+ 1290.006732
+
+
+
+
+ AQAAAACAAAAgAAAAEgAAAA==eJxjYACBD/YMKADBBwAqPgJf
+
+
+ 1
+
+
+ 1
+
+
+
+
+ AQAAAACAAAAgAAAACwAAAA==eJxjYMAPAAAgAAE=
+
+
+ 0
+
+
+ 0
+
+
+
+
+ AQAAAACAAAAgAAAAIAAAAA==eJxLlXPt95wmYr9H6tXBd63G9m7PxS5zLUbwAeLaDmw=
+
+
+ 0.00030807775822
+
+
+ 0.0003081262629
+
+
+
+
+ AQAAAACAAAAgAAAAKQAAAA==eJyr11S2/MHV5RBS+SXl1N4+h7vv/ZzNhbscNHW/nm/e1+cAAOxhDuU=
+
+
+ 1289.2711608
+
+
+ 1290.006732
+
+
+
+
+ AQAAAACAAABAAAAAJgAAAA==eJxjYACBD/Zes9o95u0PsGFAAR/sYXTTw2Xv+XbWYsgDAKkjDNE=
+
+
+ 1.4142135624
+
+
+ 1.4142135624
+
+
+
+
+ AQAAAACAAAAQAAAADwAAAA==eJx7x8QABp+gNAAWrAHl
+
+
+ AQAAAACAAAAQAAAAGAAAAA==eJyr11S2/MHV5XD3vZ+zuXCXAwA15QZC
+
+
+ AQAAAACAAAAgAAAAEgAAAA==eJxjYACBD/YMKADBBwAqPgJf
+
+
+ 1
+
+
+ 1
+
+
+
+
+ AQAAAACAAAAgAAAAKQAAAA==eJyr11S2/MHV5aDdtu7cHafXNnff+zmbC3c5xITrRJhaSNgCAOLrDK0=
+
+
+ 833.37120273
+
+
+ 834.40198385
+
+
+
+
+ AQAAAACAAAAIAAAADwAAAA==eJz79////39ADAAj2Af3
+
+
+ AQAAAACAAAAQAAAAGAAAAA==eJyriFNr/Pu43XF+1NKyL3/aHQFIjAjy
+
+
+ AQAAAACAAAAQAAAADgAAAA==eJz7xQABv6E0ABeIAfY=
+
+
+ AQAAAACAAAAQAAAAEQAAAA==eJxLSwMCpnKHNCgNADAYBW8=
+
+
+ AQAAAACAAAAQAAAAFgAAAA==eJzbc65Sri5ysr3taTUhEA0APtEGtA==
+
+
+ AQAAAACAAAAwAAAAGwAAAA==eJxjYACCjAYHBiS64e1OFD5c/MpOBwC/RwlU
+
+
+ 6654.0518671
+
+
+ 6678.8963347
+
+
+
+
+ AQAAAACAAAAgAAAAIQAAAA==eJxjYACBD/Zes9o95u0PsGGA8pseLnvPt7PWBgCLBgpz
+
+
+ 1
+
+
+ 1
+
+
+
+
+ AQAAAACAAAAQAAAAEwAAAA==eJyT1HUJ+a340l4SSgMAMF4GRQ==
+
+
+
+
+ AQAAAACAAAAkAAAAGgAAAA==eJxjcGB2YQDhC+ddGWBsDiS2wzlXAILzB34=
+
+
+ 6641.630071
+
+
+ 6691.319003
+
+
+
+
+
+
+ AQAAAACAAAAgAAAAEQAAAA==eJxjYIAARjSaCUoDAABYAAU=
+
+
+ AQAAAACAAAAQAAAADgAAAA==eJxjYoAAFigNAABQAAc=
+
+
+ AQAAAACAAAACAAAACgAAAA==eJxjZgYAAAsABw==
+
+
+
+
+
diff --git a/geos-processing/tests/data/tetra_cell.csv b/geos-processing/tests/data/tetra_cell.csv
new file mode 100644
index 000000000..38b971aaf
--- /dev/null
+++ b/geos-processing/tests/data/tetra_cell.csv
@@ -0,0 +1,4 @@
+0.0, 0.0, 0.0
+1.0, 0.0, 0.0
+0.0, 0.0, 1.0
+0.0, 1.0, 0.0
\ No newline at end of file
diff --git a/geos-processing/tests/data/tetra_mesh.csv b/geos-processing/tests/data/tetra_mesh.csv
new file mode 100644
index 000000000..2f3414b4a
--- /dev/null
+++ b/geos-processing/tests/data/tetra_mesh.csv
@@ -0,0 +1,32 @@
+0.0,0.0,0.0
+0.5,0.0,0.0
+0.0,0.0,0.5
+0.0,0.5,0.0
+0.0,0.5,0.0
+0.5,0.5,0.0
+0.0,0.5,0.5
+0.0,1.0,0.0
+0.5,0.5,0.0
+0.5,0.0,0.0
+0.5,0.0,0.5
+1.0,0.0,0.0
+0.5,0.0,0.5
+0.0,0.0,0.5
+0.0,0.5,0.5
+0.0,0.0,1.0
+0.0,0.0,0.5
+0.0,0.5,0.5
+0.0,0.5,0.0
+0.5,0.0,0.0
+0.5,0.0,0.0
+0.0,0.5,0.5
+0.0,0.5,0.0
+0.5,0.5,0.0
+0.5,0.0,0.0
+0.0,0.5,0.5
+0.5,0.5,0.0
+0.5,0.0,0.5
+0.5,0.0,0.5
+0.5,0.0,0.0
+0.0,0.5,0.5
+0.0,0.0,0.5
diff --git a/geos-processing/tests/data/triangle_cell.csv b/geos-processing/tests/data/triangle_cell.csv
new file mode 100644
index 000000000..b8b70c271
--- /dev/null
+++ b/geos-processing/tests/data/triangle_cell.csv
@@ -0,0 +1,3 @@
+0.0, 0.0, 0.0
+1.0, 0.0, 0.0
+0.0, 1.0, 0.0
\ No newline at end of file
diff --git a/geos-mesh/tests/data/triangulatedSurface.vtu b/geos-processing/tests/data/triangulatedSurface.vtu
similarity index 100%
rename from geos-mesh/tests/data/triangulatedSurface.vtu
rename to geos-processing/tests/data/triangulatedSurface.vtu
diff --git a/geos-mesh/tests/test_AttributeMapping.py b/geos-processing/tests/test_AttributeMapping.py
similarity index 83%
rename from geos-mesh/tests/test_AttributeMapping.py
rename to geos-processing/tests/test_AttributeMapping.py
index 8bba913c4..5a421a27b 100644
--- a/geos-mesh/tests/test_AttributeMapping.py
+++ b/geos-processing/tests/test_AttributeMapping.py
@@ -5,7 +5,7 @@
import pytest
from typing import Union, Any
from geos.mesh.utils.arrayModifiers import fillAllPartialAttributes
-from geos.mesh.processing.AttributeMapping import AttributeMapping
+from geos.processing.generic_processing_tools.AttributeMapping import AttributeMapping
from vtkmodules.vtkCommonDataModel import vtkMultiBlockDataSet, vtkDataSet
@@ -29,5 +29,5 @@ def test_AttributeMapping(
if isinstance( meshFrom, vtkMultiBlockDataSet ):
fillAllPartialAttributes( meshFrom )
- filter = AttributeMapping( meshFrom, meshTo, attributeNames, onPoints )
- assert filter.applyFilter()
+ attributeMappingFilter: AttributeMapping = AttributeMapping( meshFrom, meshTo, attributeNames, onPoints )
+ assert attributeMappingFilter.applyFilter()
diff --git a/geos-mesh/tests/test_CellTypeCounterEnhanced.py b/geos-processing/tests/test_CellTypeCounterEnhanced.py
similarity index 83%
rename from geos-mesh/tests/test_CellTypeCounterEnhanced.py
rename to geos-processing/tests/test_CellTypeCounterEnhanced.py
index d948d430d..030977759 100644
--- a/geos-mesh/tests/test_CellTypeCounterEnhanced.py
+++ b/geos-processing/tests/test_CellTypeCounterEnhanced.py
@@ -10,7 +10,7 @@
Iterator, )
from geos.mesh.utils.genericHelpers import createSingleCellMesh, createMultiCellMesh
-from geos.mesh.stats.CellTypeCounterEnhanced import CellTypeCounterEnhanced
+from geos.processing.pre_processing.CellTypeCounterEnhanced import CellTypeCounterEnhanced
from geos.mesh.model.CellTypeCounts import CellTypeCounts
from vtkmodules.vtkCommonDataModel import (
@@ -36,7 +36,7 @@
filename_all2: tuple[ str, ...] = ( "tetra_mesh.csv", "hexa_mesh.csv" )
cellType_all2: tuple[ int, ...] = ( VTK_TETRA, VTK_HEXAHEDRON )
-nbPtsCell_all2: tuple[ int ] = ( 4, 8 )
+nbPtsCell_all2: tuple[ int, ...] = ( 4, 8 )
@dataclass( frozen=True )
@@ -71,18 +71,18 @@ def test_CellTypeCounterEnhanced_single( test_case: TestCase ) -> None:
Args:
test_case (TestCase): Test case
"""
- filter: CellTypeCounterEnhanced = CellTypeCounterEnhanced()
- filter.SetInputDataObject( test_case.mesh )
- filter.Update()
- countsObs: CellTypeCounts = filter.GetCellTypeCountsObject()
+ cellTypeCounterEnhancedFilter: CellTypeCounterEnhanced = CellTypeCounterEnhanced()
+ cellTypeCounterEnhancedFilter.SetInputDataObject( test_case.mesh )
+ cellTypeCounterEnhancedFilter.Update()
+ countsObs: CellTypeCounts = cellTypeCounterEnhancedFilter.GetCellTypeCountsObject()
assert countsObs is not None, "CellTypeCounts is undefined"
assert countsObs.getTypeCount( VTK_VERTEX ) == test_case.mesh.GetNumberOfPoints(
), f"Number of vertices should be {test_case.mesh.GetNumberOfPoints()}"
# compute counts for each type of cell
- elementTypes: tuple[ int ] = ( VTK_TRIANGLE, VTK_QUAD, VTK_TETRA, VTK_PYRAMID, VTK_HEXAHEDRON, VTK_WEDGE )
- counts: npt.NDArray[ np.int64 ] = np.zeros( len( elementTypes ) )
+ elementTypes: tuple[ int, ...] = ( VTK_TRIANGLE, VTK_QUAD, VTK_TETRA, VTK_PYRAMID, VTK_HEXAHEDRON, VTK_WEDGE )
+ counts: npt.NDArray[ np.int64 ] = np.zeros( len( elementTypes ), dtype=np.int64 )
for i in range( test_case.mesh.GetNumberOfCells() ):
cell: vtkCell = test_case.mesh.GetCell( i )
index: int = elementTypes.index( cell.GetCellType() )
@@ -94,7 +94,7 @@ def test_CellTypeCounterEnhanced_single( test_case: TestCase ) -> None:
) == counts[ i ], f"The number of {vtkCellTypes.GetClassNameFromTypeId(elementType)} should be {counts[i]}."
nbPolygon: int = counts[ 0 ] + counts[ 1 ]
- nbPolyhedra: int = np.sum( counts[ 2: ] )
+ nbPolyhedra: int = np.sum( counts[ 2: ], dtype=int )
assert int( countsObs.getTypeCount( VTK_POLYGON ) ) == nbPolygon, f"The number of faces should be {nbPolygon}."
assert int(
countsObs.getTypeCount( VTK_POLYHEDRON ) ) == nbPolyhedra, f"The number of polyhedra should be {nbPolyhedra}."
@@ -130,17 +130,17 @@ def test_CellTypeCounterEnhanced_multi( test_case: TestCase ) -> None:
Args:
test_case (TestCase): Test case
"""
- filter: CellTypeCounterEnhanced = CellTypeCounterEnhanced()
- filter.SetInputDataObject( test_case.mesh )
- filter.Update()
- countsObs: CellTypeCounts = filter.GetCellTypeCountsObject()
+ cellTypeCounterEnhancedFilter: CellTypeCounterEnhanced = CellTypeCounterEnhanced()
+ cellTypeCounterEnhancedFilter.SetInputDataObject( test_case.mesh )
+ cellTypeCounterEnhancedFilter.Update()
+ countsObs: CellTypeCounts = cellTypeCounterEnhancedFilter.GetCellTypeCountsObject()
assert countsObs is not None, "CellTypeCounts is undefined"
assert countsObs.getTypeCount( VTK_VERTEX ) == test_case.mesh.GetNumberOfPoints(
), f"Number of vertices should be {test_case.mesh.GetNumberOfPoints()}"
# compute counts for each type of cell
- elementTypes: tuple[ int ] = ( VTK_TRIANGLE, VTK_QUAD, VTK_TETRA, VTK_PYRAMID, VTK_HEXAHEDRON, VTK_WEDGE )
+ elementTypes: tuple[ int, ...] = ( VTK_TRIANGLE, VTK_QUAD, VTK_TETRA, VTK_PYRAMID, VTK_HEXAHEDRON, VTK_WEDGE )
counts: npt.NDArray[ np.int64 ] = np.zeros( len( elementTypes ), dtype=int )
for i in range( test_case.mesh.GetNumberOfCells() ):
cell: vtkCell = test_case.mesh.GetCell( i )
@@ -153,7 +153,7 @@ def test_CellTypeCounterEnhanced_multi( test_case: TestCase ) -> None:
) == counts[ i ], f"The number of {vtkCellTypes.GetClassNameFromTypeId(elementType)} should be {counts[i]}."
nbPolygon: int = counts[ 0 ] + counts[ 1 ]
- nbPolyhedra: int = np.sum( counts[ 2: ] )
+ nbPolyhedra: int = np.sum( counts[ 2: ], dtype=int )
assert int( countsObs.getTypeCount( VTK_POLYGON ) ) == nbPolygon, f"The number of faces should be {nbPolygon}."
assert int(
- countsObs.getTypeCount( VTK_POLYHEDRON ) ) == nbPolyhedra, f"The number of polyhedra should be {nbPolyhedra}."
\ No newline at end of file
+ countsObs.getTypeCount( VTK_POLYHEDRON ) ) == nbPolyhedra, f"The number of polyhedra should be {nbPolyhedra}."
diff --git a/geos-mesh/tests/test_CreateConstantAttributePerRegion.py b/geos-processing/tests/test_CreateConstantAttributePerRegion.py
similarity index 94%
rename from geos-mesh/tests/test_CreateConstantAttributePerRegion.py
rename to geos-processing/tests/test_CreateConstantAttributePerRegion.py
index 3821c710b..988967636 100644
--- a/geos-mesh/tests/test_CreateConstantAttributePerRegion.py
+++ b/geos-processing/tests/test_CreateConstantAttributePerRegion.py
@@ -8,7 +8,7 @@
from typing import Union, Any
from vtkmodules.vtkCommonDataModel import ( vtkDataSet, vtkMultiBlockDataSet )
-from geos.mesh.processing.CreateConstantAttributePerRegion import CreateConstantAttributePerRegion
+from geos.processing.generic_processing_tools.CreateConstantAttributePerRegion import CreateConstantAttributePerRegion
import numpy as np
@@ -110,7 +110,7 @@ def test_CreateConstantAttributePerRegion(
if nbComponents == 0: # If the attribute has one component, the component has no name.
nbComponents += 1
- filter: CreateConstantAttributePerRegion = CreateConstantAttributePerRegion(
+ createConstantAttributePerRegionFilter: CreateConstantAttributePerRegion = CreateConstantAttributePerRegion(
mesh,
regionName,
dictRegionValues,
@@ -120,4 +120,4 @@ def test_CreateConstantAttributePerRegion(
componentNames=componentNames,
)
- assert filter.applyFilter() == succeed
+ assert createConstantAttributePerRegionFilter.applyFilter() == succeed
diff --git a/geos-mesh/tests/test_FillPartialArrays.py b/geos-processing/tests/test_FillPartialArrays.py
similarity index 81%
rename from geos-mesh/tests/test_FillPartialArrays.py
rename to geos-processing/tests/test_FillPartialArrays.py
index b1fd8f3a4..e5720d0f5 100644
--- a/geos-mesh/tests/test_FillPartialArrays.py
+++ b/geos-processing/tests/test_FillPartialArrays.py
@@ -9,7 +9,7 @@
from typing import Any
from vtkmodules.vtkCommonDataModel import vtkMultiBlockDataSet
-from geos.mesh.processing.FillPartialArrays import FillPartialArrays
+from geos.processing.generic_processing_tools.FillPartialArrays import FillPartialArrays
@pytest.mark.parametrize( "dictAttributesValues", [
@@ -49,5 +49,5 @@ def test_FillPartialArrays(
"""Test FillPartialArrays vtk filter."""
multiBlockDataSet: vtkMultiBlockDataSet = dataSetTest( "multiblock" )
- filter: FillPartialArrays = FillPartialArrays( multiBlockDataSet, dictAttributesValues )
- assert filter.applyFilter()
+ fillPartialArraysFilter: FillPartialArrays = FillPartialArrays( multiBlockDataSet, dictAttributesValues )
+ assert fillPartialArraysFilter.applyFilter()
diff --git a/geos-mesh/tests/test_MergeBlocksEnhanced.py b/geos-processing/tests/test_MergeBlocksEnhanced.py
similarity index 68%
rename from geos-mesh/tests/test_MergeBlocksEnhanced.py
rename to geos-processing/tests/test_MergeBlocksEnhanced.py
index a5db36f32..677a99d98 100644
--- a/geos-mesh/tests/test_MergeBlocksEnhanced.py
+++ b/geos-processing/tests/test_MergeBlocksEnhanced.py
@@ -6,7 +6,7 @@
# mypy: disable-error-code="operator"
from vtkmodules.vtkCommonDataModel import vtkMultiBlockDataSet
-from geos.mesh.processing.MergeBlockEnhanced import MergeBlockEnhanced
+from geos.processing.generic_processing_tools.MergeBlockEnhanced import MergeBlockEnhanced
from unittest import TestCase
from geos.utils.Errors import VTKError
@@ -17,15 +17,16 @@
def test_MergeBlocksEnhancedFilter( dataSetTest: vtkMultiBlockDataSet, ) -> None:
"""Test MergeBlockEnhanced vtk filter."""
multiBlockDataset: vtkMultiBlockDataSet = dataSetTest( "multiblockGeosOutput" )
- filter: MergeBlockEnhanced = MergeBlockEnhanced( multiBlockDataset )
- filter.applyFilter()
+ mergeBlockEnhancedFilter: MergeBlockEnhanced = MergeBlockEnhanced( multiBlockDataset )
+ mergeBlockEnhancedFilter.applyFilter()
class RaiseMergeBlocksEnhanced( TestCase ):
"""Test failure on empty multiBlockDataSet."""
def test_TypeError( self ) -> None:
+ """Test raise of TypeError."""
multiBlockDataset = vtkMultiBlockDataSet() # should fail on empty data
- filter: MergeBlockEnhanced = MergeBlockEnhanced( multiBlockDataset )
+ mergeBlockEnhancedFilter: MergeBlockEnhanced = MergeBlockEnhanced( multiBlockDataset )
if Version( vtk.__version__ ) < Version( "9.5" ):
- self.assertRaises( VTKError, filter.applyFilter )
+ self.assertRaises( VTKError, mergeBlockEnhancedFilter.applyFilter )
diff --git a/geos-mesh/tests/test_MeshQualityEnhanced.py b/geos-processing/tests/test_MeshQualityEnhanced.py
similarity index 79%
rename from geos-mesh/tests/test_MeshQualityEnhanced.py
rename to geos-processing/tests/test_MeshQualityEnhanced.py
index 7ae8717d6..a86e2c974 100644
--- a/geos-mesh/tests/test_MeshQualityEnhanced.py
+++ b/geos-processing/tests/test_MeshQualityEnhanced.py
@@ -13,9 +13,9 @@
Optional,
)
from geos.mesh.utils.genericHelpers import createMultiCellMesh
-from geos.mesh.processing.meshQualityMetricHelpers import (
+from geos.mesh.stats.meshQualityMetricHelpers import (
getAllCellTypesExtended, )
-from geos.mesh.stats.MeshQualityEnhanced import MeshQualityEnhanced
+from geos.processing.pre_processing.MeshQualityEnhanced import MeshQualityEnhanced
from geos.mesh.model.QualityMetricSummary import QualityMetricSummary
from vtkmodules.vtkFiltersVerdict import vtkMeshQuality
@@ -28,8 +28,8 @@
"polydata",
"tetra_mesh",
)
-cellTypes_all: set[ int ] = ( VTK_TRIANGLE, VTK_TETRA )
-qualityMetrics_all: tuple[ set[ int ], ...] = (
+cellTypes_all: tuple[ int, ...] = ( VTK_TRIANGLE, VTK_TETRA )
+qualityMetrics_all: tuple[ tuple[ int, ...], ...] = (
( int( vtkMeshQuality.QualityMeasureTypes.ASPECT_RATIO ), int( vtkMeshQuality.QualityMeasureTypes.SCALED_JACOBIAN ),
int( vtkMeshQuality.QualityMeasureTypes.MAX_ANGLE ) ),
( int( vtkMeshQuality.QualityMeasureTypes.SCALED_JACOBIAN ),
@@ -41,7 +41,7 @@
( 26324, 0, 0, 0, 0, 0, 26324, 0, ),
( 0, 0, 8, 0, 0, 0, 0, 8,)
)
-metricsSummary_all: tuple[ tuple[ float, ...], ...] = (
+metricsSummary_all: tuple[ tuple[ tuple[ float, ...], ...], ...] = (
( ( 1.07, 0.11, 1.0, 1.94, 26324.0 ), ( 0.91, 0.1, 0.53, 1.0, 26324.0 ), ( 64.59, 6.73, 60.00, 110.67, 26324.0 ) ),
( ( -0.28, 0.09, -0.49, -0.22, 8.0 ), ( 0.7, 0.1, 0.47, 0.79, 8.0 ), ( 0.8, 0.12, 0.58, 0.95, 8.0 ) ),
)
@@ -54,10 +54,10 @@ class TestCase:
__test__ = False
#: mesh
mesh: vtkUnstructuredGrid
- cellType: vtkCellTypes
- qualityMetrics: set[ int ]
- cellTypeCounts: tuple[ int ]
- metricsSummary: tuple[ float ]
+ cellType: int
+ qualityMetrics: tuple[ int, ...]
+ cellTypeCounts: tuple[ int, ...]
+ metricsSummary: tuple[ tuple[ float, ...], ...]
def __get_tetra_dataset() -> vtkUnstructuredGrid:
@@ -83,8 +83,15 @@ def __get_tetra_dataset() -> vtkUnstructuredGrid:
return mesh
-def __get_dataset( meshName ) -> vtkUnstructuredGrid:
- # Get the dataset from external vtk file
+def __get_dataset( meshName: str ) -> vtkUnstructuredGrid:
+ """Get the dataset from external vtk file.
+
+ Args:
+ meshName (str): The name of the mesh
+
+ Returns:
+ vtkUnstructuredGrid: The dataset.
+ """
if meshName == "polydata":
reader: vtkXMLUnstructuredGridReader = vtkXMLUnstructuredGridReader()
vtkFilename: str = "data/triangulatedSurface.vtu"
@@ -109,10 +116,7 @@ def __generate_test_data() -> Iterator[ TestCase ]:
metricsSummary_all,
strict=True ):
mesh: vtkUnstructuredGrid
- if meshName == "tetra_mesh":
- mesh = __get_tetra_dataset()
- else:
- mesh = __get_dataset( meshName )
+ mesh = __get_tetra_dataset() if meshName == "tetra_mesh" else __get_dataset( meshName )
yield TestCase( mesh, cellType, qualityMetrics, cellTypeCounts, metricsSummary )
@@ -128,30 +132,31 @@ def test_MeshQualityEnhanced( test_case: TestCase ) -> None:
test_case (TestCase): Test case
"""
mesh = test_case.mesh
- filter: MeshQualityEnhanced = MeshQualityEnhanced()
- filter.SetInputDataObject( mesh )
+ meshQualityEnhancedFilter: MeshQualityEnhanced = MeshQualityEnhanced()
+ meshQualityEnhancedFilter.SetInputDataObject( mesh )
if test_case.cellType == VTK_TRIANGLE:
- filter.SetTriangleMetrics( test_case.qualityMetrics )
+ meshQualityEnhancedFilter.SetTriangleMetrics( test_case.qualityMetrics )
elif test_case.cellType == VTK_QUAD:
- filter.SetQuadMetrics( test_case.qualityMetrics )
+ meshQualityEnhancedFilter.SetQuadMetrics( test_case.qualityMetrics )
elif test_case.cellType == VTK_TETRA:
- filter.SetTetraMetrics( test_case.qualityMetrics )
+ meshQualityEnhancedFilter.SetTetraMetrics( test_case.qualityMetrics )
elif test_case.cellType == VTK_PYRAMID:
- filter.SetPyramidMetrics( test_case.qualityMetrics )
+ meshQualityEnhancedFilter.SetPyramidMetrics( test_case.qualityMetrics )
elif test_case.cellType == VTK_WEDGE:
- filter.SetWedgeMetrics( test_case.qualityMetrics )
+ meshQualityEnhancedFilter.SetWedgeMetrics( test_case.qualityMetrics )
elif test_case.cellType == VTK_HEXAHEDRON:
- filter.SetHexaMetrics( test_case.qualityMetrics )
- filter.Update()
+ meshQualityEnhancedFilter.SetHexaMetrics( test_case.qualityMetrics )
+ meshQualityEnhancedFilter.Update()
# test method getComputedMetricsFromCellType
for i, cellType in enumerate( getAllCellTypesExtended() ):
- metrics: Optional[ set[ int ] ] = filter.getComputedMetricsFromCellType( cellType )
+ print( cellType )
+ metrics: Optional[ set[ int ] ] = meshQualityEnhancedFilter.getComputedMetricsFromCellType( cellType )
if test_case.cellTypeCounts[ i ] > 0:
assert metrics is not None, f"Metrics from {vtkCellTypes.GetClassNameFromTypeId(cellType)} cells is undefined."
# test attributes
- outputMesh: vtkUnstructuredGrid = filter.GetOutputDataObject( 0 )
+ outputMesh: vtkUnstructuredGrid = meshQualityEnhancedFilter.GetOutputDataObject( 0 )
cellData: vtkCellData = outputMesh.GetCellData()
assert cellData is not None, "Cell data is undefined."
@@ -172,7 +177,7 @@ def test_MeshQualityEnhanced( test_case: TestCase ) -> None:
assert fieldData.GetNumberOfArrays(
) == nbFieldArrayExp, f"Number of field data arrays is expected to be {nbFieldArrayExp}."
- stats: QualityMetricSummary = filter.GetQualityMetricSummary()
+ stats: QualityMetricSummary = meshQualityEnhancedFilter.GetQualityMetricSummary()
for i, cellType in enumerate( getAllCellTypesExtended() ):
# test Counts
assert stats.getCellTypeCountsOfCellType( cellType ) == test_case.cellTypeCounts[
diff --git a/geos-mesh/tests/test_SplitMesh.py b/geos-processing/tests/test_SplitMesh.py
similarity index 97%
rename from geos-mesh/tests/test_SplitMesh.py
rename to geos-processing/tests/test_SplitMesh.py
index 2a73cb58a..0612b7290 100644
--- a/geos-mesh/tests/test_SplitMesh.py
+++ b/geos-processing/tests/test_SplitMesh.py
@@ -10,7 +10,7 @@
Iterator, )
from geos.mesh.utils.genericHelpers import createSingleCellMesh
-from geos.mesh.processing.SplitMesh import SplitMesh
+from geos.processing.generic_processing_tools.SplitMesh import SplitMesh
from vtkmodules.util.numpy_support import vtk_to_numpy
@@ -117,7 +117,7 @@ class TestCase:
#: expected new point coordinates
pointsExp: npt.NDArray[ np.float64 ]
#: expected new cell point ids
- cellsExp: list[ int ]
+ cellsExp: list[ list[ int ] ]
def __generate_split_mesh_test_data() -> Iterator[ TestCase ]:
@@ -149,10 +149,10 @@ def test_single_cell_split( test_case: TestCase ) -> None:
test_case (TestCase): test case
"""
cellTypeName: str = vtkCellTypes.GetClassNameFromTypeId( test_case.cellType )
- filter: SplitMesh = SplitMesh()
- filter.SetInputDataObject( test_case.mesh )
- filter.Update()
- output: vtkUnstructuredGrid = filter.GetOutputDataObject( 0 )
+ splitMeshFilter: SplitMesh = SplitMesh()
+ splitMeshFilter.SetInputDataObject( test_case.mesh )
+ splitMeshFilter.Update()
+ output: vtkUnstructuredGrid = splitMeshFilter.GetOutputDataObject( 0 )
assert output is not None, "Output mesh is undefined."
pointsOut: vtkPoints = output.GetPoints()
assert pointsOut is not None, "Points from output mesh are undefined."
diff --git a/geos-mesh/tests/test_clipToMainFrame.py b/geos-processing/tests/test_clipToMainFrame.py
similarity index 90%
rename from geos-mesh/tests/test_clipToMainFrame.py
rename to geos-processing/tests/test_clipToMainFrame.py
index 12f2c1940..3324ada33 100644
--- a/geos-mesh/tests/test_clipToMainFrame.py
+++ b/geos-processing/tests/test_clipToMainFrame.py
@@ -14,7 +14,7 @@
import numpy.typing as npt
from vtkmodules.util.vtkConstants import VTK_HEXAHEDRON
-from geos.mesh.processing.ClipToMainFrame import ClipToMainFrame
+from geos.processing.generic_processing_tools.ClipToMainFrame import ClipToMainFrame
Lx, Ly, Lz = 5, 2, 8
nx, ny, nz = 10, 10, 10
@@ -102,11 +102,11 @@ def __build_test_mesh( mxx: Tuple[ int, ...] ) -> Generator[ Expected, None, Non
"expected", [ item for t in list( itertools.product( [ -1, 1 ], repeat=3 ) ) for item in __build_test_mesh( t ) ] )
def test_clipToMainFrame_polyhedron( expected: Expected ) -> None:
"""Test the ClipToMainFrameFilter on a rotated and translated box hexa mesh."""
- filter = ClipToMainFrame()
- filter.SetInputData( expected.mesh )
- filter.ComputeTransform()
- filter.Update()
- output_mesh: vtkUnstructuredGrid = filter.GetOutput()
+ clipToMainFrameFilter = ClipToMainFrame()
+ clipToMainFrameFilter.SetInputData( expected.mesh )
+ clipToMainFrameFilter.ComputeTransform()
+ clipToMainFrameFilter.Update()
+ output_mesh: vtkUnstructuredGrid = clipToMainFrameFilter.GetOutput()
assert output_mesh.GetNumberOfPoints() == expected.mesh.GetNumberOfPoints()
assert output_mesh.GetNumberOfCells() == expected.mesh.GetNumberOfCells()
@@ -133,12 +133,12 @@ def test_clipToMainFrame_polyhedron( expected: Expected ) -> None:
def test_clipToMainFrame_generic( dataSetTest: vtkMultiBlockDataSet ) -> None:
"""Test the ClipToMainFrameFilter on a MultiBlockDataSet."""
multiBlockDataSet: vtkMultiBlockDataSet = dataSetTest( "multiblock" )
- filter = ClipToMainFrame()
- filter.SetInputData( multiBlockDataSet )
- filter.ComputeTransform()
- filter.Update()
- print( filter.GetTransform() )
- output_mesh: vtkMultiBlockDataSet = filter.GetOutputDataObject( 0 )
+ clipToMainFrameFilter = ClipToMainFrame()
+ clipToMainFrameFilter.SetInputData( multiBlockDataSet )
+ clipToMainFrameFilter.ComputeTransform()
+ clipToMainFrameFilter.Update()
+ print( clipToMainFrameFilter.GetTransform() )
+ output_mesh: vtkMultiBlockDataSet = clipToMainFrameFilter.GetOutputDataObject( 0 )
assert output_mesh.GetNumberOfPoints() == multiBlockDataSet.GetNumberOfPoints()
assert output_mesh.GetNumberOfCells() == multiBlockDataSet.GetNumberOfCells()
assert output_mesh.IsA( 'vtkMultiBlockDataSet' )
diff --git a/geos-pv/src/geos/pv/plugins/PVAttributeMapping.py b/geos-pv/src/geos/pv/plugins/PVAttributeMapping.py
index 90e914e0c..a8dfc28c2 100644
--- a/geos-pv/src/geos/pv/plugins/PVAttributeMapping.py
+++ b/geos-pv/src/geos/pv/plugins/PVAttributeMapping.py
@@ -14,7 +14,7 @@
update_paths()
-from geos.mesh.processing.AttributeMapping import AttributeMapping
+from geos.processing.generic_processing_tools.AttributeMapping import AttributeMapping
from paraview.util.vtkAlgorithm import ( # type: ignore[import-not-found]
VTKPythonAlgorithmBase, smdomain, smhint, smproperty, smproxy,
)
@@ -188,12 +188,13 @@ def RequestData(
outData.ShallowCopy( meshTo )
- filter: AttributeMapping = AttributeMapping( meshFrom, outData, set( self.attributeNames ), self.onPoints,
- True )
- if not filter.logger.hasHandlers():
- filter.setLoggerHandler( VTKHandler() )
+ attributeMappingFilter: AttributeMapping = AttributeMapping( meshFrom, outData, set( self.attributeNames ),
+ self.onPoints, True )
- filter.applyFilter()
+ if not attributeMappingFilter.logger.hasHandlers():
+ attributeMappingFilter.setLoggerHandler( VTKHandler() )
+
+ attributeMappingFilter.applyFilter()
self.clearAttributeNames = True
return 1
diff --git a/geos-pv/src/geos/pv/plugins/PVCellTypeCounterEnhanced.py b/geos-pv/src/geos/pv/plugins/PVCellTypeCounterEnhanced.py
index 0fdfea560..c5d3f0466 100644
--- a/geos-pv/src/geos/pv/plugins/PVCellTypeCounterEnhanced.py
+++ b/geos-pv/src/geos/pv/plugins/PVCellTypeCounterEnhanced.py
@@ -26,7 +26,7 @@
update_paths()
-from geos.mesh.stats.CellTypeCounterEnhanced import CellTypeCounterEnhanced
+from geos.processing.pre_processing.CellTypeCounterEnhanced import CellTypeCounterEnhanced
from geos.mesh.model.CellTypeCounts import CellTypeCounts
__doc__ = """
@@ -137,13 +137,13 @@ def RequestData(
assert inputMesh is not None, "Input server mesh is null."
assert outputTable is not None, "Output pipeline is null."
- filter: CellTypeCounterEnhanced = CellTypeCounterEnhanced()
- filter.SetInputDataObject( inputMesh )
- filter.Update()
- outputTable.ShallowCopy( filter.GetOutputDataObject( 0 ) )
+ cellTypeCounterEnhancedFilter: CellTypeCounterEnhanced = CellTypeCounterEnhanced()
+ cellTypeCounterEnhancedFilter.SetInputDataObject( inputMesh )
+ cellTypeCounterEnhancedFilter.Update()
+ outputTable.ShallowCopy( cellTypeCounterEnhancedFilter.GetOutputDataObject( 0 ) )
# print counts in Output Messages view
- counts: CellTypeCounts = filter.GetCellTypeCountsObject()
+ counts: CellTypeCounts = cellTypeCounterEnhancedFilter.GetCellTypeCountsObject()
self._countsAll += counts
# save to file if asked
diff --git a/geos-pv/src/geos/pv/plugins/PVClipToMainFrame.py b/geos-pv/src/geos/pv/plugins/PVClipToMainFrame.py
index cb29430f7..ac5bad1b9 100644
--- a/geos-pv/src/geos/pv/plugins/PVClipToMainFrame.py
+++ b/geos-pv/src/geos/pv/plugins/PVClipToMainFrame.py
@@ -22,8 +22,8 @@
update_paths()
-from geos.pv.utils.details import SISOFilter, FilterCategory
-from geos.mesh.processing.ClipToMainFrame import ClipToMainFrame
+from geos.pv.utils.details import ( SISOFilter, FilterCategory )
+from geos.processing.generic_processing_tools.ClipToMainFrame import ClipToMainFrame
__doc__ = """
Clip the input mesh to the main frame applying the correct LandmarkTransform
diff --git a/geos-pv/src/geos/pv/plugins/PVCreateConstantAttributePerRegion.py b/geos-pv/src/geos/pv/plugins/PVCreateConstantAttributePerRegion.py
index aabb2e561..8865739d6 100644
--- a/geos-pv/src/geos/pv/plugins/PVCreateConstantAttributePerRegion.py
+++ b/geos-pv/src/geos/pv/plugins/PVCreateConstantAttributePerRegion.py
@@ -25,7 +25,7 @@
geos_pv_path: Path = Path( __file__ ).parent.parent.parent.parent.parent
sys.path.insert( 0, str( geos_pv_path / "src" ) )
-from geos.mesh.processing.CreateConstantAttributePerRegion import ( CreateConstantAttributePerRegion )
+from geos.processing.generic_processing_tools.CreateConstantAttributePerRegion import CreateConstantAttributePerRegion
from geos.pv.utils.details import SISOFilter, FilterCategory
@@ -280,7 +280,7 @@ def Filter( self, inputMesh: vtkDataSet, outputMesh: vtkDataSet ) -> None:
inputMesh : A mesh to transform
outputMesh : A mesh transformed.
"""
- filter: CreateConstantAttributePerRegion = CreateConstantAttributePerRegion(
+ createConstantAttributePerRegionFilter: CreateConstantAttributePerRegion = CreateConstantAttributePerRegion(
outputMesh,
self.regionName,
self.dictRegionValues,
@@ -291,10 +291,10 @@ def Filter( self, inputMesh: vtkDataSet, outputMesh: vtkDataSet ) -> None:
self.speHandler,
)
- if not filter.logger.hasHandlers():
- filter.setLoggerHandler( VTKHandler() )
+ if not createConstantAttributePerRegionFilter.logger.hasHandlers():
+ createConstantAttributePerRegionFilter.setLoggerHandler( VTKHandler() )
- filter.applyFilter()
+ createConstantAttributePerRegionFilter.applyFilter()
self.clearDictRegion = True
diff --git a/geos-pv/src/geos/pv/plugins/PVFillPartialArrays.py b/geos-pv/src/geos/pv/plugins/PVFillPartialArrays.py
index b5c60dc8c..5bf662340 100644
--- a/geos-pv/src/geos/pv/plugins/PVFillPartialArrays.py
+++ b/geos-pv/src/geos/pv/plugins/PVFillPartialArrays.py
@@ -4,7 +4,7 @@
# ruff: noqa: E402 # disable Module level import not at top of file
import sys
from pathlib import Path
-from typing import Union, Any
+from typing import Any, Optional, Union
from typing_extensions import Self
from paraview.util.vtkAlgorithm import ( # type: ignore[import-not-found]
@@ -25,7 +25,7 @@
update_paths()
from geos.pv.utils.details import SISOFilter, FilterCategory
-from geos.mesh.processing.FillPartialArrays import FillPartialArrays
+from geos.processing.generic_processing_tools.FillPartialArrays import FillPartialArrays
__doc__ = """
Fill partial arrays of input mesh.
@@ -75,12 +75,12 @@ def __init__( self: Self, ) -> None:
""" )
- def setDictAttributesValues( self: Self, attributeName: str, values: str ) -> None:
+ def setDictAttributesValues( self: Self, attributeName: Optional[ str ], values: Optional[ str ] ) -> None:
"""Set the dictionary with the region indexes and its corresponding list of value for each components.
Args:
- attributeName (str): Name of the attribute to consider.
- values (str): List of the filing values. If multiple components use a comma between the value of each component.
+ attributeName (Optional[str]): Name of the attribute to consider.
+ values (Optional[str]): List of the filing values. If multiple components use a comma between the value of each component.
"""
if self.clearDictAttributesValues:
self.dictAttributesValues = {}
@@ -90,28 +90,28 @@ def setDictAttributesValues( self: Self, attributeName: str, values: str ) -> No
if values is not None:
self.dictAttributesValues[ attributeName ] = list( values.split( "," ) )
else:
- self.dictAttributesValues[ attributeName ] = None #ignore : type[unreachable]
+ self.dictAttributesValues[ attributeName ] = None
self.Modified()
def Filter( self, inputMesh: vtkMultiBlockDataSet, outputMesh: vtkMultiBlockDataSet ) -> None:
- """Is applying FillPartialArrays to the mesh and return with the class's dictionnary for attributes values.
+ """Is applying FillPartialArrays to the mesh and return with the class's dictionary for attributes values.
Args:
inputMesh : A mesh to transform.
outputMesh : A mesh transformed.
"""
- filter: FillPartialArrays = FillPartialArrays(
+ fillPartialArraysFilter: FillPartialArrays = FillPartialArrays(
outputMesh,
self.dictAttributesValues,
speHandler=True,
)
- if not filter.logger.hasHandlers():
- filter.setLoggerHandler( VTKHandler() )
+ if not fillPartialArraysFilter.logger.hasHandlers():
+ fillPartialArraysFilter.setLoggerHandler( VTKHandler() )
- filter.applyFilter()
+ fillPartialArraysFilter.applyFilter()
self.clearDictAttributesValues = True
diff --git a/geos-pv/src/geos/pv/plugins/PVMergeBlocksEnhanced.py b/geos-pv/src/geos/pv/plugins/PVMergeBlocksEnhanced.py
index ea852b950..3ebcd7ebb 100644
--- a/geos-pv/src/geos/pv/plugins/PVMergeBlocksEnhanced.py
+++ b/geos-pv/src/geos/pv/plugins/PVMergeBlocksEnhanced.py
@@ -29,7 +29,7 @@
update_paths()
-from geos.mesh.processing.MergeBlockEnhanced import MergeBlockEnhanced
+from geos.processing.generic_processing_tools.MergeBlockEnhanced import MergeBlockEnhanced
__doc__ = """
Merge Blocks Keeping Partial Attributes is a Paraview plugin filter that allows to merge blocks from a multiblock dataset while keeping partial attributes.
@@ -117,17 +117,17 @@ def RequestData(
assert inputMesh is not None, "Input mesh is null."
assert outputMesh is not None, "Output pipeline is null."
- filter: MergeBlockEnhanced = MergeBlockEnhanced( inputMesh, True )
+ mergeBlockEnhancedFilter: MergeBlockEnhanced = MergeBlockEnhanced( inputMesh, True )
- if not filter.logger.hasHandlers():
- filter.setLoggerHandler( VTKHandler() )
+ if not mergeBlockEnhancedFilter.logger.hasHandlers():
+ mergeBlockEnhancedFilter.setLoggerHandler( VTKHandler() )
try:
- filter.applyFilter()
+ mergeBlockEnhancedFilter.applyFilter()
except ( ValueError, TypeError, RuntimeError ) as e:
- filter.logger.error( f"MergeBlock failed due to {e}", exc_info=True )
+ mergeBlockEnhancedFilter.logger.error( f"MergeBlock failed due to {e}", exc_info=True )
return 0
else:
- outputMesh.ShallowCopy( filter.getOutput() )
+ outputMesh.ShallowCopy( mergeBlockEnhancedFilter.getOutput() )
outputMesh.Modified()
return 1
diff --git a/geos-pv/src/geos/pv/plugins/PVMeshQualityEnhanced.py b/geos-pv/src/geos/pv/plugins/PVMeshQualityEnhanced.py
index 2145fc1d4..ebccf9db1 100644
--- a/geos-pv/src/geos/pv/plugins/PVMeshQualityEnhanced.py
+++ b/geos-pv/src/geos/pv/plugins/PVMeshQualityEnhanced.py
@@ -22,9 +22,9 @@
update_paths()
from geos.mesh.model.QualityMetricSummary import QualityMetricSummary
-from geos.mesh.stats.MeshQualityEnhanced import MeshQualityEnhanced
+from geos.processing.pre_processing.MeshQualityEnhanced import MeshQualityEnhanced
-from geos.mesh.processing.meshQualityMetricHelpers import (
+from geos.mesh.stats.meshQualityMetricHelpers import (
getQualityMetricsOther,
getQualityMeasureNameFromIndex,
getQualityMeasureIndexFromName,
@@ -41,7 +41,7 @@
createModifiedCallback, )
from geos.pv.utils.paraviewTreatments import getArrayChoices
-from geos.pv.utils.details import SISOFilter, FilterCategory
+from geos.pv.utils.details import ( SISOFilter, FilterCategory )
__doc__ = """
The ``Mesh Quality Enhanced`` filter computes requested mesh quality metrics on meshes. Both surfaces and volumic metrics can be computed with this plugin.
@@ -239,23 +239,23 @@ def Filter( self, inputMesh: vtkUnstructuredGrid, outputMesh: vtkUnstructuredGri
self._getQualityMetricsToUse( self._HexQualityMetric ) )
otherMetrics: set[ int ] = self._getQualityMetricsToUse( self._commonMeshQualityMetric )
- filter: MeshQualityEnhanced = MeshQualityEnhanced()
+ meshQualityEnhancedFilter: MeshQualityEnhanced = MeshQualityEnhanced()
- filter.SetInputDataObject( inputMesh )
- filter.SetCellQualityMetrics( triangleMetrics=triangleMetrics,
- quadMetrics=quadMetrics,
- tetraMetrics=tetraMetrics,
- pyramidMetrics=pyrMetrics,
- wedgeMetrics=wedgeMetrics,
- hexaMetrics=hexaMetrics )
- filter.SetOtherMeshQualityMetrics( otherMetrics )
- filter.Update()
+ meshQualityEnhancedFilter.SetInputDataObject( inputMesh )
+ meshQualityEnhancedFilter.SetCellQualityMetrics( triangleMetrics=triangleMetrics,
+ quadMetrics=quadMetrics,
+ tetraMetrics=tetraMetrics,
+ pyramidMetrics=pyrMetrics,
+ wedgeMetrics=wedgeMetrics,
+ hexaMetrics=hexaMetrics )
+ meshQualityEnhancedFilter.SetOtherMeshQualityMetrics( otherMetrics )
+ meshQualityEnhancedFilter.Update()
- outputMesh.ShallowCopy( filter.GetOutputDataObject( 0 ) )
+ outputMesh.ShallowCopy( meshQualityEnhancedFilter.GetOutputDataObject( 0 ) )
# save to file if asked
if self._saveToFile:
- stats: QualityMetricSummary = filter.GetQualityMetricSummary()
+ stats: QualityMetricSummary = meshQualityEnhancedFilter.GetQualityMetricSummary()
self.saveFile( stats )
self._blockIndex += 1
return
diff --git a/geos-pv/src/geos/pv/plugins/PVSplitMesh.py b/geos-pv/src/geos/pv/plugins/PVSplitMesh.py
index 089e6a8f3..f4381a833 100644
--- a/geos-pv/src/geos/pv/plugins/PVSplitMesh.py
+++ b/geos-pv/src/geos/pv/plugins/PVSplitMesh.py
@@ -19,7 +19,7 @@
update_paths()
-from geos.mesh.processing.SplitMesh import SplitMesh
+from geos.processing.generic_processing_tools.SplitMesh import SplitMesh
from geos.pv.utils.details import SISOFilter, FilterCategory
__doc__ = """
@@ -37,7 +37,7 @@
@SISOFilter( category=FilterCategory.GEOS_UTILS,
- decoratedLabel="Split Mesh",
+ decoratedLabel="Split Mesh",
decoratedType="vtkPointSet" )
class PVSplitMesh( VTKPythonAlgorithmBase ):
@@ -52,7 +52,9 @@ def Filter( self: Self, inputMesh: vtkPointSet, outputMesh: vtkPointSet ) -> Non
inputMesh(vtkPointSet): Input mesh.
outputMesh: Output mesh.
"""
- filter: SplitMesh = SplitMesh()
- filter.SetInputDataObject( inputMesh )
- filter.Update()
- outputMesh.ShallowCopy( filter.GetOutputDataObject( 0 ) )
+ splitMeshFilter: SplitMesh = SplitMesh()
+ splitMeshFilter.SetInputDataObject( inputMesh )
+ splitMeshFilter.Update()
+ outputMesh.ShallowCopy( splitMeshFilter.GetOutputDataObject( 0 ) )
+
+ return