Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
06eca95
Modify isAttributeGlobal function to take into account recursive mult…
paloma-martinez Sep 2, 2025
8651018
Add bool output to mergeBlocks function for better logging and error …
paloma-martinez Sep 2, 2025
fbe6bf2
Adding a VTK filter for enhanced merge block
paloma-martinez Sep 2, 2025
b9855ce
Move and update plugin
paloma-martinez Sep 2, 2025
21d8b7d
Merge branch 'main' into pmartinez/refactor/createMergeBlockEnhancedV…
paloma-martinez Sep 12, 2025
54c70eb
Clean
paloma-martinez Sep 17, 2025
2de326a
Fix import format
paloma-martinez Sep 17, 2025
3d20b99
Typing
paloma-martinez Sep 17, 2025
22828f7
Adding tests and data for test for merge blocks
paloma-martinez Sep 17, 2025
29a038b
Documentation
paloma-martinez Sep 17, 2025
3d153cd
Yapf
paloma-martinez Sep 17, 2025
af3990e
Yapf again
paloma-martinez Sep 17, 2025
d9f289d
Yapf
paloma-martinez Sep 17, 2025
14bcb85
Fix docstring and typing
paloma-martinez Sep 17, 2025
05a1c17
Fix from Romain review
paloma-martinez Sep 18, 2025
df24923
Merge branch 'main' into pmartinez/refactor/createMergeBlockEnhancedV…
paloma-martinez Sep 18, 2025
f771dd6
Modification of mergeBlocks function following review's comment
paloma-martinez Sep 29, 2025
4d9c3d0
Merge branch 'main' into pmartinez/refactor/createMergeBlockEnhancedV…
paloma-martinez Sep 29, 2025
b3112f9
yapf
paloma-martinez Sep 29, 2025
b1b681b
bad merge fix
paloma-martinez Sep 29, 2025
682f50e
first error handling version
jafranc Oct 3, 2025
7da34e9
adding Fails test
jafranc Oct 6, 2025
43dd2d1
First completed attempt to capture errors from VTK
jafranc Oct 7, 2025
396ed11
last fixes
jafranc Oct 7, 2025
e0ab6fc
ruff + yapf
jafranc Oct 7, 2025
ba9e2b1
yapf tests
jafranc Oct 7, 2025
f8d2b1a
Update python-package.yml as order might matters
jafranc Oct 7, 2025
b8b1481
clean up
jafranc Oct 7, 2025
cd48656
Merge branch 'pmartinez/refactor/createMergeBlockEnhancedVTKFilter' o…
jafranc Oct 8, 2025
b839532
CI is testing vtk9.5.1 so skip the failing test for now
jafranc Oct 8, 2025
262932a
mypy and yapf
jafranc Oct 8, 2025
b98b49e
wrong version dispatch
jafranc Oct 8, 2025
073f4cd
Clean and formatting
paloma-martinez Oct 16, 2025
3d0c57c
Merge branch 'main' into pmartinez/refactor/createMergeBlockEnhancedV…
paloma-martinez Oct 16, 2025
3a7b061
bad merge
paloma-martinez Oct 16, 2025
907b2d6
Force int type to avoid errors
alexbenedicto Oct 16, 2025
24a8d27
Add comments to new Logger functionalities
alexbenedicto Oct 16, 2025
f9b5cf0
Correct invalid pattern
alexbenedicto Oct 16, 2025
df766cd
Fix error in doc
alexbenedicto Oct 17, 2025
d572700
Fix ruff error
alexbenedicto Oct 17, 2025
18b13f7
Add child logger to prevent to much verbosity in parent logger
paloma-martinez Oct 17, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 24 additions & 24 deletions .github/workflows/python-package.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: geosPythonPackages CI
name: geosPythonPackages CI
on: pull_request

# Cancels in-progress workflows for a PR when updated
Expand All @@ -9,13 +9,13 @@ concurrency:

jobs:
# Checks if PR title follows conventional semantics
semantic_pull_request:
semantic_pull_request:
permissions:
pull-requests: write # for amannn/action-semantic-pull-request to analyze PRs and
pull-requests: write # for amannn/action-semantic-pull-request to analyze PRs and
statuses: write # for amannn/action-semantic-pull-request to mark status of analyzed PR
contents: read
contents: read
runs-on: ubuntu-latest

steps:
- name: Check if the PR name has conventional semantics
if: github.event_name == 'pull_request'
Expand All @@ -27,7 +27,7 @@ jobs:
wip: true
# Configure that a scope doesn't need to be provided.
requireScope: false

- name: Skip the check on main branch
if: github.ref_name == 'main'
run: |
Expand All @@ -40,14 +40,14 @@ jobs:
max-parallel: 3
matrix:
python-version: ["3.10", "3.11", "3.12"]
package-name:
package-name:
- geos-ats
- geos-utils
- geos-geomechanics
- geos-mesh
- geos-posp
- geos-timehistory
- geos-trame
- geos-utils
- geos-xml-tools
- geos-xml-viewer
- hdf5-wrapper
Expand Down Expand Up @@ -77,7 +77,7 @@ jobs:
python -m pip install --upgrade pip
python -m pip install pytest yapf toml

DEPS="${{ matrix.dependencies || '' }}"
DEPS="${{ matrix.dependencies || '' }}"

if [ -n "$DEPS" ]; then
echo "Installing additional dependencies: $DEPS"
Expand Down Expand Up @@ -114,20 +114,20 @@ jobs:
uses: actions/checkout@v4
with:
fetch-depth: 0 # Fetch all history to compare with base branch

- name: Check if GEOS integration is required
id: check_changes
run: |
echo "Analyzing changed files to determine if GEOS integration test is required..."

# Get list of changed files
git fetch origin ${{ github.base_ref }}
CHANGED_FILES=$(git diff --name-only origin/${{ github.base_ref }}...HEAD)

echo "Changed files:"
echo "$CHANGED_FILES"
echo ""

# Define packages that are integrated into GEOS (from GEOS/scripts/setupPythonEnvironment.bash)
GEOS_INTEGRATED_PACKAGES=(
"geos-utils"
Expand All @@ -137,7 +137,7 @@ jobs:
"pygeos-tools"
"geos-ats"
)

# Define patterns that DON'T require GEOS integration testing
SKIP_PATTERNS=(
"^docs/"
Expand All @@ -158,21 +158,21 @@ jobs:
"^geos-trame/"
"^geos-xml-viewer/"
)

# Check if label is present (overrides automatic detection)
HAS_LABEL=$(echo '${{ toJson(github.event.pull_request.labels.*.name) }}' | grep -q "test-geos-integration" && echo "true" || echo "false")

if [[ "$HAS_LABEL" == "true" ]]; then
echo "✓ Label 'test-geos-integration' found - GEOS integration test will run"
echo "required=true" >> "$GITHUB_OUTPUT"
echo "skip_reason=none" >> "$GITHUB_OUTPUT"
exit 0
fi

# Check if any changed file affects GEOS-integrated packages
REQUIRES_GEOS_TEST=false
AFFECTED_PACKAGES=""

for file in $CHANGED_FILES; do
# Check if file matches any skip pattern
SHOULD_SKIP=false
Expand All @@ -182,7 +182,7 @@ jobs:
break
fi
done

if [[ "$SHOULD_SKIP" == "false" ]]; then
# Check if file is in a GEOS-integrated package
for package in "${GEOS_INTEGRATED_PACKAGES[@]}"; do
Expand All @@ -193,21 +193,21 @@ jobs:
fi
fi
done

# Check for CI workflow changes that affect GEOS integration
if echo "$file" | grep -qE "^\.github/workflows/(python-package\.yml|test_geos_integration\.yml)$"; then
REQUIRES_GEOS_TEST=true
AFFECTED_PACKAGES="$AFFECTED_PACKAGES [CI-workflows]"
fi

# Check for root-level scripts that might affect integration
if echo "$file" | grep -qE "^install_packages\.sh$"; then
REQUIRES_GEOS_TEST=true
AFFECTED_PACKAGES="$AFFECTED_PACKAGES [install-scripts]"
fi
fi
done

if [[ "$REQUIRES_GEOS_TEST" == "true" ]]; then
echo "✓ GEOS integration test REQUIRED"
echo " Affected packages/components:$AFFECTED_PACKAGES"
Expand Down Expand Up @@ -240,11 +240,11 @@ jobs:
run: |
echo "Final CI Validation"
echo "==================="

GEOS_REQUIRED="${{ needs.check_geos_integration_required.outputs.geos_integration_required }}"
SKIP_REASON="${{ needs.check_geos_integration_required.outputs.skip_reason }}"
GEOS_RESULT="${{ needs.geos_integration_test.result }}"

if [[ "$GEOS_REQUIRED" == "true" ]]; then
echo "GEOS integration test was required and triggered"
if [[ "$GEOS_RESULT" == "success" ]]; then
Expand Down
12 changes: 11 additions & 1 deletion docs/geos_mesh_docs/processing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,20 @@ geos.mesh.processing.SplitMesh filter
: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:
:show-inheritance:
5 changes: 0 additions & 5 deletions docs/geos_posp_docs/PVplugins.rst
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,6 @@ PVGeomechanicsWorkflowVolumeWell plugin

.. automodule:: PVplugins.PVGeomechanicsWorkflowVolumeWell

PVplugins.PVMergeBlocksEnhanced module
--------------------------------------

.. automodule:: PVplugins.PVMergeBlocksEnhanced


PVMohrCirclePlot plugin
---------------------------------
Expand Down
6 changes: 6 additions & 0 deletions docs/geos_pv_docs/processing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ PVSplitMesh
.. automodule:: geos.pv.plugins.PVSplitMesh


PVMergeBlocksEnhanced module
--------------------------------------

.. automodule:: geos.pv.plugins.PVMergeBlocksEnhanced


PVClipToMainFrame
----------------------------------

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@
# SPDX-FileCopyrightText: Copyright 2023-2024 TotalEnergies.
# SPDX-FileContributor: Romain Baville
import numpy as np
import numpy.typing as npt
import logging

import numpy.typing as npt
from typing import Union, Any
from typing_extensions import Self

Expand All @@ -13,7 +14,7 @@
vtkDataSet,
)

from geos.utils.Logger import ( getLogger, Logger, logging, CountWarningHandler )
from geos.utils.Logger import ( getLogger, Logger, CountWarningHandler )
from geos.mesh.utils.arrayHelpers import ( getArrayInObject, getComponentNames, getNumberOfComponents,
getVtkDataTypeInObject, isAttributeGlobal, getAttributePieceInfo,
checkValidValuesInDataSet, checkValidValuesInMultiBlock )
Expand Down
128 changes: 128 additions & 0 deletions geos-mesh/src/geos/mesh/processing/MergeBlockEnhanced.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright 2023-2024 TotalEnergies.
# SPDX-FileContributor: Paloma Martinez
# ruff: noqa: E402 # disable Module level import not at top of file
import logging

from typing_extensions import Self

from geos.utils.Logger import Logger, getLogger
from geos.mesh.utils.multiblockModifiers import mergeBlocks

from vtkmodules.vtkCommonDataModel import (
vtkMultiBlockDataSet,
vtkUnstructuredGrid,
)

__doc__ = """
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.

.. Note::
- You may encounter issues if two datasets of the input multiblock dataset have duplicated cell IDs.
- Partial attributes are filled with default values depending on their types.
- 0 for uint data.
- -1 for int data.
- nan for float data.


To use it:

.. code-block:: python

from geos.mesh.processing.MergeBlockEnhanced import MergeBlockEnhanced
import logging
from geos.utils.Errors import VTKError

# Define filter inputs
multiblockdataset: vtkMultiblockDataSet
speHandler: bool # optional

# Instantiate the filter
filter: MergeBlockEnhanced = MergeBlockEnhanced( multiblockdataset, speHandler )

# Use your own handler (if speHandler is True)
yourHandler: logging.Handler
filter.setLoggerHandler( yourHandler )

# Do calculations
try:
filter.applyFilter()
except VTKError:
logging.error("Something went wrong in VTK")

# Get the merged mesh
filter.getOutput()
"""

loggerTitle: str = "Merge Block Enhanced"


class MergeBlockEnhanced:

def __init__(
self: Self,
inputMesh: vtkMultiBlockDataSet,
speHandler: bool = False,
) -> None:
"""Merge a multiblock dataset and keep the partial attributes in the output mesh.

Partial attributes are filled with default values depending on the data type such that:
- 0 for uint data.
- -1 for int data.
- nan for float data.

Args:
inputMesh (vtkMultiBlockDataSet): The input multiblock dataset to merge.
speHandler (bool, optional) : True to use a specific handler, False to use the internal handler.
Defaults to False.
"""
self.inputMesh: vtkMultiBlockDataSet = inputMesh
self.outputMesh: vtkUnstructuredGrid = vtkUnstructuredGrid()

# 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 ) -> None:
"""Merge the blocks of a multiblock dataset mesh.

Returns:
bool: True if the blocks were successfully merged, False otherwise.

Raises:
VTKError (geos.utils.Errors) : error captured if any from the VTK log
"""
self.logger.info( f"Applying filter { self.logger.name }." )

outputMesh: vtkUnstructuredGrid
outputMesh = mergeBlocks( self.inputMesh, keepPartialAttributes=True, logger=self.logger )
self.outputMesh = outputMesh

def getOutput( self: Self ) -> vtkUnstructuredGrid:
"""Get the merged mesh.

Returns:
vtkUnstructuredGrid: The merged mesh.
"""
return self.outputMesh
1 change: 0 additions & 1 deletion geos-mesh/src/geos/mesh/utils/arrayHelpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -677,7 +677,6 @@ def isAttributeGlobal( multiBlockDataSet: vtkMultiBlockDataSet, attributeName: s
dataSet: vtkDataSet = vtkDataSet.SafeDownCast( multiBlockDataSet.GetDataSet( blockIndex ) )
if not isAttributeInObjectDataSet( dataSet, attributeName, onPoints ):
return False

return True


Expand Down
4 changes: 2 additions & 2 deletions geos-mesh/src/geos/mesh/utils/arrayModifiers.py
Original file line number Diff line number Diff line change
Expand Up @@ -762,13 +762,13 @@ def transferAttributeToDataSetWithElementMap(

for idElementTo in range( nbElementsTo ):
valueToTransfer: Any = defaultValue
idElementFrom: int = elementMap[ flatIdDataSetTo ][ idElementTo ][ 1 ]
idElementFrom: int = int( elementMap[ flatIdDataSetTo ][ idElementTo ][ 1 ] )
if idElementFrom != -1:
dataFrom: Union[ vtkPointData, vtkCellData ]
if isinstance( meshFrom, vtkDataSet ):
dataFrom = meshFrom.GetPointData() if onPoints else meshFrom.GetCellData()
elif isinstance( meshFrom, vtkMultiBlockDataSet ):
flatIdDataSetFrom: int = elementMap[ flatIdDataSetTo ][ idElementTo ][ 0 ]
flatIdDataSetFrom: int = int( elementMap[ flatIdDataSetTo ][ idElementTo ][ 0 ] )
dataSetFrom: vtkDataSet = vtkDataSet.SafeDownCast( meshFrom.GetDataSet( flatIdDataSetFrom ) )
dataFrom = dataSetFrom.GetPointData() if onPoints else dataSetFrom.GetCellData()

Expand Down
Loading