Comprobación de miembros sujetos a fatiga según FEM 2131/2132 (5)
Tensión de cortadura
Tras analizar las tensiones de tracción y compresión, el trabajo para comprobar la tensión de cortadura está prácticamente hecho. Primero voy a ver la definición que hace la norma:
Para cada uno de los grupos de E1 a E8 se toma el esfuerzo de fatiga admisible en tensión del caso W0 dividido por √3.
τa=σt of case W0√3El proceso de creación de las clases para el cálculo de la tensión de cortadura será similar al empleado con las tensiones de tracción y compresión.
- En una primera clase llamada
DataFrame
obtendré los valores básicos para calcular las tensiones admisibles. - En una segunda clase llamada
Formulae
definiré el formulario para el cálculo. - Y en un tercera y última clase
PermissibleTau
obtendré las tensiones admisibles según las diferentes condiciones de cálculo.
La razón de organizar el código de esta manera, como expliqué en el post anterior, es una mezcla de programación defensiva y organización del código con vistas al mantenimiento.
La clase DataFrame
contiene la variable de instancia df
con los datos de estudio de la fatiga. Los métodos de la clase DataFrame
son los getters de las variables del cálculo.
class DataFrame:
"""
Pandas DataFrame with the data for the calculation of the
stresses for fatigue.
"""
def __init__(self, df):
"""
Asumes df is the pandas DataFrame with the data for the
calculation of the stresses for fatigue, get the values
of the columns.
Parameters
----------
df : pandas DataFrame ; data for the calculation of the
stresses for fatigue.
"""
self.df = df
def get_df(self):
"""Getter of the DataFrame."""
return self.df.copy()
def get_df_columns(self):
"""Getter of the list wiht the DataFrame columns."""
return list(self.df.columns)
def get_sigma_W0(self):
"""Basic stress for W0 [MPa]."""
return self.df['sigma_W0_[MPa]'].copy()
def get_k_txy(self):
"""Ratio between the extreme stresses tau_xy."""
return self.df['k_txy'].copy()
La segunda clase Formulae
hereda de la clase DataFrame
los atributos para operar e inicializa las variables de instancia del límite elástico σE y de la tensión de rotura σR.
class Formulae(DataFrame):
"""
Formulae for de permissible stresses for fatigue with shear
loads according to FEM 2131/2132.
"""
def __init__(self, df, sigma_E, sigma_R):
"""
Asumes df, sigma_E and sigma_R the data for the calculation
of the stresses for fatigue, get the permissible stresses
for fatigue in case of ratio k ≤ 0 and k > 0 for shear.
Parameters
----------
df : pandas DataFrame ; data for the calculation of
the stresses for fatigue.
sigma_E : int ; [MPa] elastic limit of steel.
sigma_R : int ; [MPa] ultimate tensile strength
of steel.
"""
DataFrame.__init__(self, df)
self.sigma_W0 = self.get_sigma_W0()
self.sigma_E = sigma_E
self.sigma_R = sigma_R
La norma indica que para calcular la tensión de cortadura se toma la tensión de fatiga admisible en tracción para el caso de W0. Las tensiones de fatiga admisible en tracción están indicadas en el post anterior. Como recordatorio estas son las fórmulas:
-
Si κ≤0
σt=σW·53–2·κ≤0,66·σE
El código equivalente a la fórmula se recoge en el método tension_stress_k_neg
de la clase Formulae
.
def tension_stress_k_neg(self, k):
"""
Permissible stress for k ≤ 0 and tension.
Parameters
----------
k : pandas Serie : ratio between the extreme stresses.
"""
sigma_t = self.sigma_W0 * 5 / (3 - 2 * k)
sigma_t = sigma_t.where(
sigma_t <= 0.66 * self.sigma_E, 0.66 * self.sigma_E
)
return sigma_t
-
Si κ>0
σt=σ01−(1−σ0σ+1)·κ≤0,66·σE
Donde
σ0 = tensión de tracción para κ = 0; se da en la fórmula (1), esto es:
σ0=1,66·σWσ+1 = tensión de tracción para κ = +1, esto es, la tensión última σR dividida por el coeficiente de seguridad 1,33:
σ+1=0,75·σRσt está limitada en todo caso a 0,66·σE.
En este caso de la tensión de cortadura, habrá que considerar σW=σW0.
Todo esto traducido a código:
def tension_stress_k_pos(self, k):
"""
Permissible stress for k > 0 and tension.
Parameters
----------
k : pandas Serie : ratio between the extreme stresses.
"""
sigma_0 = self.tensile_stress_k_0()
sigma_1 = self.tensile_sttress_k_1()
sigma_t = sigma_0 / (1 - (1 - sigma_0 / sigma_1) * k)
sigma_t = sigma_t.where(
sigma_t <= 0.66 * self.sigma_E, 0.66 * self.sigma_E
)
return sigma_t
def tensile_stress_k_0(self):
"""Tensile stress for k = 0."""
sigma_0 = 1.66 * self.sigma_W0
return sigma_0
def tensile_sttress_k_1(self):
"""Tensile stress for k = +1."""
sigma_1 = 0.75 * self.sigma_R
return sigma_1
La tercera clase PermissibleTau
hereda de la clase Formulae
los diferentes atributos y métodos, y como en el caso de las tensiones admisibles a tracción y compresión, obtengo los resultados finales de la tensión admisible a cortante en función de si κ toma un valor positivo o negativo.
class PermissibleTau(Formulae):
"""
Permissible stresses for fatigue with shear loads according to
FEM 2131/2132.
"""
def __init__(self, df, sigma_E, sigma_R):
"""
Asumes df, sigma_E, sigma_R the data for the calculation of
the stresses for fatigue, get the permissible stresses for
fatigue in case of ratio k ≤ 0 and k > 0 for shear.
Parameters
----------
df : pandas DataFrame ; data for the calculation of
the stresses for fatigue.
sigma_W : pandas Serie ; [MPa] basic stress.
sigma_E : int ; [MPa] elastic limit of steel.
sigma_R : int ; [MPa] ultimate tensile strength
of steel.
"""
Formulae.__init__(self, df, sigma_E, sigma_R)
self.k_txy = self.get_k_txy()
def shear_stress(self):
"""Permissible stress for shear."""
tension_stress_k_neg = self.tension_stress_k_neg(self.k_txy)
tension_stress_k_pos = self.tension_stress_k_pos(self.k_txy)
tension_stress = tension_stress_k_neg.where(
self.k_txy <= 0, tension_stress_k_pos
)
shear_stress = tension_stress / 3**(0.5)
return shear_stress
Ya solo queda correr el código.
permissible_stress = PermissibleTau(df, sigma_E, sigma_R)
shear_stress = permissible_stress.shear_stress()
df['tau_a_[MPa]'] = round(shear_stress, 1)
cols = [
'bar', 'node', 'component_group', 'notch_effect', 'tau_a_[MPa]'
]
df[cols]
bar | node | component_group | notch_effect | tau_a_[MPa] | |
0 | 1 | 1 | E8 | K3 | 115.5 |
1 | 2 | 2 | E8 | K3 | 115.5 |
2 | 3 | 3 | E7 | K4 | 91.0 |
3 | 4 | 4 | E6 | K4 | 135.3 |
4 | 5 | 5 | E7 | K2 | 131.4 |
5 | 6 | 6 | E8 | K4 | 94.5 |
6 | 7 | 7 | E8 | K4 | 82.5 |
7 | 8 | 8 | E8 | K4 | 135.3 |
8 | 9 | 9 | E6 | K0 | 93.6 |
9 | 10 | 10 | E6 | K4 | 135.3 |
Para validar los resultados voy a hacer un cálculo manual de las tensiones τa de la barra 3 con el índice 2 del DataFrame
.
Grado de acero: S 355
Grupo de la componente: E7
Tensión máxima τxy,max = -6 N/mm²
Tensión mínima τxy,min = 4 N/mm²
(Las tensiones máxima y mínima se definen en términos de valores absolutos).
κ=4−6=−0,667<0Tensión básica σW=σW0=136,6N/mm²
σt of case W0=σW·53–2⋅κ=136,6·53−2⋅(−0,667)= =157,62 N/mm²≤0,66⋅σE=0,66⋅355=234,3N/mm² τa=σt of case W0√3=157,62√3=91,00Como era de esperar, el valor τa=91,00N/mm² coincide con el valor tau_a_[MPa]
del índice 2 del DataFrame df
. Si no lo hiciera, habría que buscar el error, bien en el código, bien en la comprobación.
He hecho la verificación para un caso donde κ es negativo. Para completar la verificación voy a comprobar un caso donde κ sea positivo.
La fila con el índice 3 con la barra 4 tiene un κ igual a 0,556.
Grupo de la componente: E6
Tensión máxima τxy,max=9N/mm²
Tensión mínima τxy,min=5N/mm²
κ=59=0,556>0Tensión básica σW=σW0=155,6N/mm²
σ0=1,66⋅ σW=1,66⋅155,6=258,3 N/mm² σ+1=0,75⋅ σR=0,75⋅490=367,5 N/mm² σt of case W0=σ01−(1−σ0σ+1)⋅κ=258,31−(1−258,3367,5)⋅0,556= =309,42 N/mm²≤0,66⋅σE=0,66⋅355=234,3N/mm²Debe cumplirse la limitación.
σt of case W0=234,3N/mm² τa=σt of case W0√3=234,3√3=135,27El valor τa=135,27N/mm² coincide con el valore tau_a_[MPa]
del índice 3 del DataFrame df
con los resultados.
Ya solo queda un último paso, la comprobación para las tensiones combinadas σ y τ.
Comentar