# -*- coding: utf-8 -*-
"""
A class for the Eurocode related structural calculations of an RCPS.
"""
import numpy as np
import PySS.steel_design as sd
[docs]class TheoreticalSpecimen(sd.Part):
"""
Properties and calculations of a theoretical (ideal geometry) polygonal column.
"""
[docs] def __init__(self,
geometry=None,
cs_props=None,
material=None,
struct_props=None,
bc_loads=None):
super().__init__(
geometry,
cs_props,
material,
struct_props,
bc_loads)
[docs] @classmethod
def from_geometry(
cls,
n_sides,
r_cyl,
thickness,
length,
f_y_nominal,
fab_class,
a_b=3.,
f_y_real=None
):
"""
Create theoretical polygonal column object for given geometric data.
The constructor calculates properties of the polygonal column object (cross-section props,
resistance, geometric props etc). The calculated data is then used to construct an object.
This is the basic alternative constructor, several other alternative constructors are defined for different
cases of input data. All of the following alternative constructors are calling this one to create the object
after having performed the necessary geometrical pre-calculations.
Parameters
----------
n_sides : int
Number of sides of the polygon cross-section.
r_cyl : float
Radius of the circle circumscribed to the polygon.
thickness : float
Thickness of the cross-section.
length : float
Length of the column.
f_y_nominal : float
Yield stress of the material.
fab_class : {'fcA', 'fcB', 'fcC'}
Fabrication class, as described in EN 1996-1-6. It is used in the calculation of the buckling resistance of
the cylinder of equal thickness-perimeter.
a_b : float
Corner bending radius over thickness ratio.
f_y_real : float, optional
Measured yield stress. Default uses the nominal value.
"""
if f_y_real is None:
f_y = f_y_nominal
else:
f_y = f_y_real
# Create material
material = sd.Material(210000., 0.3, f_y_nominal, f_y_real)
# Bending radius
r_b = a_b * thickness
# Theta angle
theta = np.pi / n_sides
# Radius of the polygon's circumscribed circle
r_p = (np.pi * r_cyl + a_b * thickness * (n_sides * np.tan(theta) - np.pi)) / (n_sides * np.sin(theta))
# Width of each side
bbbb = 2 * r_p * np.sin(theta)
# Width of the corner bend half arc projection on the plane of the facet
b_c = r_b * np.tan(theta)
# Flat width of each facet (excluding the bended arcs)
cccc = bbbb - 2 * b_c
# Buckling width of each side as per EN 1993-1-3
g_r = r_b * (np.tan(theta)-np.sin(theta))
ccc3 = bbbb - 2 * g_r
# Cross sectional area
area = 2 * np.pi * r_cyl * thickness
# Moment of inertia
b_o = bbbb + thickness * np.tan(theta)
alfa = thickness * np.tan(theta) / b_o
moi = (n_sides * b_o ** 3 * thickness / 8) * (1 / 3 + 1 / (np.tan(theta) ** 2)) * (1 - 3 * alfa + 4 * alfa ** 2 - 2 * alfa ** 3)
# Effective cross section area
corner_area = 2 * np.pi * r_b * thickness
a_eff = n_sides * sd.calc_a_eff(thickness, cccc, f_y) + corner_area
# Gather all cross sectional properties in an appropriate class
cs_props = sd.CsProps(
area=area,
a_eff=a_eff,
xc=0.,
yc=0.,
moi_xx=moi,
moi_yy=moi,
moi_xy=0.,
moi_1=moi,
moi_2=moi)
# cs_props = sd.CsProps.from_cs_sketch(cs_sketch)
cs_props.max_dist = r_p
cs_props.min_dist = np.sqrt(r_p ** 2 - (bbbb / 2) ** 2)
# Polar coordinate of the polygon vertices on the cross-section plane
phii = []
for i_index in range(n_sides):
phii.append(i_index * theta)
# Polygon corners coordinates.
x_corners = tuple(r_p * np.cos(phii))
y_corners = tuple(r_p * np.sin(phii))
# Cross-sectional properties
nodes = [x_corners, y_corners]
elem = [
list(range(0, len(x_corners))),
list(range(1, len(x_corners))) + [0],
len(x_corners) * [thickness]
]
cs_sketch = sd.CsSketch(nodes, elem)
geometry = sd.Geometry(cs_sketch, length, thickness)
# Additional geometric properties (exclusive to the polygonal)
geometry.r_circle = r_cyl
geometry.r_circumscribed = r_p
geometry.facet_width = bbbb
geometry.facet_flat_width = cccc
geometry.n_sides = n_sides
geometry.r_bend = r_b
lmbda_y = sd.lmbda_flex(
length,
cs_props.a_eff,
cs_props.moi_1,
kapa_bc=1.,
e_modulus=material.e_modulus,
f_yield=material.f_y_nominal
)
lmbda_z = lmbda_y
# Plate classification (acc. to EC3-1-1)
p_classification = cccc / (material.epsilon * thickness)
# Critical stress acc. to plate theory.
sigma_cr_plate = sd.sigma_cr_plate(thickness, bbbb - 3*thickness)
# Critical load acc. to plate theory.
n_cr_plate = cs_props.area * sigma_cr_plate
# Axial compression resistance, Npl (acc. to EC3-1-5)
n_pl_rd = cs_props.a_eff * f_y
# Buckling load
n_b_rd = sd.n_b_rd(geometry.length, cs_props.a_eff, cs_props.moi_1, f_y, "d")
# Buckling stress (account for both flex and local)
sigma_b_rd_plate = n_b_rd / cs_props.area
##############################################################################
# Plate classification (acc. to EC3-1-3)
pc_classification = ccc3 / (material.epsilon * thickness)
# Critical stress acc. to plate theory.
sigma_cr_platec = sd.sigma_cr_plate(thickness, ccc3)
# Critical load acc. to plate theory for CF sections.
n_cr_platec = cs_props.area * sigma_cr_platec
# Axial compression resistance, Npl (acc. to EC3-1-3)
# rho3 = sd.calc_a_eff(thickness, ccc3, f_y) / (thickness * ccc3)
# cs_props.a_eff3 = n_sides * rho3 * cccc * thickness + corner_area
cs_props.a_eff3 = n_sides * sd.calc_a_eff(thickness, ccc3, f_y)
n_pl_rdc = cs_props.a_eff3 * f_y
# Buckling load
n_b_rdc = sd.n_b_rd(geometry.length, cs_props.a_eff3, cs_props.moi_1, f_y, "d")
# Buckling stress (account for both flex and local)
sigma_b_rd_platec = n_b_rdc / cs_props.area
##############################################################################
# Tube classification slenderness acc. to EC3-1-1
t_classification = 2 * r_cyl / (material.epsilon ** 2 * thickness)
# Length categorisation acc. to EC3-1-1, new draft proposal
lenca = sd.shell_length_category(r_cyl, thickness, length)
lenca_new = sd.shell_length_category_new(r_cyl, thickness, length)
# Critical stress acc. to shell theory.
sigma_cr_shell = sd.sigma_x_rcr(thickness, r_cyl, length)
sigma_cr_shell_new = sd.sigma_x_rcr_new(thickness, r_cyl, length)
# Critical load acc. to shell theory.
n_cr_shell = sd.n_cr_shell(thickness, r_cyl, length)
n_cr_shell_new = sd.n_cr_shell_new(thickness, r_cyl, length)
# Characteristic compression stress of equivalent cylindrical shell (acc. to EC3-1-6)
sigma_b_rk_shell = sd.sigma_x_rk(thickness, r_cyl, length, f_y, fab_quality=fab_class)
sigma_b_rk_shell_new = sd.sigma_x_rk_new(thickness, r_cyl, length, f_y, fab_quality=fab_class)
# Characteristic compression resistance of equivalent cylindrical shell (acc. to EC3-1-6)
n_b_rk_shell = cs_props.area * sigma_b_rk_shell
n_b_rk_shell_new = cs_props.area * sigma_b_rk_shell_new
# Compression stress of equivalent cylindrical shell (acc. to EC3-1-6)
sigma_b_rd_shell = sd.sigma_x_rd(thickness, r_cyl, length, f_y, fab_quality=fab_class)
sigma_b_rd_shell_new = sd.sigma_x_rd_new(thickness, r_cyl, length, f_y, fab_quality=fab_class)
# Compression resistance of equivalent cylindrical shell (acc. to EC3-1-6)
n_b_rd_shell = cs_props.area * sigma_b_rd_shell
n_b_rd_shell_new = cs_props.area * sigma_b_rd_shell_new
struct_props = sd.StructProps(
t_classification=t_classification,
p_classification=p_classification,
pc_classification=pc_classification,
lmbda_y=lmbda_y,
lmbda_z=lmbda_z,
n_cr_plate=n_cr_plate,
sigma_cr_plate=sigma_cr_plate,
n_pl_rd=n_pl_rd,
sigma_b_rd_plate=sigma_b_rd_plate,
n_b_rd_plate=n_b_rd,
sigma_cr_shell=sigma_cr_shell,
sigma_cr_shell_new=sigma_cr_shell_new,
lenca=lenca,
lenca_new=lenca_new,
n_cr_shell=n_cr_shell,
n_cr_shell_new=n_cr_shell_new,
sigma_b_rk_shell=sigma_b_rk_shell,
sigma_b_rk_shell_new=sigma_b_rk_shell_new,
n_b_rk_shell=n_b_rk_shell,
n_b_rk_shell_new=n_b_rk_shell_new,
sigma_b_rd_shell=sigma_b_rd_shell,
sigma_b_rd_shell_new=sigma_b_rd_shell_new,
n_b_rd_shell=n_b_rd_shell,
n_b_rd_shell_new=n_b_rd_shell_new,
n_cr_platec=n_cr_platec,
sigma_cr_platec=sigma_cr_platec,
n_pl_rdc=n_pl_rdc,
sigma_b_rd_platec=sigma_b_rd_platec,
n_b_rd_platec=n_b_rdc
)
return cls(geometry, cs_props, material, struct_props)
[docs] @classmethod
def from_pclass_thickness_length(
cls,
n_sides,
p_classification,
thickness,
length,
f_y_nominal,
fab_class,
a_b=3.,
f_y_real=None
):
"""
Create theoretical polygonal column object for given plate slenderness, thickness and length.
Uses the :func:`~PySS.polygonal.from_geometry`.
Parameters
----------
n_sides : int
Number of sides of the polygon cross-section.
p_classification : float
Facet slenderness, c/(ε*t).
thickness : float
Thickness of the cross-section.
length : float
Length of the column.
f_y_nominal : float
Yield stress of the material.
fab_class : {'fcA', 'fcB', 'fcC'}
Fabrication class, as described in EN 1996-1-6. It is used in the calculation of the buckling resistance of
the cylinder of equal thickness-perimeter.
a_b : float
Thickness to bending radius ratio.
f_y_real : float, optional
Measured yield stress. Default uses the nominal value.
"""
# Epsilon for the material
if f_y_real is None:
epsilon = np.sqrt(235. / f_y_nominal)
else:
epsilon = np.sqrt(235. / f_y_real)
# Radius of the equal perimeter cylinder
#r_circle = (n_sides * thickness / np.pi) * ((p_classification * epsilon / 2) + arc_to_thickness * np.tan(np.pi / n_sides))
r_circle = thickness*(n_sides * p_classification * epsilon / (2*np.pi) + a_b)
return cls.from_geometry(
n_sides,
r_circle,
thickness,
length,
f_y_nominal,
fab_class,
f_y_real=f_y_real
)
[docs] @classmethod
def from_pclass_radius_length(
cls,
n_sides,
r_cyl,
p_classification,
length,
f_y_nominal,
fab_class,
a_b=3.,
f_y_real=None
):
"""
Create theoretical polygonal column object for given equivalent cylinder radius, plate slenderness and length.
Uses the :func:`~PySS.polygonal.from_geometry`.
Parameters
----------
n_sides : int
Number of sides of the polygon cross-section.
r_cyl : float
Radius of the equivalent cylinder.
p_classification : float
Facet slenderness, c/(ε*t).
length : float
Length of the column.
f_y_nominal : float
Yield stress of the material.
fab_class : {'fcA', 'fcB', 'fcC'}
Fabrication class, as described in EN 1996-1-6. It is used in the calculation of the buckling resistance of
the cylinder of equal thickness-perimeter.
a_b : float
Thickness to bending radius ratio.
f_y_real : float, optional
Measured yield stress. Default uses the nominal value.
"""
# Epsilon for the material
if f_y_real is None:
epsilon = np.sqrt(235. / f_y_nominal)
else:
epsilon = np.sqrt(235. / f_y_real)
# Calculate the thickness
thickness = r_cyl / ((n_sides * p_classification * epsilon / (2 * np.pi)) + a_b)
return cls.from_geometry(
n_sides,
r_cyl,
thickness,
length,
f_y_nominal,
fab_class,
f_y_real=f_y_real
)
[docs] @classmethod
def from_pclass_area_length(
cls,
n_sides,
p_classification,
area,
length,
f_y_nominal,
fab_class,
a_b=3,
f_y_real=None
):
"""
Create theoretical polygonal column object for given equivalent cylinder radius, plate slenderness and
length.
Uses the :func:`~PySS.polygonal.from_geometry`.
Parameters
----------
n_sides : int
Number of sides of the polygon cross-section.
p_classification : float
Facet slenderness, c/(ε*t).
area : float
Cross-sectional area.
length : float
Length of the column.
f_y_nominal : float
Yield stress of the material.
fab_class : {'fcA', 'fcB', 'fcC'}
Fabrication class, as described in EN 1996-1-6. It is used in the calculation of the buckling resistance of
the cylinder of equal thickness-perimeter.
a_b : float
Thickness to bending radius ratio.
f_y_real : float, optional
Measured yield stress. Default uses the nominal value.
"""
# Epsilon for the material
if f_y_real is None:
epsilon = np.sqrt(235. / f_y_nominal)
else:
epsilon = np.sqrt(235. / f_y_real)
# Thickness
thickness = np.sqrt(area / (n_sides * p_classification * epsilon + 2 * np.pi * a_b))
# Radius of equivalent cylinder
r_cyl = area / (2 * np.pi * thickness)
return cls.from_geometry(
n_sides,
r_cyl,
thickness,
length,
f_y_nominal,
fab_class,
f_y_real=f_y_real
)
[docs] @classmethod
def from_radius_area_length(
cls,
n_sides,
r_cyl,
area,
length,
f_y_nominal,
fab_class,
a_b=3,
f_y_real=None
):
"""
Create theoretical polygonal column object for given equivalent cylinder radius, area and length.
Uses the :func:`~PySS.polygonal.from_geometry`.
Parameters
----------
n_sides : int
Number of sides of the polygon cross-section.
r_cyl : float
Radius of the equivalent cylinder.
area : float
Cross-sectional area.
length : float
Length of the column.
f_y_nominal : float
Yield stress of the material.
fab_class : {'fcA', 'fcB', 'fcC'}
Fabrication class, as described in EN 1996-1-6. It is used in the calculation of the buckling resistance of
the cylinder of equal thickness-perimeter.
a_b : float
Thickness to bending radius ratio.
f_y_real : float, optional
Measured yield stress. Default uses the nominal value.
"""
thickness = area / (2 * np.pi *r_cyl)
return cls.from_geometry(
n_sides,
r_cyl,
thickness,
length,
f_y_nominal,
fab_class,
a_b=a_b,
f_y_real=f_y_real
)
[docs] @classmethod
def from_radius_thickness_flexslend(
cls,
n_sides,
r_cyl,
thickness,
lambda_flex,
f_y_nominal,
fab_class,
a_b=3.,
f_y_real=None
):
"""
Create theoretical polygonal column object for given equivalent cylinder radius, thickness and flexural
slenderness.
Uses the :func:`~PySS.polygonal.from_geometry`.
Parameters
----------
n_sides : int
Number of sides of the polygon cross-section.
r_cyl : float
Radius of the equivalent cylinder.
thickness : float
Thickness of the cross-section.
lambda_flex : float
Flexural slenderness.
f_y_nominal : float
Yield stress of the material.
fab_class : {'fcA', 'fcB', 'fcC'}
Fabrication class, as described in EN 1996-1-6. It is used in the calculation of the buckling resistance of
the cylinder of equal thickness-perimeter.
a_b : float
Thickness to bending radius ratio.
f_y_real : float, optional
Measured yield stress. Default uses the nominal value.
"""
if f_y_real is None:
f_y = f_y_nominal
else:
f_y = f_y_real
# Bending radius
r_b = a_b * thickness
# Theta angle
theta = np.pi / n_sides
# Radius of the polygon's circumscribed circle
r_p = (np.pi * r_cyl + a_b * thickness * (n_sides * np.tan(theta) - np.pi)) / (n_sides * np.sin(theta))
# Width of each side
bbbb = 2 * r_p * np.sin(theta)
# Width of the corner bend half arc projection on the plane of the facet
b_c = r_b * np.tan(theta)
# Flat width of each facet (excluding the bended arcs)
cccc = bbbb - 2 * b_c
# Moment of inertia
b_o = bbbb + thickness * np.tan(theta)
alfa = thickness * np.tan(theta) / b_o
moi = (n_sides * b_o ** 3 * thickness / 8) * (1 / 3. + 1 / (np.tan(theta) ** 2)) * (
1 - 3 * alfa + 4 * alfa ** 2 - 2 * alfa ** 3)
# Effective cross secion area
corner_area = 2 * np.pi * r_b * thickness
a_eff = n_sides * sd.calc_a_eff(thickness, cccc, f_y) + corner_area
# Calculate column length for the given flexural slenderness.
length = lambda_flex * np.pi * np.sqrt(210000. * moi / (a_eff * f_y))
return cls.from_geometry(
n_sides,
r_cyl,
thickness,
length,
f_y_nominal,
fab_class,
a_b=a_b,
f_y_real=f_y_real
)
[docs] @classmethod
def from_pclass_radius_flexslend(
cls,
n_sides,
r_cyl,
p_classification,
lambda_flex,
f_y_nominal,
fab_class,
a_b=3.,
f_y_real=None
):
"""
Create theoretical polygonal column object for given equivalent cylinder radius, plate classification and
flexural slenderness.
Uses the :func:`~PySS.polygonal.from_geometry`.
Parameters
----------
n_sides : int
Number of sides of the polygon cross-section.
r_cyl : float
Radius of the equivalent cylinder.
p_classification : float
Facet slenderness, c/(ε*t).
lambda_flex : float
Flexural slenderness.
f_y_nominal : float
Yield stress of the material.
fab_class : {'fcA', 'fcB', 'fcC'}
Fabrication class, as described in EN 1996-1-6. It is used in the calculation of the buckling resistance of
the cylinder of equal thickness-perimeter.
a_b : float
Thickness to bending radius ratio.
f_y_real : float, optional
Measured yield stress. Default uses the nominal value.
"""
# Epsilon for the material
if f_y_real is None:
epsilon = np.sqrt(235. / f_y_nominal)
else:
epsilon = np.sqrt(235. / f_y_real)
# Calculate the thickness
thickness = r_cyl / ((n_sides * p_classification * epsilon / (2 * np.pi)) + a_b)
return cls.from_radius_thickness_flexslend(
n_sides,
r_cyl,
thickness,
lambda_flex,
f_y_nominal,
fab_class,
a_b=a_b,
f_y_real=f_y_real
)
[docs] @classmethod
def from_pclass_area_flexslend(
cls,
n_sides,
p_classification,
area,
lambda_flex,
f_y_nominal,
fab_class,
a_b=3.,
f_y_real=None
):
"""
Create theoretical polygonal column object for given plate classification, area and flexural slenderness.
Uses the :func:`~PySS.polygonal.from_geometry`.
Parameters
----------
n_sides : int
Number of sides of the polygon cross-section.
p_classification : float
Facet slenderness, c/(ε*t).
area : float
Cross-sectional area.
lambda_flex : float
Flexural slenderness.
f_y : float
Yield stress of the material.
fab_class : {'fcA', 'fcB', 'fcC'}
Fabrication class, as described in EN 1996-1-6. It is used in the calculation of the buckling resistance of
the cylinder of equal thickness-perimeter.
a_b : float
Thickness to bending radius ratio.
f_y_real : float, optional
Measured yield stress. Default uses the nominal value.
"""
# Epsilon for the material
if f_y_real is None:
epsilon = np.sqrt(235. / f_y_nominal)
else:
epsilon = np.sqrt(235. / f_y_real)
# Thickness
thickness = np.sqrt(area / (n_sides * p_classification * epsilon + 2 * np.pi * a_b))
# Radius of equivalent cylinder
r_cyl = area / (2 * np.pi * thickness)
return cls.from_radius_thickness_flexslend(
n_sides,
r_cyl,
thickness,
lambda_flex,
f_y_nominal,
fab_class,
a_b=3,
f_y_real=f_y_real
)
[docs] @staticmethod
def behaviour_limit(fy, uu):
"""
Calculate the limit between plated and shell behaviour according to
the functions derived in my thesis.
Parameters
----------
fy : float
Yield stress.
uu : float
Returns
-------
:obj:`PySS.analytic_geometry.Line2D`
"""
kapa = (1193 - fy) / 50
zeta = 364e3*uu**2-5e3*uu+21
ksi = -zeta*kapa+27
return(ag.Line2D.from_line_coeff(-zeta, 1, -ksi))
[docs] @staticmethod
def plate_behaviour(nv, pc, fy, uu):
kapa = (1193 - fy) / 50
zeta = 364e3*uu**2-5e3*uu+21
ksi = -zeta*kapa+27
return(pc-zeta*nv > ksi)