"""
Contains functions for managing sections specific to CSAo86-19
Note, right now all limits are calculated at once BEFORE the
"""
from .element import BeamColumnSteelCsa24
from limitstates import SectionSteel, SteelSectionTypes, DesignDiagram
from typing import Callable
from numpy import pi, cumsum
from enum import IntEnum
"""
!!!
Consider a refactor of the steel design using a factory and intermediate
design classes.
This can simplify complicated if statements that might develop within functions
"""
class DesignSectionSteel:
classify:Callable
checkMrSupported:Callable
checkMrUnsupported:Callable
checkPrUnsupported:Callable
checkInterCaseA:Callable
checkInterCaseB:Callable
checkInterCaseC:Callable
def _checkType(section):
SUPPORTEDTYPES = ['W', 'HSS']
if section.type not in SUPPORTEDTYPES:
_SectionUnsupporedError(section, SUPPORTEDTYPES)
def _SectionUnsupporedError(secton, SUPPORTEDTYPES):
raise Exception(f'Section of type {secton.type} not supported, expected one of {SUPPORTEDTYPES}')
# =============================================================================
#
# =============================================================================
def checkElementSlenderness(element:BeamColumnSteelCsa24, useX = True):
"""
Checks the slenderness ratio of a steel element.
Parameters
----------
rx : float
The radius of gyration for the section.
Lx : float
The design length of teh section.
Kx : float, optional
The buckling effective length factor. The default is 1.0.
Returns
-------
slenderness : float
The output slenderness of the section.
"""
lconvert = element.member.lConvert('mm')
lsconvert = element.section.lConvert('mm')
if useX:
L = element.designProps.Lx * lconvert
k = element.designProps.kx
r = element.section.rx * lsconvert
else:
L = element.designProps.Ly * lconvert
k = element.designProps.ky
r = element.section.ry* lsconvert
return checkSlendernessRatio(r, L, k)
def checkSlendernessRatio(r:float, L:float, K:float=1.0) -> (bool, float):
"""
Checks the slenderness ratio of a steel element.
Parameters
----------
rx : float
The radius of gyration for the section.
Lx : float
The design length of teh section.
Kx : float, optional
The buckling effective length factor. The default is 1.0.
Returns
-------
slenderness : float
The output slenderness of the section.
"""
return K*L/r
# =============================================================================
# Tension
# =============================================================================
def checkTg(Ag, Fy):
"""
Get the yield capacity for the goss section using c.l. 13.2
Parameters
----------
Ag : float
The sections area in mm.
Fy : float
The yield capacity of the section in MPa.
Returns
-------
Tg : float
The gross tension capacity of the section..
"""
phi = 0.9
return phi*Ag*Fy
# TODO! Test
def checkTgElement(beam:BeamColumnSteelCsa24):
"""
Uses c.l. 13.4.1.1 To calculate the Fs for a W section.
Inputs are in mm and MPa.
Force out is in N.
Parameters
----------
h : float
The clear depth of the web between flanges of the flange.
tw : float
The thickness of the web of the flange.
Fy : float
The yield stress for the material used.
Returns
-------
Fs : TYPE
DESCRIPTION.
"""
section = beam.section
lconvert = section.lConvert('mm')
sfactor = section.mat.sConvert('MPa')
Fy = section.mat.Fy*sfactor
A = section.A * lconvert**2
return checkTg(A, Fy)
# =============================================================================
# Bending
# =============================================================================
[docs]def classifySection(section:SectionSteel, useX=True, Cf = 0):
"""
Used to classify a section, returning the worst case section class for
the flange and web. Currently only applies
Class 4 sections are not supported.
Parameters
----------
section : SectionSteel
The steel section to check the section class of.
useX : bool, optional
A flag that specifies if the x axis (strong axis) should be used.
The default is True.
Cf : float, optional
The force acting on the section in N. The default is 0.
Returns
-------
section class : int
The worst case between the section class and web class.
"""
_checkType(section)
if section.typeEnum == SteelSectionTypes.w:
cflange = classifyFlangeWSection(section, useX)
cweb = classifyWebWSection(section, useX, Cf)
return max(cflange, cweb)
elif section.typeEnum == SteelSectionTypes.hss:
cflange = classifyFlangeHssSection(section, useX)
cweb = classifyWebHssSection(section, useX, Cf)
return max(cflange, cweb)
else:
raise Exception(r'Section {section.type} not supported')
[docs]def classifyFlangeWSection(section:SectionSteel, useX = True):
"""
Used to classify the flange of a W section.
Class 4 sections are not supported.
Parameters
----------
section : SectionSteel
The steel section to check the section class of.
useX : bool, optional
A flag that specifies if the x axis (strong axis) should be used.
The default is True.
Returns
-------
section class : int
The flange section class
"""
# section.mat.sConvert()
Fy = section.mat.Fy * section.mat.sConvert('MPa')
t = section.tf
bel = section.bf / 2
if useX:
return classifyFlangeW(bel, t, Fy)
else:
return classifyFlangeWMinor(bel, t, Fy)
[docs]def classifyWebWSection(section:SectionSteel, useX = True, Cf:float= 0):
"""
Used to classify a W section's web. See #11.3.2.c.
Class 4 sections are not supported.
Parameters
----------
section : SectionSteel
The steel section to check the section class of.
useX : bool, optional
A flag that specifies if the x axis (strong axis) should be used.
The default is True.
Cf : float, optional
The force acting on the section in N. The default is 0.
Returns
-------
section class : int
The web section class.
"""
Fy = section.mat.Fy * section.mat.sConvert('MPa')
t = section.tw
h = section.d - section.tf*2
Cy = section.Cy
if useX:
return classifyWebWMajor(h, t, Fy, Cf, Cy)
else:
return classifyWebWMinor(h, t, Fy, Cf, Cy)
[docs]def classifyWebHssSection(section:SectionSteel, useX = True, Cf:float= 0):
"""
Classifys a HSS web. The web is the portion of hss the which is in both
compression and tension.
If useX is toggled true the web is the vertical edge, i.e. height.
Otherwise it's the horizontal edge, i.e. width.
Assumes that the section is supported along two edges, and has bending
and compression.
see #11.3.2.c. for a definittion of h
Parameters
----------
section : SectionSteel
The section to classify.
useX : bool, optional
A toggle that activates the X direction. The default is True.
Cf : float, optional
The factored compression force of the section in N. The default is 0.
Returns
-------
int
The section class.
"""
Fy = section.mat.Fy * section.mat.sConvert('MPa')
t = section.t
Cy = section.Cy
if useX:
h = section.h - t*4
else:
h = section.b - t*4
return classifyWebWMajor(h, t, Fy, Cf, Cy)
def _getBelHSSSection(section:SectionSteel, useX = True):
"""
see #11.3.2.b. for a definition of bel
"""
# In the strong axis, use the section
if useX:
return section.b - section.t*4
else:
return section.d - section.t*4
[docs]def classifyFlangeHssSection(section:SectionSteel, useX = True):
"""
Classifys a HSS flange
If useX is toggled true the web is the vertical edge, i.e. height.
Otherwise it's the horizontal edge, i.e. width.
Assumes that the section is supported along two edges, and has bending
and compression.
see #11.3.2.b. for a definittion of bel
Parameters
----------
section : SectionSteel
The steel section to classify.
useX : TYPE, optional
A toggle that activates the X direction. The default is True.
Cf : float, optional
The factored compression force of the section in N. The default is 0.
Returns
-------
int
The section class.
"""
Fy = section.mat.Fy * section.mat.sConvert('MPa')
# units are not needed because bel and t divide eachother.
t = section.t
bel = _getBelHSSSection(section,useX)
return classifyHssRectFlange(bel, t, Fy)
def _categorize(ratio:float, lims:list[float]):
if ratio <= lims[0]:
return 1
elif ratio <= lims[1]:
return 2
elif ratio <= lims[2]:
return 3
else:
return 4
def classifyFlangeW(bel, t, Fy):
"""
Classify a W section for bending about it's major axis.
Assumes that the section is supported along one edge.
See c.l. 11.3.2.b. for a definition of bel
"""
lim = 1/Fy**0.5
lim1 = 145*lim
lim2 = 170*lim
lim3 = 250*lim
ratio = bel / t
return _categorize(ratio, [lim1, lim2, lim3])
def classifyFlangeWMinor(bel, t, Fy):
"""
Classify a W section for bending about it's major axis.
Assumes that the section is supported along one edge.
See c.l. 11.3.2.b. for a definition of bel
"""
lim = 1/Fy**0.5
lim1 = 145*lim
lim2 = 170*lim
lim3 = 340*lim
ratio = bel / t
return _categorize(ratio, [lim1, lim2, lim3])
def classifyWebWMajor(h, w, Fy, Cf, Cy):
"""
Classify a W section for bending about it's major axis.
Assumes that the section is supported along two edges, and has bending
and compression.
Table 1
"""
phi = 0.9
ratio = Cf / (phi*Cy)
lim = 1/Fy**0.5
lim1 = 1100*lim*(1 - 0.39 * ratio)
lim2 = 1700*lim*(1 - 0.61 * ratio)
lim3 = 1900*lim*(1 - 0.65 * ratio)
return _categorize(h/w, [lim1, lim2, lim3])
def classifyWebWMinor(h, w, Fy, Cf, Cy):
"""
Classify a W section for bending about it's major axis.
Assumes that the section is supported along one edge.
From Table 2
"""
phi = 0.9
ratio = Cf / (phi*Cy)
if Cf == 0:
useCaseA = False
else:
# Rearrange 0.4*phi*Cy < Cf
useCaseA = 0.4*ratio**-1 < 1
lim = 1/Fy**0.5
if useCaseA:
lim1 = 525*lim
lim2 = 525*lim
lim3 = 1900*lim*(1 - 0.65 * ratio)
else:
lim1 = 1100*lim*(1 - 1.31 * ratio)
lim2 = 1700*lim*(1 - 1.73 * ratio)
lim3 = 1900*lim*(1 - 0.65 * ratio)
return _categorize(h/w, [lim1, lim2, lim3])
def classifyHssRectFlange(bel, t, Fy):
"""
Classify a square or rectangular HSS section for bending about an axis.
The flange is the portion of the section which is fully in compression.
Parameters
----------
bel : float
The effective width, factoring in the curvature of the HSS
See c.l. 11.3.2.b. for a definition of bel
t : float
The wall thickness in mm.
Fy : float
The yield stress in MPa.
Returns
-------
float
The class for the flange.
"""
lim = 1/Fy**0.5
lim1 = 420*lim
lim2 = 525*lim
lim3 = 670*lim
ratio = bel / t
return _categorize(ratio, [lim1, lim2, lim3])
# =============================================================================
# Moment
# =============================================================================
def getOmega2(Mmax, Ma, Mb, Mc):
"""
Omega is a load amplification factor
"""
return min(4 * Mmax / (Mmax**2 + 4*Ma**2 + 7*Mb**2 + 4*Mc**2), 2.5)
def getOmega2Linear(Mmax, Mmin):
"""
For approximately linearly varying loads 13.6.1.a
"""
kappa = Mmin / Mmax
return min(1.75 + 1.05*kappa + 0.3*kappa**2, 2.5)
def getMp(Z, Fy):
"""
Assumes Z and Fy are in mm3 and MPa
Returns in Nm
"""
phi = 0.9
return Z*Fy*phi / 1000
def getMy(S, Fy):
"""
Assumes Z and Fy are in mm3 and MPa
Returns in Nm
"""
phi = 0.9
return S*Fy*phi / 1000
[docs]def checkBeamMrSupported(beam:BeamColumnSteelCsa24, useX:bool=True, Cf:float = 0):
"""
Calcualtes Mr for a supported member in Nm.
For laterally supported members, Mr is calculated the same way for HSS and
W sections. The only exception is class 4 sections, which are not supported
by limitstates currently.
Parameters
----------
beam : BeamColumnSteelCsa24
The beam to check the capacity of.
useX : TYPE, optional
A toggle that activates the X direction. The default is True.
Cf : float, optional
The factored compression force of the section in N. The default is 0.
Returns
-------
float
The capacity of the beam in N*m.
"""
section = beam.section
_checkType(section)
sectionClass = _getSectionClassIfNotSet(section, useX, Cf)
Fy = section.mat.Fy * section.mat.sConvert('MPa')
if sectionClass <=2:
Z = section.getZ(useX, 'mm')
return getMp(Z, Fy)
elif sectionClass <=3:
S = section.getS(useX, 'mm')
return getMy(S, Fy)
else:
raise Exception(f'{section} recieved is class 4, limitstates currently cannot design class 4 sections.')
[docs]def checkBeamMrUnsupportedW(beam:BeamColumnSteelCsa24, omega:float=1,
Lu:float = None, Cf = 0):
"""
Calculates Mr for an unsupported W section according to c.l.13.6.1.a.
Does not apply to cantilevers.
Note that in the weak axis, the unsupported strength is equal to the
supported strength
For loads applied to a top flange, Mu can be calculated with omega = 1
and Lu = 1.2 for simply supported members, and Lu = 1.4 for other member
types.
The user should set the length of the beam
These can be modified by changing the keff factor in the x direction
Parameters
----------
section : SectionSteel
A W section.
omega : float, optional
The moment distribution factor. The default is 1.
Lu : float
An override for the unbraced length in mm.
By defult is none, which will use the design length of the beam in
it's x direction.
Cf : float, optional
The factored compression force of the section in N. The default is 0.
Returns
-------
float
The capacity of the beam in N*m.
"""
# sectionClass = _getSectionClassIfNotSet(beam.sectionsection, True, Cf)
# if
if not Lu:
lconvert = beam.member.lConvert('mm')
Lu = beam.designProps.Lx * beam.designProps.kx * lconvert
phi = 0.9
Mu = checkSectionMu(beam.section, Lu, omega)*phi
Mx = checkBeamMrSupported(beam, True, Cf)
if 0.67*Mx < Mu:
return min(1.15*Mx*(1 - 0.28*Mx / Mu), Mx)
else:
return Mu
[docs]def checkBeamMrUnsupported(beam:BeamColumnSteelCsa24, omega2:float=1,
Lu:float = None, Cf = 0):
"""
Calculates Mr for an unsupported W section according to c.l.13.6.1.a.
Does not apply to cantilevers.
Note that in the weak axis, the unsupported strength is equal to the
supported strength
For Hss sections, the unsupported results are the same as the supported
results.
For loads applied to a top flange, Mu should be calculated with omega = 1
and Lu = 1.2 for simply supported members, and Lu = 1.4 for other member
types.
These can be modified by changing the keff factor in the x direction
Parameters
----------
section : SectionSteel
A W section.
omega : float, optional
The moment distribution factor. The default is 1.
Lu : float
An override for the unbraced length in mm.
By defult is none, which will use the design length of the beam in
it's x direction.
Returns
-------
float
The capacity of the beam in N*m.
"""
if beam.section.typeEnum == SteelSectionTypes.w:
return checkBeamMrUnsupportedW(beam, omega2, Lu, Cf)
elif beam.section.typeEnum == SteelSectionTypes.hss:
return checkBeamMrSupported(beam, Cf = Cf)
else:
raise Exception(f'Section type {beam.section.type} is unsupported' )
# !!! This might not be the correct place to store the section class.
def _getSectionClassIfNotSet(section:SectionSteel,
useX:bool = True, Cf:float = 0):
if not section.sectionClass:
sectionClass = classifySection(section, useX, Cf=Cf)
else:
sectionClass = section.sectionClass
return sectionClass
[docs]def checkSectionMu(section:SectionSteel, Lu:float, omega:float):
"""
Calculates Mu, the laterally unsupported buckling moment,
as per c.l. 13.6.1.a, assuming length is input in mm.
Returns capacity in N*m
Parameters
----------
section : SectionSteel
The steel section to check.
Lu : float
The input length in mm.
omega : float
The omega factor to apply to the span..
Returns
-------
float
The buckling moment for the beam.
"""
lfactor = section.lConvert('mm')
sfactor = section.mat.sConvert('MPa')
E = section.mat.E * sfactor
G = section.mat.G * sfactor
Iy = section.Iy * lfactor**4
J = section.J * lfactor**4
Cw = section.Cw * lfactor**6
return checkMu(E, Iy, G, J, Cw, Lu, omega) / 1000
def checkMu(E:float, Iy:float, G:float, J:float, Cw:float, Lu:float,
omega:float):
"""
Calculates critical bucklimg moment for a beam.
Parameters
----------
E : float
The elastic modulus of the section in MPa.
Iy : float
The weak axis moment of inetia in mm4.
G : float
The shear modulus of the section in MPa.
J : float
The polar moment of enrtia for the section in mm4.
Cw : float
The warpping torsion constant in mm6 (mm$^6$).
Lu : float
The unsupported length of the beam for bending in the strong axis in
mm.
omega : float
The omega load factor.
Returns
-------
float
Mu for the element.
"""
return (omega*pi / Lu) * (E*Iy*G*J + Iy*Cw*(pi*E/Lu)**2)**0.5
def checkOmega(Mmax, Ma, Mb, Mc):
return min(4 * Mmax / (Mmax**2 + 4*Ma**2 + 7*Mb**2 + 4*Mc**2)**0.5, 2.5)
# =============================================================================
# Multispan
# =============================================================================
[docs]class SegmentSupportTypes(IntEnum):
"""
Options for multispan design checks:
- If option 1 is selected, the beam is assumed to be continously laterally
supported over the entire beam. Note, Mr is the same for each segment.
- If option 2 is selected, the beam is assumed to be laterally unsupported
between supports. In this case, it is assumed the load is applied to the
compression flange, and torsional fixity is provided at each support.
For W sections, the length is increased by 1.4 per c.l. 13.6.1.
- If option 3 is selected, then the design propreties will be used to.
The user should manually set the attributed Lx, kx, and lateralSupport
in the designpropreties. Note, in this case Lx should be the actual length
(Not a design length), and kx should be the effective lenght factor.
"""
continuous = 1
supoorts = 2
supportsAndTopFlange = 3
manual = 4
def _getOmegas(bmd, Nspan, Lsegs):
omegas = [None]*Nspan
x1 = x2 = 0
for ii in range(Nspan):
dx = Lsegs[ii]
x2 = x1 + dx
xa = 0.25*dx + x1
xb = 0.5*dx + x1
xc = 0.75*dx + x1
ya, yb, yc = bmd.getForceAtx([xa, xb, xc])
ymax = bmd.getMaxForceInRange(x1, x2)
omegas[ii] = checkOmega(ymax, ya, yb, yc)
x1 = x2
return omegas
[docs]def getOmega1FromDesignDiagram(bmd:DesignDiagram):
"""
Returns the value of Omega1 from a bending moment diagram per c.l. 13.8.6.
Assumes that the input bending moment diagram is for a single span.
Linear interoplation is used to determing the y values used in the omega
equation.
Parameters
----------
bmd : DesignDiagram
The bending moment diagram to check for Omega.
Returns
-------
float
The output value of omega.
"""
x = bmd.xy[:,0]
x1 = min(x)
x2 = max(x)
dx = x2 - x1
x2 = x1 + dx
xa = 0.25*dx + x1
xb = 0.5*dx + x1
xc = 0.75*dx + x1
ya, yb, yc = bmd.getForceAtx([xa, xb, xc])
ymax = bmd.getMaxForceInRange(x1, x2)
return checkOmega(ymax, ya, yb, yc)
[docs]def checkMrBeamMultiSpan(element: BeamColumnSteelCsa24,
bmd: DesignDiagram = None,
lateralSupportType: SegmentSupportTypes | int = 3):
"""
Returns the Mr value for each region of a multiSpanBeam.
Each span is given a value for Mr.
The beam is assumed to bend about it's strong axis.
Assumes the BMD and member have the same units for length. The designer
must judge the torsional support conditions provided and select an option
as per below:
1, the beam is assumed to be continously laterally supported over the
entire beam. Where there are regions of siginficant negative bending,
the bottom chord of the stucture must also be continously braced.
2, the beam is assumed to be laterally unsupported between supports,
**the load is applied to the at the shear center**, and torsional
fixity is provided at each support. Omega is calculated per the BMD.
3, the beam is assumed to be laterally unsupported between supports,
**the load is applied to the top chord**, and torsional fixity is
provided at each support.
For W sections, the length is increased by 1.4 per c.l. 13.6.1.,
and omega is set to be equal to one.
4, The user should manually set the attributed Lx, kx, and
lateralSupportin the designpropreties. Note, in this case Lx should be
the actual length (Not a design length), and kx should be the
effective lenght factor.
Lu = Lx * kx
Parameters
----------
element : BeamColumnGlulamCsa19
The multi-span element to check.
bmd : DesignDiagram
The bending moment diagram for the load case to be checked.
lateralSupportType : SegmentSupportTypes | int, optional
The type of lateral support condition for bending. The default is 3:
- 1 will return a beam lateral restraint on all segments
- 2 will return a beam with no lateral restraint except at supports
- 3 will return a beam with no lateral restraint except at supports,
and load applied at the top flange.
- 4 will use the user define support conditions. The Lx, kex, and
lateralSupport must be set for each beam segment
Returns
-------
MrOut : list[float]
The Mr out for each design segment.
xOut : list[float]
The breakpoints for the beam, including the end of the beam. Moment
applies, i.e.
Mr = MrOut[0] from 0 to xOut[0]
Mr = MrOut[1] from xOut[0] to xOut[1]
omega : list[float]
The omega factor for each span.
"""
mlfactor = element.member.lConvert('mm')
if True in element.member.isCantilever:
raise Exception('A cantilever was found in the input beam. Cantilevers are not currently supported.')
# Get the positive and negative bending regions.
member = element.member
# Get the kL factor depending on the condition used.
if lateralSupportType == 1:
Nspan = member.Nspan
isContinouslyBraced = [True] * Nspan
Lsegs = [line.L for line in member.curves]
Ldesign = [-1]*Nspan
omegas = [None]*Nspan
if lateralSupportType == 2:
Nspan = member.Nspan
isContinouslyBraced = [False] * Nspan
Lsegs = [line.L for line in member.curves]
Ldesign = [L*mlfactor for L in Lsegs]
omegas = _getOmegas(bmd, Nspan, Lsegs)
if lateralSupportType == 3:
Nspan = member.Nspan
isContinouslyBraced = [False] * Nspan
Lfactor = 1.4
Lsegs = [line.L for line in member.curves]
Ldesign = [L*Lfactor*mlfactor for L in Lsegs]
omegas = [1]*Nspan
if lateralSupportType == 4:
dProps = element.designProps
Nspan = len(dProps.Lx)
isContinouslyBraced = dProps.lateralSupport
Lsegs = dProps.Lx
Ldesign = [L * kx * mlfactor for kx, L in zip(dProps.kx, Lsegs)]
omegas = _getOmegas(bmd,Nspan,Lsegs)
MrOut = [None]* Nspan
for ii in range(Nspan):
spanSupport = isContinouslyBraced[ii]
L = Ldesign[ii]
if spanSupport:
Mr = checkBeamMrSupported(element)
else:
omega = omegas[ii]
Mr = checkBeamMrUnsupported(element, omega, L)
MrOut[ii] = Mr
xOut = cumsum(Lsegs)
return MrOut, xOut, omegas
# =============================================================================
# Shear
# =============================================================================
def getFsWUnstiffened(h:float, tw:float, Fy:float):
"""
uses c.l. 13.4.1.1 To calculate the Fs for a W section.
Inputs are in mm and MPa.
Force out is in N.
Parameters
----------
h : float
The clear depth of the web between flanges of the flange.
tw : float
The thickness of the web of the flange.
Fy : float
The yield stress for the material used.
Returns
-------
Fs : TYPE
DESCRIPTION.
"""
ratio = h / tw
sqrtFy = Fy**0.5
r1 = 1014/sqrtFy
if ratio <= r1:
Fs = 0.66*Fy
elif (r1 < ratio) and (ratio <= 1435/sqrtFy):
Fs = 670*sqrtFy / ratio
elif ratio <= 1014/sqrtFy:
Fs = 961200 / (ratio)
return Fs
[docs]def checkFsBeam(beam:BeamColumnSteelCsa24, Cf:float = 0):
"""
Uses c.l. 13.4.1.1 To calculate the Fs for a W section or HSS.
Only strong axis bending is supported
Inputs are in mm and MPa.
Force out is in N.
Parameters
----------
beam : BeamColumnSteelCsa24
The beam to check the shear of.
Cf : float
The applied compressive load (N).
Returns
-------
Fs : float
The shear capacity of the beam in N.
"""
phi = 0.9
section = beam.section
lfactor = section.lConvert('mm')
if section.typeEnum == SteelSectionTypes.w:
As, Fs = _getFsW(section, lfactor, beam.designProps.webStiffened)
elif section.typeEnum == SteelSectionTypes.hss:
sectionClass = classifySection(section, True, Cf)
t = section.tw * lfactor
sfactor = section.mat.sConvert('MPa')
Fy = section.mat.Fy*sfactor
if 3 <= sectionClass:
# We need the width in the strong axis
h = _getBelHSSSection(section, False)* lfactor
As = 2 * h * t
Fs = getFsWUnstiffened(h, t, Fy)
else:
# NOTE: in weak axis loading these need to be swapped.
As = section.A * section.d / (section.b + section.d)
Fs = 0.66*Fy
else:
raise Exception('Member not yet supported for shear.')
return phi* Fs * As
def _getFsW(section, lfactor, isWebStiffened = False):
sfactor = section.mat.sConvert('MPa')
Fy = section.mat.Fy*sfactor
# Some section databases do not explicitly set this term
if hasattr(section, 'ho'):
h = section.ho * lfactor
else:
h = section.d - section.tf *2
h *= lfactor
tw = section.tw * lfactor
As = section.d * lfactor * tw
if isWebStiffened != True:
Fs = getFsWUnstiffened(h, tw, Fy)
else:
raise Exception('Only unstiffned webs are currently supported.')
return As, Fs
# =============================================================================
# Compression
# =============================================================================
[docs]def checkCompressionLimits(section:SectionSteel):
"""
Checks the column agains table 1 compression limits.
Parameters
----------
section : SectionSteel
DESCRIPTION.
Returns
-------
bool
A pass/Fail depending on if the memeber passes or not.
"""
_checkType(section)
isW = section.typeEnum == SteelSectionTypes.w
if isW:
checkPasses = checkCompresionLimitsW(section)
elif section.typeEnum == SteelSectionTypes.hss:
checkPasses = checkCompresionLimitsHss(section)
if checkPasses:
return True
else:
raise Exception('Element is class 4 for compression. Check flange and web limits with Table 1.')
def _getCompressionLim(section:SectionSteel):
sconvert = section.mat.sConvert('MPa')
Fy = section.mat.Fy*sconvert
return 1/Fy**0.5
[docs]def getCompressionThicknessRatioW(section:SectionSteel):
"""
Check b/t rations for the flange and web of a W section in compression.
See c.l. 11.3.2.b. for a definition of bel and h.
Parameters
----------
section : SectionSteel
The steel section to check the section class of in compression
Returns
-------
flangeRatio : float
The ratio of bel divided by tflange.
webRatio : float
The ratio of h divided by tweb.
"""
# flange propreties
tf = section.tf
bel = section.bf / 2
flangeRatio = (bel / tf)
# Web propreties
tw = section.tw
h = section.d - section.tf*2
webRatio = (h / tw)
return flangeRatio, webRatio
def checkCompresionLimitsW(section:SectionSteel) -> bool:
"""
Determines if a section complies with Table 1 for it's thickness to
depth ratios.
See c.l. 11.3.2.b. for a definition of bel
Parameters
----------
section : SectionSteel
The steel section to check the section class of in compression
Returns
-------
bool
True if the section passes, false if it fails.
"""
lim = _getCompressionLim(section)
flangeLim = 250*lim
webLim = 670*lim
# flange/web propreties
flangeRatio, webRatio = getCompressionThicknessRatioW(section)
flangePasses = flangeRatio < flangeLim
webPasses = webRatio < webLim
if flangePasses and webPasses:
return True
else:
return False
def getCompressionThicknessRatioHss(section:SectionSteel):
"""
Check b/t rations for the flange and web of a Hss section in compression.
See c.l. 11.3.2.b. for a definition of bel and h.
Parameters
----------
section : SectionSteel
The steel section to check the section class of in compression
Returns
-------
strongAxisRatio : float
The ratio of bel divided by tflange.
weakAxisRatio : float
The ratio of h divided by tweb.
"""
# flange propreties
tf = section.t
belFange = _getBelHSSSection(section, True)
strongAxisRatio = (belFange / tf)
# Web propreties
tw = section.t
belWeb = _getBelHSSSection(section, False)
weakAxisRatio = (belWeb / tw)
return strongAxisRatio, weakAxisRatio
def checkCompresionLimitsHss(section:SectionSteel):
"""
Determines if a section complies with Table 1 for it's thickness to
depth ratios.
See c.l. 11.3.2.b. for a definition of bel
Parameters
----------
section : SectionSteel
The steel section to check the section class of in compression
Returns
-------
bool
True if the section passes, false if it fails.
"""
lim = _getCompressionLim(section)
strongAxisLim = weakAxislim = 670*lim
# flange/WEB propreties
strongAxisRatio, weakAxisRatio = getCompressionThicknessRatioHss(section)
flangePasses = strongAxisRatio < strongAxisLim
webPasses = weakAxisRatio < weakAxislim
if flangePasses and webPasses:
return True
else:
return False
def checkCr(A:float, Fy:float, lamda:float, n:float = 1.34):
"""
Calculates compression resistance per 13.3.1.1
Parameters
----------
A : float
The sections area in sqmm.
Fy : float
The sections yield stress in MPa.
lamda : float
The ratio of yeld stress to the euler buckling stress.
n : float, optional
The parameter for compressive resistance. The default is 1.34, but the
parameter can be increased for certain section types per c.l. 13.3.1.1.
Returns
-------
float
The compression resistance for the system in N.
"""
phi = 0.9
return phi*A*Fy / (1 + lamda**(2*n))**(1/n)
def checkFe(E:float, Leff:float, reff:float):
"""
Calculates the euler buckling stress for a column in a given direction.
Effective buckling stress per c.l. 13.3.1.2
Leff is the effective buckling length, i.e. k*L
"""
return pi**2 * E / (Leff/reff)**2
def getrBar(x0:float, y0:float, rx:float, ry:float):
"""
Effective buckling stress per c.l. 13.3.1.2
"""
return (x0**2 + y0**2 + rx**2 + ry**2)**0.5
def checkFez(E:float, Cw:float, Leff:float, G:float,
J:float, A:float, rbar:float):
"""
Effective buckling stress per c.l. 13.3.1.2
Leff is the effective buckling length, i.e. k*L
all length units are the same.
"""
return ((pi**2 * E * Cw ) / Leff**2 + G*J) / (A*rbar**2)
[docs]def checkColumnFeDirection(column:BeamColumnSteelCsa24, useX = True):
"""
Calculates buckling stress in a single direction stress per 13.3.1.1
Only applies to double symettric sections, i.e. W sections and
HSS sections.
Finds effective buckling stresses using 13.3.1.2
Parameters
----------
beam : BeamColumnSteelCsa24
The structural element to check.
useX : bool, optional
A flag that specifies the direction to check the column in.
The default is True, which checks the x direction.
Returns
-------
float
The buckling stress in MPa.
"""
lconvert = column.member.lConvert('mm')
lsconvert = column.section.lConvert('mm')
sconvert = column.section.mat.sConvert('MPa')
E = column.section.mat.E*sconvert
if useX:
Le = column.designProps.Lex * lconvert
r = column.section.rx * lsconvert
else:
Le = column.designProps.Ley * lconvert
r = column.section.ry * lsconvert
return checkFe(E, Le, r)
[docs]def checkColumnCeDirection(column:BeamColumnSteelCsa24, useX = True):
"""
Calculates buckling force (Fe*A) in a single direction stress per 13.3.1.1
Only applies to double symettric sections, i.e. W sections and
HSS sections.
Finds effective buckling stresses using 13.3.1.2
Parameters
----------
beam : BeamColumnSteelCsa24
The structural element to check..
useX : TYPE, optional
The x direction to check the column in. The default is True.
Returns
-------
float
The buckling force in N.
"""
lsconvert = column.section.lConvert('mm')
A = column.section.A * lsconvert**2
return checkColumnFeDirection(column, useX) * A
[docs]def checkColumnFeTorsion(beam:BeamColumnSteelCsa24, x0:float=0, y0:float=0):
"""
Calculates the torsion bucking stress 13.3.1.1
Only applies to double symetric sections, i.e. W sections and
HSS sections.
Finds effective buckling stresses using 13.3.1.2
The variables x0 and y0 are the location of the shear center
with respect tohte centroid of the cross section.
kz, the buckling lenght for torsion, must be set in the member.
Parameters
----------
beam : BeamColumnSteelCsa24
The structural element to check..
useX : bool, optional
A flag that specifies the direction to check the column in.
The default is True, which checks the x direction.
Returns
-------
float
The buckling stress in MPa.
"""
lsconvert = beam.section.lConvert('mm')
rx = beam.section.rx*lsconvert
ry = beam.section.ry*lsconvert
sconvert = beam.section.mat.sConvert('MPa')
E = beam.section.mat.E*sconvert
lconvert = beam.member.lConvert('mm')
Lez = beam.designProps.Lez*lconvert
G = beam.section.mat.G*sconvert
Cw = beam.section.Cw*lsconvert**6
J = beam.section.J*lsconvert**4
A = beam.section.A*lsconvert**2
lsconvert = beam.section.lConvert('mm')
rx = beam.section.rx*lsconvert
ry = beam.section.ry*lsconvert
rbar = getrBar(x0,y0,rx,ry)
return checkFez(E, Cw, Lez, G, J, A, rbar)
"""
!!! There is code repetition in sub functions, e.g. we recall E several times
in each function.
"""
[docs]def checkColumnFe(beam:BeamColumnSteelCsa24):
"""
Calculates buckling compression stress per 13.3.1.1
Only applies to double symettric sections, i.e. W sections and
HSS sections.
Finds effective buckling stresses using 13.3.1.2
kz, the buckling lenght for torsion, must be set in the member.
Parameters
----------
beam : BeamColumnSteelCsa24
The steelbeamcolumn to check.
Returns
-------
float
The buckling stress in MPa.
"""
# Confirm that the beam falls within the limits for compression.
checkCompressionLimits(beam.section)
# Check the member class and raise an exception if
_checkType(beam.section)
enum = beam.section.typeEnum
isNotHss = (enum != SteelSectionTypes.hss) and (enum != SteelSectionTypes.hssr)
# Get the stress in each direction.
Fex = checkColumnFeDirection(beam)
Fey = checkColumnFeDirection(beam, False)
# If the section is a W we have to check torsion and return that.
# For now, assume that X0 and y0 are part of the cross section.
if isNotHss:
Fez = checkColumnFeTorsion(beam, 0, 0)
return min(Fex, Fey, Fez)
return min(Fex, Fey)
[docs]def checkColumnCr(column:BeamColumnSteelCsa24, n:float = 1.34,
lam:float = None):
"""
Calculates compression resistance per 13.3.1.1
Only applies to double symettric sections, i.e. W sections and
HSS sections.
Buckling effective stress is computed using 13.3.1.2
Finds effective buckling stresses using 13.3.1.2
kz, the buckling lenght for torsion, must be set in the member.
Parameters
----------
beam : BeamColumnSteelCsa24
The steelbeamcolumn to check.
n : float, optional
The parameter for compressive resistance. The default is 1.34, but the
parameter can be increased for certain section types per c.l. 13.3.1.1.
lam : float, optional
A manual override on the lambda factor. The default is calcualted using
clause 13.3.1.2.
Returns
-------
float
The strength of the column in N.
"""
lsconvert = column.section.lConvert('mm')
A = column.section.A*lsconvert**2
sconvert = column.section.mat.sConvert('MPa')
Fy = column.section.mat.Fy*sconvert
# If there is no manual overide for lambda, check it
if lam == None:
Fe = checkColumnFe(column)
lam = (Fy/Fe)**0.5
return checkCr(A, Fy, lam, n)
# =============================================================================
# Combined Bending / compression
# =============================================================================
# !!! there is a lot of re=work occuring in these functions.
# !!! Consider making a class.
[docs]class Omega1LoadConditions(IntEnum):
"""
An enumeration that represents possible loading cases for omega from
13.8.6
1 = No loads
2 = uniformly distributed loads, or regularly spaced point loads
3 = concentrated loads applied at to the member.
"""
noLoads = 1
distLoads = 2
concentratedLoads = 3
[docs]def getOmega1(loadCase:Omega1LoadConditions, Mmax = 1, Mmin = -1):
"""
Calculates the amplifction factor when no transvers loads acts between
supports. See c.l. 13.8.6 for details.
Parameters
----------
loadCase : Omega1LoadConditions
The load condition:
1 if there are no intermediate loads
2 if there are uniformy distributed loads
3 if there are concentrated loads applied at to the member.
Mmax : TYPE, optional
TYhe maximum load. The default is 1.
Mmin : TYPE, optional
THe minimum load, negative if single curvature, positive if double
curvature. The default is 1.
Returns
-------
float
The output value of the factor.
"""
if loadCase == Omega1LoadConditions.noLoads:
return getOmega1CaseA(Mmax, Mmin)
elif loadCase == Omega1LoadConditions.distLoads:
return 1
elif loadCase == Omega1LoadConditions.concentratedLoads:
return 0.85
def getOmega1CaseA(Mmax, Mmin):
"""
The amplifaction factor when no transverse loads act between supports.
"""
kappa = Mmin / Mmax
return max(0.6 - 0.4*kappa, 0.4)
def _getBeta(sectionType, lamy=0):
"""
c.l. 13.8.2
"""
if sectionType == SteelSectionTypes.hss:
return 0.5
return min(0.6 + 0.4*lamy, 0.85)
def _getUtil(Cf, Cr, U1x, Mfx, Mrx, U1y, Mfy, Mry, beta, betax = 0.85):
return Cf/Cr + betax*U1x*Mfx/Mrx + beta*U1y*Mfy/Mry
def _getCaseAResistance(beamColumn:BeamColumnSteelCsa24, Cf, n, lam = None):
Cr = checkColumnCr(beamColumn, n, lam)
Mrx = checkBeamMrSupported(beamColumn, True, Cf)
Mry = checkBeamMrSupported(beamColumn, False, Cf)
return Cr, Mrx, Mry
def getU1(omega:float, Cf:float, Ce:float):
ratio = Cf/Ce
if 1 <= ratio:
return omega * 1000
return omega / (1-ratio)
[docs]def checkCombinedCaseA(beamColumn:BeamColumnSteelCsa24, Cf:float, Mfx:float,
Mfy:float, n:float, omega1:float):
"""
Checks the cross sectional member strength, where:
- Clause 13.8.2 a
- beta = 0.6
- lamda = 0
- Mr is calculated as normal
- U1x/U2x are specified in 13.8.5 >= 1
Parameters
----------
beamColumn : BeamColumnSteelCsa24
The beamcolumn to check.
Cf : float
The applied compressive load (N).
Mfx : float
The applied moment in the strong axis direction (Nm).
Mfy : float, optional
The applied moment in the strong weak direction (Nm). The default is 0.
n : float, optional
The parameter for compressive resistance. The default is 1.34, but the
parameter can be increased for certain section types per c.l. 13.3.1.1.
omegax1 : float, optional
Omega 1 calculated as per 13.8.6. It has a default value of is 1.0,
which represents a constant moment in single curvature..
Returns
-------
u : float
The the output utilziation
"""
Cr, Mrx, Mry = _getCaseAResistance(beamColumn, Cf, n, 0)
Cex = checkColumnCeDirection(beamColumn, True)
Cey = checkColumnCeDirection(beamColumn, False)
U1x = max(getU1(omega1, Cf, Cex),1)
U1y = max(getU1(omega1, Cf, Cey),1)
return _getUtil(Cf, Cr, U1x, Mfx, Mrx, U1y, Mfy, Mry, beta=0.6)
[docs]def checkCombinedCaseB(beamColumn:BeamColumnSteelCsa24, Cf:float, Mfx:float,
Mfy:float, n:float, omega1:float,
isBracedFrame:bool = False):
"""
Overall member strength
Unbraced moment Moment is amplified due to p-delta in the axis of bending
only. Assumes the following:
- Clause 13.8.2 b
- k = 1 for compression, based on axis of bending only.
- If there is uniaxial bending, use calulate Cr in that direction.
- Mr is calculated as if the column is braced
- U1x/U2x are taken as 1, unless the system is in a braced frame
- If the system is a braced frame, it is calcualted with 13.8.5
Parameters
----------
beamColumn : BeamColumnSteelCsa24
The beamcolumn to check.
Cf : float
The applied compressive load (N).
Mfx : float
The applied moment in the strong axis direction (Nm).
Mfy : float, optional
The applied moment in the strong weak direction (Nm). The default is 0.
n : float, optional
The parameter for compressive resistance. The default is 1.34, but the
parameter can be increased for certain section types per c.l. 13.3.1.1.
omegax1 : float, optional
Omega 1 calculated as per 13.8.6. It has a default value of is 1.0,
which represents a constant moment in single curvature..
isBracedFrame : bool, optional
A flag that specifies if the beam is in a braced frame.
The default is False.
Returns
-------
u : float
The the output utilziation
"""
# Temporarily set kx to one
oldkx = beamColumn.designProps.kx
oldky = beamColumn.designProps.ky
oldkz = beamColumn.designProps.kz
beamColumn.designProps.setkx(1)
beamColumn.designProps.setkz(0.0001)
# Use a small k factor in the y direction if there is only uniaxial bending
# this forces the column to consider buckling in the strong axis only.
if Mfy == 0:
beamColumn.designProps.setky(0.0001)
else:
beamColumn.designProps.setky(1)
Cr, Mrx, Mry = _getCaseAResistance(beamColumn, Cf, n, None)
# # If the applied load is greater than the buckling load
# if min(Cex, Cey) < Cf:
# return 1000
if isBracedFrame:
Cex = checkColumnCeDirection(beamColumn,True)
Cey = checkColumnCeDirection(beamColumn,False)
U1x = getU1(omega1, Cf, Cex)
U1y = getU1(omega1, Cf, Cey)
else:
U1x = U1y = 1
beamColumn.designProps.setkx(oldkx)
beamColumn.designProps.setky(oldky)
beamColumn.designProps.setkz(oldkz)
# if lamy == None:
sconvert = beamColumn.section.mat.sConvert('MPa')
Fy = beamColumn.section.mat.Fy*sconvert
Fey = checkColumnFeDirection(beamColumn, useX = False)
lamy = (Fy/Fey)**0.5
beta = _getBeta(beamColumn.section.typeEnum, lamy)
return _getUtil(Cf, Cr, U1x, Mfx, Mrx, U1y, Mfy, Mry, beta=beta)
[docs]def checkCombinedCaseC(beamColumn:BeamColumnSteelCsa24,
Cf:float, Mfx:float, Mfy:float, n:float,
omega1:float, omega2:float, isBracedFrame = False):
"""
Lateral Torsional Buckling
Typically govens sections with strong axis loaded. Assumes the following:
- Clause 13.8.2 with weak axis bending only.
- Mrx is calculated as unbraced
- Mry is calculated as braced
- U1x/U1y = 1 for members in unbraced framses.
- U1x is calcualted as in clause 13.8.5, but not less than 1.0 if braced
- U1y is calculated as in clause 13.8.5
- U1x/U2x are taken as 1, unless the system is in a braced frame
- If the system is a braced frame, it is calcualted with 13.8.5
Parameters
----------
beamColumn : BeamColumnSteelCsa24
The beamcolumn to check.
Cf : float
The applied compressive load (N).
Mfx : float
The applied moment in the strong axis direction (Nm).
Mfy : float, optional
The applied moment in the strong weak direction (Nm). The default is 0.
n : float, optional
The parameter for compressive resistance. The default is 1.34, but the
parameter can be increased for certain section types per c.l. 13.3.1.1.
omegax1 : float, optional
Omega 1 calculated as per 13.8.6. It has a default value of is 1.0,
which represents a constant moment in single curvature.
omegax2 : float, optional
Omega 1 calculated as per 13.8.1. It has a default value of is 1.0,
which represents a constant moment in single curvature.
isBracedFrame : bool, optional
A flag that specifies if the beam is in a braced frame.
The default is False.
Returns
-------
u : float
The the output utilziation
"""
Cr = checkColumnCr(beamColumn, n)
Mrx = checkBeamMrUnsupported(beamColumn, omega2, Cf = Cf)
Mry = checkBeamMrSupported(beamColumn, False, Cf)
if isBracedFrame:
Cex = checkColumnCeDirection(beamColumn,True)
Cey = checkColumnCeDirection(beamColumn,False)
U1x = max(getU1(omega1, Cf, Cex),1)
U1y = max(getU1(omega1, Cf, Cey),1)
else:
U1x = U1y = 1
# If Mfy !=0, then the value of beta doesn't matter.
if Mfy !=0:
sconvert = beamColumn.section.mat.sConvert('MPa')
Fy = beamColumn.section.mat.Fy*sconvert
Fey = checkColumnFeDirection(beamColumn, useX = False)
lamy = (Fy/Fey)**0.5
beta = _getBeta(beamColumn.section.typeEnum, lamy)
else:
beta = 0.6
return _getUtil(Cf, Cr, U1x, Mfx, Mrx, U1y, Mfy, Mry, beta=beta)
[docs]def checkCombinedCaseD(beamColumn:BeamColumnSteelCsa24, Cf, Mfx, Mfy,
isBracedFrame = False):
"""
Biaxial Bending
Members are checked for biaxial bending, without considering compression.
Compression is still passed to the function to determine section class.
Parameters
----------
beamColumn : BeamColumnSteelCsa24
The beamcolumn to check.
Cf : float
The applied compressive load (N).
Mfx : float
The applied moment in the strong axis direction (Nm).
Mfy : float, optional
The applied moment in the strong weak direction (Nm). The default is 0.
n : float, optional
The parameter for compressive resistance. The default is 1.34, but the
parameter can be increased for certain section types per c.l. 13.3.1.1.
omegax1 : float, optional
Omega 1 calculated as per 13.8.6. It has a default value of is 1.0,
which represents a constant moment in single curvature..
isBracedFrame : bool, optional
A flag that specifies if the beam is in a braced frame.
The default is False.
"""
Mrx = checkBeamMrUnsupported(beamColumn, True, Cf = Cf)
Mry = checkBeamMrSupported(beamColumn, False, Cf)
return _getUtil(0, 1, 1, Mfx, Mrx, 1, Mfy, Mry, beta=1, betax = 1)
[docs]def checkBeamColumnCombined(beamColumn:BeamColumnSteelCsa24, Cf:float,
Mfx:float, Mfy:float = 0, n:float = 1.34,
omegax1:float = 1.0, omegax2:float=1.0,
isBracedFrame = False):
"""
Checks the 4 cases required to assess a steel element in combined bending
and shear: cross section strength (c.l. 13.8.2a);
Overall member strength (c.l. 13.8.2b); Lateral Torsional Buckling
(c.l. 13.8.2c); and biaxial bending (c.l. 13.8.2d).
Parameters
----------
beamColumn : BeamColumnSteelCsa24
The beamcolumn to check.
Cf : float
The applied compressive load (N).
Mfx : float
The applied moment in the strong axis direction (Nm).
Mfy : float, optional
The applied moment in the strong weak direction (Nm). The default is 0.
n : float, optional
The parameter for compressive resistance. The default is 1.34, but the
parameter can be increased for certain section types per c.l. 13.3.1.1.
omegax1 : float, optional
Omega 1 calculated as per 13.8.6. It has a default value of is 1.0,
which represents a constant moment in single curvature..
isBracedFrame : bool, optional
A flag that specifies if the beam is in a braced frame.
The default is False.
Returns
-------
u1 : float
The utilization in case 1, cross section strength.
u2 : float
The utilization in case 2, overall member strength.
u3 : float
The utilization in case 3, Lateral Torsional Buckling.
u4 : float
The utilization in case 4, biaxial bending.
"""
if isBracedFrame:
u1 = checkCombinedCaseA(beamColumn, Cf, Mfx, Mfy, n, omegax1)
else:
u1 = 0
u2 = checkCombinedCaseB(beamColumn, Cf, Mfx, Mfy, n, omegax1, isBracedFrame)
u3 = checkCombinedCaseC(beamColumn, Cf, Mfx, Mfy, n, omegax1, omegax2, isBracedFrame)
u4 = checkCombinedCaseD(beamColumn, Cf, Mfx, Mfy, isBracedFrame)
return u1, u2, u3, u4