Source code for pylife.materiallaws.rambgood

# Copyright (c) 2019-2023 - for information on the respective copyright owner
# see the NOTICE file and/or the repository
# https://github.com/boschresearch/pylife
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

__author__ = ["Johannes Mueller", 'Alexander Maier']
__maintainer__ = __author__

import numpy as np
from scipy import optimize


[docs] class RambergOsgood: '''Simple implementation of the Ramberg-Osgood relation Parameters ---------- E : float Young's Modulus K : float The strength coefficient, usually named ``K'`` or ``K_prime`` in FKM nonlinear related formulas. n : float The strain hardening coefficient, usually named ``n'`` or ``n_prime`` in FKM nonlinear related formulas. Notes ----- The equation implemented is the one that `Wikipedia <https://en.wikipedia.org/wiki/Ramberg%E2%80%93Osgood_relationship#Alternative_Formulations>`__ refers to as "Alternative Formulation". The parameters `n` and `k` in this are formulation are the Hollomon parameters. ''' def __init__(self, E, K, n): self._E = E self._K = K self._n = n @property def E(self): '''Get Young's Modulus''' return self._E @property def K(self): '''Get the strength coefficient''' return self._K @property def n(self): '''Get the strain hardening coefficient''' return self._n
[docs] def strain(self, stress): '''Calculate the elastic plastic strain for a given stress Parameters ---------- stress : array-like float The stress Returns ------- strain : array-like float The resulting strain ''' stress = np.asarray(stress) return self.elastic_strain(stress) + self.plastic_strain(stress)
[docs] def elastic_strain(self, stress): '''Calculate the elastic strain for a given stress Parameters ---------- stress : array-like float The stress Returns ------- strain : array-like float The resulting elastic strain ''' return stress/self._E
[docs] def plastic_strain(self, stress): '''Calculate the plastic strain for a given stress Parameters ---------- stress : array-like float The stress Returns ------- strain : array-like float The resulting plastic strain ''' absstress, signstress = self._get_abs_sign(stress) return signstress * np.power(absstress/self._K, 1./self._n)
def _get_abs_sign(self, x): '''Calculate the absolute value and the sign for a given input Parameters ---------- x : array-like float The input Returns ------- abs_x : array-like float The resulting absolute value sign_x : array-like float The resulting sign of the input ''' abs_x = np.fabs(x) sign_x = np.sign(x) return abs_x, sign_x
[docs] def stress(self, strain, *, rtol=1e-5, tol=1e-6): '''Calculate the stress for a given strain Parameters ---------- strain : array-like float The strain Returns ------- stress : array-like float The resulting stress ''' def residuum(stress): return self.strain(stress) - abs_strain def dresiduum(stress): return self.tangential_compliance(stress) strain = np.asarray(strain) abs_strain, sign_strain = self._get_abs_sign(strain) stress0 = self._E * abs_strain abs_stress = optimize.newton( func=residuum, x0=stress0, fprime=dresiduum, rtol=rtol, tol=tol ) return abs_stress * sign_strain
[docs] def tangential_compliance(self, stress): '''Calculate the derivative of the strain with respect to the stress for a given stress Parameters ---------- stress : array-like float The stress Returns ------- dstrain : array-like float The resulting derivative ''' stress = np.abs(stress) return 1./self._E + 1./(self._n*self._K) * np.power(stress/self._K, 1./self._n - 1)
[docs] def tangential_modulus(self, stress): '''Calculate the derivative of the stress with respect to the strain for a given stress Parameters ---------- stress : array-like float The stress Returns ------- dstress : array-like float The resulting derivative ''' return 1. / self.tangential_compliance(stress)
[docs] def delta_strain(self, delta_stress): '''Calculate the cyclic Masing strain span for a given stress span Parameters ---------- delta_stress : array-like float The stress span Returns ------- delta_strain : array-like float The corresponding strain span Notes ----- A Masing like behavior is assumed for the material as described in `Kerbgrundkonzept <https://de.wikipedia.org/wiki/Kerbgrundkonzept#Masing-Verhalten_und_Werkstoffged%C3%A4chtnis>`__. ''' return 2*self.strain(stress=delta_stress/2.)
[docs] def delta_stress(self, delta_strain): '''Calculate the cyclic Masing stress span for a given strain span Parameters ---------- delta_strain : array-like float The strain span Returns ------- delta_stress : array-like float The corresponding stress span Notes ----- A Masing like behavior is assumed for the material as described in `Kerbgrundkonzept <https://de.wikipedia.org/wiki/Kerbgrundkonzept#Masing-Verhalten_und_Werkstoffged%C3%A4chtnis>`__. ''' return 2*self.stress(strain=delta_strain/2.)
[docs] def lower_hysteresis(self, stress, max_stress): '''Calculate the lower (relaxation to compression) hysteresis starting from a given maximum stress Parameters ---------- stress : array-like float The stress (must be below the maximum stress) max_stress : float The maximum stress of the hysteresis look Returns ------- lower_hysteresis : array-like float The lower hysteresis branch from `max_stress` all the way to `stress` Raises ------ ValueError if stress > max_stress ''' stress = np.asarray(stress) if (stress > max_stress).any(): raise ValueError("Value for 'stress' must not be higher than 'max_stress'.") return self.strain(max_stress) - self.delta_strain(max_stress-stress)