Skip to content

feat: improve and update of geos-mesh utils functions #109

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
merged 34 commits into from
Aug 6, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
0ca3fe5
add a function to get the type of a vtk array
RomainBaville Jun 24, 2025
a905450
uptade the function createAttribute to preserve the type of the vtk a…
RomainBaville Jun 24, 2025
ec0302f
update the typing in the test of the function createAttribute
RomainBaville Jun 24, 2025
6c501c4
Update createAttribute and createConstantAttributeDataSet
RomainBaville Jun 26, 2025
510887d
Merge branch 'main' into RomainBaville/feature/update_geos-mesh_utils
RomainBaville Jun 26, 2025
490135c
update fillPartialAttribute and fillAllPartialAttributes
RomainBaville Jun 27, 2025
15a67fa
Add a function to get the vtk data type of an attribute of a multiblo…
RomainBaville Jun 27, 2025
5b17644
Formating for the CI
RomainBaville Jun 27, 2025
bd63003
Uptade functions calling utils functions
RomainBaville Jun 30, 2025
19ffa8d
Fix the doc issue
RomainBaville Jun 30, 2025
bcdf4bd
Apply suggestions from code review
RomainBaville Jul 15, 2025
e79f5ab
Generalize error message of copyAttribute
RomainBaville Jul 15, 2025
b17e2e5
Add a raise assertion error in case of the mesh doen't have the attri…
RomainBaville Jul 15, 2025
5941980
Update the default value for uint case for fillpartialattribute
RomainBaville Jul 15, 2025
f46fde5
Cleen and add logger to manadge output messages
RomainBaville Jul 16, 2025
614cafa
clear the tests and functions of arrayModifiers
RomainBaville Jul 18, 2025
1423482
Clean fillpartialattribute and its test
RomainBaville Jul 22, 2025
0e2ded2
clean the code and add a funtion to test if an attribute is partial.
RomainBaville Jul 22, 2025
68d6c3c
fix the test of isAttributeGlobal
RomainBaville Jul 22, 2025
57c9bd2
Clean the code
RomainBaville Jul 22, 2025
b4ff24e
Clean for ci
RomainBaville Jul 23, 2025
7da8f9b
Clean for the ci
RomainBaville Jul 23, 2025
3c8f5d6
Clean doc
RomainBaville Jul 23, 2025
1d16852
Clean for ci
RomainBaville Jul 23, 2025
b4e2084
Clean For ci
RomainBaville Jul 23, 2025
f052c14
Clean For ci
RomainBaville Jul 23, 2025
6fc4f5d
Apply suggestions from Paloma's code review
RomainBaville Jul 28, 2025
80c08ae
Merge branch 'main' into RomainBaville/feature/update_geos-mesh_utils
RomainBaville Jul 28, 2025
36d715f
fix error in transferAttributes
RomainBaville Jul 28, 2025
8f0ed47
Merge branch 'main' into RomainBaville/feature/update_geos-mesh_utils
RomainBaville Jul 30, 2025
96f2237
Clean variables name and typing
RomainBaville Aug 6, 2025
2ac03bc
Remove the AsDF function
RomainBaville Aug 6, 2025
a021fa7
Change variables iter to iterator
RomainBaville Aug 6, 2025
f100bb8
Clean for ci
RomainBaville Aug 6, 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
352 changes: 179 additions & 173 deletions geos-mesh/src/geos/mesh/utils/arrayHelpers.py

Large diffs are not rendered by default.

762 changes: 551 additions & 211 deletions geos-mesh/src/geos/mesh/utils/arrayModifiers.py

Large diffs are not rendered by default.

3 changes: 1 addition & 2 deletions geos-mesh/src/geos/mesh/utils/multiblockModifiers.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,7 @@ def mergeBlocks(

"""
if keepPartialAttributes:
fillAllPartialAttributes( input, False )
fillAllPartialAttributes( input, True )
fillAllPartialAttributes( input )

af = vtkAppendDataSets()
af.MergePointsOn()
Expand Down
144 changes: 137 additions & 7 deletions geos-mesh/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
# ruff: noqa: E402 # disable Module level import not at top of file
import os
import pytest
from typing import Union
from typing import Union, Any
import numpy as np
import numpy.typing as npt

Expand All @@ -15,6 +15,7 @@

@pytest.fixture
def arrayExpected( request: pytest.FixtureRequest ) -> npt.NDArray[ np.float64 ]:
"""Get an array from a file."""
reference_data = "data/data.npz"
reference_data_path = os.path.join( os.path.dirname( os.path.realpath( __file__ ) ), reference_data )
data = np.load( reference_data_path )
Expand All @@ -24,6 +25,7 @@ def arrayExpected( request: pytest.FixtureRequest ) -> npt.NDArray[ np.float64 ]

@pytest.fixture
def arrayTest( request: pytest.FixtureRequest ) -> npt.NDArray[ np.float64 ]:
"""Get a random array of float64."""
np.random.seed( 42 )
array: npt.NDArray[ np.float64 ] = np.random.rand(
request.param,
Expand All @@ -33,22 +35,150 @@ def arrayTest( request: pytest.FixtureRequest ) -> npt.NDArray[ np.float64 ]:


@pytest.fixture
def dataSetTest() -> Union[ vtkMultiBlockDataSet, vtkPolyData, vtkDataSet ]:
def getArrayWithSpeTypeValue() -> Any:
"""Get a random array of input type with the function _getarray().

def _get_dataset( datasetType: str ):
Returns:
npt.NDArray[Any]: Random array of input type.
"""

def _getarray( nb_component: int, nb_elements: int, valueType: str ) -> Any:
"""Get a random array of input type.

Args:
nb_component (int): Number of components.
nb_elements (int): Number of elements.
valueType (str): The type of the value.

Returns:
npt.NDArray[Any]: Random array of input type.
"""
np.random.seed( 28 )
if valueType == "int8":
if nb_component == 1:
return np.array( [ np.int8( 10 * np.random.random() ) for _ in range( nb_elements ) ] )
else:
return np.array( [ [ np.int8( 10 * np.random.random() ) for _ in range( nb_component ) ]
for _ in range( nb_elements ) ] )

elif valueType == "int16":
if nb_component == 1:
return np.array( [ np.int16( 1000 * np.random.random() ) for _ in range( nb_elements ) ] )
else:
return np.array( [ [ np.int16( 1000 * np.random.random() ) for _ in range( nb_component ) ]
for _ in range( nb_elements ) ] )

elif valueType == "int32":
if nb_component == 1:
return np.array( [ np.int32( 1000 * np.random.random() ) for _ in range( nb_elements ) ] )
else:
return np.array( [ [ np.int32( 1000 * np.random.random() ) for _ in range( nb_component ) ]
for _ in range( nb_elements ) ] )

elif valueType == "int64":
if nb_component == 1:
return np.array( [ np.int64( 1000 * np.random.random() ) for _ in range( nb_elements ) ] )
else:
return np.array( [ [ np.int64( 1000 * np.random.random() ) for _ in range( nb_component ) ]
for _ in range( nb_elements ) ] )

if valueType == "uint8":
if nb_component == 1:
return np.array( [ np.uint8( 10 * np.random.random() ) for _ in range( nb_elements ) ] )
else:
return np.array( [ [ np.uint8( 10 * np.random.random() ) for _ in range( nb_component ) ]
for _ in range( nb_elements ) ] )

elif valueType == "uint16":
if nb_component == 1:
return np.array( [ np.uint16( 1000 * np.random.random() ) for _ in range( nb_elements ) ] )
else:
return np.array( [ [ np.uint16( 1000 * np.random.random() ) for _ in range( nb_component ) ]
for _ in range( nb_elements ) ] )

elif valueType == "uint32":
if nb_component == 1:
return np.array( [ np.uint32( 1000 * np.random.random() ) for _ in range( nb_elements ) ] )
else:
return np.array( [ [ np.uint32( 1000 * np.random.random() ) for _ in range( nb_component ) ]
for _ in range( nb_elements ) ] )

elif valueType == "uint64":
if nb_component == 1:
return np.array( [ np.uint64( 1000 * np.random.random() ) for _ in range( nb_elements ) ] )
else:
return np.array( [ [ np.uint64( 1000 * np.random.random() ) for _ in range( nb_component ) ]
for _ in range( nb_elements ) ] )

elif valueType == "int":
if nb_component == 1:
return np.array( [ int( 1000 * np.random.random() ) for _ in range( nb_elements ) ] )
else:
return np.array( [ [ int( 1000 * np.random.random() ) for _ in range( nb_component ) ]
for _ in range( nb_elements ) ] )

elif valueType == "float":
if nb_component == 1:
return np.array( [ float( 1000 * np.random.random() ) for _ in range( nb_elements ) ] )
else:
return np.array( [ [ float( 1000 * np.random.random() ) for _ in range( nb_component ) ]
for _ in range( nb_elements ) ] )

elif valueType == "float32":
if nb_component == 1:
return np.array( [ np.float32( 1000 * np.random.random() ) for _ in range( nb_elements ) ] )
else:
return np.array( [ [ np.float32( 1000 * np.random.random() ) for _ in range( nb_component ) ]
for _ in range( nb_elements ) ] )

elif valueType == "float64":
if nb_component == 1:
return np.array( [ np.float64( 1000 * np.random.random() ) for _ in range( nb_elements ) ] )
else:
return np.array( [ [ np.float64( 1000 * np.random.random() ) for _ in range( nb_component ) ]
for _ in range( nb_elements ) ] )

return _getarray


@pytest.fixture
def dataSetTest() -> Any:
"""Get a vtkObject from a file with the function _get_dataset().

Returns:
(vtkMultiBlockDataSet, vtkPolyData, vtkDataSet): The vtk object.
"""

def _get_dataset( datasetType: str ) -> Union[ vtkMultiBlockDataSet, vtkPolyData, vtkDataSet ]:
"""Get a vtkObject from a file.

Args:
datasetType (str): The type of vtk object wanted.

Returns:
(vtkMultiBlockDataSet, vtkPolyData, vtkDataSet): The vtk object.
"""
reader: Union[ vtkXMLMultiBlockDataReader, vtkXMLUnstructuredGridReader ]
if datasetType == "multiblock":
reader = reader = vtkXMLMultiBlockDataReader()
reader = vtkXMLMultiBlockDataReader()
vtkFilename = "data/displacedFault.vtm"
elif datasetType == "emptymultiblock":
reader = vtkXMLMultiBlockDataReader()
vtkFilename = "data/displacedFaultempty.vtm"
elif datasetType == "dataset":
reader: vtkXMLUnstructuredGridReader = vtkXMLUnstructuredGridReader()
reader = vtkXMLUnstructuredGridReader()
vtkFilename = "data/domain_res5_id.vtu"
elif datasetType == "emptydataset":
reader = vtkXMLUnstructuredGridReader()
vtkFilename = "data/domain_res5_id_empty.vtu"
elif datasetType == "polydata":
reader: vtkXMLUnstructuredGridReader = vtkXMLUnstructuredGridReader()
reader = vtkXMLUnstructuredGridReader()
vtkFilename = "data/surface.vtu"

datapath: str = os.path.join( os.path.dirname( os.path.realpath( __file__ ) ), vtkFilename )
reader.SetFileName( datapath )
reader.Update()

return reader.GetOutput()

return _get_dataset
return _get_dataset
7 changes: 7 additions & 0 deletions geos-mesh/tests/data/displacedFaultempty.vtm
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0"?>
<VTKFile type="vtkMultiBlockDataSet" version="1.0">
<vtkMultiBlockDataSet>
<DataSet name="main" file="domain_res5_id_empty.vtu"/>
<DataSet name="fracture" file="fracture_res5_id_empty.vtu"/>
</vtkMultiBlockDataSet>
</VTKFile>
39 changes: 39 additions & 0 deletions geos-mesh/tests/data/domain_res5_id_empty.vtu

Large diffs are not rendered by default.

41 changes: 41 additions & 0 deletions geos-mesh/tests/data/fracture_res5_id_empty.vtu
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?xml version="1.0"?>
<VTKFile type="UnstructuredGrid" version="0.1" byte_order="LittleEndian" header_type="UInt32" compressor="vtkZLibDataCompressor">
<UnstructuredGrid>
<Piece NumberOfPoints="212" NumberOfCells="156">
<PointData GlobalIds="GLOBAL_IDS_POINTS">
<DataArray type="Int64" IdType="1" Name="GLOBAL_IDS_POINTS" format="binary" RangeMin="0" RangeMax="211">
AQAAAACAAACgBgAAbgEAAA==eJwtxdciEAAAAEBRUmlpK9q0aEpbey/tTUMb0d57T6VBO+2NSGjvoflDHrp7uYCA/6o40EGu6moOdnWHuIZrupZDXdt1XNf1XN9hbuCGbuTGbuKmbuZwN3cLRzjSLd3Krd3Gbd3O7R3laHdwR3dyZ3dxjGPd1d3c3T3c070c596Odx/3dT/39wAP9CAneLCHeKiHebhHeKRHebTHeKzHebwneKInebITPcVTPc3TPcMzPcuzPcdzPc/zvcBJTvZCL/JiL3GKl3qZl3uFV3qVVzvVaU73Gmc402u9zuu9wRu9yZu9xVu9zdu9wzu9y7u9x3u9z/t9wAd9yId9xEd9zMd9wid9ylk+7TPO9lmf83lfcI5zfdGXfNlXfNXXfN03nOebvuXbvuO7vuf7fuCHfuTHfuKnzneBC/3MRS72c5f4hUtd5nK/9Cu/9hu/9Tu/9wd/9Cd/9hd/9Td/9w9X+Kd/+bf/+K//uRLqf1df
</DataArray>
</PointData>
<CellData GlobalIds="GLOBAL_IDS_CELLS">
<DataArray type="Int64" IdType="1" Name="GLOBAL_IDS_CELLS" format="binary" RangeMin="0" RangeMax="155">
AQAAAACAAADgBAAAEgEAAA==eJwtxddCCAAAAMAiozSkoaGh0NAeqGhrSNEg7SFkJKFhlIhoaCBUP9tDdy8XEHAo0Ed81EE+5uM+4ZMOdohPOdRhDneETzvSZxzlaMc41mcd53gnONHnnORkpzjV553mdF/wRV9yhjOd5Wxfdo5zned8F7jQRS52iUt9xVd9zWUud4Wv+4YrXeVq17jWda73TTe40U1u9i23+LZb3eY7vut2d7jTXb7n++72A/e4133u94AHPeRhj3jUDz3mR37sJx73Uz/zc7/whF960q885dd+47ee9oxnPed3fu8P/uh5L/iTF/3ZX7zkr/7mZX/3D6941Wte909veNNb3vYv//Yf7/iv//m/d73nfR8ARZMvOw==
</DataArray>
</CellData>
<Points>
<DataArray type="Float32" Name="Points" NumberOfComponents="3" format="binary" RangeMin="0" RangeMax="2304.886114323222">
AQAAAACAAADwCQAAXQIAAA==eJxtlaFOK1EQhheFQZCKq1E3+xQN6Zm+QR8ATdKER1iPQVVvVhxxa6rQtNy6DcFhGzwJkhzF9ITO/93kVn3Z7M78Z86XTtP4r7/YN6dfey7enInvvv4Gdx/ih3dx/ybejOKnrfj1UXxYiz97cbMSX96LrzrxzS3yLJBhir4tek1QvzwHXr+IuwG8FDe/wKtd89/faob3E+qAB/H1i7gp4sPEkF/cT8XdQnxzK77qxJf34mYl/uzFh7X49RF9t+LNiAxv4od35PkQ333h27N5cHsu7i/I+/Wf3+nnHbG7F+zuBbt7we5esLunb0exuxfs7gW7e8HuXrC7F+zuBbt7we6e8iyQYYq+LXpNUL88B7t7qjOAl2J3D9l24qbB8xneT6gDHhL6JuRJyGnIbziX4byGORjmY5ibIZthzob5i9093JfY3cP9it09+CB29+DPHF6J3T2wO5bhXoZ7Ge5luJfhXoZ7p29HcXUvw70M9zLcy3Avw70M9zLcO+VZIMMUfVv0mqD+0b0M9051BvBSXN2LbDvx0b14PsP7CXXAQ0LfhDwJOQ35DecynNcwB8N8DHMzZDPM2TB/cXUv7ktc3Yv7FVf3wgdxdS/8mcMrcXUveB//+3XnlnAvuO7cEu4F151bwj19O4rrzi3hXnDduSXc0+5ZievOLeFecN25pzwLZJiib4teE9Q/7twS7qnOAF6K686NbLt/dqSez/B+Qh3wkNA3IU9CTkN+w7kM5zXMwTAfw9wM2QxzFtedG/eCvltx3blxv+K6c8MHcd254c8cXonrzi3pG10/Tpw=
<InformationKey name="L2_NORM_RANGE" location="vtkDataArray" length="2">
<Value index="0">
0
</Value>
<Value index="1">
2304.8861143
</Value>
</InformationKey>
</DataArray>
</Points>
<Cells>
<DataArray type="Int64" Name="connectivity" format="binary" RangeMin="0" RangeMax="211">
AQAAAACAAACAEwAAWQMAAA==eJxd1Vf7CAQYhnEjpKiUWYmiREX29rf33nvvvffee29KoShbpE2plJXxhRy474Oe9+R3Xff1nL/1Cz2/BjgFJ2M9rB99EtaNnX0ifho7+wSsEzv7eKwdO/s4/CR29rH4cezsY/Cj2NlHY63Y2UdhzdjZR+KHsbOPwBqxsw/HD2JnH4bvx84+FKvHzj4Eq8XOPhjfi519EL4bO/tArBo7+wCsEjt7f3wndvZ+WDl29r74duzsffCt2Nl745uxs/fCSrGz98SKsbP3wAqxs3fH8rGzd8NysbN3xbKxs3fBN2Jn74yvx87eCcvEzt4RX4udvQO+Gjt7e3wldvZ2WDp29rZYKnb2Nvhy7Oyt8aXY2QuwZOzsrfDF2NlbYonY2Vtg8djZm2Ox2Nmb4QuxszfForGzN8EisbM3xsKxszcq9P8rHL0h+k/8O5/jZzgpdvbjODF29mM4IXb2ozg+dvYjOC529sM4Nnb2QzgmdvaDODp29gM4Knb2/TgydvZ9OCJ29r04PHb2PTgsdvbdODR29l04JHb2nTg4dvYdOCh29u04MHb2bTggdvat2D929i3YL3b2zdg3dvZN2Cd29o3YO3b2Ddgrdvb12DN29nXYI3b2tdg9dvY12C129tXYNXb2VdgldvaV2Dl29hXYKXb25dgxdvZl2CF29qXYPnb2JdgudvbF2DZ29kXYJnb2hdg6dvYFWBA7+3xsFTv7PGwZO/tcbBE7+xxsHjv7bGwWO/ssbBo7+0xsEjv7DGwcO/t0bBQ7+zRsGDv7VPSf+Hee4hM8Hjv7YzwWO/sjPBo7+394JHb2h3g4dvYHeCh29vt4MHb2e3ggdva7uD929n9xX+zs/+De2Nnv4J7Y2f/G3bGz/4W7Ymf/E3fGzn4bd8TO/gduj539d9wWO/st3Bo7+03cEjv7b7g5dvZfcVPs7L/gxtjZf8YNsbP/hOtjZ/8R18XO/gOujZ39Bq6Jnf17XB07+3VcFTv7NVwZO/t3uCJ29qu4PHb2K7gsdvbLuDR29ku4JHb2i7g4dvYLuCh29vO4MHb2c7ggdvZvcX7s7N/gvNjZz+Lc2NnP4JzY2b/G2bGzf4WzYmc/jTNjZz+FM2JnP4nTY2f/EqfFzv4FTo2d/QQ+A6EeATg=
</DataArray>
<DataArray type="Int64" Name="offsets" format="binary" RangeMin="4" RangeMax="624">
AQAAAACAAADgBAAADgEAAA==eJwtxRFwAgAAAMC2C4IgCIIgCIIgCIIgCIIgCIIgCIIgCIIgCIIgCIIgCIIgCAaDwSAIgiAIgiAIBkEQDPqXDwbeQg474qhjjjvhpFNOO+Osc8674KJLLrviqmuuu+GmW26746577nvgoUcee+KpZ5574aVXXnvjrb/87R//eue9Dz765LMvvvrmu//88NMvBz7eBR1y2BFHHXPcCSedctoZZ51z3gUXXXLZFVddc90NN91y2x133XPfAw898tgTTz3z3AsvvfLaG2/95W//+Nc7733w0SefffHVN9/954effjnw+S7okMOOOOqY40446ZTTzjjrnPMuuOiSy6646prrbrjpltvu+B9fwUXT
</DataArray>
<DataArray type="UInt8" Name="types" format="binary" RangeMin="7" RangeMax="7">
AQAAAACAAACcAAAADAAAAA==eJxjZx+8AABPhQRF
</DataArray>
</Cells>
</Piece>
</UnstructuredGrid>
</VTKFile>
45 changes: 45 additions & 0 deletions geos-mesh/tests/test_arrayHelpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,22 @@ def test_isAttributeInObjectDataSet( dataSetTest: vtkDataSet, attributeName: str
assert obtained == expected


@pytest.mark.parametrize( "attributeName, onpoints, expected", [
( "PORO", False, False ),
( "GLOBAL_IDS_POINTS", True, True ),
] )
def test_isAttributeGlobal(
dataSetTest: vtkMultiBlockDataSet,
attributeName: str,
onpoints: bool,
expected: bool,
) -> None:
"""Test if the attribute is global or partial."""
multiBlockDataset: vtkMultiBlockDataSet = dataSetTest( "multiblock" )
obtained: bool = arrayHelpers.isAttributeGlobal( multiBlockDataset, attributeName, onpoints )
assert obtained == expected


@pytest.mark.parametrize( "arrayExpected, onpoints", [
( "PORO", False ),
( "PERM", False ),
Expand All @@ -100,6 +116,35 @@ def test_getArrayInObject( request: pytest.FixtureRequest, arrayExpected: npt.ND
assert ( obtained == expected ).all()


@pytest.mark.parametrize( "attributeName, vtkDataType, onPoints", [
( "CellAttribute", 11, False ),
( "PointAttribute", 11, True ),
( "collocated_nodes", 12, True ),
] )
def test_getVtkArrayTypeInMultiBlock( dataSetTest: vtkMultiBlockDataSet, attributeName: str, vtkDataType: int,
onPoints: bool ) -> None:
"""Test getting the type of the vtk array of an attribute from multiBlockDataSet."""
multiBlockDataSet: vtkMultiBlockDataSet = dataSetTest( "multiblock" )

vtkDataTypeTest: int = arrayHelpers.getVtkArrayTypeInMultiBlock( multiBlockDataSet, attributeName, onPoints )

assert ( vtkDataTypeTest == vtkDataType )


@pytest.mark.parametrize( "attributeName, onPoints", [
( "CellAttribute", False ),
( "PointAttribute", True ),
] )
def test_getVtkArrayTypeInObject( dataSetTest: vtkDataSet, attributeName: str, onPoints: bool ) -> None:
"""Test getting the type of the vtk array of an attribute from dataset."""
vtkDataSetTest: vtkDataSet = dataSetTest( "dataset" )

obtained: int = arrayHelpers.getVtkArrayTypeInObject( vtkDataSetTest, attributeName, onPoints )
expected: int = 11

assert ( obtained == expected )


@pytest.mark.parametrize( "arrayExpected, onpoints", [
( "PORO", False ),
( "PointAttribute", True ),
Expand Down
Loading