Skip to content

Commit e40795b

Browse files
committed
Merge branch 'master' into rcanton/m2pv_def
2 parents 6e729f3 + aef98e7 commit e40795b

File tree

5 files changed

+113
-59
lines changed

5 files changed

+113
-59
lines changed

examples/09-averaging/00-compute_and_average.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,6 @@ def compute_von_mises_then_average(analysis):
9999
min_max.inputs.field.connect(avg_von_mises)
100100
max_val = min_max.outputs.field_max()
101101

102-
mesh.plot(avg_von_mises)
103-
104102
return max_val.data[0]
105103

106104

@@ -139,8 +137,6 @@ def average_then_compute_von_mises(analysis):
139137
min_max.inputs.field.connect(avg_von_mises)
140138
max_val = min_max.outputs.field_max()
141139

142-
mesh.plot(avg_von_mises)
143-
144140
return max_val.data[0]
145141

146142

src/ansys/dpf/core/meshed_region.py

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ def __init__(self, num_nodes=None, num_elements=None, mesh=None, server=None):
108108
self._full_grid = None
109109
self._elements = None
110110
self._nodes = None
111+
self.as_linear = None
111112

112113
def _get_scoping(self, loc=locations.nodal):
113114
"""
@@ -457,20 +458,10 @@ def _as_vtk(self, coordinates=None, as_linear=True, include_ids=False):
457458

458459
# consider adding this when scoping request is faster
459460
if include_ids:
460-
self._nodeids = self.elements.scoping.ids
461-
self._elementids = self.nodes.scoping.ids
462-
grid["node_ids"] = self._elementids
463-
grid["element_ids"] = self._nodeids
464-
465-
# Quick fix required to hold onto the data as PyVista does not make a copy.
466-
# All of those now return DPFArrays
467-
if coordinates is None:
468-
coordinates_field = self.nodes.coordinates_field
469-
coordinates = self.nodes.coordinates_field.data
470-
else:
471-
coordinates_field = coordinates
472-
coordinates = coordinates.data
473-
setattr(grid, "_dpf_cache", [coordinates, coordinates_field])
461+
self._nodeids = self.nodes.scoping.ids
462+
self._elementids = self.elements.scoping.ids
463+
grid["node_ids"] = self._nodeids
464+
grid["element_ids"] = self._elementids
474465

475466
return grid
476467

src/ansys/dpf/core/plotter.py

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ def add_plane(self, plane, field=None, **kwargs):
125125
plane[f"{field.name}"] = field.data
126126
self._plotter.add_mesh(plane_plot, **kwargs)
127127

128-
def add_mesh(self, meshed_region, deform_by=None, scale_factor=1.0, **kwargs):
128+
def add_mesh(self, meshed_region, deform_by=None, scale_factor=1.0, as_linear=True, **kwargs):
129129

130130
kwargs = self._set_scalar_bar_title(kwargs)
131131

@@ -144,9 +144,17 @@ def add_mesh(self, meshed_region, deform_by=None, scale_factor=1.0, **kwargs):
144144
# otherwise we get two scalar bars when calling several plot_contour on the same mesh
145145
# but not for the same field. The PyVista UnstructuredGrid keeps memory of it.
146146
if not deform_by:
147-
grid = meshed_region.grid
147+
if as_linear != meshed_region.as_linear:
148+
grid = meshed_region._as_vtk(
149+
meshed_region.nodes.coordinates_field, as_linear=as_linear
150+
)
151+
meshed_region.as_linear = as_linear
152+
else:
153+
grid = meshed_region.grid
148154
else:
149-
grid = meshed_region._as_vtk(meshed_region.deform_by(deform_by, scale_factor))
155+
grid = meshed_region._as_vtk(
156+
meshed_region.deform_by(deform_by, scale_factor), as_linear=as_linear
157+
)
150158

151159
# show axes
152160
show_axes = kwargs.pop("show_axes", None)
@@ -228,6 +236,7 @@ def add_field(
228236
deform_by=None,
229237
scale_factor=1.0,
230238
scale_factor_legend=None,
239+
as_linear=True,
231240
**kwargs,
232241
):
233242
# Get the field name
@@ -276,7 +285,9 @@ def add_field(
276285
if not deform_by:
277286
grid = meshed_region.grid
278287
else:
279-
grid = meshed_region._as_vtk(meshed_region.deform_by(deform_by, scale_factor))
288+
grid = meshed_region._as_vtk(
289+
meshed_region.deform_by(deform_by, scale_factor), as_linear
290+
)
280291
grid.set_active_scalars(None)
281292
self._plotter.add_mesh(grid, scalars=overall_data, **kwargs_in)
282293

@@ -481,6 +492,7 @@ def add_mesh(self, meshed_region, deform_by=None, scale_factor=1.0, **kwargs):
481492
meshed_region=meshed_region,
482493
deform_by=deform_by,
483494
scale_factor=scale_factor,
495+
as_linear=True,
484496
**kwargs,
485497
)
486498

@@ -543,6 +555,7 @@ def add_field(
543555
label_point_size=label_point_size,
544556
deform_by=deform_by,
545557
scale_factor=scale_factor,
558+
as_linear=True,
546559
**kwargs,
547560
)
548561

@@ -859,11 +872,16 @@ def plot_contour(
859872
kwargs_in = _sort_supported_kwargs(
860873
bound_method=self._internal_plotter._plotter.add_mesh, **kwargs
861874
)
875+
as_linear = True
862876
if deform_by:
863-
grid = mesh._as_vtk(mesh.deform_by(deform_by, scale_factor))
877+
grid = mesh._as_vtk(mesh.deform_by(deform_by, scale_factor), as_linear=as_linear)
864878
self._internal_plotter.add_scale_factor_legend(scale_factor, **kwargs)
865879
else:
866-
grid = mesh.grid
880+
if as_linear != mesh.as_linear:
881+
grid = mesh._as_vtk(mesh.nodes.coordinates_field, as_linear=as_linear)
882+
mesh.as_linear = as_linear
883+
else:
884+
grid = mesh.grid
867885
grid.clear_data()
868886
self._internal_plotter._plotter.add_mesh(grid, scalars=overall_data, **kwargs_in)
869887

src/ansys/dpf/core/vtk_helper.py

Lines changed: 83 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ def dpf_mesh_to_vtk_py(mesh, nodes, as_linear):
176176
Meshed Region to export to pyVista format
177177
178178
nodes : dpf.Field
179-
Field containing the nodes of the mesh.
179+
Field containing the node coordinates of the mesh.
180180
181181
as_linear : bool
182182
Export quadratic surface elements as linear.
@@ -189,9 +189,11 @@ def dpf_mesh_to_vtk_py(mesh, nodes, as_linear):
189189
etypes = mesh.elements.element_types_field.data
190190
connectivity = mesh.elements.connectivities_field
191191
if nodes is None:
192-
nodes = mesh.nodes.coordinates_field.data
192+
coordinates_field = mesh.nodes.coordinates_field
193+
node_coordinates = coordinates_field.data
193194
else:
194-
nodes = nodes.data
195+
coordinates_field = nodes
196+
node_coordinates = nodes.data
195197

196198
elem_size = np.ediff1d(np.append(connectivity._data_pointer, connectivity.shape))
197199

@@ -207,22 +209,21 @@ def dpf_mesh_to_vtk_py(mesh, nodes, as_linear):
207209
insert_ind = np.cumsum(elem_size)
208210
insert_ind = np.hstack(([0], insert_ind))[:-1]
209211

210-
# Handle semiparabolic elements
211-
nullmask = connectivity.data == -1
212-
connectivity.data[nullmask] = 0
213-
if nullmask.any():
214-
nodes[0] = np.nan
212+
# if not as_linear:
213+
# # Pre-handle semi-parabolic elements
214+
# semi_mask = connectivity.data == -1
215+
# if semi_mask.any():
216+
# # Modify -1 connectivity values
217+
# repeated_data_pointers = connectivity._data_pointer.repeat(repeats=elem_size)
218+
# connectivity.data[semi_mask] = connectivity.data[repeated_data_pointers[semi_mask]]
215219

216-
# For each polyhedron, cell = [nCellFaces, nFace0pts, i, j, k, ..., nFace1pts, i, j, k, ...]
217-
# polys_ind = insert_ind[polyhedron_mask]
218-
# cells = np.take(cells, sorted(set(insert_ind)-set(polys_ind)))
219220
# partition cells in vtk format
220221
cells = np.insert(connectivity.data, insert_ind, elem_size)
221222

222223
# Check if polyhedrons are present
223224
if element_types.Polyhedron.value in etypes:
224225
cells = np.array(cells)
225-
nodes = np.array(nodes)
226+
nodes = np.array(node_coordinates)
226227
insert_ind = insert_ind + np.asarray(list(range(len(insert_ind))))
227228
# Replace in cells values for polyhedron format
228229
# [NValuesToFollow,
@@ -252,45 +253,93 @@ def compute_offset():
252253
"""Return the starting point of a cell in the cells array"""
253254
return insert_ind + np.arange(insert_ind.size)
254255

256+
cells_insert_ind = compute_offset()
255257
# convert kAns to VTK cell type
256258
offset = None
257259
if as_linear:
260+
# Map the vtk_cell_type to linear versions of the initial elements types
258261
vtk_cell_type = VTK_LINEAR_MAPPING[etypes]
259262

260-
# visualization bug within VTK with quadratic surf cells
261-
ansquad8_mask = etypes == 6
262-
if np.any(ansquad8_mask): # kAnsQuad8
263-
264-
# simply copy the edge node indices to the midside points
265-
offset = compute_offset()
266-
cell_pos = offset[ansquad8_mask]
267-
cells[cell_pos + 5] = cells[cell_pos + 1]
268-
cells[cell_pos + 6] = cells[cell_pos + 2]
269-
cells[cell_pos + 7] = cells[cell_pos + 3]
270-
cells[cell_pos + 8] = cells[cell_pos + 4]
271-
272-
anstri6_mask = etypes == 4 # kAnsTri6 = 4
273-
if np.any(anstri6_mask):
274-
if offset is None:
275-
offset = compute_offset()
276-
cell_pos = offset[anstri6_mask]
277-
cells[cell_pos + 4] = cells[cell_pos + 1]
278-
cells[cell_pos + 5] = cells[cell_pos + 2]
279-
cells[cell_pos + 6] = cells[cell_pos + 3]
263+
# Create a global mask of connectivity values to take
264+
mask = np.full(cells.shape, True)
265+
266+
# Get a mask of quad8 elements in etypes
267+
quad8_mask = etypes == 6
268+
# If any quad8
269+
if np.any(quad8_mask): # kAnsQuad8
270+
# Get the starting indices of quad8 elements in cells
271+
insert_ind_quad8 = cells_insert_ind[quad8_mask]
272+
# insert_ind_quad8 += np.arange(insert_ind_quad8.size)
273+
mask[insert_ind_quad8 + 5] = False
274+
mask[insert_ind_quad8 + 6] = False
275+
mask[insert_ind_quad8 + 7] = False
276+
mask[insert_ind_quad8 + 8] = False
277+
cells[insert_ind_quad8] //= 2
278+
279+
tri6_mask = etypes == 4 # kAnsTri6 = 4
280+
if np.any(tri6_mask):
281+
insert_ind_tri6 = cells_insert_ind[tri6_mask]
282+
# insert_ind_tri6 += np.arange(insert_ind_tri6.size)
283+
mask[insert_ind_tri6 + 4] = False
284+
mask[insert_ind_tri6 + 5] = False
285+
mask[insert_ind_tri6 + 6] = False
286+
cells[insert_ind_tri6] //= 2
287+
cells = cells[mask]
280288

281289
else:
282290
vtk_cell_type = VTK_MAPPING[etypes]
283291

292+
# Handle semi-parabolic elements
293+
semi_mask = cells == -1
294+
if semi_mask.any():
295+
cells_insert_ind = compute_offset()
296+
# Create a global mask of connectivity values to take
297+
mask = np.full(cells.shape, True)
298+
# Build a map of size cells with repeated element beginning index
299+
repeated_insert_ind = cells_insert_ind.repeat(repeats=elem_size + 1)
300+
# Apply the semi-mask to get a unique set of indices of semi-parabolic elements in cells
301+
semi_indices_in_cells = np.array(list(set(repeated_insert_ind[semi_mask])))
302+
semi_sizes = cells[semi_indices_in_cells]
303+
semi_quad8 = semi_sizes == 8
304+
if semi_quad8.any():
305+
mask[semi_indices_in_cells[semi_quad8] + 5] = False
306+
mask[semi_indices_in_cells[semi_quad8] + 6] = False
307+
mask[semi_indices_in_cells[semi_quad8] + 7] = False
308+
mask[semi_indices_in_cells[semi_quad8] + 8] = False
309+
cells[semi_indices_in_cells[semi_quad8]] //= 2
310+
311+
quad8_mask = etypes == 6
312+
semi_quad8_mask = (cells[cells_insert_ind] == 4) & quad8_mask
313+
vtk_cell_type[semi_quad8_mask] = VTK_LINEAR_MAPPING[6]
314+
semi_tri6 = semi_sizes == 6
315+
if semi_tri6.any():
316+
mask[semi_indices_in_cells[semi_tri6] + 4] = False
317+
mask[semi_indices_in_cells[semi_tri6] + 5] = False
318+
mask[semi_indices_in_cells[semi_tri6] + 6] = False
319+
cells[semi_indices_in_cells[semi_tri6]] //= 2
320+
321+
tri6_mask = etypes == 4
322+
semi_tri6_mask = (cells[cells_insert_ind] == 3) & tri6_mask
323+
vtk_cell_type[semi_tri6_mask] = VTK_LINEAR_MAPPING[4]
324+
# Update cells with the mask
325+
cells = cells[mask]
326+
284327
# different treatment depending on the version of vtk
285328
if VTK9:
286329
# compute offset array when < VTK v9
287-
return pv.UnstructuredGrid(cells, vtk_cell_type, nodes)
330+
grid = pv.UnstructuredGrid(cells, vtk_cell_type, node_coordinates)
331+
332+
# Quick fix required to hold onto the data as PyVista does not make a copy.
333+
# All of those now return DPFArrays
334+
setattr(grid, "_dpf_cache", [node_coordinates, coordinates_field])
335+
336+
return grid
288337

289338
# might be computed when checking for VTK quadratic bug
290339
if offset is None:
291340
offset = compute_offset()
292341

293-
return pv.UnstructuredGrid(offset, cells, vtk_cell_type, nodes)
342+
return pv.UnstructuredGrid(offset, cells, vtk_cell_type, node_coordinates)
294343

295344

296345
def dpf_mesh_to_vtk(mesh, nodes=None, as_linear=True):

tests/test_meshregion.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ def test_get_set_unit_meshedregion(simple_bar_model):
6565
def test_get_node_meshedregion(simple_bar_model):
6666
mesh = simple_bar_model.metadata.meshed_region
6767
node = mesh.nodes.node_by_index(1)
68-
scop = mesh._get_scoping(dpf.core.locations.nodal)
68+
scop = mesh.nodes.scoping
6969
assert node.id == scop.id(1)
7070
assert node.index == 1
7171

0 commit comments

Comments
 (0)