How to import VMAP meshes
This notebook demonstrates how to import finite element meshes in VMAP format in pylife, e.g., to be used for a FKM nonlinear assessment.
[1]:
# standard modules
import pandas as pd
import numpy as np
import itertools
import matplotlib.pyplot as plt
import timeit
# pylife
import pylife
import pylife.vmap
import pylife.mesh
import pylife.stress.equistress
import pylife.mesh.gradient
[2]:
# import the vmap file
filename = 'data/kt1.vmap'
vmap_mesh = pylife.vmap.VMAPImport(filename)
# select the geometry and state in the vmap file
geometry = 'KT1-1'
state = 'Step-1'
pylife_mesh = (vmap_mesh.make_mesh(geometry, state)
.join_coordinates()
.join_variable('STRESS_CAUCHY')
.to_frame())
# calculate the Mises equistress
pylife_mesh['mises'] = pylife_mesh.equistress.mises()
[3]:
pylife_mesh
[3]:
| x | y | z | S11 | S22 | S33 | S12 | S13 | S23 | mises | ||
|---|---|---|---|---|---|---|---|---|---|---|---|
| element_id | node_id | ||||||||||
| 1 | 68 | -0.058024 | 0.005909 | 0.001042 | 107.280235 | 15.659771 | 23.321180 | -13.440862 | -5.005887 | -3.322926 | 91.658809 |
| 95 | -0.058024 | 0.004247 | 0.000926 | 107.280235 | 15.659771 | 23.321180 | -13.440862 | -5.005887 | -3.322926 | 91.658809 | |
| 96 | -0.058024 | 0.003611 | 0.002350 | 107.280235 | 15.659771 | 23.321180 | -13.440862 | -5.005887 | -3.322926 | 91.658809 | |
| 58 | -0.058024 | 0.005196 | 0.003000 | 107.280235 | 15.659771 | 23.321180 | -13.440862 | -5.005887 | -3.322926 | 91.658809 | |
| 14 | -0.060000 | 0.005909 | 0.001042 | 107.280235 | 15.659771 | 23.321180 | -13.440862 | -5.005887 | -3.322926 | 91.658809 | |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 2684 | 3315 | 0.060000 | -0.000494 | 0.002577 | 100.007462 | 0.000952 | 0.000791 | 0.000580 | -0.000230 | -0.000831 | 100.006590 |
| 3290 | 0.058024 | -0.001621 | 0.002328 | 100.007462 | 0.000952 | 0.000791 | 0.000580 | -0.000230 | -0.000831 | 100.006590 | |
| 3287 | 0.058024 | -0.002545 | 0.003241 | 100.007462 | 0.000952 | 0.000791 | 0.000580 | -0.000230 | -0.000831 | 100.006590 | |
| 3288 | 0.058024 | -0.001180 | 0.003989 | 100.007462 | 0.000952 | 0.000791 | 0.000580 | -0.000230 | -0.000831 | 100.006590 | |
| 3261 | 0.058024 | -0.000494 | 0.002577 | 100.007462 | 0.000952 | 0.000791 | 0.000580 | -0.000230 | -0.000831 | 100.006590 |
21472 rows × 10 columns
We can filter only element Id 1:
[4]:
# entries of element 1
pylife_mesh[pylife_mesh.index.get_level_values("element_id") == 1]
[4]:
| x | y | z | S11 | S22 | S33 | S12 | S13 | S23 | mises | ||
|---|---|---|---|---|---|---|---|---|---|---|---|
| element_id | node_id | ||||||||||
| 1 | 68 | -0.058024 | 0.005909 | 0.001042 | 107.280235 | 15.659771 | 23.32118 | -13.440862 | -5.005887 | -3.322926 | 91.658809 |
| 95 | -0.058024 | 0.004247 | 0.000926 | 107.280235 | 15.659771 | 23.32118 | -13.440862 | -5.005887 | -3.322926 | 91.658809 | |
| 96 | -0.058024 | 0.003611 | 0.002350 | 107.280235 | 15.659771 | 23.32118 | -13.440862 | -5.005887 | -3.322926 | 91.658809 | |
| 58 | -0.058024 | 0.005196 | 0.003000 | 107.280235 | 15.659771 | 23.32118 | -13.440862 | -5.005887 | -3.322926 | 91.658809 | |
| 14 | -0.060000 | 0.005909 | 0.001042 | 107.280235 | 15.659771 | 23.32118 | -13.440862 | -5.005887 | -3.322926 | 91.658809 | |
| 41 | -0.060000 | 0.004247 | 0.000926 | 107.280235 | 15.659771 | 23.32118 | -13.440862 | -5.005887 | -3.322926 | 91.658809 | |
| 42 | -0.060000 | 0.003611 | 0.002350 | 107.280235 | 15.659771 | 23.32118 | -13.440862 | -5.005887 | -3.322926 | 91.658809 | |
| 4 | -0.060000 | 0.005196 | 0.003000 | 107.280235 | 15.659771 | 23.32118 | -13.440862 | -5.005887 | -3.322926 | 91.658809 |
[5]:
# Calculate the stress gradient
tstart = timeit.default_timer()
grad = pylife_mesh.gradient_3D.gradient_of('mises')
tend = timeit.default_timer()
print(f"duration calculate stress gradient: {tend-tstart:.1f} s")
grad["abs_grad"] = np.linalg.norm(grad, axis=1)
pylife_mesh = pylife_mesh.join(grad, sort=False)
duration calculate stress gradient: 21.4 s
[6]:
display(grad)
| dmises_dx | dmises_dy | dmises_dz | abs_grad | |
|---|---|---|---|---|
| node_id | ||||
| 68 | 0.000000e+00 | 3.796075e-12 | -6.432715e-12 | 7.469271e-12 |
| 95 | 0.000000e+00 | 7.655099e-12 | 4.389822e-13 | 7.667675e-12 |
| 96 | -7.275958e-12 | 1.017575e-11 | -9.370560e-13 | 1.254446e-11 |
| 58 | 0.000000e+00 | 5.083878e-12 | 3.156447e-12 | 5.984060e-12 |
| 14 | 0.000000e+00 | -9.094947e-13 | 0.000000e+00 | 9.094947e-13 |
| ... | ... | ... | ... | ... |
| 3303 | 0.000000e+00 | 0.000000e+00 | 0.000000e+00 | 0.000000e+00 |
| 3313 | 0.000000e+00 | 1.455192e-11 | -2.910383e-11 | 3.253907e-11 |
| 3348 | 0.000000e+00 | 0.000000e+00 | -7.275958e-12 | 7.275958e-12 |
| 3296 | 0.000000e+00 | 7.275958e-12 | 0.000000e+00 | 7.275958e-12 |
| 3297 | 0.000000e+00 | -7.275958e-12 | 3.637979e-12 | 8.134768e-12 |
3348 rows × 4 columns
Next, we visualize the absolute stress gradient G using the pyvista package.
[7]:
### Plotting using pyvista
import pyvista as pv
grid = pv.UnstructuredGrid(*pylife_mesh.mesh.vtk_data())
plotter = pv.Plotter()
plotter.add_mesh(grid, scalars=pylife_mesh.groupby('element_id')['abs_grad'].mean().to_numpy(),
show_edges=True, cmap='jet')
plotter.add_scalar_bar()
plotter.show()