Skip to content

Commit e8806a5

Browse files
authored
Add python unit tests (#2142)
* Adding parameterized pygeosx unit tests * Adding pytest target to cmake
1 parent f1f395b commit e8806a5

File tree

13 files changed

+65
-82
lines changed

13 files changed

+65
-82
lines changed

geosx_mesh_doctor/checks/collocated_nodes.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@
1010
vtkPoints,
1111
)
1212
from vtkmodules.vtkCommonDataModel import (
13-
vtkIncrementalOctreePointLocator,
14-
)
13+
vtkIncrementalOctreePointLocator, )
1514

1615
from . import vtk_utils
1716

@@ -46,7 +45,9 @@ def __check(mesh, options: Options) -> Result:
4645
# If it's not inserted, `point_id` contains the node that was already at that location.
4746
# But in that case, `point_id` is the new numbering in the destination points array.
4847
# It's more useful for the user to get the old index in the original mesh, so he can look for it in his data.
49-
logging.debug(f"Point {i} at {points.GetPoint(i)} has been rejected, point {filtered_to_original[point_id.get()]} is already inserted.")
48+
logging.debug(
49+
f"Point {i} at {points.GetPoint(i)} has been rejected, point {filtered_to_original[point_id.get()]} is already inserted."
50+
)
5051
rejected_points[point_id.get()].append(i)
5152
else:
5253
# If it's inserted, `point_id` contains the new index in the destination array.

geosx_mesh_doctor/checks/generate_fractures.py

Lines changed: 35 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,9 @@
2424
vtkUnstructuredGrid,
2525
)
2626
from vtkmodules.vtkFiltersGeometry import (
27-
vtkMarkBoundaryFilter,
28-
)
27+
vtkMarkBoundaryFilter, )
2928
from vtk.util.numpy_support import (
30-
vtk_to_numpy,
31-
)
29+
vtk_to_numpy, )
3230

3331
import networkx
3432

@@ -56,6 +54,7 @@ class FractureNodesInfo:
5654

5755

5856
class FractureCellsInfo:
57+
5958
def __init__(self, mesh: vtkUnstructuredGrid, cell_to_faces: Dict[int, Iterable[int]]):
6059
# For each cell (the key), gets the local (to the face, i.e. 0 to 3 for a tet) faces that are part of the fracture.
6160
# There can be multiple faces involved.
@@ -93,8 +92,7 @@ def _iter(id_list: vtkIdList) -> Iterator[int]:
9392
yield id_list.GetId(i)
9493

9594

96-
def __duplicate_fracture_nodes(mesh: vtkUnstructuredGrid,
97-
connected_components: Iterable[Iterable[int]],
95+
def __duplicate_fracture_nodes(mesh: vtkUnstructuredGrid, connected_components: Iterable[Iterable[int]],
9896
node_frac_info: FractureNodesInfo) -> Tuple[vtkUnstructuredGrid, DuplicatedNodesInfo]:
9997
"""
10098
Splits the mesh on the fracture.
@@ -123,7 +121,7 @@ def __duplicate_fracture_nodes(mesh: vtkUnstructuredGrid,
123121

124122
# Building an indicator to find fracture cells.
125123
# A fracture cell is a cell which touches a fracture internal node.
126-
is_fracture_side_cells = numpy.zeros(num_cells, dtype=bool) # Defaults to "not a fracture cell".
124+
is_fracture_side_cells = numpy.zeros(num_cells, dtype=bool) # Defaults to "not a fracture cell".
127125
for fracture_side_cells in connected_components:
128126
for fracture_side_cell in fracture_side_cells:
129127
is_fracture_side_cells[fracture_side_cell] = True
@@ -132,8 +130,8 @@ def __duplicate_fracture_nodes(mesh: vtkUnstructuredGrid,
132130
# The idea is that I do not want to fill holes in the numbering,
133131
# I just want to increment the next number by one.
134132
# A negative number means that this is a duplicated number.
135-
renumbered_nodes = numpy.ones(num_points, dtype=int) * -1 # Defaults to "moved".
136-
next_point_id = 0 # When a node needs to be duplicated, `next_point_id` is the next available node.
133+
renumbered_nodes = numpy.ones(num_points, dtype=int) * -1 # Defaults to "moved".
134+
next_point_id = 0 # When a node needs to be duplicated, `next_point_id` is the next available node.
137135
for node_idx in range(num_points):
138136
if not node_frac_info.is_internal_fracture_node[node_idx]:
139137
renumbered_nodes[node_idx] = next_point_id
@@ -157,13 +155,13 @@ def __duplicate_fracture_nodes(mesh: vtkUnstructuredGrid,
157155
# Here we find or build the new number of the node.
158156
if node_frac_info.is_internal_fracture_node[new_cell_point_id]:
159157
assert renumbered_nodes[new_cell_point_id] == -1
160-
if new_cell_point_id in dup_nodes: # if already duplicated, take the same
158+
if new_cell_point_id in dup_nodes: # if already duplicated, take the same
161159
new_cell_point_ids.SetId(i, dup_nodes[new_cell_point_id])
162-
else: # otherwise, duplicate
160+
else: # otherwise, duplicate
163161
dup_nodes[new_cell_point_id] = next_point_id
164162
new_cell_point_ids.SetId(i, next_point_id)
165163
next_point_id += 1
166-
else: # Here, it's not an internal fracture node which was not duplicated.
164+
else: # Here, it's not an internal fracture node which was not duplicated.
167165
assert not renumbered_nodes[new_cell_point_id] == -1
168166
new_cell_point_ids.SetId(i, renumbered_nodes[new_cell_point_id])
169167
new_cells.ReplaceCellAtId(fracture_side_cell, new_cell_point_ids)
@@ -184,7 +182,8 @@ def __duplicate_fracture_nodes(mesh: vtkUnstructuredGrid,
184182
new_cells.ReplaceCellAtId(cell_idx, new_cell_point_ids)
185183

186184
# Now we finish the process for vtk points.
187-
num_new_points = num_points - sum(node_frac_info.is_internal_fracture_node) + sum(map(len, component_to_dup_nodes.values()))
185+
num_new_points = num_points - sum(node_frac_info.is_internal_fracture_node) + sum(
186+
map(len, component_to_dup_nodes.values()))
188187
assert next_point_id == num_new_points
189188

190189
old_points = mesh.GetPoints()
@@ -216,19 +215,16 @@ def __duplicate_fracture_nodes(mesh: vtkUnstructuredGrid,
216215
nodes_validation[renumbered_nodes[n]] = True
217216
assert all(nodes_validation)
218217

219-
output = mesh.NewInstance() # keeping the same instance type.
218+
output = mesh.NewInstance() # keeping the same instance type.
220219
output.SetPoints(new_points)
221-
output.SetCells(mesh.GetCellTypesArray(), new_cells) # The cell types are unchanged; we reuse the old cell types!
220+
output.SetCells(mesh.GetCellTypesArray(), new_cells) # The cell types are unchanged; we reuse the old cell types!
222221

223-
duplicated_nodes_info = DuplicatedNodesInfo(renumbered_nodes=renumbered_nodes,
224-
duplicated_nodes=duplicated_nodes)
222+
duplicated_nodes_info = DuplicatedNodesInfo(renumbered_nodes=renumbered_nodes, duplicated_nodes=duplicated_nodes)
225223

226224
return output, duplicated_nodes_info
227225

228226

229-
def __copy_fields(input_mesh: vtkUnstructuredGrid,
230-
output_mesh: vtkUnstructuredGrid,
231-
cell_frac_info: FractureCellsInfo,
227+
def __copy_fields(input_mesh: vtkUnstructuredGrid, output_mesh: vtkUnstructuredGrid, cell_frac_info: FractureCellsInfo,
232228
duplicated_nodes_info: DuplicatedNodesInfo) -> None:
233229
"""
234230
Given input and output meshes, copies the fields from the input into the output.
@@ -269,15 +265,16 @@ def __copy_fields(input_mesh: vtkUnstructuredGrid,
269265
# The "field data" will contain the fracture information
270266
field_data = input_mesh.GetFieldData()
271267
if field_data.GetNumberOfArrays() > 0:
272-
logging.warning(f"Copying field data that already has arrays. No modification was made w.r.t. nodes duplications.")
268+
logging.warning(
269+
f"Copying field data that already has arrays. No modification was made w.r.t. nodes duplications.")
273270

274271
# Building the field data for the fracture
275272
if field_data.HasArray("fracture_info"):
276273
logging.warning("Field data \"fracture_info\" already exists, nothing done.")
277274
else:
278275
frac_array = vtkIntArray()
279-
frac_array.SetName("fracture_info") # TODO hard coded name.
280-
frac_array.SetNumberOfComponents(4) # Warning the component has to be defined first...
276+
frac_array.SetName("fracture_info") # TODO hard coded name.
277+
frac_array.SetNumberOfComponents(4) # Warning the component has to be defined first...
281278
frac_array.SetNumberOfTuples(len(cell_frac_info.field_data))
282279
for i, data in enumerate(cell_frac_info.field_data):
283280
frac_array.SetTuple(i, data)
@@ -290,7 +287,8 @@ def __copy_fields(input_mesh: vtkUnstructuredGrid,
290287
duplication_max_multiplicity = max(map(len, duplicated_nodes_info.duplicated_nodes.values()))
291288
nodes_array = vtkIntArray()
292289
nodes_array.SetName("duplicated_points_info")
293-
nodes_array.SetNumberOfComponents(duplication_max_multiplicity) # Warning the component has to be defined first...
290+
nodes_array.SetNumberOfComponents(
291+
duplication_max_multiplicity) # Warning the component has to be defined first...
294292
nodes_array.SetNumberOfTuples(len(duplicated_nodes_info.duplicated_nodes))
295293
for i, data in enumerate(duplicated_nodes_info.duplicated_nodes.values()):
296294
tmp = list(data) + [-1] * (duplication_max_multiplicity - len(data))
@@ -300,21 +298,24 @@ def __copy_fields(input_mesh: vtkUnstructuredGrid,
300298
output_mesh.SetFieldData(field_data)
301299

302300

303-
def __color_fracture_sides(mesh: vtkUnstructuredGrid, cell_frac_info: FractureCellsInfo, node_frac_info: FractureNodesInfo) -> Iterable[Iterable[int]]:
301+
def __color_fracture_sides(mesh: vtkUnstructuredGrid, cell_frac_info: FractureCellsInfo,
302+
node_frac_info: FractureNodesInfo) -> Iterable[Iterable[int]]:
304303
"""
305304
Given all the cells that are in contact with the detected fracture,
306305
we separate them into bucket of connected cells touching the fractures.
307306
We do this because all the cells in one same bucket are connected and need to stay connected.
308307
So they need to share the same nodes as they did before the split.
309308
:return: All the buckets connected fracture cells.
310309
"""
311-
def does_face_contain_boundary_node(_face_point_ids: Iterable[int]) -> bool: # Small helper function.
310+
311+
def does_face_contain_boundary_node(_face_point_ids: Iterable[int]) -> bool: # Small helper function.
312312
for face_point_id in _face_point_ids:
313313
if node_frac_info.is_boundary_fracture_node[face_point_id]:
314314
return True
315315
return False
316316

317-
face_node_set_to_cell = defaultdict(list) # For each face (defined by its node set), gives all the cells containing this face.
317+
face_node_set_to_cell = defaultdict(
318+
list) # For each face (defined by its node set), gives all the cells containing this face.
318319
for c, local_frac_f in cell_frac_info.cell_to_faces.items():
319320
cell = mesh.GetCell(c)
320321
for f in [i for i in range(cell.GetNumberOfFaces()) if i not in local_frac_f]:
@@ -357,8 +358,7 @@ def __find_boundary_nodes(mesh: vtkUnstructuredGrid) -> Sequence[int]:
357358
return vtk_to_numpy(is_boundary_point)
358359

359360

360-
def __build_fracture_nodes(mesh: vtkUnstructuredGrid,
361-
cell_frac_info: FractureCellsInfo,
361+
def __build_fracture_nodes(mesh: vtkUnstructuredGrid, cell_frac_info: FractureCellsInfo,
362362
split_on_domain_boundary: bool) -> FractureNodesInfo:
363363
"""
364364
Given the description of the fracture in @p cell_frac_info, computes the underlying nodes.
@@ -375,9 +375,9 @@ def __build_fracture_nodes(mesh: vtkUnstructuredGrid,
375375
for e in range(face.GetNumberOfEdges()):
376376
edge = face.GetEdge(e)
377377
edge_nodes = []
378-
for i in range(edge.GetNumberOfPoints()): # TODO, do less pedantic
378+
for i in range(edge.GetNumberOfPoints()): # TODO, do less pedantic
379379
edge_nodes.append(edge.GetPointId(i))
380-
fracture_edges[tuple(sorted(edge_nodes))] += 1 # TODO frozenset?
380+
fracture_edges[tuple(sorted(edge_nodes))] += 1 # TODO frozenset?
381381

382382
boundary_fracture_edges = []
383383
# Boundary edges are seen twice because each 2d fracture element is seen twice too.
@@ -414,7 +414,7 @@ def __build_fracture_nodes(mesh: vtkUnstructuredGrid,
414414

415415
# Now compute the internal fracture nodes by "difference".
416416
is_internal_fracture_node = numpy.zeros(mesh.GetNumberOfPoints(), dtype=bool)
417-
for n in range(mesh.GetNumberOfPoints()): # TODO duplicated, reorg the code.
417+
for n in range(mesh.GetNumberOfPoints()): # TODO duplicated, reorg the code.
418418
if is_fracture_node[n] and not is_boundary_fracture_node[n]:
419419
is_internal_fracture_node[n] = True
420420

@@ -438,21 +438,21 @@ def __find_involved_cells(mesh: vtkUnstructuredGrid, options: Options) -> Tuple[
438438
raise ValueError(f"Cell field {options.field} does not exist in mesh, nothing done")
439439

440440
cells_to_faces = defaultdict(list)
441-
is_fracture_node = numpy.zeros(mesh.GetNumberOfPoints(), dtype=bool) # all False
441+
is_fracture_node = numpy.zeros(mesh.GetNumberOfPoints(), dtype=bool) # all False
442442

443443
# For each face of each cell, we search for the unique neighbor cell (if it exists).
444444
# Then, if the 2 values of the two cells match the field requirements,
445445
# we store the cell and its local face index: this is indeed part of the surface that we'll need to be split.
446446
neighbor_cell_ids = vtkIdList()
447447
for cell_id in range(mesh.GetNumberOfCells()):
448-
if f[cell_id] not in options.field_values: # No need to consider a cell if its field value is not in the target range.
448+
if f[cell_id] not in options.field_values: # No need to consider a cell if its field value is not in the target range.
449449
continue
450450
cell = mesh.GetCell(cell_id)
451451
for i in range(cell.GetNumberOfFaces()):
452452
face = cell.GetFace(i)
453453
mesh.GetCellNeighbors(cell_id, face.GetPointIds(), neighbor_cell_ids)
454454
assert neighbor_cell_ids.GetNumberOfIds() < 2
455-
for j in range(neighbor_cell_ids.GetNumberOfIds()): # It's 0 or 1...
455+
for j in range(neighbor_cell_ids.GetNumberOfIds()): # It's 0 or 1...
456456
neighbor_cell_id = neighbor_cell_ids.GetId(j)
457457
if f[neighbor_cell_id] != f[cell_id] and f[neighbor_cell_id] in options.field_values:
458458
cells_to_faces[cell_id].append(i)

geosx_mesh_doctor/checks/generate_global_ids.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@
22
import logging
33

44
from vtkmodules.vtkCommonCore import (
5-
vtkIdTypeArray,
6-
)
5+
vtkIdTypeArray, )
76

87
from . import vtk_utils
98

geosx_mesh_doctor/checks/vtk_utils.py

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,17 @@
22
import logging
33

44
from vtkmodules.vtkCommonDataModel import (
5-
vtkUnstructuredGrid,
6-
)
5+
vtkUnstructuredGrid, )
76
from vtkmodules.vtkIOLegacy import (
87
vtkUnstructuredGridWriter,
98
vtkUnstructuredGridReader,
109
)
1110
from vtkmodules.vtkIOXML import (
12-
vtkXMLUnstructuredGridReader,
13-
)
11+
vtkXMLUnstructuredGridReader, )
1412

1513

1614
def read_mesh(vtk_input_file: str) -> vtkUnstructuredGrid:
17-
reader = vtkXMLUnstructuredGridReader() # TODO Find a generic way to read the vtk mesh.
15+
reader = vtkXMLUnstructuredGridReader() # TODO Find a generic way to read the vtk mesh.
1816
reader.SetFileName(vtk_input_file)
1917
reader.Update()
2018
return reader.GetOutput()
@@ -36,5 +34,3 @@ def write_mesh(mesh: vtkUnstructuredGrid, output: str) -> None:
3634
writer.SetInputData(mesh)
3735
logging.info(f"Writing mesh into file {output}")
3836
writer.Write()
39-
40-

geosx_mesh_doctor/parsing/cli_parsing.py

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77

88
from . import all_checks_helpers
99

10-
1110
__OPTIONS_SEP = ":"
1211
__KV_SEP = "="
1312

@@ -60,7 +59,8 @@ def validate_cli_options(check_name: str, valid_keys: Set[str], options: Dict[st
6059
if len(invalid_keys) == 1:
6160
logging.warning(f"Key \"{invalid_keys.pop()}\" is not a valid option of \"{check_name}\". Ignoring it.")
6261
else:
63-
logging.warning(f"Keys \"{', '.join(invalid_keys)}\" are not valid options of \"{check_name}\". Ignoring them.")
62+
logging.warning(
63+
f"Keys \"{', '.join(invalid_keys)}\" are not valid options of \"{check_name}\". Ignoring them.")
6464

6565

6666
def parse_and_set_verbosity(cli_args: List[str]) -> None:
@@ -70,16 +70,8 @@ def parse_and_set_verbosity(cli_args: List[str]) -> None:
7070
:return: None
7171
"""
7272
dummy_verbosity_parser = argparse.ArgumentParser(add_help=None)
73-
dummy_verbosity_parser.add_argument('-v',
74-
'--verbose',
75-
action='count',
76-
default=1,
77-
dest=__VERBOSE_KEY)
78-
dummy_verbosity_parser.add_argument('-q',
79-
'--quiet',
80-
action='count',
81-
default=0,
82-
dest=__QUIET_KEY)
73+
dummy_verbosity_parser.add_argument('-v', '--verbose', action='count', default=1, dest=__VERBOSE_KEY)
74+
dummy_verbosity_parser.add_argument('-q', '--quiet', action='count', default=0, dest=__QUIET_KEY)
8375
args = dummy_verbosity_parser.parse_known_args(cli_args[1:])[0]
8476
d = vars(args)
8577
v = d[__VERBOSE_KEY] - d[__QUIET_KEY]
@@ -141,7 +133,7 @@ def parse(cli_args: List[str]) -> Arguments:
141133
help=check_helper.get_help())
142134
args = parser.parse_args(cli_args[1:])
143135

144-
args = vars(args) # converting to `dict` allows to access keys by variable.
136+
args = vars(args) # converting to `dict` allows to access keys by variable.
145137
checks = OrderedDict()
146138
for check_name in all_checks_helpers.keys():
147139
options = args[check_name]

geosx_mesh_doctor/parsing/collocated_nodes_parsing.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ def display_results(options: Options, result: Result):
3333
for bucket in result.nodes_buckets:
3434
for node in bucket:
3535
all_duplicated_nodes.append(node)
36-
all_duplicated_nodes = set(all_duplicated_nodes) # Surely useless
36+
all_duplicated_nodes = set(all_duplicated_nodes) # Surely useless
3737
logging.error(f"You have {len(all_duplicated_nodes)} collocated nodes (tolerance = {options.tolerance}).")
3838

3939
logging.info("Here are all the buckets of collocated nodes.")

geosx_mesh_doctor/parsing/generate_fractures_parsing.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
__POLICY = "policy"
1010
__FIELD_POLICY = "field"
11-
__POLICIES = (__FIELD_POLICY,)
11+
__POLICIES = (__FIELD_POLICY, )
1212

1313
__FIELD_NAME = "name"
1414
__FIELD_VALUES = "values"
@@ -17,10 +17,13 @@
1717
__SPLIT_ON_DOMAIN_BOUNDARY = "split_on_domain_boundary"
1818
__GENERATE_FIELD_DATA = "generate_field_data"
1919

20-
__ALL_KEYWORDS = {__POLICY, __FIELD_NAME, __FIELD_VALUES, __FIELD_POLICY, __OUTPUT_FILE, __SPLIT_ON_DOMAIN_BOUNDARY, __GENERATE_FIELD_DATA}
20+
__ALL_KEYWORDS = {
21+
__POLICY, __FIELD_NAME, __FIELD_VALUES, __FIELD_POLICY, __OUTPUT_FILE, __SPLIT_ON_DOMAIN_BOUNDARY,
22+
__GENERATE_FIELD_DATA
23+
}
2124

2225

23-
def get_help(): # TODO use a formatter module.
26+
def get_help(): # TODO use a formatter module.
2427
msg = f"""\
2528
Splits the mesh to generate the faults and fractures. [EXPERIMENTAL]
2629

geosx_mesh_doctor/parsing/generate_global_ids_parsing.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66

77
from . import cli_parsing
88

9-
109
__OUTPUT_FILE = "output"
1110

1211
__ALL_KEYWORDS = {__OUTPUT_FILE}

geosx_mesh_doctor/tests/test_collocated_nodes.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,9 @@
33
import pytest
44

55
from vtkmodules.vtkCommonCore import (
6-
vtkPoints,
7-
)
6+
vtkPoints, )
87
from vtkmodules.vtkCommonDataModel import (
9-
vtkUnstructuredGrid,
10-
)
8+
vtkUnstructuredGrid, )
119

1210
from checks.collocated_nodes import Options, __check
1311

@@ -40,4 +38,3 @@ def test_simple_collocated_points(data: Tuple[vtkPoints, int]):
4038
assert len(result.nodes_buckets) == num_nodes_bucket
4139
if num_nodes_bucket == 1:
4240
assert len(result.nodes_buckets[0]) == points.GetNumberOfPoints()
43-

0 commit comments

Comments
 (0)