Local stress approach

FE based failure probability calculation

FE Data

we are using VMAP data format and rst file formats. It is also possible to use odb data,

[1]:
import numpy as np
import pandas as pd
import pickle
import pylife.vmap
import pylife.mesh
import pylife.mesh.meshsignal
import pylife.stress.equistress
import pylife.stress
import pylife.strength.fatigue
import pylife.utils.histogram as psh
import pyvista as pv

# from ansys.dpf import post
pv.set_plot_theme('document')
pv.set_jupyter_backend('panel')

VMAP

For plotting of VMAP data we are using pyVista.

[2]:
pyLife_mesh = (pylife.vmap.VMAPImport("plate_with_hole.vmap").make_mesh('1', 'STATE-2')
               .join_coordinates()
               .join_variable('STRESS_CAUCHY')
               .to_frame())

pyLife_mesh['mises'] = pyLife_mesh.equistress.mises()
grid = pv.UnstructuredGrid(*pyLife_mesh.mesh.vtk_data())
plotter = pv.Plotter(window_size=[1920, 1080])
plotter.add_mesh(grid, scalars=pyLife_mesh.groupby('element_id')['mises'].mean().to_numpy(),
                show_edges=True, cmap='jet')
plotter.add_scalar_bar()
plotter.show()

Now we want to apply the collectives to the mesh

[3]:
mises = pyLife_mesh.groupby('element_id')['S11', 'S22', 'S33', 'S12', 'S13', 'S23'].mean().equistress.mises()
mises /= mises.max()  # the nominal load level in the FEM analysis is set, that s_max = 1
collectives = pickle.load(open("collectives.p", "rb"))
collectives = collectives.unstack().T.fillna(0)
collectives_sorted = psh.combine_histogram([collectives[col] for col in collectives],
                                             method="sum")

scaled_collectives = collectives_sorted.load_collective.scale(mises)
display(scaled_collectives.to_pandas().sample(5))
range                                    element_id
(52.84455763836598, 59.450127343161725]  3319           360.0
(29.701874484295328, 35.64224938115439]  524           5660.0
(0.0, 10.377658896752912]                4339             2.0
(60.20962944836768, 72.25155533804123]   397              0.0
(0.0, 6.246165170746606]                 2142             2.0
Name: cycles, dtype: float64

Define the material parameters

[4]:
mat = pd.Series({
    'k_1': 8.,
    'ND': 1.0e6,
    'SD': 200.0, # range
    'TN': 1./12.,
    'TS': 1./1.1
})

Damage Calculation

[5]:
damage = mat.fatigue.miner_haibach().damage(scaled_collectives)
print("Max damage : %f" % damage.max())
damage = damage.groupby(['element_id']).sum()
Max damage : 0.001484
[6]:
grid = pv.UnstructuredGrid(*pyLife_mesh.mesh.vtk_data())
plotter = pv.Plotter(window_size=[1920, 1080])
plotter.add_mesh(grid, scalars=damage.to_numpy(),
                show_edges=True, cmap='jet')
plotter.add_scalar_bar()
plotter.show()

ANSYS

[7]:
#%% Ansys (license is necessary)
# For Ansys  *.rst files we are using pymapdl
# from ansys.mapdl import reader as pymapdl_reader
# # for more information please go to pymapdl
# # rst_input = post.load_solution("beam_3d.rst")
# # # pymapdl has some nice features
# # rst_input.plot_nodal_displacement(0)
# # rst_input.plot_nodal_stress(0,"X")
# ansys_mesh = pymapdl_reader.read_binary('beam_3d.rst')
# grid_ansys = ansys_mesh.grid
# plotter = pv.Plotter(window_size=[1920, 1080])
# _, volume, _  = ansys_mesh.element_solution_data(0,"ENG")
# volume = pd.DataFrame(volume)[1]

# nodes, ansys_mesh_mises = ansys_mesh.nodal_stress(0)
# ansys_mesh_mises = pd.DataFrame(data = ansys_mesh_mises,
#                                 columns=['S11', 'S22', 'S33', 'S12', 'S13', 'S23']).equistress.mises()


# test = pd.DataFrame(ansys_mesh.mesh.elem).iloc[:, 8:]
# #%%
# plotter.add_mesh(grid_ansys, scalars=ansys_mesh_mises,
#                 show_edges=True, cmap='jet')
# plotter.add_scalar_bar()
# plotter.show()