-
Notifications
You must be signed in to change notification settings - Fork 0
refactor: Move GeosBlockExtractor from geos-posp to geos-proccessing #142
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
paloma-martinez
merged 30 commits into
main
from
RomainBaville/refactor/MoveGeosBlockExtractor
Oct 31, 2025
Merged
Changes from 14 commits
Commits
Show all changes
30 commits
Select commit
Hold shift + click to select a range
e7447e4
Move GeosBlockExtractor to geos-mesh
RomainBaville 89c8f0c
Remove getBlockFromName
RomainBaville f9b2e3f
Refactor using vtkExtractBlock instead of vtkPythonAlgorithmBase
RomainBaville bcf5d59
Update and clean the doc
RomainBaville 889f59a
Update file using GeosExtractBlock
RomainBaville 22abd05
fix the ci
RomainBaville a524d2d
Merge branch 'main' into RomainBaville/refactor/MoveGeosBlockExtractor
RomainBaville 063ee86
Merge branch 'main' into RomainBaville/refactor/MoveGeosBlockExtractor
RomainBaville e577e07
Use dataclass for the extracted domain
RomainBaville 445711f
Update the doc
RomainBaville 7d79d28
Update de doc
RomainBaville e5835d0
fix AddGeosDomainIndex function
RomainBaville 57c29e2
Merge branch 'main' into RomainBaville/refactor/MoveGeosBlockExtractor
RomainBaville c81193d
Add the test file and the test mesh
RomainBaville c22e876
Clarify the variable names and the doc
RomainBaville 70b9358
Merge branch 'main' into RomainBaville/refactor/MoveGeosBlockExtractor
RomainBaville 6a922d3
Test CI labels identification and dispatch
alexbenedicto 14ea06c
Merge branch 'main' into RomainBaville/refactor/MoveGeosBlockExtractor
alexbenedicto 757732f
Fix docs
alexbenedicto 323b315
Revert Test CI labels identification and dispatch to create a dedicat…
alexbenedicto 4fbe721
add a mesh with a well only
RomainBaville 354dae9
Add a function to get the cell dimension of a mesh
RomainBaville e782d7e
Apply Palomas and Jacques suggestion
RomainBaville 86b09f5
Merge branch 'main' into RomainBaville/refactor/MoveGeosBlockExtractor
RomainBaville 28122b5
move GeosExtractBlock in geos-processing
RomainBaville 57fa533
fix bad move
RomainBaville 0161e2b
update the doc files
RomainBaville 70fcbfb
fix doc
RomainBaville b17ead9
Apply Jacques suggestion
RomainBaville 7aca9a8
Merge branch 'main' into RomainBaville/refactor/MoveGeosBlockExtractor
RomainBaville File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
254 changes: 254 additions & 0 deletions
254
geos-mesh/src/geos/mesh/processing/GeosBlockExtractor.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,254 @@ | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
| # SPDX-FileCopyrightText: Copyright 2023-2024 TotalEnergies. | ||
| # SPDX-FileContributor: Martin Lemay, Romain Baville | ||
| import logging | ||
| from dataclasses import dataclass | ||
| from typing_extensions import Self | ||
|
|
||
| from geos.utils.Logger import ( Logger, getLogger ) | ||
| from geos.utils.GeosOutputsConstants import ( GeosDomainNameEnum ) | ||
| from geos.mesh.utils.multiblockHelpers import ( getBlockIndexFromName ) | ||
|
|
||
| from vtkmodules.vtkCommonDataModel import vtkMultiBlockDataSet | ||
| from vtkmodules.vtkFiltersExtraction import vtkExtractBlock | ||
|
|
||
| __doc__ = """ | ||
| GeosBlockExtractor is a vtk filter that allows to extract from an output Geos multiBlockDataSet | ||
| all the blocks in a multiBlockDataSet of a Geos domain with its index. | ||
| There is tree domains: | ||
| 0: all the blocks referring to volume, | ||
| 1: all the blocks referring to faults, | ||
| 2: all the blocks referring to wells, | ||
| .. Important:: | ||
| The input mesh must be an output of a Geos simulation or have the same domain name. | ||
| .. Note:: | ||
| The volume domain is automatically extracted, by defaults the fault and well domain are empty multiBlockDataSet. | ||
| To use the filter: | ||
| .. code-block:: python | ||
| from geos.mesh.processing.GeosBlockExtractor import GeosBlockExtractor | ||
| # Filter inputs. | ||
| geosMesh: vtkMultiBlockDataSet | ||
| # Optional inputs. | ||
| extractFaults: bool # Defaults to False | ||
| extractWells: bool # Defaults to False | ||
| speHandler: bool # Defaults to False | ||
| # Instantiate the filter | ||
| filter: GeosBlockExtractor = GeosBlockExtractor( geosMesh, extractFaults, extractWells, speHandler ) | ||
| # Set the handler of yours (only if speHandler is True). | ||
| yourHandler: logging.Handler | ||
| filter.setLoggerHandler( yourHandler ) | ||
| # Do calculations | ||
| filter.applyFilter() | ||
| # Get the mesh of the wanted extracted domain | ||
| domainId: int | ||
| domainExtracted: vtkMultiBlockDataSet = filter.getOutput( domainId ) | ||
| """ | ||
|
|
||
| loggerTitle: str = "Geos Block Extractor Filter" | ||
|
|
||
|
|
||
| class GeosExtractDomain( vtkExtractBlock ): | ||
|
|
||
| def __init__( self: Self ) -> None: | ||
| """Extract domain (volume, fault, well) from geos output.""" | ||
| super().__init__() | ||
|
|
||
| self.geosDomainName: dict[ int, str ] = { | ||
| 0: GeosDomainNameEnum.VOLUME_DOMAIN_NAME.value, | ||
| 1: GeosDomainNameEnum.FAULT_DOMAIN_NAME.value, | ||
| 2: GeosDomainNameEnum.WELL_DOMAIN_NAME.value, | ||
| } | ||
|
|
||
| def GetGeosDomainName( self: Self, domainId: int ) -> str: | ||
| """Get the name from the Geos domain index. | ||
| Args: | ||
| domainId (int): The index of the Geos domain. | ||
| Returns: | ||
| str: The name of the Geos domain. | ||
| """ | ||
| return self.geosDomainName[ domainId ] | ||
|
|
||
| def AddGeosDomainIndex( self, domainId: int ) -> None: | ||
| """Add the index of the wanted Geos domain block to extract. | ||
| The domain type to extract are: | ||
| - Volumes -> domain index = 0 | ||
| - Faults -> domain index = 1 | ||
| - Wells -> domain index = 2 | ||
| Args: | ||
| domainId (int): Index of the Geos domain to extract. | ||
| """ | ||
| blockIndex: int = getBlockIndexFromName( self.GetInput(), self.geosDomainName[ domainId ] ) | ||
| print( domainId ) | ||
paloma-martinez marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| return super().AddIndex( blockIndex ) | ||
|
|
||
|
|
||
| class GeosBlockExtractor: | ||
|
|
||
| @dataclass | ||
| class ExtractDomain: | ||
| """The dataclass with the three Geos domains (volume, fault, well).""" | ||
| _volume: vtkMultiBlockDataSet = vtkMultiBlockDataSet() | ||
| _fault: vtkMultiBlockDataSet = vtkMultiBlockDataSet() | ||
| _well: vtkMultiBlockDataSet = vtkMultiBlockDataSet() | ||
|
|
||
| @property | ||
| def volume( self: Self ) -> vtkMultiBlockDataSet: | ||
| """Get the mesh corresponding to the Geos volume domain.""" | ||
| return self._volume | ||
|
|
||
| @volume.setter | ||
| def volume( self: Self, multiBlockDataSet: vtkMultiBlockDataSet ) -> None: | ||
| self._volume.DeepCopy( multiBlockDataSet ) | ||
|
|
||
| @property | ||
| def fault( self: Self ) -> vtkMultiBlockDataSet: | ||
| """Get the mesh corresponding to the Geos fault domain.""" | ||
| return self._fault | ||
|
|
||
| @fault.setter | ||
| def fault( self: Self, multiBlockDataSet: vtkMultiBlockDataSet ) -> None: | ||
| self._fault.DeepCopy( multiBlockDataSet ) | ||
|
|
||
| @property | ||
| def well( self: Self ) -> vtkMultiBlockDataSet: | ||
| """Get the mesh corresponding to the Geos well domain.""" | ||
| return self._well | ||
|
|
||
| @well.setter | ||
| def well( self: Self, multiBlockDataSet: vtkMultiBlockDataSet ) -> None: | ||
| self._well.DeepCopy( multiBlockDataSet ) | ||
|
|
||
| def getExtractDomain( self: Self, domainId: int ) -> vtkMultiBlockDataSet: | ||
| """Get the mesh for the correct domain. | ||
| Args: | ||
| domainId (int): The index of the Geos domain to get. | ||
| Returns: | ||
| vtkMultiBlockDataSet: The mesh with the Geos domain. | ||
| """ | ||
| if domainId == 0: | ||
| return self.volume | ||
| elif domainId == 1: | ||
| return self.fault | ||
| elif domainId == 2: | ||
| return self.well | ||
| else: | ||
| raise IndexError | ||
|
|
||
| def setExtractDomain( self: Self, domainId: int, multiBlockDataSet: vtkMultiBlockDataSet ) -> None: | ||
| """Set the mesh to the correct domain. | ||
| Args: | ||
| domainId (int): The index of the Geos domain. | ||
| multiBlockDataSet (vtkMultiBlockDataSet): The mesh to set. | ||
| """ | ||
| if domainId == 0: | ||
| self.volume = multiBlockDataSet | ||
| elif domainId == 1: | ||
| self.fault = multiBlockDataSet | ||
| elif domainId == 2: | ||
| self.well = multiBlockDataSet | ||
|
|
||
| extractDomain: ExtractDomain = ExtractDomain() | ||
|
|
||
| def __init__( | ||
| self: Self, | ||
| geosMesh: vtkMultiBlockDataSet, | ||
| extractFaults: bool = False, | ||
| extractWells: bool = False, | ||
| speHandler: bool = False, | ||
| ) -> None: | ||
| """Extract the volume, the surface or the well domain block of the mesh from Geos. | ||
| Args: | ||
| geosMesh (vtkMultiBlockDataSet): The mesh from Geos. | ||
| extractFaults (bool, Optional): True if the mesh contains Faults to extract, False otherwise. | ||
| Defaults to False. | ||
| extractWells (bool, Optional): True if the mesh contains wells to extract, False otherwise. | ||
| Defaults to False. | ||
| speHandler (bool, optional): True to use a specific handler, False to use the internal handler. | ||
| Defaults to False. | ||
| """ | ||
| self.geosMesh: vtkMultiBlockDataSet = geosMesh | ||
|
|
||
| self.domainIdToExtract: list[ int ] = [ 0 ] | ||
| if extractFaults: | ||
| self.domainIdToExtract.append( 1 ) | ||
| if extractWells: | ||
| self.domainIdToExtract.append( 2 ) | ||
|
|
||
| # Logger. | ||
| self.logger: Logger | ||
| if not speHandler: | ||
| self.logger = getLogger( loggerTitle, True ) | ||
| else: | ||
| self.logger = logging.getLogger( loggerTitle ) | ||
| self.logger.setLevel( logging.INFO ) | ||
|
|
||
| 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. | ||
| Args: | ||
| handler (logging.Handler): The handler to add. | ||
| """ | ||
| 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." | ||
| ) | ||
|
|
||
| def applyFilter( self: Self ) -> bool: | ||
|
||
| """Extract the volume, the surface or the well domain of the mesh from Geos. | ||
| Returns: | ||
| bool: True if calculation successfully ended, False otherwise. | ||
| """ | ||
| extractBlock: GeosExtractDomain = GeosExtractDomain() | ||
| extractBlock.SetInputData( self.geosMesh ) | ||
|
|
||
| for domainId in self.domainIdToExtract: | ||
| extractBlock.RemoveAllIndices() | ||
| extractBlock.AddGeosDomainIndex( domainId ) | ||
| extractBlock.Update() | ||
| self.extractDomain.setExtractDomain( domainId, extractBlock.GetOutput() ) | ||
| if self.extractDomain.getExtractDomain( domainId ).GetNumberOfBlocks() == 0: | ||
| self.logger.error( | ||
| f"The input mesh does not have { extractBlock.GetGeosDomainName( domainId ) } to extract." ) | ||
| return False | ||
|
|
||
| return True | ||
|
|
||
| def getOutput( self: Self, domainId: int ) -> vtkMultiBlockDataSet: | ||
| """Get the Geos domain extracted. | ||
| The domain extracted are: | ||
| - Volumes -> domain index = 0 | ||
| - Faults -> domain index = 1 | ||
| - Wells -> domain index = 2 | ||
| Args: | ||
| domainId (int): The index of the Geos domain to get. | ||
| Returns: | ||
| vtkMultiBlockDataSet: The Geos domain extracted. | ||
| """ | ||
| return self.extractDomain.getExtractDomain( domainId ) | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| <?xml version="1.0"?> | ||
| <VTKFile type="vtkMultiBlockDataSet" version="1.0"> | ||
| <vtkMultiBlockDataSet> | ||
| <Block name="CellElementRegion"> | ||
| <DataSet name="domain" file="domain_res5_id.vtu"/> | ||
| <DataSet name="emptyDomain" file="domain_res5_id_empty.vtu"/> | ||
| </Block> | ||
| <Block name="SurfaceElementRegion"> | ||
| <DataSet name="fracture" file="fracture_res5_id.vtu"/> | ||
| <DataSet name="emptyFracture" file="fracture_res5_id_empty.vtu"/> | ||
| </Block> | ||
| <Block name="WellElementRegion"> | ||
| <DataSet name="triangulatedSurface" file="triangulatedSurface.vtu"/> | ||
| </Block> | ||
| </vtkMultiBlockDataSet> | ||
| </VTKFile> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
| # SPDX-FileCopyrightText: Copyright 2023-2024 TotalEnergies. | ||
| # SPDX-FileContributor: Romain Baville | ||
| # SPDX-License-Identifier: Apache 2.0 | ||
| # ruff: noqa: E402 # disable Module level import not at top of file | ||
| # mypy: disable-error-code="operator" | ||
| import pytest | ||
|
|
||
| from vtkmodules.vtkCommonDataModel import vtkMultiBlockDataSet | ||
| from geos.mesh.processing.GeosBlockExtractor import GeosBlockExtractor | ||
|
|
||
|
|
||
| @pytest.mark.parametrize( "extractFaults, extractWells", [ | ||
| ( False, False ), | ||
| ( True, False ), | ||
| ( False, True ), | ||
| ( True, True ), | ||
| ] ) | ||
| def test_GeosExtractBlock( | ||
| dataSetTest: vtkMultiBlockDataSet, | ||
| extractFaults: bool, | ||
| extractWells: bool, | ||
| ) -> None: | ||
| """Test GeosExtractBlock vtk filter.""" | ||
| multiBlockDataSet: vtkMultiBlockDataSet = dataSetTest( "meshGeosExtractBlockTmp" ) | ||
|
|
||
| filter: GeosBlockExtractor = GeosBlockExtractor( multiBlockDataSet, extractFaults, extractWells ) | ||
| assert filter.applyFilter() | ||
|
|
||
| extractVolume: vtkMultiBlockDataSet = filter.getOutput( 0 ) | ||
| extractFault: vtkMultiBlockDataSet = filter.getOutput( 1 ) | ||
| extractWell: vtkMultiBlockDataSet = filter.getOutput( 2 ) | ||
|
|
||
| assert extractVolume.GetNumberOfBlocks() == 2 | ||
|
|
||
| if extractFaults: | ||
| assert extractFault.GetNumberOfBlocks() == 2 | ||
|
|
||
| if extractWells: | ||
| assert extractWell.GetNumberOfBlocks() == 1 |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.