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

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
frequency  (8.5243575109601, 17.0487150219202]       1626              0.0
           (7.136310851059432, 14.272621702118863]   108               0.0
           (109.79119357051275, 123.51509276682684]  214           14990.0
           (28.795998430531647, 32.3954982343481]    337             360.0
           (42.5854331233906, 49.68300531062236]     2679           1654.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()