diff --git a/geos-processing/src/geos/processing/generic_processing_tools/SplitMesh.py b/geos-processing/src/geos/processing/generic_processing_tools/SplitMesh.py
index 2695c8f8..2d917027 100644
--- a/geos-processing/src/geos/processing/generic_processing_tools/SplitMesh.py
+++ b/geos-processing/src/geos/processing/generic_processing_tools/SplitMesh.py
@@ -83,6 +83,13 @@ def __init__( self, inputMesh: vtkUnstructuredGrid, speHandler: bool = False ) -
self.logger = logging.getLogger( loggerTitle )
self.logger.setLevel( logging.INFO )
self.logger.propagate = False
+ handlers: list[ logging.Handler ] = self.logger.handlers
+ # Get the handler to specify if the logger already exist and has it
+ for handler in handlers:
+ # The CountWarningHandler can't be the handler to specify
+ if type( handler ) is not type( CountWarningHandler() ):
+ self.handler = handler
+ break
counter: CountWarningHandler = CountWarningHandler()
self.counter: CountWarningHandler
diff --git a/geos-processing/src/geos/processing/pre_processing/MeshQualityEnhanced.py b/geos-processing/src/geos/processing/pre_processing/MeshQualityEnhanced.py
index 0e75daff..3f75cfae 100644
--- a/geos-processing/src/geos/processing/pre_processing/MeshQualityEnhanced.py
+++ b/geos-processing/src/geos/processing/pre_processing/MeshQualityEnhanced.py
@@ -132,6 +132,7 @@ def __init__(
self._allCellTypesExtended: tuple[ int, ...] = getAllCellTypesExtended()
self._allCellTypes: tuple[ int, ...] = getAllCellTypes()
self.speHandler: bool = speHandler
+ self.handler: logging.Handler
# Logger
self.logger: Logger
@@ -141,6 +142,13 @@ def __init__(
self.logger = logging.getLogger( loggerTitle )
self.logger.setLevel( logging.INFO )
self.logger.propagate = False
+ handlers: list[ logging.Handler ] = self.logger.handlers
+ # Get the handler to specify if the logger already exist and has it
+ for handler in handlers:
+ # The CountWarningHandler can't be the handler to specify
+ if type( handler ) is not type( CountWarningHandler() ):
+ self.handler = handler
+ break
counter: CountWarningHandler = CountWarningHandler()
self.counter: CountWarningHandler
diff --git a/geos-pv/src/geos/pv/plugins/generic_processing/PVAttributeMapping.py b/geos-pv/src/geos/pv/plugins/generic_processing/PVAttributeMapping.py
index d6b07cab..20c29a0b 100644
--- a/geos-pv/src/geos/pv/plugins/generic_processing/PVAttributeMapping.py
+++ b/geos-pv/src/geos/pv/plugins/generic_processing/PVAttributeMapping.py
@@ -54,6 +54,8 @@
"""
+HANDLER: logging.Handler = VTKHandler()
+
@smproxy.filter( name="PVAttributeMapping", label="Attribute Mapping" )
@smhint.xml( f'' )
@@ -76,7 +78,6 @@ def __init__( self: Self ) -> None:
self.piece: Piece = Piece.CELLS
self.clearAttributeNames = True
self.attributeNames: list[ str ] = []
- self.handler: logging.Handler = VTKHandler()
@smproperty.intvector(
name="AttributePiece",
@@ -190,8 +191,8 @@ def RequestData(
attributeMappingFilter: AttributeMapping = AttributeMapping( meshFrom, outData, set( self.attributeNames ),
self.piece, True )
- if not isHandlerInLogger( self.handler, attributeMappingFilter.logger ):
- attributeMappingFilter.setLoggerHandler( self.handler )
+ if not isHandlerInLogger( HANDLER, attributeMappingFilter.logger ):
+ attributeMappingFilter.setLoggerHandler( HANDLER )
try:
attributeMappingFilter.applyFilter()
diff --git a/geos-pv/src/geos/pv/plugins/generic_processing/PVClipToMainFrame.py b/geos-pv/src/geos/pv/plugins/generic_processing/PVClipToMainFrame.py
index 4c04589a..3461b134 100644
--- a/geos-pv/src/geos/pv/plugins/generic_processing/PVClipToMainFrame.py
+++ b/geos-pv/src/geos/pv/plugins/generic_processing/PVClipToMainFrame.py
@@ -36,6 +36,8 @@
"""
+HANDLER: logging.Handler = VTKHandler()
+
@SISOFilter( category=FilterCategory.GENERIC_PROCESSING,
decoratedLabel="Clip to the main frame",
@@ -45,10 +47,9 @@ class PVClipToMainFrame( VTKPythonAlgorithmBase ):
def __init__( self ) -> None:
"""Init motherclass, filter and logger."""
self._realFilter = ClipToMainFrame( speHandler=True )
- self.handler: logging.Handler = VTKHandler()
- if not isHandlerInLogger( self.handler, self._realFilter.logger ):
- self._realFilter.SetLoggerHandler( self.handler )
+ if not isHandlerInLogger( HANDLER, self._realFilter.logger ):
+ self._realFilter.SetLoggerHandler( HANDLER )
def ApplyFilter( self, inputMesh: vtkMultiBlockDataSet, outputMesh: vtkMultiBlockDataSet ) -> None:
"""Is applying clipToMainFrame filter.
diff --git a/geos-pv/src/geos/pv/plugins/generic_processing/PVCreateConstantAttributePerRegion.py b/geos-pv/src/geos/pv/plugins/generic_processing/PVCreateConstantAttributePerRegion.py
index 372ea2c3..bb8973aa 100644
--- a/geos-pv/src/geos/pv/plugins/generic_processing/PVCreateConstantAttributePerRegion.py
+++ b/geos-pv/src/geos/pv/plugins/generic_processing/PVCreateConstantAttributePerRegion.py
@@ -50,6 +50,8 @@
"""
+HANDLER: logging.Handler = VTKHandler()
+
@SISOFilter( category=FilterCategory.GENERIC_PROCESSING,
decoratedLabel="Create Constant Attribute Per Region",
@@ -72,7 +74,6 @@ def __init__( self: Self ) -> None:
# Use the handler of paraview for the log.
self.speHandler: bool = True
- self.handler: logging.Handler = VTKHandler()
# Settings of the attribute with the region indexes:
@smproperty.stringvector(
@@ -292,8 +293,8 @@ def ApplyFilter( self, inputMesh: vtkDataSet, outputMesh: vtkDataSet ) -> None:
self.speHandler,
)
- if not isHandlerInLogger( self.handler, createConstantAttributePerRegionFilter.logger ):
- createConstantAttributePerRegionFilter.setLoggerHandler( self.handler )
+ if not isHandlerInLogger( HANDLER, createConstantAttributePerRegionFilter.logger ):
+ createConstantAttributePerRegionFilter.setLoggerHandler( HANDLER )
try:
createConstantAttributePerRegionFilter.applyFilter()
diff --git a/geos-pv/src/geos/pv/plugins/generic_processing/PVFillPartialArrays.py b/geos-pv/src/geos/pv/plugins/generic_processing/PVFillPartialArrays.py
index 547945aa..4a6e27d2 100644
--- a/geos-pv/src/geos/pv/plugins/generic_processing/PVFillPartialArrays.py
+++ b/geos-pv/src/geos/pv/plugins/generic_processing/PVFillPartialArrays.py
@@ -41,6 +41,8 @@
"""
+HANDLER: logging.Handler = VTKHandler()
+
@SISOFilter( category=FilterCategory.GENERIC_PROCESSING,
decoratedLabel="Fill Partial Arrays",
@@ -51,7 +53,6 @@ def __init__( self: Self, ) -> None:
"""Fill a partial attribute with constant value per component."""
self.clearDictAttributesValues: bool = True
self.dictAttributesValues: dict[ str, Union[ list[ Any ], None ] ] = {}
- self.handler: logging.Handler = VTKHandler()
@smproperty.xml( """
' )
@@ -68,7 +70,6 @@ def __init__( self: Self ) -> None:
inputType="vtkMultiBlockDataSet",
outputType="vtkUnstructuredGrid",
)
- self.handler: logging.Handler = VTKHandler()
def RequestDataObject(
self: Self,
@@ -118,8 +119,8 @@ def RequestData(
mergeBlockEnhancedFilter: MergeBlockEnhanced = MergeBlockEnhanced( inputMesh, True )
- if not isHandlerInLogger( self.handler, mergeBlockEnhancedFilter.logger ):
- mergeBlockEnhancedFilter.setLoggerHandler( self.handler )
+ if not isHandlerInLogger( HANDLER, mergeBlockEnhancedFilter.logger ):
+ mergeBlockEnhancedFilter.setLoggerHandler( HANDLER )
try:
mergeBlockEnhancedFilter.applyFilter()
diff --git a/geos-pv/src/geos/pv/plugins/generic_processing/PVSplitMesh.py b/geos-pv/src/geos/pv/plugins/generic_processing/PVSplitMesh.py
index 81da5b81..7a3b15d5 100644
--- a/geos-pv/src/geos/pv/plugins/generic_processing/PVSplitMesh.py
+++ b/geos-pv/src/geos/pv/plugins/generic_processing/PVSplitMesh.py
@@ -39,13 +39,14 @@
"""
+HANDLER: logging.Handler = VTKHandler()
+
@SISOFilter( category=FilterCategory.GENERIC_PROCESSING, decoratedLabel="Split Mesh", decoratedType="vtkPointSet" )
class PVSplitMesh( VTKPythonAlgorithmBase ):
def __init__( self: Self ) -> None:
"""Split mesh cells."""
- self.handler: logging.Handler = VTKHandler()
def ApplyFilter( self: Self, inputMesh: vtkPointSet, outputMesh: vtkPointSet ) -> None:
"""Apply vtk filter.
@@ -55,8 +56,8 @@ def ApplyFilter( self: Self, inputMesh: vtkPointSet, outputMesh: vtkPointSet ) -
outputMesh: Output mesh.
"""
splitMeshFilter: SplitMesh = SplitMesh( inputMesh, True )
- if not isHandlerInLogger( self.handler, splitMeshFilter.logger ):
- splitMeshFilter.setLoggerHandler( self.handler )
+ if not isHandlerInLogger( HANDLER, splitMeshFilter.logger ):
+ splitMeshFilter.setLoggerHandler( HANDLER )
try:
splitMeshFilter.applyFilter()
diff --git a/geos-pv/src/geos/pv/plugins/post_processing/PVGeomechanicsCalculator.py b/geos-pv/src/geos/pv/plugins/post_processing/PVGeomechanicsCalculator.py
index 693a5f5f..0f707256 100644
--- a/geos-pv/src/geos/pv/plugins/post_processing/PVGeomechanicsCalculator.py
+++ b/geos-pv/src/geos/pv/plugins/post_processing/PVGeomechanicsCalculator.py
@@ -73,6 +73,8 @@
"""
+HANDLER: logging.Handler = VTKHandler()
+
loggerTitle: str = "Geomechanics Calculator"
@@ -93,10 +95,9 @@ def __init__( self: Self ) -> None:
self.rockCohesion: float = DEFAULT_ROCK_COHESION
self.frictionAngle: float = DEFAULT_FRICTION_ANGLE_DEG
- self.handler: logging.Handler = VTKHandler()
self.logger = logging.getLogger( loggerTitle )
self.logger.setLevel( logging.INFO )
- self.logger.addHandler( self.handler )
+ self.logger.addHandler( HANDLER )
self.logger.propagate = False
counter: CountWarningHandler = CountWarningHandler()
@@ -265,8 +266,8 @@ def ApplyFilter(
speHandler=True,
)
- if not isHandlerInLogger( self.handler, geomechanicsCalculatorFilter.logger ):
- geomechanicsCalculatorFilter.setLoggerHandler( self.handler )
+ if not isHandlerInLogger( HANDLER, geomechanicsCalculatorFilter.logger ):
+ geomechanicsCalculatorFilter.setLoggerHandler( HANDLER )
geomechanicsCalculatorFilter.physicalConstants.grainBulkModulus = self.grainBulkModulus
geomechanicsCalculatorFilter.physicalConstants.specificDensity = self.specificDensity
@@ -303,8 +304,8 @@ def ApplyFilter(
True,
)
- if not isHandlerInLogger( self.handler, geomechanicsCalculatorFilter.logger ):
- geomechanicsCalculatorFilter.setLoggerHandler( self.handler )
+ if not isHandlerInLogger( HANDLER, geomechanicsCalculatorFilter.logger ):
+ geomechanicsCalculatorFilter.setLoggerHandler( HANDLER )
geomechanicsCalculatorFilter.physicalConstants.grainBulkModulus = self.grainBulkModulus
geomechanicsCalculatorFilter.physicalConstants.specificDensity = self.specificDensity
diff --git a/geos-pv/src/geos/pv/plugins/post_processing/PVGeomechanicsWorkflow.py b/geos-pv/src/geos/pv/plugins/post_processing/PVGeomechanicsWorkflow.py
index 0b446062..efb1c089 100644
--- a/geos-pv/src/geos/pv/plugins/post_processing/PVGeomechanicsWorkflow.py
+++ b/geos-pv/src/geos/pv/plugins/post_processing/PVGeomechanicsWorkflow.py
@@ -85,6 +85,7 @@
"""
+HANDLER: logging.Handler = VTKHandler()
loggerTitle: str = "GEOS Geomechanics Workflow"
@@ -139,10 +140,9 @@ def __init__( self: Self ) -> None:
self.rockCohesion: float = DEFAULT_ROCK_COHESION
self.frictionAngle: float = DEFAULT_FRICTION_ANGLE_DEG
- self.handler: logging.Handler = VTKHandler()
self.logger = logging.getLogger( loggerTitle )
self.logger.setLevel( logging.INFO )
- self.logger.addHandler( self.handler )
+ self.logger.addHandler( HANDLER )
self.logger.propagate = False
counter: CountWarningHandler = CountWarningHandler()
diff --git a/geos-pv/src/geos/pv/plugins/post_processing/PVGeosBlockExtractAndMerge.py b/geos-pv/src/geos/pv/plugins/post_processing/PVGeosBlockExtractAndMerge.py
index dff27de7..62e415a8 100644
--- a/geos-pv/src/geos/pv/plugins/post_processing/PVGeosBlockExtractAndMerge.py
+++ b/geos-pv/src/geos/pv/plugins/post_processing/PVGeosBlockExtractAndMerge.py
@@ -82,6 +82,7 @@
"""
+HANDLER: logging.Handler = VTKHandler()
loggerTitle: str = "Extract & Merge GEOS Block"
@@ -129,10 +130,9 @@ def __init__( self: Self ) -> None:
self.outputCellsT0: vtkMultiBlockDataSet = vtkMultiBlockDataSet()
- self.handler: logging.Handler = VTKHandler()
self.logger = logging.getLogger( loggerTitle )
self.logger.setLevel( logging.INFO )
- self.logger.addHandler( self.handler )
+ self.logger.addHandler( HANDLER )
self.logger.propagate = False
counter: CountWarningHandler = CountWarningHandler()
diff --git a/geos-pv/src/geos/pv/plugins/post_processing/PVGeosLogReader.py b/geos-pv/src/geos/pv/plugins/post_processing/PVGeosLogReader.py
index 4b8aea9f..b46fd463 100644
--- a/geos-pv/src/geos/pv/plugins/post_processing/PVGeosLogReader.py
+++ b/geos-pv/src/geos/pv/plugins/post_processing/PVGeosLogReader.py
@@ -60,6 +60,7 @@
"""
+HANDLER: logging.Handler = VTKHandler()
loggerTitle: str = "Geos Log Reader"
@@ -150,10 +151,9 @@ def __init__( self: Self ) -> None:
for prop in propsSolvers:
self.m_convergence.AddArray( prop )
- self.handler: logging.Handler = VTKHandler()
self.logger = logging.getLogger( loggerTitle )
self.logger.setLevel( logging.INFO )
- self.logger.addHandler( self.handler )
+ self.logger.addHandler( HANDLER )
self.logger.propagate = False
counter: CountWarningHandler = CountWarningHandler()
diff --git a/geos-pv/src/geos/pv/plugins/post_processing/PVMohrCirclePlot.py b/geos-pv/src/geos/pv/plugins/post_processing/PVMohrCirclePlot.py
index e3ff2585..625ac5c3 100644
--- a/geos-pv/src/geos/pv/plugins/post_processing/PVMohrCirclePlot.py
+++ b/geos-pv/src/geos/pv/plugins/post_processing/PVMohrCirclePlot.py
@@ -91,6 +91,7 @@
* The attribute 'CellId' has to be used for the 'Selection Labels'.
"""
+HANDLER: logging.Handler = VTKHandler()
loggerTitle: str = "Mohr Circle"
@@ -181,10 +182,9 @@ def __init__( self: Self ) -> None:
# Request data processing step - incremented each time RequestUpdateExtent is called
self.requestDataStep: int = -1
- self.handler: logging.Handler = VTKHandler()
self.logger = logging.getLogger( loggerTitle )
self.logger.setLevel( logging.INFO )
- self.logger.addHandler( self.handler )
+ self.logger.addHandler( HANDLER )
self.logger.propagate = False
counter: CountWarningHandler = CountWarningHandler()
diff --git a/geos-pv/src/geos/pv/plugins/post_processing/PVSurfaceGeomechanics.py b/geos-pv/src/geos/pv/plugins/post_processing/PVSurfaceGeomechanics.py
index 2cbc5ba2..f63c2b82 100644
--- a/geos-pv/src/geos/pv/plugins/post_processing/PVSurfaceGeomechanics.py
+++ b/geos-pv/src/geos/pv/plugins/post_processing/PVSurfaceGeomechanics.py
@@ -52,6 +52,7 @@
"""
+HANDLER: logging.Handler = VTKHandler()
loggerTitle: str = "Surface Geomechanics"
@@ -70,10 +71,9 @@ def __init__( self: Self ) -> None:
# friction angle (°)
self.frictionAngle: float = DEFAULT_FRICTION_ANGLE_DEG
- self.handler: logging.Handler = VTKHandler()
self.logger = logging.getLogger( loggerTitle )
self.logger.setLevel( logging.INFO )
- self.logger.addHandler( self.handler )
+ self.logger.addHandler( HANDLER )
self.logger.propagate = False
counter: CountWarningHandler = CountWarningHandler()
@@ -148,8 +148,8 @@ def ApplyFilter( self: Self, inputMesh: vtkMultiBlockDataSet, outputMesh: vtkMul
loggerName: str = f"Surface geomechanics for the blockIndex { blockIndex }"
sgFilter: SurfaceGeomechanics = SurfaceGeomechanics( surfaceBlock, loggerName, True )
- if not isHandlerInLogger( self.handler, sgFilter.logger ):
- sgFilter.SetLoggerHandler( self.handler )
+ if not isHandlerInLogger( HANDLER, sgFilter.logger ):
+ sgFilter.SetLoggerHandler( HANDLER )
sgFilter.SetRockCohesion( self._getRockCohesion() )
sgFilter.SetFrictionAngle( self._getFrictionAngle() )
diff --git a/geos-pv/src/geos/pv/plugins/qc/PVCellTypeCounterEnhanced.py b/geos-pv/src/geos/pv/plugins/qc/PVCellTypeCounterEnhanced.py
index 44e99ced..c46c429a 100644
--- a/geos-pv/src/geos/pv/plugins/qc/PVCellTypeCounterEnhanced.py
+++ b/geos-pv/src/geos/pv/plugins/qc/PVCellTypeCounterEnhanced.py
@@ -41,6 +41,8 @@
"""
+HANDLER: logging.Handler = VTKHandler()
+
@smproxy.filter( name="PVCellTypeCounterEnhanced", label="Cell Type Counter Enhanced" )
@smhint.xml( f'' )
@@ -60,8 +62,6 @@ def __init__( self: Self ) -> None:
# used to concatenate results if vtkMultiBlockDataSet
self._countsAll: CellTypeCounts = CellTypeCounts()
- self.handler: logging.Handler = VTKHandler()
-
@smproperty.intvector(
name="SetSaveToFile",
label="Save to file",
@@ -141,8 +141,8 @@ def RequestData(
assert outputTable is not None, "Output pipeline is null."
cellTypeCounterEnhancedFilter: CellTypeCounterEnhanced = CellTypeCounterEnhanced( inputMesh, True )
- if not isHandlerInLogger( self.handler, cellTypeCounterEnhancedFilter.logger ):
- cellTypeCounterEnhancedFilter.setLoggerHandler( self.handler )
+ if not isHandlerInLogger( HANDLER, cellTypeCounterEnhancedFilter.logger ):
+ cellTypeCounterEnhancedFilter.setLoggerHandler( HANDLER )
try:
cellTypeCounterEnhancedFilter.applyFilter()
diff --git a/geos-pv/src/geos/pv/plugins/qc/PVMeshQualityEnhanced.py b/geos-pv/src/geos/pv/plugins/qc/PVMeshQualityEnhanced.py
index d959b1e8..2c00aadc 100644
--- a/geos-pv/src/geos/pv/plugins/qc/PVMeshQualityEnhanced.py
+++ b/geos-pv/src/geos/pv/plugins/qc/PVMeshQualityEnhanced.py
@@ -58,6 +58,8 @@
Please refer to the `Verdict Manual `_ for metrics and range definitions.
"""
+HANDLER: logging.Handler = VTKHandler()
+
@SISOFilter( category=FilterCategory.QC, decoratedLabel="Mesh Quality Enhanced", decoratedType="vtkUnstructuredGrid" )
class PVMeshQualityEnhanced( VTKPythonAlgorithmBase ):
@@ -68,8 +70,6 @@ def __init__( self: Self ) -> None:
self._saveToFile: bool = True
self._blockIndex: int = 0
- self.handler: logging.Handler = VTKHandler()
-
# Used to concatenate results if vtkMultiBlockDataSet
self._metricsAll: list[ float ] = []
@@ -232,8 +232,8 @@ def ApplyFilter( self, inputMesh: vtkUnstructuredGrid, outputMesh: vtkUnstructur
otherMetrics: set[ int ] = self._getQualityMetricsToUse( self._commonMeshQualityMetric )
meshQualityEnhancedFilter: MeshQualityEnhanced = MeshQualityEnhanced( inputMesh, True )
- if not isHandlerInLogger( self.handler, meshQualityEnhancedFilter.logger ):
- meshQualityEnhancedFilter.setLoggerHandler( self.handler )
+ if not isHandlerInLogger( HANDLER, meshQualityEnhancedFilter.logger ):
+ meshQualityEnhancedFilter.setLoggerHandler( HANDLER )
meshQualityEnhancedFilter.SetCellQualityMetrics( triangleMetrics=triangleMetrics,
quadMetrics=quadMetrics,
diff --git a/geos-pv/src/geos/pv/utils/workflowFunctions.py b/geos-pv/src/geos/pv/utils/workflowFunctions.py
index 1a66f1a7..88b6f6f8 100644
--- a/geos-pv/src/geos/pv/utils/workflowFunctions.py
+++ b/geos-pv/src/geos/pv/utils/workflowFunctions.py
@@ -9,8 +9,9 @@
from vtkmodules.vtkCommonDataModel import vtkMultiBlockDataSet
-from paraview.detail.loghandler import ( VTKHandler ) # type: ignore[import-not-found]
+from paraview.detail.loghandler import VTKHandler # type: ignore[import-not-found]
+HANDLER: logging.Handler = VTKHandler()
def doExtractAndMerge(
mesh: vtkMultiBlockDataSet,
@@ -37,9 +38,8 @@ def doExtractAndMerge(
extractFault=extractFault,
extractWell=extractWell,
speHandler=True )
- handler: logging.Handler = VTKHandler()
- if not isHandlerInLogger( handler, blockExtractor.logger ):
- blockExtractor.setLoggerHandler( handler )
+ if not isHandlerInLogger( HANDLER, blockExtractor.logger ):
+ blockExtractor.setLoggerHandler( HANDLER )
blockExtractor.applyFilter()
# Add to the warning counter the number of warning logged with the call of GeosBlockExtractor filter
@@ -84,9 +84,8 @@ def mergeBlocksFilter(
"""
loggerName = f"GEOS Block Merge for the domain { domainToMerge }"
mergeBlockFilter: GeosBlockMerge = GeosBlockMerge( mesh, convertSurfaces, True, loggerName )
- handler: logging.Handler = VTKHandler()
- if not isHandlerInLogger( handler, mergeBlockFilter.logger ):
- mergeBlockFilter.setLoggerHandler( handler )
+ if not isHandlerInLogger( HANDLER, mergeBlockFilter.logger ):
+ mergeBlockFilter.setLoggerHandler( HANDLER )
mergeBlockFilter.applyFilter()
# Add to the warning counter the number of warning logged with the call of GeosBlockMerge filter
diff --git a/mesh-doctor/src/geos/mesh_doctor/actions/checkInternalTags.py b/mesh-doctor/src/geos/mesh_doctor/actions/checkInternalTags.py
new file mode 100644
index 00000000..4a2f242c
--- /dev/null
+++ b/mesh-doctor/src/geos/mesh_doctor/actions/checkInternalTags.py
@@ -0,0 +1,369 @@
+# SPDX-License-Identifier: Apache-2.0
+# SPDX-FileCopyrightText: Copyright 2023-2024 TotalEnergies.
+"""Check that tagged 2D elements are internal (have exactly 2 volume neighbors)."""
+
+from dataclasses import dataclass
+from typing import Optional, Dict, List, Union
+import vtk
+from tqdm import tqdm
+
+from geos.mesh_doctor.parsing.cliParsing import setupLogger
+from geos.mesh.io.vtkIO import readUnstructuredGrid, writeMesh, VtkOutput
+
+
+@dataclass( frozen=True )
+class Options:
+ """Options for the internal tags check.
+
+ Attributes:
+ tagValues: List of tag values to check
+ tagArrayName: Name of the cell data array containing tags
+ outputCsv: Optional path to output CSV file with problematic elements
+ nullTagValue: Optional tag value to assign to faulty cells (e.g., 9999)
+ fixedVtkOutput: Optional VtkOutput for mesh with faulty cells retagged
+ verbose: Enable detailed connectivity diagnostics for problematic cells
+ """
+ tagValues: tuple[ int, ...]
+ tagArrayName: str
+ outputCsv: Optional[ str ]
+ nullTagValue: Optional[ int ]
+ fixedVtkOutput: Optional[ VtkOutput ]
+ verbose: bool = False
+
+
+@dataclass( frozen=True )
+class Result:
+ """Result of the internal tags check.
+
+ Attributes:
+ info: Summary information about the check
+ passed: Whether all checked elements have exactly 2 neighbors
+ """
+ info: str
+ passed: bool
+
+
+@dataclass( frozen=True )
+class ElementInfo:
+ """Information about a tagged element.
+
+ Attributes:
+ cellId: Cell ID in the mesh
+ tag: Tag value
+ numNeighbors: Number of volume neighbors
+ neighbors: List of neighbor cell IDs
+ """
+ cellId: int
+ tag: int
+ numNeighbors: int
+ neighbors: list[ int ]
+
+
+def __getVolumeNeighbors( mesh: vtk.vtkUnstructuredGrid, cellId: int, volumeCells: set[ int ],
+ surfaceCellTypes: list[ int ] ) -> list[ int ]:
+ """Find all volume neighbors of a 2D cell.
+
+ Args:
+ mesh: The unstructured grid
+ cellId: ID of the 2D cell
+ volumeCells: Set of volume cell IDs
+ surfaceCellTypes: List of surface cell type IDs
+
+ Returns:
+ List of volume cell IDs that share all points with the 2D cell
+ """
+ surfaceCell = mesh.GetCell( cellId )
+
+ # Get all points of the surface cell
+ surfacePoints = set()
+ for i in range( surfaceCell.GetNumberOfPoints() ):
+ surfacePoints.add( surfaceCell.GetPointId( i ) )
+
+ # Get cells connected to the first point
+ firstPoint = surfaceCell.GetPointId( 0 )
+ neighborCells = vtk.vtkIdList()
+ mesh.GetPointCells( firstPoint, neighborCells )
+
+ # Find volume cells that contain all surface points
+ volumeNeighbors = []
+ for i in range( neighborCells.GetNumberOfIds() ):
+ neighborId = neighborCells.GetId( i )
+
+ # Skip if not a volume cell
+ if neighborId not in volumeCells:
+ continue
+
+ # Get points of the volume cell
+ volumeCell = mesh.GetCell( neighborId )
+ volumePoints = set()
+ for j in range( volumeCell.GetNumberOfPoints() ):
+ volumePoints.add( volumeCell.GetPointId( j ) )
+
+ # Check if all surface points are in the volume cell
+ if surfacePoints.issubset( volumePoints ):
+ volumeNeighbors.append( neighborId )
+
+ return volumeNeighbors
+
+
+def __diagnose1NeighborCell( mesh: vtk.vtkUnstructuredGrid, elem: ElementInfo, volumeCells: set[ int ] ) -> None:
+ """Diagnose a cell with only 1 neighbor by showing face-by-face neighbors.
+
+ Args:
+ mesh: The unstructured grid
+ elem: The problematic element info (must have exactly 1 neighbor)
+ volumeCells: Set of all volume cell IDs
+ """
+ if elem.numNeighbors != 1:
+ return
+
+ # Get the 2D surface cell we're trying to match
+ surfaceCell = mesh.GetCell( elem.cellId )
+ surfacePointIds = surfaceCell.GetPointIds()
+ surfaceNodes = [ surfacePointIds.GetId( i ) for i in range( surfacePointIds.GetNumberOfIds() ) ]
+
+ neighborCellId = elem.neighbors[ 0 ]
+ volumeCell = mesh.GetCell( neighborCellId )
+ cellTypeName = volumeCell.GetClassName()
+ numFaces = volumeCell.GetNumberOfFaces()
+
+ setupLogger.warning( f" Cell {elem.cellId} (tag={elem.tag}) has only 1 neighbor: cell {neighborCellId}" )
+ setupLogger.warning( f" 2D element nodes: {surfaceNodes}" )
+ setupLogger.warning( f" Cell type: {cellTypeName} ({numFaces} faces)" )
+ setupLogger.warning( " Face-by-face neighbors:" )
+
+ # For each face of the volume cell, find the neighbor
+ for faceIdx in range( numFaces ):
+ face = volumeCell.GetFace( faceIdx )
+ facePointIds = face.GetPointIds()
+
+ # Find neighboring cells that share this face
+ neighborCells = vtk.vtkIdList()
+ mesh.GetCellNeighbors( neighborCellId, facePointIds, neighborCells )
+
+ # Filter to only volume cells
+ volumeNeighbors = []
+ for i in range( neighborCells.GetNumberOfIds() ):
+ nId = neighborCells.GetId( i )
+ if nId in volumeCells and nId != neighborCellId:
+ volumeNeighbors.append( nId )
+
+ if volumeNeighbors:
+ setupLogger.warning( f" Face {faceIdx}: {volumeNeighbors}" )
+ else:
+ setupLogger.warning( f" Face {faceIdx}: " )
+
+
+def checkInternalTags( mesh: vtk.vtkUnstructuredGrid, options: Options ) -> Result:
+ """Check that all 2D elements with specified tags have exactly 2 volume neighbors.
+
+ Args:
+ mesh: Input unstructured grid
+ options: Check options
+
+ Returns:
+ Result with summary information
+
+ Raises:
+ ValueError: If tag array not found or other validation errors
+ """
+ setupLogger.info( f"Mesh: {mesh.GetNumberOfPoints()} points, {mesh.GetNumberOfCells()} cells" )
+
+ # Get tags array
+ cellData = mesh.GetCellData()
+ if not cellData.HasArray( options.tagArrayName ):
+ availableArrays = [ cellData.GetArrayName( i ) for i in range( cellData.GetNumberOfArrays() ) ]
+ raise ValueError( f"Tag array '{options.tagArrayName}' not found. "
+ f"Available cell data arrays: {availableArrays}" )
+
+ tags = cellData.GetArray( options.tagArrayName )
+
+ # Convert tag array to int if needed
+ if not isinstance( tags, vtk.vtkIntArray ):
+ setupLogger.info( f"Converting tag array '{options.tagArrayName}' to integer type..." )
+ intTagsArray = vtk.vtkIntArray()
+ intTagsArray.SetName( tags.GetName() )
+ intTagsArray.SetNumberOfComponents( tags.GetNumberOfComponents() )
+ for i in range( tags.GetNumberOfTuples() ):
+ intTagsArray.InsertNextValue( int( tags.GetValue( i ) ) )
+ mesh.GetCellData().RemoveArray( options.tagArrayName )
+ mesh.GetCellData().AddArray( intTagsArray )
+ tags = intTagsArray
+
+ # Define cell types
+ SURFACE_CELL_TYPES = [ vtk.VTK_TRIANGLE, vtk.VTK_QUAD, vtk.VTK_POLYGON, vtk.VTK_PIXEL ]
+ VOLUME_CELL_TYPES = [ vtk.VTK_TETRA, vtk.VTK_HEXAHEDRON, vtk.VTK_WEDGE, vtk.VTK_PYRAMID, vtk.VTK_VOXEL ]
+
+ # Build connectivity
+ setupLogger.info( "Building cell connectivity..." )
+ mesh.BuildLinks()
+
+ # Find volume cells and build tag mapping for 2D cells in one pass
+ nCells = mesh.GetNumberOfCells()
+ volumeCells = set()
+ tagToCells: Dict[ int, List[ int ] ] = {} # Map tag values to list of 2D cell IDs
+
+ for cellId in tqdm( range( nCells ), desc="Building cell mappings" ):
+ cellType = mesh.GetCellType( cellId )
+
+ # Collect volume cells
+ if cellType in VOLUME_CELL_TYPES:
+ volumeCells.add( cellId )
+
+ # Collect 2D cells by tag (only for tags we're interested in)
+ if cellType in SURFACE_CELL_TYPES:
+ currentTag = tags.GetValue( cellId )
+ if currentTag in options.tagValues:
+ if currentTag not in tagToCells:
+ tagToCells[ currentTag ] = []
+ tagToCells[ currentTag ].append( cellId )
+
+ setupLogger.info( f"Found {len(volumeCells)} volume cells" )
+
+ # Store results by tag
+ tagResults = {}
+ allBadElements = []
+
+ # Process each tag value
+ for tagValue in options.tagValues:
+ setupLogger.info( f"{'='*60}" )
+ setupLogger.info( f"Checking tag = {tagValue}" )
+ setupLogger.info( f"{'='*60}" )
+
+ elementsByNeighbors: Dict[ Union[ int, str ], List[ ElementInfo ] ] = { 0: [], 1: [], 2: [], 'other': [] }
+
+ # Get cells with this tag (pre-filtered)
+ cellsWithTag = tagToCells.get( tagValue, [] )
+ setupLogger.info( f"Found {len(cellsWithTag)} cells with tag {tagValue}" )
+
+ # Process only the cells with this specific tag
+ for cellId in tqdm( cellsWithTag, desc=f"Processing tag {tagValue}" ):
+ # Count volume neighbors
+ volumeNeighbors = __getVolumeNeighbors( mesh, cellId, volumeCells, SURFACE_CELL_TYPES )
+ numNeighbors = len( volumeNeighbors )
+
+ elemInfo = ElementInfo( cellId=cellId, tag=tagValue, numNeighbors=numNeighbors, neighbors=volumeNeighbors )
+
+ # Categorize by neighbor count
+ if numNeighbors in { 0, 1, 2 }:
+ elementsByNeighbors[ numNeighbors ].append( elemInfo )
+ else:
+ elementsByNeighbors[ 'other' ].append( elemInfo )
+
+ # Calculate totals
+ total = sum( len( v ) for v in elementsByNeighbors.values() )
+
+ # Print summary for this tag
+ setupLogger.info( f"Summary for tag = {tagValue}:" )
+ setupLogger.info( f" Total 2D cells: {total}" )
+ setupLogger.info( f" With 0 neighbors: {len(elementsByNeighbors[0])} cells" )
+ setupLogger.info( f" With 1 neighbor: {len(elementsByNeighbors[1])} cells" )
+ setupLogger.info( f" With 2 neighbors: {len(elementsByNeighbors[2])} cells" )
+ setupLogger.info( f" With 3+ neighbors: {len(elementsByNeighbors['other'])} cells" )
+
+ # Collect bad elements
+ allBadElements.extend( elementsByNeighbors[ 0 ] )
+ allBadElements.extend( elementsByNeighbors[ 1 ] )
+ allBadElements.extend( elementsByNeighbors[ 'other' ] )
+
+ tagResults[ tagValue ] = elementsByNeighbors
+
+ # Print overall summary
+ setupLogger.info( f"{'='*60}" )
+ setupLogger.info( "OVERALL SUMMARY" )
+ setupLogger.info( f"{'='*60}" )
+
+ totalBad = len( allBadElements )
+ totalChecked = sum( sum( len( v ) for v in neighbors.values() ) for neighbors in tagResults.values() )
+
+ setupLogger.info( f"Tags checked: {list(options.tagValues)}" )
+ setupLogger.info( f"Total 2D cells checked: {totalChecked}" )
+ setupLogger.info( f"Cells with exactly 2 neighbors: {totalChecked - totalBad}" )
+ setupLogger.info( f"Cells with other than 2 neighbors: {totalBad}" )
+
+ if totalBad > 0:
+ setupLogger.warning( f"Found {totalBad} problematic cells across all tags!" )
+ # Group bad elements by tag for reporting
+ badByTag = {}
+ for elem in allBadElements:
+ if elem.tag not in badByTag:
+ badByTag[ elem.tag ] = 0
+ badByTag[ elem.tag ] += 1
+ for tag, count in sorted( badByTag.items() ):
+ setupLogger.warning( f" Tag {tag}: {count} problematic cells" )
+
+ # Diagnose cells with only 1 neighbor (only in verbose mode)
+ if options.verbose:
+ oneNeighborCells = [ elem for elem in allBadElements if elem.numNeighbors == 1 ]
+ if oneNeighborCells:
+ setupLogger.warning( f"{'='*60}" )
+ setupLogger.warning( "CONNECTIVITY ANALYSIS FOR 1-NEIGHBOR CELLS" )
+ setupLogger.warning( f"{'='*60}" )
+
+ for elem in oneNeighborCells:
+ __diagnose1NeighborCell( mesh, elem, volumeCells )
+ else:
+ setupLogger.info( "All cells have exactly 2 neighbors!" )
+
+ # Write to CSV if requested
+ if options.outputCsv and allBadElements:
+ setupLogger.info( f"Writing bad elements to: {options.outputCsv}" )
+ with open( options.outputCsv, 'w' ) as f:
+ f.write( "cell_id,tag,num_neighbors,neighbor_1,neighbor_2\n" )
+ for elem in allBadElements:
+ neighbor1 = elem.neighbors[ 0 ] if len( elem.neighbors ) > 0 else -1
+ neighbor2 = elem.neighbors[ 1 ] if len( elem.neighbors ) > 1 else -1
+ f.write( f"{elem.cellId},{elem.tag},{elem.numNeighbors},{neighbor1},{neighbor2}\n" )
+ setupLogger.info( f"Written {len(allBadElements)} rows" )
+ elif options.outputCsv and not allBadElements:
+ setupLogger.info( "No bad elements to write (all cells have 2 neighbors)" )
+
+ # Retag faulty cells and write fixed mesh if requested
+ if options.fixedVtkOutput and options.nullTagValue is not None and allBadElements:
+ setupLogger.info( f"Retagging {len(allBadElements)} faulty cells to tag {options.nullTagValue}..." )
+
+ # Get the tags array
+ tagsArray = mesh.GetCellData().GetArray( options.tagArrayName )
+
+ # Create set of bad cell IDs for fast lookup
+ badCellIds = { elem.cellId for elem in allBadElements }
+
+ # Retag the problematic cells
+ numRetagged = 0
+ for cellId in badCellIds:
+ tagsArray.SetValue( cellId, options.nullTagValue )
+ numRetagged += 1
+
+ setupLogger.info( f"Retagged {numRetagged} cells" )
+
+ # Write the modified mesh (tag array already in int format)
+ writeMesh( mesh, options.fixedVtkOutput )
+ setupLogger.info( f"Written fixed mesh to: {options.fixedVtkOutput.output}" )
+ elif options.fixedVtkOutput and not allBadElements:
+ setupLogger.info( "No faulty cells to retag (all cells have 2 neighbors)" )
+ elif options.fixedVtkOutput and options.nullTagValue is None:
+ setupLogger.warning( "Cannot write fixed mesh: --nullTagValue not provided (e.g., add --nullTagValue 9999)" )
+
+ # Create result message
+ if totalBad > 0:
+ resultMsg = f"FAILED: Found {totalBad} non-internal elements out of {totalChecked} checked"
+ passed = False
+ else:
+ resultMsg = f"PASSED: All {totalChecked} tagged elements are internal (have exactly 2 volume neighbors)"
+ passed = True
+
+ return Result( info=resultMsg, passed=passed )
+
+
+def action( vtuInputFile: str, options: Options ) -> Result:
+ """Main action to check that tagged elements are internal.
+
+ Args:
+ vtuInputFile: Path to input VTU file
+ options: Check options
+
+ Returns:
+ Result with summary information
+ """
+ mesh = readUnstructuredGrid( vtuInputFile )
+ return checkInternalTags( mesh, options )
diff --git a/mesh-doctor/src/geos/mesh_doctor/parsing/__init__.py b/mesh-doctor/src/geos/mesh_doctor/parsing/__init__.py
index 2aca9fcd..8c9a2e03 100644
--- a/mesh-doctor/src/geos/mesh_doctor/parsing/__init__.py
+++ b/mesh-doctor/src/geos/mesh_doctor/parsing/__init__.py
@@ -17,6 +17,7 @@
SELF_INTERSECTING_ELEMENTS = "selfIntersectingElements"
SUPPORTED_ELEMENTS = "supportedElements"
ORPHAN_2D = "orphan2d"
+CHECK_INTERNAL_TAGS = "checkInternalTags"
@dataclass( frozen=True )
diff --git a/mesh-doctor/src/geos/mesh_doctor/parsing/checkInternalTagsParsing.py b/mesh-doctor/src/geos/mesh_doctor/parsing/checkInternalTagsParsing.py
new file mode 100644
index 00000000..fe47ed0b
--- /dev/null
+++ b/mesh-doctor/src/geos/mesh_doctor/parsing/checkInternalTagsParsing.py
@@ -0,0 +1,124 @@
+# SPDX-License-Identifier: Apache-2.0
+"""Command line parsing for internal tags check."""
+
+from __future__ import annotations
+import argparse
+from typing import Any, Optional
+
+from geos.mesh_doctor.actions.checkInternalTags import Options, Result
+from geos.mesh_doctor.parsing import CHECK_INTERNAL_TAGS
+from geos.mesh_doctor.parsing.cliParsing import setupLogger, addVtuInputFileArgument
+from geos.mesh.io.vtkIO import VtkOutput
+
+__TAG_VALUES = "tagValues"
+__TAG_ARRAY = "tagArray"
+__OUTPUT_CSV = "outputCsv"
+__NULL_TAG_VALUE = "nullTagValue"
+__FIXED_OUTPUT = "fixedOutput"
+__VERBOSE = "verbose"
+
+__TAG_ARRAY_DEFAULT = "tags"
+
+
+def convert( parsedOptions: dict[ str, Any ] ) -> Options:
+ """Convert parsed command-line options to Options object.
+
+ Args:
+ parsedOptions: Dictionary of parsed command-line options.
+
+ Returns:
+ Options: Configuration options for internal tags check.
+ """
+ # Create VtkOutput for fixed mesh if specified (always binary mode)
+ fixedOutput: Optional[ str ] = parsedOptions.get( __FIXED_OUTPUT )
+ fixedVtkOutput = None
+ if fixedOutput:
+ fixedVtkOutput = VtkOutput( output=fixedOutput, isDataModeBinary=True )
+
+ return Options( tagValues=tuple( parsedOptions[ __TAG_VALUES ] ),
+ tagArrayName=parsedOptions.get( __TAG_ARRAY, __TAG_ARRAY_DEFAULT ),
+ outputCsv=parsedOptions.get( __OUTPUT_CSV ),
+ nullTagValue=parsedOptions.get( __NULL_TAG_VALUE ),
+ fixedVtkOutput=fixedVtkOutput,
+ verbose=parsedOptions.get( __VERBOSE, False ) )
+
+
+def fillSubparser( subparsers: argparse._SubParsersAction[ Any ] ) -> None:
+ """Fill the argument parser for the checkInternalTags action.
+
+ Args:
+ subparsers: Subparsers from the main argument parser
+ """
+ p = subparsers.add_parser( CHECK_INTERNAL_TAGS,
+ help="Check that tagged 2D elements are internal (have exactly 2 volume neighbors).",
+ description="""\
+Validates that 2D elements with specified tag values have exactly 2 volume neighbors.
+Elements with 0, 1, or 3+ neighbors are reported as problematic, as they indicate elements
+on the mesh boundary or other geometric issues.
+
+This check helps ensure that tagged internal surfaces (e.g., fractures) are properly embedded
+in the volume mesh and not inadvertently placed on external boundaries.
+""" )
+
+ addVtuInputFileArgument( p )
+
+ p.add_argument( '--' + __TAG_VALUES,
+ nargs='+',
+ type=int,
+ required=True,
+ metavar='VALUE',
+ help="[ints]: Tag values to check (space-separated list, e.g., --tagValues 8 9 10)" )
+
+ p.add_argument( '--' + __TAG_ARRAY,
+ type=str,
+ default=__TAG_ARRAY_DEFAULT,
+ metavar='NAME',
+ help=f"[string]: Name of the cell data array containing tags. Defaults to '{__TAG_ARRAY_DEFAULT}'" )
+
+ p.add_argument( '--' + __OUTPUT_CSV,
+ type=str,
+ default=None,
+ metavar='FILE',
+ help="[string]: Output CSV file for problematic elements (optional)" )
+
+ p.add_argument( '--' + __NULL_TAG_VALUE,
+ type=int,
+ default=None,
+ metavar='VALUE',
+ help="[int]: Tag value to assign to faulty cells (e.g., 9999). Required to use --fixedOutput." )
+
+ p.add_argument( '--' + __FIXED_OUTPUT,
+ type=str,
+ default=None,
+ metavar='FILE',
+ help="[string]: Output VTU file with faulty cells retagged to nullTagValue (optional)" )
+
+ p.add_argument( '--' + __VERBOSE,
+ '-v',
+ action='store_true',
+ help="[flag]: Enable detailed connectivity diagnostics for problematic cells" )
+
+
+def displayResults( options: Options, result: Result ) -> None:
+ """Display the results of the internal tags check.
+
+ Args:
+ options: The options used for the check.
+ result: The result of the check.
+ """
+ setupLogger.results( "=" * 80 )
+ setupLogger.results( "INTERNAL TAGS CHECK RESULTS" )
+ setupLogger.results( "=" * 80 )
+ setupLogger.results( result.info )
+ setupLogger.results( "=" * 80 )
+
+ if "FAILED" in result.info:
+ setupLogger.results( "Validation FAILED: Some tagged elements are not internal" )
+ if options.outputCsv:
+ setupLogger.results( f"See {options.outputCsv} for details on problematic elements" )
+ if options.fixedVtkOutput and options.nullTagValue is not None:
+ setupLogger.results(
+ f"Fixed mesh written to {options.fixedVtkOutput.output} (faulty cells retagged to {options.nullTagValue})"
+ )
+ else:
+ setupLogger.results( "Validation PASSED: All tagged elements are internal" )
diff --git a/mesh-doctor/src/geos/mesh_doctor/parsing/orphan2dParsing.py b/mesh-doctor/src/geos/mesh_doctor/parsing/orphan2dParsing.py
index f8777aec..afdb277e 100644
--- a/mesh-doctor/src/geos/mesh_doctor/parsing/orphan2dParsing.py
+++ b/mesh-doctor/src/geos/mesh_doctor/parsing/orphan2dParsing.py
@@ -11,9 +11,6 @@
__ORPHAN_OUTPUT = "orphanOutput"
__CLEAN_OUTPUT = "cleanOutput"
-__DATA_MODE = "dataMode"
-__DATA_MODE_VALUES = "binary", "ascii"
-__DATA_MODE_DEFAULT = __DATA_MODE_VALUES[ 0 ]
def convert( parsedOptions: dict[ str, Any ] ) -> Options:
@@ -27,18 +24,16 @@ def convert( parsedOptions: dict[ str, Any ] ) -> Options:
"""
orphanOutput: Optional[ str ] = parsedOptions.get( __ORPHAN_OUTPUT )
cleanOutput: Optional[ str ] = parsedOptions.get( __CLEAN_OUTPUT )
- dataMode: str = parsedOptions.get( __DATA_MODE, __DATA_MODE_DEFAULT )
- isDataModeBinary: bool = dataMode == __DATA_MODE_DEFAULT
- # Create VtkOutput for orphan file if specified
+ # Create VtkOutput for orphan file if specified (always binary mode)
orphanVtkOutput = None
if orphanOutput:
- orphanVtkOutput = VtkOutput( output=orphanOutput, isDataModeBinary=isDataModeBinary )
+ orphanVtkOutput = VtkOutput( output=orphanOutput, isDataModeBinary=True )
- # Create VtkOutput for clean file if specified
+ # Create VtkOutput for clean file if specified (always binary mode)
cleanVtkOutput = None
if cleanOutput:
- cleanVtkOutput = VtkOutput( output=cleanOutput, isDataModeBinary=isDataModeBinary )
+ cleanVtkOutput = VtkOutput( output=cleanOutput, isDataModeBinary=True )
return Options( orphanVtkOutput=orphanVtkOutput, cleanVtkOutput=cleanVtkOutput )
@@ -60,12 +55,6 @@ def fillSubparser( subparsers: _SubParsersAction[ Any ] ) -> None:
type=str,
metavar='FILE',
help="[string]: Output VTU file with orphaned 2D cells removed." )
- p.add_argument(
- '--' + __DATA_MODE,
- type=str,
- metavar=", ".join( __DATA_MODE_VALUES ),
- default=__DATA_MODE_DEFAULT,
- help='[string]: For ".vtu" output format, the data mode can be binary or ascii. Defaults to binary.' )
def displayResults( options: Options, result: Result ) -> None:
diff --git a/mesh-doctor/src/geos/mesh_doctor/register.py b/mesh-doctor/src/geos/mesh_doctor/register.py
index 3a39b705..04932204 100644
--- a/mesh-doctor/src/geos/mesh_doctor/register.py
+++ b/mesh-doctor/src/geos/mesh_doctor/register.py
@@ -58,7 +58,8 @@ def registerParsingActions(
for actionName in ( parsing.ALL_CHECKS, parsing.COLLOCATES_NODES, parsing.ELEMENT_VOLUMES,
parsing.FIX_ELEMENTS_ORDERINGS, parsing.GENERATE_CUBE, parsing.GENERATE_FRACTURES,
parsing.GENERATE_GLOBAL_IDS, parsing.MAIN_CHECKS, parsing.NON_CONFORMAL,
- parsing.SELF_INTERSECTING_ELEMENTS, parsing.SUPPORTED_ELEMENTS, parsing.ORPHAN_2D ):
+ parsing.SELF_INTERSECTING_ELEMENTS, parsing.SUPPORTED_ELEMENTS, parsing.ORPHAN_2D,
+ parsing.CHECK_INTERNAL_TAGS ):
__HELPERS[ actionName ] = actionName
__ACTIONS[ actionName ] = actionName