Life time Calculation

This Notebook shows a general calculation stream for a nominal and local stress reliability approach.

Stress derivation

First we read in different time signals (coming from a test bench or a vehicle measurement e.g.).

  1. Import the time series into a pandas Data Frame
  2. Resample the time series if necessary
  3. Filter the time series with a bandpass filter if necessary
  4. Edititing time series using Running Statistics methods
  5. Rainflow Calculation
  6. Mean stress correction
  7. Multiplication with repeating factor of every manoveur

Damage Calculation

  1. Select the damage calculation method (Miner elementary, Miner-Haibach, …)
  2. Calculate the damage for every load level and the damage sum
  3. Calculate the failure probability with or w/o field scatter

Local stress approach

  1. Load the FE mesh
  2. Apply the load history to the FE mesh
  3. Calculate the damage
[1]:
import numpy as np
import pandas as pd

from pylife.stress.histogram import *
import pylife.stress.timesignal as ts
from pylife.stress.rainflow import *
import pylife.stress.equistress

import pylife.strength.meanstress
from pylife.strength import miner
from pylife.strength import sn_curve
from pylife.strength.miner import MinerElementar, MinerHaibach
from pylife.strength import failure_probability as fp
import pylife.vmap

import pyvista as pv

from pylife.materialdata.woehler.diagrams.woehler_curve_diagrams import WoehlerCurveDiagrams

import pylife.mesh.meshplot
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
import matplotlib as mpl

from scipy.stats import norm

from ipywidgets import interact, interactive, fixed, interact_manual
import ipywidgets as widgets
import io
from IPython.display import HTML
import base64

# mpl.style.use('seaborn')
# mpl.style.use('seaborn-notebook')
mpl.style.use('bmh')
%matplotlib inline

pv.set_plot_theme('document')
pv.set_jupyter_backend('ipygany')
---------------------------------------------------------------------------
NoSectionError                            Traceback (most recent call last)
File ~/checkouts/readthedocs.org/user_builds/pylife/envs/1.1.4/lib/python3.8/site-packages/theano/configparser.py:238, in TheanoConfigParser.fetch_val_for_key(self, key, delete_key)
    237 try:
--> 238     return self._theano_cfg.get(section, option)
    239 except InterpolationError:

File ~/.pyenv/versions/3.8.6/lib/python3.8/configparser.py:781, in RawConfigParser.get(self, section, option, raw, vars, fallback)
    780 try:
--> 781     d = self._unify_values(section, vars)
    782 except NoSectionError:

File ~/.pyenv/versions/3.8.6/lib/python3.8/configparser.py:1149, in RawConfigParser._unify_values(self, section, vars)
   1148     if section != self.default_section:
-> 1149         raise NoSectionError(section) from None
   1150 # Update with the entry specific variables

NoSectionError: No section: 'blas'

During handling of the above exception, another exception occurred:

KeyError                                  Traceback (most recent call last)
File ~/checkouts/readthedocs.org/user_builds/pylife/envs/1.1.4/lib/python3.8/site-packages/theano/configparser.py:354, in ConfigParam.__get__(self, cls, type_, delete_key)
    353 try:
--> 354     val_str = cls.fetch_val_for_key(self.name, delete_key=delete_key)
    355     self.is_default = False

File ~/checkouts/readthedocs.org/user_builds/pylife/envs/1.1.4/lib/python3.8/site-packages/theano/configparser.py:242, in TheanoConfigParser.fetch_val_for_key(self, key, delete_key)
    241 except (NoOptionError, NoSectionError):
--> 242     raise KeyError(key)

KeyError: 'blas__ldflags'

During handling of the above exception, another exception occurred:

AttributeError                            Traceback (most recent call last)
Cell In [1], line 18
     14 import pylife.vmap
     16 import pyvista as pv
---> 18 from pylife.materialdata.woehler.diagrams.woehler_curve_diagrams import WoehlerCurveDiagrams
     20 import pylife.mesh.meshplot
     21 import matplotlib.pyplot as plt

File ~/checkouts/readthedocs.org/user_builds/pylife/envs/1.1.4/lib/python3.8/site-packages/pylife/materialdata/woehler/__init__.py:26
     24 from .analyzers.probit import Probit
     25 from .analyzers.maxlike import MaxLikeInf, MaxLikeFull
---> 26 from .analyzers.bayesian import Bayesian

File ~/checkouts/readthedocs.org/user_builds/pylife/envs/1.1.4/lib/python3.8/site-packages/pylife/materialdata/woehler/analyzers/bayesian.py:22
     20 import numpy as np
     21 import pandas as pd
---> 22 import theano.tensor as tt
     23 import pymc3 as pm
     25 from .elementary import Elementary

File ~/checkouts/readthedocs.org/user_builds/pylife/envs/1.1.4/lib/python3.8/site-packages/theano/__init__.py:83
     75 # This is the api version for ops that generate C code.  External ops
     76 # might need manual changes if this number goes up.  An undefined
     77 # __api_version__ can be understood to mean api version 0.
     78 #
     79 # This number is not tied to the release version and should change
     80 # very rarely.
     81 __api_version__ = 1
---> 83 from theano import scalar, tensor
     84 from theano.compile import (
     85     In,
     86     Mode,
   (...)
     93     shared,
     94 )
     95 from theano.compile.function import function, function_dump

File ~/checkouts/readthedocs.org/user_builds/pylife/envs/1.1.4/lib/python3.8/site-packages/theano/tensor/__init__.py:20
      9 from theano.compile import SpecifyShape, specify_shape
     10 from theano.gradient import (
     11     Lop,
     12     Rop,
   (...)
     18     verify_grad,
     19 )
---> 20 from theano.tensor import nnet  # used for softmax, sigmoid, etc.
     21 from theano.tensor import sharedvar  # adds shared-variable constructors
     22 from theano.tensor import (
     23     blas,
     24     blas_c,
   (...)
     29     xlogx,
     30 )

File ~/checkouts/readthedocs.org/user_builds/pylife/envs/1.1.4/lib/python3.8/site-packages/theano/tensor/nnet/__init__.py:3
      1 import warnings
----> 3 from . import opt
      4 from .abstract_conv import conv2d as abstract_conv2d
      5 from .abstract_conv import conv2d_grad_wrt_inputs, conv3d, separable_conv2d

File ~/checkouts/readthedocs.org/user_builds/pylife/envs/1.1.4/lib/python3.8/site-packages/theano/tensor/nnet/opt.py:32
     24 from theano.tensor.nnet.blocksparse import (
     25     SparseBlockGemv,
     26     SparseBlockOuter,
     27     sparse_block_gemv_inplace,
     28     sparse_block_outer_inplace,
     29 )
     31 # Cpu implementation
---> 32 from theano.tensor.nnet.conv import ConvOp, conv2d
     33 from theano.tensor.nnet.corr import CorrMM, CorrMM_gradInputs, CorrMM_gradWeights
     34 from theano.tensor.nnet.corr3d import Corr3dMM, Corr3dMMGradInputs, Corr3dMMGradWeights

File ~/checkouts/readthedocs.org/user_builds/pylife/envs/1.1.4/lib/python3.8/site-packages/theano/tensor/nnet/conv.py:20
     18 from theano.graph.basic import Apply
     19 from theano.graph.op import OpenMPOp
---> 20 from theano.tensor import blas
     21 from theano.tensor.basic import (
     22     NotScalarConstantError,
     23     as_tensor_variable,
     24     get_scalar_constant_value,
     25     patternbroadcast,
     26 )
     27 from theano.tensor.nnet.abstract_conv import get_conv_output_shape, get_conv_shape_1axis

File ~/checkouts/readthedocs.org/user_builds/pylife/envs/1.1.4/lib/python3.8/site-packages/theano/tensor/blas.py:163
    161 from theano.scalar import bool as bool_t
    162 from theano.tensor import basic as tt
--> 163 from theano.tensor.blas_headers import blas_header_text, blas_header_version
    164 from theano.tensor.opt import in2out, local_dimshuffle_lift
    165 from theano.tensor.type import values_eq_approx_remove_inf_nan

File ~/checkouts/readthedocs.org/user_builds/pylife/envs/1.1.4/lib/python3.8/site-packages/theano/tensor/blas_headers.py:1016
    997             header += textwrap.dedent(
    998                 """\
    999                     static float sdot_(int* Nx, float* x, int* Sx, float* y, int* Sy)
   (...)
   1010                     """
   1011             )
   1013     return header + blas_code
-> 1016 if not config.blas__ldflags:
   1017     _logger.warning("Using NumPy C-API based implementation for BLAS functions.")
   1020 def mkl_threads_text():

File ~/checkouts/readthedocs.org/user_builds/pylife/envs/1.1.4/lib/python3.8/site-packages/theano/configparser.py:358, in ConfigParam.__get__(self, cls, type_, delete_key)
    356 except KeyError:
    357     if callable(self.default):
--> 358         val_str = self.default()
    359     else:
    360         val_str = self.default

File ~/checkouts/readthedocs.org/user_builds/pylife/envs/1.1.4/lib/python3.8/site-packages/theano/link/c/cmodule.py:2621, in default_blas_ldflags()
   2617 try:
   2618     if hasattr(numpy.distutils, "__config__") and numpy.distutils.__config__:
   2619         # If the old private interface is available use it as it
   2620         # don't print information to the user.
-> 2621         blas_info = numpy.distutils.__config__.blas_opt_info
   2622     else:
   2623         # We do this import only here, as in some setup, if we
   2624         # just import theano and exit, with the import at global
   (...)
   2630         # This happen with Python 2.7.3 |EPD 7.3-1 and numpy 1.8.1
   2631         # isort: off
   2632         import numpy.distutils.system_info  # noqa

AttributeError: module 'numpy.distutils.__config__' has no attribute 'blas_opt_info'

Time series signal

import, filtering and so on. You can import your own signal with

and so on

[2]:
t = np.linspace(0,60,60*2048)
files = ['wn','sine']
wn = pd.DataFrame(index = t, columns = ['sensor_1'], data = 120*np.random.randn(len(t)))
sine = pd.DataFrame(index = t, columns = ['sensor_1'], data = 80*np.sin(2*np.pi*50*t))
input_data = [wn,sine]
[3]:
# input_data = []
# for upload in files:
#     data_akt = pd.read_csv(data_loc + upload, sep = ",")
#     if len(data_akt.columns) == 1:
#         print ('please use "," as seperator next time')
#         data_akt = pd.read_csv(data_loc + upload, sep = ";")
#         input_data.append(data_akt)
#     print(upload + " imported succesfully")

Resampling

[4]:
f_resample = widgets.FloatText(value = 1024,min=1,max=100e3,step=1,
    description='Resampling frequency [Hz]',
    disabled=False,readout=True,readout_format='d')
display(f_resample)
# select time column
# timeColumn = widgets.Dropdown(options = data_akt.columns)
# display(timeColumn)
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In [4], line 1
----> 1 f_resample = widgets.FloatText(value = 1024,min=1,max=100e3,step=1,
      2     description='Resampling frequency [Hz]',
      3     disabled=False,readout=True,readout_format='d')
      4 display(f_resample)
      5 # select time column
      6 # timeColumn = widgets.Dropdown(options = data_akt.columns)
      7 # display(timeColumn)

NameError: name 'widgets' is not defined
[5]:
meas_resample = []
for file_act in input_data:
#     file_act = file_act.set_index(timeColumn.value)
    meas_resample.append(ts.TimeSignalPrep(file_act).resample_acc(f_resample.value))
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In [5], line 4
      1 meas_resample = []
      2 for file_act in input_data:
      3 #     file_act = file_act.set_index(timeColumn.value)
----> 4     meas_resample.append(ts.TimeSignalPrep(file_act).resample_acc(f_resample.value))

NameError: name 'f_resample' is not defined
[6]:
print("select channel to plot")
plotChan = widgets.Dropdown(options = file_act.columns)
display(plotChan)
select channel to plot
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In [6], line 2
      1 print("select channel to plot")
----> 2 plotChan = widgets.Dropdown(options = file_act.columns)
      3 display(plotChan)

NameError: name 'widgets' is not defined
[7]:
fig, ax = plt.subplots(len(meas_resample))
fig.suptitle('Resampled input data')
ii = 0
for df_act in meas_resample:
    if len(meas_resample) == 1:
        ax.plot(df_act.index, df_act[plotChan.value])
    else:
        ax[ii].plot(df_act.index, df_act[plotChan.value])
    ii += 1
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In [7], line 1
----> 1 fig, ax = plt.subplots(len(meas_resample))
      2 fig.suptitle('Resampled input data')
      3 ii = 0

NameError: name 'plt' is not defined

Filtering

[8]:
f_min = widgets.FloatText(value = 5,description='min frequency [Hz]',disabled=False)
f_max = widgets.FloatText(value = 100,description='max frequency [Hz]',disabled=False)
display(f_min)
display(f_max)
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In [8], line 1
----> 1 f_min = widgets.FloatText(value = 5,description='min frequency [Hz]',disabled=False)
      2 f_max = widgets.FloatText(value = 100,description='max frequency [Hz]',disabled=False)
      3 display(f_min)

NameError: name 'widgets' is not defined
[9]:
bandpass = []
for df_act in meas_resample:
    bandpassDF = pd.DataFrame(index = df_act.index)
    for col_act in df_act.columns:
        bandpassDF[col_act] = ts.TimeSignalPrep(df_act[col_act]).butter_bandpass(f_min.value,f_max.value,f_resample.value,5)
    bandpass.append(bandpassDF)
display(bandpassDF)
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In [9], line 7
      5         bandpassDF[col_act] = ts.TimeSignalPrep(df_act[col_act]).butter_bandpass(f_min.value,f_max.value,f_resample.value,5)
      6     bandpass.append(bandpassDF)
----> 7 display(bandpassDF)

NameError: name 'bandpassDF' is not defined

Running statistics

[10]:
print("select channel to for running stats")
runChan = widgets.Dropdown(options = df_act.columns)
display(runChan)
print(" Running statistics method")
method_choice = widgets.Dropdown(options = ['rms','max','min','abs'])
display(method_choice)

paraRunStats = ['window_length', 'buffer_overlap', 'limit']
values = [800,0.1,0.015]
child = [widgets.FloatText(description=name) for name in paraRunStats]
tab = widgets.Tab()
tab.children = child
for i in range(len(child)):
    tab.set_title(i, paraRunStats[i])
    tab.children[i].value = values[i]

tab
select channel to for running stats
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In [10], line 2
      1 print("select channel to for running stats")
----> 2 runChan = widgets.Dropdown(options = df_act.columns)
      3 display(runChan)
      4 print(" Running statistics method")

NameError: name 'widgets' is not defined
[11]:
""" Running statistics to drop out zero values """
cleaned = []
for df_act in bandpass:
    cleaned_df = ts.TimeSignalPrep(df_act).running_stats_filt(
                            col = runChan.value,
                            window_length = int(tab.children[0].value),
                            buffer_overlap = int(tab.children[1].value),
                            limit = tab.children[2].value,
                            method = method_choice.value)
    cleaned.append(cleaned_df)
# display(cleaned_df)
[12]:
print("select channel to plot")
plotChan = widgets.Dropdown(options = file_act.columns)
display(plotChan)
select channel to plot
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In [12], line 2
      1 print("select channel to plot")
----> 2 plotChan = widgets.Dropdown(options = file_act.columns)
      3 display(plotChan)

NameError: name 'widgets' is not defined
[13]:
fig, ax = plt.subplots(len(meas_resample))
fig.suptitle('Cleaned input data')
for i, df_act in enumerate(cleaned):
    if len(meas_resample) == 1:
        ax.plot(df_act.index, df_act[plotChan.value])
    else:
        ax[i].plot(df_act.index, df_act[plotChan.value])
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In [13], line 1
----> 1 fig, ax = plt.subplots(len(meas_resample))
      2 fig.suptitle('Cleaned input data')
      3 for i, df_act in enumerate(cleaned):

NameError: name 'plt' is not defined

Rainflow

[14]:
rfcChan = widgets.Dropdown(options = df_act.columns)
display(rfcChan)
binwidget = widgets.IntSlider(value = 64, min=1, max=1024, step=1,description='Bins:')
display(binwidget)
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In [14], line 1
----> 1 rfcChan = widgets.Dropdown(options = df_act.columns)
      2 display(rfcChan)
      3 binwidget = widgets.IntSlider(value = 64, min=1, max=1024, step=1,description='Bins:')

NameError: name 'widgets' is not defined
[15]:
rainflow = []
for df_act in cleaned:
    rfc = RainflowCounterFKM().process(df_act[rfcChan.value].values)
    rfm = rfc.get_rainflow_matrix_frame(binwidget.value)
    rainflow.append(rfm)
[16]:
colormap = cm.ScalarMappable()
cmap = cm.get_cmap('PuRd')
# fig, ax = plt.subplots(2,len(rainflow))
fig = plt.figure(figsize = (8,11))
fig.suptitle('Rainflow of Channel ' + rfcChan.value)

for i, rf_act in enumerate(rainflow):
    # 2D
    ax = fig.add_subplot(3,2,2*(i+1)-1)
    froms = rf_act.index.get_level_values('from').mid
    tos = rf_act.index.get_level_values('to').mid
    counts = np.flipud((rf_act.values.reshape(rf_act.index.levshape).T))#.ravel()
    ax.set_xlabel('From')
    ax.set_ylabel('To')
    ax.imshow(np.log10(counts), extent=[froms.min(), froms.max(), tos.min(), tos.max()])
    # 3D
    ax = fig.add_subplot(3,2,2*(i+1), projection='3d')
    bottom = np.zeros_like(counts.ravel())
    width = rf_act.index.get_level_values('from').length.min()
    depth = rf_act.index.get_level_values('to').length.min()
    max_height = np.max(counts.ravel())   # get range of colorbars
    min_height = np.min(counts.ravel())
    rgba = [cmap((k-min_height)/max_height) for k in counts.ravel()]
    ax.set_xlabel('From')
    ax.set_ylabel('To')
    ax.set_zlabel('Count')
    ax.bar3d(froms.ravel(), tos.ravel(), bottom, width, depth, counts.ravel(), shade=True, color=rgba, zsort='average')
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In [16], line 1
----> 1 colormap = cm.ScalarMappable()
      2 cmap = cm.get_cmap('PuRd')
      3 # fig, ax = plt.subplots(2,len(rainflow))

NameError: name 'cm' is not defined

Meanstress transformation

[17]:
meanstress_para = ['M', 'M2', 'R_Goal']
values = [0.3,0.2,-1]
child = [widgets.FloatText(description=name) for name in meanstress_para]
tab_mean = widgets.Tab()
tab_mean.children = child
for i in range(len(child)):
    tab_mean.set_title(i, meanstress_para[i])
    tab_mean.children[i].value = values[i]

tab_mean
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In [17], line 3
      1 meanstress_para = ['M', 'M2', 'R_Goal']
      2 values = [0.3,0.2,-1]
----> 3 child = [widgets.FloatText(description=name) for name in meanstress_para]
      4 tab_mean = widgets.Tab()
      5 tab_mean.children = child

Cell In [17], line 3, in <listcomp>(.0)
      1 meanstress_para = ['M', 'M2', 'R_Goal']
      2 values = [0.3,0.2,-1]
----> 3 child = [widgets.FloatText(description=name) for name in meanstress_para]
      4 tab_mean = widgets.Tab()
      5 tab_mean.children = child

NameError: name 'widgets' is not defined
[18]:
transformed = []
for rf_act in rainflow:
    transformed.append(rf_act.meanstress_hist.FKM_goodman(pd.Series({'M': tab_mean.children[0].value,
                                                                     'M2': tab_mean.children[1].value})
                                                          , R_goal = tab_mean.children[2].value))

Repeating factor

[19]:
child = [widgets.FloatText(description=name) for name in files]
tab_repeat = widgets.Tab()
tab_repeat.children = child
for i in range(len(child)):
    tab_repeat.set_title(i, files[i])
    tab_repeat.children[i].value = int(50/(i+1))
tab_repeat
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In [19], line 1
----> 1 child = [widgets.FloatText(description=name) for name in files]
      2 tab_repeat = widgets.Tab()
      3 tab_repeat.children = child

Cell In [19], line 1, in <listcomp>(.0)
----> 1 child = [widgets.FloatText(description=name) for name in files]
      2 tab_repeat = widgets.Tab()
      3 tab_repeat.children = child

NameError: name 'widgets' is not defined
[20]:
for ii in range(len(files)):
    transformed[ii] = transformed[ii]*tab_repeat.children[ii].value
range_only_total = combine_hist(transformed,method = "sum")
display(range_only_total)
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
Cell In [20], line 2
      1 for ii in range(len(files)):
----> 2     transformed[ii] = transformed[ii]*tab_repeat.children[ii].value
      3 range_only_total = combine_hist(transformed,method = "sum")
      4 display(range_only_total)

IndexError: list index out of range
[21]:
fig, ax = plt.subplots(nrows=1, ncols=2,figsize=(10, 5))
# plot total
amplitude = range_only_total.index.get_level_values('range').left.values[::-1]/2
cycles = range_only_total.values[::-1].ravel()
ax[0].step(cycles,amplitude,c = "black",linewidth = 3, label = "total")
ax[1].step(np.cumsum(cycles),amplitude,c = "black",linewidth = 3, label = "total")
ii = 0
for range_only in transformed:
    amplitude = range_only.index.get_level_values('range').mid.values[::-1]/2
    cycles = range_only.values[::-1].ravel()
    ax[0].step(cycles,amplitude,label = files [ii])
    ax[1].step(np.cumsum(cycles),amplitude,label = files [ii])
    ii += 1
ax[0].set_title('Count')
ax[1].set_title('Cumulated sum count')
ax[1].legend()
for ai in ax:
    ai.xaxis.grid(True)
    ai.set_xlabel('count')
    ai.set_ylabel('amplitude of ' + rfcChan.value)
    ai.set_ylim((0,max(amplitude)))
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In [21], line 1
----> 1 fig, ax = plt.subplots(nrows=1, ncols=2,figsize=(10, 5))
      2 # plot total
      3 amplitude = range_only_total.index.get_level_values('range').left.values[::-1]/2

NameError: name 'plt' is not defined

Nominal stress approach

Material parameters

You can create your own material data from Woeler tests using the Notebook woehler_analyzer

[22]:
mat = pd.Series(index = ['k_1', 'ND_50', 'SD_50', '1/TN', '1/TS'],
                data = [8, 1.5e+06, 1.5e+02, 12, 1.1])
display(mat)
k_1            8.0
ND_50    1500000.0
SD_50        150.0
1/TN          12.0
1/TS           1.1
dtype: float64

Damage Calculation

[23]:
SNmethod = widgets.Dropdown(options = ['Miner Elementar','Miner Haibach','Miner original'])
display(SNmethod)
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In [23], line 1
----> 1 SNmethod = widgets.Dropdown(options = ['Miner Elementar','Miner Haibach','Miner original'])
      2 display(SNmethod)

NameError: name 'widgets' is not defined
[24]:
damage_calc = sn_curve.FiniteLifeCurve(**mat.drop(['1/TN','1/TS']))
damage = damage_calc.calc_damage(range_only_total,method = 'original')
# display(damage)
print("\033[5m  Total Damage of channel %s: %.2e  \033[0m" % (rfcChan.value,damage.sum()))
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In [24], line 2
      1 damage_calc = sn_curve.FiniteLifeCurve(**mat.drop(['1/TN','1/TS']))
----> 2 damage = damage_calc.calc_damage(range_only_total,method = 'original')
      3 # display(damage)
      4 print("\033[5m  Total Damage of channel %s: %.2e  \033[0m" % (rfcChan.value,damage.sum()))

NameError: name 'range_only_total' is not defined
[25]:
SRI = mat['SD_50']*(mat['ND_50']**(1/mat['k_1']))
# Plotting
diagdata = WoehlerCurveDiagrams(mat, fatigue_data = None, analyzer = None,
                                y_min=2, y_max=SRI, x_min=1e1, x_max=1e12, ax = None)
diagdata.plot_fitted_curve( k_2=15)
plt.step(np.cumsum(cycles),2*amplitude)

---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In [25], line 3
      1 SRI = mat['SD_50']*(mat['ND_50']**(1/mat['k_1']))
      2 # Plotting
----> 3 diagdata = WoehlerCurveDiagrams(mat, fatigue_data = None, analyzer = None,
      4                                 y_min=2, y_max=SRI, x_min=1e1, x_max=1e12, ax = None)
      5 diagdata.plot_fitted_curve( k_2=15)
      6 plt.step(np.cumsum(cycles),2*amplitude)

NameError: name 'WoehlerCurveDiagrams' is not defined

Failure Probaility

Without field scatter

[26]:
D50 = 0.05
d = damage.sum()
di = np.logspace(np.log10(1e-1*d),np.log10(1e3*d),1000).flatten()
std = np.log10(mat['1/TN'])/2.5631031311
failprob = fp.FailureProbability(D50,std).pf_simple_load(di)
#print(failprob)
fig, ax = plt.subplots()
ax.semilogx(di, failprob, label='cdf')
ax.vlines(d, max(failprob), fp.FailureProbability(D50,std).pf_simple_load(d))
#
plt.xlabel("Damage")
plt.ylabel("cdf")
plt.title("Failure probability = %.2e" %fp.FailureProbability(D50,std).pf_simple_load(d))
plt.ylim(0,max(failprob))
plt.xlim(min(di),max(di))
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In [26], line 2
      1 D50 = 0.05
----> 2 d = damage.sum()
      3 di = np.logspace(np.log10(1e-1*d),np.log10(1e3*d),1000).flatten()
      4 std = np.log10(mat['1/TN'])/2.5631031311

NameError: name 'damage' is not defined

With field scatter

[27]:
field_std = 0.35
fig, ax = plt.subplots()
# plot pdf of material
mat_pdf = norm.pdf(np.log10(di), loc=np.log10(D50), scale=std)
ax.semilogx(di, mat_pdf, label='pdf_mat')
# plot pdf of load
field_pdf = norm.pdf(np.log10(di), loc=np.log10(d), scale=field_std)
ax.semilogx(di, field_pdf, label='pdf_load',color = 'r')
plt.xlabel("Damage")
plt.ylabel("pdf")
plt.title("Failure probability = %.2e" %fp.FailureProbability(D50,std).pf_norm_load(d,field_std))
plt.legend()
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In [27], line 2
      1 field_std = 0.35
----> 2 fig, ax = plt.subplots()
      3 # plot pdf of material
      4 mat_pdf = norm.pdf(np.log10(di), loc=np.log10(D50), scale=std)

NameError: name 'plt' is not defined

FE based failure probability calculation

FE Data

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

pyLife_mesh.sample(10)
[28]:
x y z S11 S22 S33 S12 S13 S23 dx dy dz
element_id node_id
2348 2529 -12.898024 5.043483 0.0 31.530674 2.548773 0.0 15.299500 0.0 0.0 -0.005355 -2.683275e-05 0.0
4375 4495 -12.949039 -6.678593 0.0 43.582188 1.339038 0.0 -12.696354 0.0 0.0 -0.005050 8.312715e-05 0.0
152 5456 11.613465 8.801641 0.0 71.453232 -0.010022 0.0 -1.659853 0.0 0.0 0.003944 -4.149746e-04 0.0
7 4943 6.531105 4.282071 0.0 7.892305 -8.635008 0.0 1.650274 0.0 0.0 0.004573 -1.685894e-03 0.0
617 819 6.382044 4.971782 0.0 24.553560 -7.306720 0.0 -4.594051 0.0 0.0 0.004121 -1.815735e-03 0.0
381 6246 8.700279 6.144556 0.0 49.453789 -6.915460 0.0 -8.297787 0.0 0.0 0.003934 -8.298817e-04 0.0
3729 12898 -5.862029 -4.604344 0.0 9.270004 -1.616697 0.0 -0.216634 0.0 0.0 -0.004689 1.961728e-03 0.0
4638 4591 -14.018771 -6.163092 0.0 37.169250 2.586217 0.0 -12.849130 0.0 0.0 -0.005351 2.429623e-05 0.0
2954 10846 11.770742 -0.774989 0.0 4.559637 0.088149 0.0 4.189425 0.0 0.0 0.005776 3.926224e-06 0.0
1742 192 -8.303333 0.000000 0.0 -8.103550 -53.486710 0.0 2.622392 0.0 0.0 -0.006014 8.659753e-38 0.0
[29]:
# Equivalent stress range
pyLife_mesh['mises'] = 2*pyLife_mesh.equistress.mises()
# Scaling with amplitude
pyLife_mesh['mises'] = 2*pyLife_mesh['mises']/pyLife_mesh['mises'].max()
ampl_fe = pd.DataFrame(data = amplitude, columns = ["ampl"] ,index =cycles)
s_vm_scaled = pd.DataFrame(data = ampl_fe.values*pyLife_mesh['mises'].transpose().values,index = ampl_fe.index,columns = pyLife_mesh['mises'].index)
display(s_vm_scaled)
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In [29], line 5
      3 # Scaling with amplitude
      4 pyLife_mesh['mises'] = 2*pyLife_mesh['mises']/pyLife_mesh['mises'].max()
----> 5 ampl_fe = pd.DataFrame(data = amplitude, columns = ["ampl"] ,index =cycles)
      6 s_vm_scaled = pd.DataFrame(data = ampl_fe.values*pyLife_mesh['mises'].transpose().values,index = ampl_fe.index,columns = pyLife_mesh['mises'].index)
      7 display(s_vm_scaled)

NameError: name 'amplitude' is not defined

Damage Calculation

[30]:
N = damage_calc.calc_N(s_vm_scaled,ignore_limits = True)
d_mesh_cycle =  1/(N.div(N.index.values, axis = 'index'))
#np.sum(data_act[range_mid > sn_curve_parameters["sigma_ak"]].values/N)

d_mesh = d_mesh_cycle.sum()
display(d_mesh)
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In [30], line 1
----> 1 N = damage_calc.calc_N(s_vm_scaled,ignore_limits = True)
      2 d_mesh_cycle =  1/(N.div(N.index.values, axis = 'index'))
      3 #np.sum(data_act[range_mid > sn_curve_parameters["sigma_ak"]].values/N)

NameError: name 's_vm_scaled' is not defined
[31]:
pyLife_mesh = pyLife_mesh.join(pd.DataFrame(data = d_mesh,columns = ['d']))
display(pyLife_mesh)
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In [31], line 1
----> 1 pyLife_mesh = pyLife_mesh.join(pd.DataFrame(data = d_mesh,columns = ['d']))
      2 display(pyLife_mesh)

NameError: name 'd_mesh' is not defined
[32]:
# plotting using pyvista
pyLife_nodes = pyLife_mesh.groupby('node_id').mean()
mesh = pv.PolyData(pyLife_nodes[['x', 'y', 'z']].values)
mesh.point_arrays["d"] = pyLife_nodes["d"].values
mesh.plot(scalars="d",log_scale = True)
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
File ~/checkouts/readthedocs.org/user_builds/pylife/envs/1.1.4/lib/python3.8/site-packages/pandas/core/indexes/base.py:3803, in Index.get_loc(self, key, method, tolerance)
   3802 try:
-> 3803     return self._engine.get_loc(casted_key)
   3804 except KeyError as err:

File ~/checkouts/readthedocs.org/user_builds/pylife/envs/1.1.4/lib/python3.8/site-packages/pandas/_libs/index.pyx:138, in pandas._libs.index.IndexEngine.get_loc()

File ~/checkouts/readthedocs.org/user_builds/pylife/envs/1.1.4/lib/python3.8/site-packages/pandas/_libs/index.pyx:165, in pandas._libs.index.IndexEngine.get_loc()

File pandas/_libs/hashtable_class_helper.pxi:5745, in pandas._libs.hashtable.PyObjectHashTable.get_item()

File pandas/_libs/hashtable_class_helper.pxi:5753, in pandas._libs.hashtable.PyObjectHashTable.get_item()

KeyError: 'd'

The above exception was the direct cause of the following exception:

KeyError                                  Traceback (most recent call last)
Cell In [32], line 4
      2 pyLife_nodes = pyLife_mesh.groupby('node_id').mean()
      3 mesh = pv.PolyData(pyLife_nodes[['x', 'y', 'z']].values)
----> 4 mesh.point_arrays["d"] = pyLife_nodes["d"].values
      5 mesh.plot(scalars="d",log_scale = True)

File ~/checkouts/readthedocs.org/user_builds/pylife/envs/1.1.4/lib/python3.8/site-packages/pandas/core/frame.py:3804, in DataFrame.__getitem__(self, key)
   3802 if self.columns.nlevels > 1:
   3803     return self._getitem_multilevel(key)
-> 3804 indexer = self.columns.get_loc(key)
   3805 if is_integer(indexer):
   3806     indexer = [indexer]

File ~/checkouts/readthedocs.org/user_builds/pylife/envs/1.1.4/lib/python3.8/site-packages/pandas/core/indexes/base.py:3805, in Index.get_loc(self, key, method, tolerance)
   3803     return self._engine.get_loc(casted_key)
   3804 except KeyError as err:
-> 3805     raise KeyError(key) from err
   3806 except TypeError:
   3807     # If we have a listlike key, _check_indexing_error will raise
   3808     #  InvalidIndexError. Otherwise we fall through and re-raise
   3809     #  the TypeError.
   3810     self._check_indexing_error(key)

KeyError: 'd'
[33]:
print("Maximal damage sum: %f" % d_mesh.max())
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In [33], line 1
----> 1 print("Maximal damage sum: %f" % d_mesh.max())

NameError: name 'd_mesh' is not defined