ansys / pydpf-core

Data Processing Framework - Python Core
http://dpf.docs.pyansys.com/
MIT License
68 stars 25 forks source link

Visualization bug with LS-DYNA model/mesh #741

Open mhoeijm opened 1 year ago

mhoeijm commented 1 year ago

Before submitting the issue

Description of the bug

When visualizing a LS-DYNA mesh/model with dpf the show_edges=True option may not always work properly. For convenience I extract the underlying pyvista.UnstructuredGrid object in the example below - which gives the same results. This issue may be model specific.

import os 

from ansys.dpf import core as dpf
import pyvista as pv
import numpy as np

# set datasources
server = dpf.start_local_server()
ds = dpf.DataSources()
ds.set_result_file_path("d3plot", "d3plot")
model = dpf.Model(ds)

# get pyvista grid generated by dpf
grid: pv.UnstructuredGrid = model.metadata.meshed_region.grid

# recreate unstructured grid from just the tets and points with pyvista
tets = grid.cells_dict[10]
num_tets = tets.shape[0]
cell_types = [pv.CellType.TETRA] * num_tets
cells = np.hstack([np.ones((tets.shape[0], 1),dtype=int)*4, tets])
grid2 = pv.UnstructuredGrid(cells, cell_types, grid.points)

# visualize
plotter = pv.Plotter(shape=(1,2))
# dpf grid
plotter.subplot(0,0)
plotter.add_mesh(grid, show_edges=True )
plotter.add_title("dpf")
# reconstructed grid
plotter.subplot(0,1)
plotter.add_mesh(grid2, show_edges=True)
plotter.add_title("reconstructed")

plotter.link_views(True)
plotter.show()

image

edit: I did some additional tests where I remove the triangles and lines from the unstructured grid. Somehow the presence of line cells seems to mess up the visualization:

# get pyvista grid generated by dpf
grid: pv.UnstructuredGrid = model.metadata.meshed_region.grid

# get different mixed grids
grid_tets_tris = grid.remove_cells(grid.celltypes == 3)
grid_tets_lines = grid.remove_cells(grid.celltypes == 5)
grid_tets_only = grid.remove_cells( np.any([grid.celltypes==3, grid.celltypes==5], axis=0) )

plotter = pv.Plotter(shape=(2,2))
# original grid. tets+triangles+lines
plotter.subplot(0,0)
plotter.add_mesh(grid, show_edges=True, color="w")
plotter.add_title("tets+tris+lines", color="r")
# with tets + triangles
plotter.subplot(0,1)
plotter.add_mesh(grid_tets_tris, show_edges=True, color="w")
plotter.add_title("tets+tris", color="r")
# with tets + lines
plotter.subplot(1,0)
plotter.add_mesh(grid_tets_lines, show_edges=True, color="w")
plotter.add_title("tets+lines", color="r")
# with just the tets
plotter.subplot(1,1)
plotter.add_mesh(grid_tets_only, show_edges=True, color="w")
plotter.add_title("tets only", color="r")

plotter.link_views(True)
plotter.show()

image

The line-cells defined in my model come from springs connected to ground and which are defined all across the outer surfaces - but only seems to be causing visualization issues in very specific parts. The line-cells look as follows in the pyvista unstructured grid:

>>> grid.cells_dict[3]
array([[18831, 18831],
       [18833, 18833],
       [18832, 18832],
       ...,
       [32467, 32467],
       [32468, 32468],
       [32469, 32469]], dtype=int64)

Steps To Reproduce

See ^. @rafacanton has the files and should be able to reproduce on his side.

Which Operating System are you using?

Windows

Which Ansys version are you using?

Ansys 2023 R1

Which Python version are you using?

3.8

Installed packages

Package Version Editable project location


ansys-api-fluent 0.3.5 ansys-api-platform-instancemanagement 1.0.0b3 ansys-dpf-core 0.7.2 ansys-dpf-gate 0.3.0 ansys-dpf-gatebin 0.3.0 ansys-dpf-server-2023-2-pre0 2023.2rc0 ansys-grpc-dpf 0.7.0 ansys-platform-instancemanagement 1.0.2 appdirs 1.4.4 cachetools 5.2.0 certifi 2022.12.7 charset-normalizer 2.1.1 colorama 0.4.6 commonmark 0.9.1 contourpy 1.0.6 cycler 0.11.0 decorator 5.1.1 fonttools 4.38.0 google-api-core 2.11.0 google-api-python-client 2.70.0 google-auth 2.15.0 google-auth-httplib2 0.1.0 googleapis-common-protos 1.56.4 grpcio 1.51.1 h5py 3.7.0 hollerith 0.1.2 httplib2 0.21.0 idna 3.4 imageio 2.23.0 importlib-metadata 6.0.0 Jinja2 3.1.2 kiwisolver 1.4.4 MarkupSafe 2.1.1 matplotlib 3.6.2 meshio 5.3.4 numpy 1.21.6 packaging 22.0 pandas 1.5.2 Pillow 9.4.0 pip 22.3.1 pooch 1.6.0 protobuf 4.21.12 protoc-gen-swagger 0.1.0 psutil 5.9.4 pyasn1 0.4.8 pyasn1-modules 0.2.8 Pygments 2.14.0 pyparsing 3.0.9 python-dateutil 2.8.2 pytz 2022.7 pyvista 0.37.0 requests 2.28.1 rich 13.0.0 rsa 4.9 scipy 1.7.3 scooby 0.7.0 setuptools 65.5.0 six 1.16.0 tqdm 4.64.0 typing_extensions 4.4.0 uritemplate 4.1.1 urllib3 1.26.13 validators 0.20.0 vtk 9.2.4 wget 3.2 wheel 0.37.1 wincertstore 0.2 zipp 3.11.0

PProfizi commented 1 year ago

Hi @ansmhoeij, have you tried using model.metadata.meshed_region.plot()?

Also, I understand from your edit that the problem might be from the way that LINE elements are written into the pyvista.UnstructuredGrid generated by DPF, right?

mhoeijm commented 1 year ago

@PProfizi. Yes, model.metadata.meshed_region.plot() gives me exactly the same result as directly using the pyvista grid from model.metadata.meshed_region.grid, hence I used that grid directly for visualization and trying to find the cause.

Also, I understand from your edit that the problem might be from the way that LINE elements are written into the pyvista.UnstructuredGrid generated by DPF, right?

Yes I suspect so, although I would need to somehow confirm that.

rafacanton commented 1 year ago

@ansmhoeij @PProfizi Hi, I'm investigating this issue, and the root cause doesn't seem to be on the Dpf side, but in pyVista. Take a look at this defect that is currently open: https://github.com/pyvista/pyvista/issues/3738. There seem to be issues with the way pyVista extracts the external surface to display wireframe of a UnstructuredGrid if some of the surfaces of the model overlap with each other. This is your case:

image

That being said and unrelated, while investigating I have seen that this model has an inherent problem: Element Ids are not unique. All solid and shell elements range from Id = 1 to Id = 416354. However, the "beam" elements have Ids ranging from 1-6895. This will for sure cause issues downstream while postprocessing/analyzing data with Dpf. For example, if you print one of these beam elements:

>>>print(model.metadata.meshed_region.elements.element_by_index(423508- 6895)) # Get it by Index
DPF Element 1
    Index:       416613
    Nodes:            2
    Type:       element_types.Tri3
    Shape:        Shell

As you can see, it has identified Id = 1, the right index but then although it has 2 nodes (it's a "beam"), it is marked as Tri3 and Shell. This is happening because the other element that has Id = 1 is a shell indeed.

Thus, I propose to close this bug, as it is affected by a 3rd party bug.

rafacanton commented 1 year ago

@banesullivan Hi, while investigating this defect, I came across with the one in PyVista that I linked in my comment above (https://github.com/pyvista/pyvista/issues/3738). Do you think that with the PR that you have linked to the PyVista bug this issue will be fixed? I'm talking about the way edges are rendered if the surface intersects with each other. Thanks!

banesullivan commented 1 year ago

I have limited availability to help here at this time -- but from a quick glance, while pyvista/pyvista#3738 seems related, I think these are different issues. I'd need to look at the mesh in detail, but it looks like it is folding back on itself which may be an issue in how the mesh is generated

mhoeijm commented 1 year ago

Thanks @rafacanton and @banesullivan. I managed to reproduce the wireframe bug on a simple sphere and posted in the pyvista repository. See: https://github.com/pyvista/pyvista/issues/3738#issuecomment-1520454125

@banesullivan The self-intersecting mesh is not necessarily a bug, it is the result of a model (no contact was defined), so I am expecting it to intersect with itself in this case. The main reason I opened the issue was the fact that the wireframe wasn't consistently visualized, which can indeed be reproduced by adding beams to an unstructured grid.

banesullivan commented 1 year ago

I see, thanks for clarifying and posting the minimal example