"""
Common functions for representing structural sections.
Sections are design agnostic - they only store information about a sections
geometry and the material used.
These objects are archetypes that have their details filled in later.
For example, a csao86 CLT section will store it's information.
"""
from abc import ABC, abstractmethod
from enum import Enum
from .. material import MaterialAbstract, MaterialElastic
from ... units import ConverterLength
# from .plot import GeomRectangle, SectionPlotter, plotDisplayParameters
__all__ = ['SectionAbstract', 'SectionMonolithic', 'SectionGeneric',
'SectionRectangle', 'SectionSteel', 'SteelSectionTypes']
#Rename this to SectionArchetype?
[docs]class SectionAbstract(ABC):
"""
The Abstract section should not be directly used. It contains interfaces
that other structural classes inheret from. This includes unit definitions,
and getters for section stiffness.
"""
[docs] @abstractmethod
def getEIx(lUnit='m', sUnit='Pa' ):
"""
Returns EI about the sections local x axis, which is generally the
strong axis. Returns in units of sUnit x lUnit^4
Parameters
----------
lUnit : float, optional
The length units to output Ix in. The default is 'm'.
sUnit : float, optional
Stress units to output E in. The default is 'Pa'.
Returns
-------
float.
The EIx for the section.
"""
pass
[docs] @abstractmethod
def getEIy(lUnit='m', sUnit='Pa'):
"""
Returns EI about the sections local y axis, which is generally the
weak axis. Returns in units of sUnit x lUnit^4
Parameters
----------
lUnit : float, optional
The length units to output Iy in. The default is 'm'.
sUnit : float, optional
Stress units to output E in. The default is 'Pa'.
Returns
-------
float.
The EIy for the section.
"""
pass
[docs] @abstractmethod
def getGAx(lUnit='m', sUnit='Pa'):
"""
Returns GA about the sections local x axis, which is generally the
strong axis. Returns in units of sUnit x lUnit^2
Parameters
----------
lUnit : float, optional
The length units to output Ax in. The default is 'm'.
sUnit : float, optional
Stress units to output E in. The default is 'Pa'.
Returns
-------
float.
The GAx for the section.
"""
pass
[docs] @abstractmethod
def getGAy():
"""
Returns GA about the sections local y axis, which is generally the
strong axis. Returns in units of sUnit x lUnit^2
Parameters
----------
lUnit : float, optional
The length units to output Ay in. The default is 'm'.
sUnit : float, optional
Stress units to output E in. The default is 'Pa'.
Returns
-------
float.
The GAy for the section.
"""
pass
def _initUnits(self, lUnit:str='mm'):
"""
Initiates units of the cross sections. Cross sections have length units
only.
Parameters
----------
lUnit : str, optional
The length unit to use. The default is 'mm'.
"""
self.lUnit = lUnit
self.lConverter = ConverterLength()
[docs] def lConvert(self, outputUnit:str):
"""
Get the conversion factor from the current unit to the output unit
for length units
Parameters
----------
outputUnit : str
The unit to get the conversion factor to.
Returns
-------
float
The conversion factor between the current length unit and the
target output length unit.
"""
return self.lConverter.getConversionFactor(self.lUnit, outputUnit)
def _validateLunit(self, lUnit):
"""
returns the sections default unit if no units are given.
"""
if lUnit:
return lUnit
else:
return self.lUnit
[docs]class SectionMonolithic(SectionAbstract):
"""
The Monolithic section should not be used directly, it defines interfaces
that all sections that use only one uniform material over their
whole cross section will have.
"""
def __len__(self):
return 1
def _getCfactors(self, lUnit='m', sUnit='Pa'):
return self.mat.sConvert(sUnit), self.lConvert(lUnit)
[docs] def getEA(self, lUnit='m', sUnit='Pa'):
"""
Returns the axis stiffness EA for the section.
Returns in units of sUnit x lUnit^2
Parameters
----------
lUnit : float, optional
The length units to output A in. The default is 'm'.
sUnit : float, optional
Stress units to output E in. The default is 'Pa'.
Returns
-------
float.
The EA for the section.
"""
sfactor, lfactor = self._getCfactors(lUnit, sUnit)
return self.mat.E * sfactor * self.A * lfactor**2
[docs] def getEIx(self, lUnit='m', sUnit='Pa'):
"""
Returns EI about the sections local x axis, which is generally the
strong axis. Returns in units of sUnit x lUnit^4
Parameters
----------
lUnit : float, optional
The length units to output Ix in. The default is 'm'.
sUnit : float, optional
Stress units to output E in. The default is 'Pa'.
Returns
-------
float.
The EIx for the section.
"""
sfactor, lfactor = self._getCfactors(lUnit, sUnit)
return self.mat.E * sfactor * self.Ix * lfactor**4
[docs] def getEIy(self, lUnit='m', sUnit='Pa'):
"""
Returns EI about the sections local y axis, which is generally the
strong axis. Returns in units of sUnit x lUnit^4
Parameters
----------
lUnit : float, optional
The length units to output Iy in. The default is 'm'.
sUnit : float, optional
Stress units to output E in. The default is 'Pa'.
Returns
-------
float.
The EIy for the section.
"""
sfactor, lfactor = self._getCfactors(lUnit, sUnit)
return self.mat.E * sfactor * self.Iy * lfactor**4
[docs] def getGAx(self, lUnit='m', sUnit='Pa'):
"""
Returns GA about the sections local x axis, which is generally the
strong axis. Returns in units of sUnit x lUnit^2
Parameters
----------
lUnit : float, optional
The length units to output Ax in. The default is 'm'.
sUnit : float, optional
Stress units to output E in. The default is 'Pa'.
Returns
-------
float.
The GAx for the section.
"""
sfactor, lfactor = self._getCfactors(lUnit, sUnit)
return self.mat.E * sfactor * self.Avx * lfactor**2
[docs] def getGAy(self, lUnit='m', sUnit='Pa'):
"""
Returns GA about the sections local y axis, which is generally the
strong axis. Returns in units of sUnit x lUnit^2
Parameters
----------
lUnit : float, optional
The length units to output Ay in. The default is 'm'.
sUnit : float, optional
Stress units to output E in. The default is 'Pa'.
Returns
-------
float.
The GAy for the section.
"""
sfactor, lfactor = self._getCfactors(lUnit, sUnit)
return self.mat.E * sfactor * self.Avy * lfactor**2
def _initMat(self, mat):
self.mat = mat
@property
def E(self):
return self.mat.E
@property
def G(self):
return self.mat.E
@property
def Iz(self):
return self.Ix
[docs]class SectionGeneric(SectionMonolithic):
"""
The generic section is unique in that it has no base geometry.
Instead, all section propreties are set by the user, instead of infered
from geometry!
Parameters
----------
mat : MaterialAbstract
The material to use in the section.
Ix : float, optional
The moment of interia of the section about it's local x axis.
The default is 1.
A : float, optional
The area of the section about it's local. The default is 1.
Iy : float, optional
The moment of interia of the section about it's local y axis.
The default is 1.
J : float, optional
The torsion constant for the section. The default is 1.
Ax : float, optional
The area in the shear direction x. The default is None.
Ay : float, optional
The area in the shear direction y. The default is None.
lUnit : str, optional
The units for length used in the section. The default is 'mm'.
Returns
-------
None.
"""
def __init__(self, mat:MaterialElastic, Ix:float = 1, A:float = 1,
Iy:float = 1, J:float = 1, Avx:float = None, Avy:float = None,
lUnit:str='mm'):
self.mat:MaterialAbstract = mat
self.Ix = Ix
self.A = A
self.Iy = Iy
self.J = J
self.Avx = Avx
self.Avy = Avy
[docs]class SectionRectangle(SectionMonolithic):
"""
A defines a rectangular monolitihic section. Section propreties are defined
using geometry and mechanics of materials.
Parameters
----------
mat : MaterialElastic
The material to use for the section.
b : float
The section width.
d : float
The section depth.
lUnit : str, optional
The length units. The default is 'mm'.
"""
def __init__(self, mat:MaterialElastic, b:float, d:float, lUnit:str='mm'):
self._initUnits(lUnit)
self.mat = mat
self.d = d
self.b = b
self._setupSectionProps()
self.plotGeom = None
def _setupSectionProps(self):
b = self.b
d = self.d
self.A = d*b
self.Avx = self.A * (5/6)
self.Avy = self.A * (5/6)
self.Ix = b*d**3 / 12
self.Iy = d*b**3 / 12
self.Sx = b*d**2 / 6
self.Sy = (b**2)*d / 6
# Torsion modulus
a = max(b, d)
b = min(b, d)
self.J = (a*b**3) * (1/3 - 0.21*(b/a)*(1 - b**4/(12*a**4)))
# Radius of Gyration
self.rx = (self.Ix / self.A)**0.5
self.ry = (self.Iy / self.A)**0.5
[docs] def convertUnits(self, lUnit:str):
"""
Converts the section from one set of units to another.
Parameters
----------
lUnit : string
Converts the section units.
"""
cfactor = self.lConvert(lUnit)
self.lUnit = lUnit
self.b = self.b*cfactor
self.d = self.d*cfactor
self._setupSectionProps()
@property
def name(self):
return f"{self.b}x{self.d} {self.mat.name} Rectangle"
def __repr__(self):
return f"<limitstates {self.name} Section.>"
[docs]class SectionSteel(SectionMonolithic):
"""
A class that represents the geometry for a steel section from one of the
standard shapes. This include I beams (W sections), hollow sections (hss),
etc.
All steel sections will have a "type attribute, which will be either "w"
for W sections, 'hss' for hss sections, or 'hssr' for round hss sections.
Steel sections are defined by importing from a database. See section
databases for all availible databases.
Parameters
----------
mat : MaterialElastic
The steel material to use for the section.
sectionDict : dict
The input section dictionary, generally loaded from a database.
lUnit : str, optional
The length units for the section dictionary. The default is 'mm'.
"""
sectionClass = None
def __init__(self, mat:MaterialElastic, sectionDict:dict, lUnit:str='mm'):
# add all items from the input section dictionary
self.__dict__.update(sectionDict)
self._initUnits(lUnit)
self.mat = mat
self.typeEnum = self._classifySectionType()
if self.typeEnum == SteelSectionTypes.hss:
self._patchHssThickness()
self._patchHSSWidth()
self._patchHSSradius()
def _patchHssThickness(self):
"""
some section libraries call thickness tdes.
add t for convetsion
"""
if not hasattr(self, 't'):
self.t = self.tdes
# self.t = self.tnom
if not hasattr(self, 'tw'):
self.tw = self.t
def _patchHSSWidth(self):
if not hasattr(self, 'bf'):
self.bf = self.b
def _patchHSSradius(self):
if not hasattr(self, 'ro'):
self.ro = self.t*2
if not hasattr(self, 'ri'):
self.ri = self.t
@property
def name(self):
return f'{self.EDI_Std_Nomenclature} {self.sectionDB}'
def __repr__(self):
return f'<limitstates {self.name} Section>'
[docs] def getCy(self, lUnit = 'm', sUnit='Pa'):
lfactor = self.lConvert(lUnit)
sfactor = self.mat.sConvert(sUnit)
return self.A * lfactor**2 * self.mat.Fy * sfactor
@property
def Cy(self):
return self.getCy( 'm', 'Pa')
[docs] def getZ(self, useX:bool = True, lUnit:str = 'mm'):
"""
Returns the section's plastic modulus in the units and direction input.
Parameters
----------
useX : bool, optional
A flag that toggles if the x (strong) or y (weak) axis is used.
The default is True, which uses the strong axis.
lUnit : string, optional
The length units to use for the section. The default is 'mm'.
Returns
-------
float
The section's plastic modulus in the direction input.
"""
lfactor = self.lConvert(lUnit)
if useX:
return self.Zx*lfactor**3
else:
return self.Zy*lfactor**3
[docs] def getS(self, useX = True, lUnit = 'mm'):
"""
Returns the section's elastic modulus in the units and direction input.
Parameters
----------
useX : bool, optional
A flag that toggles if the x (strong) or y (weak) axis is used.
The default is True, which uses the strong axis.
lUnit : string, optional
The length units to use for the section. The default is 'mm'.
Returns
-------
float
The section's elastic modulus in the direction input.
"""
lfactor = self.lConvert(lUnit)
if useX:
return self.Sx*lfactor**3
else:
return self.Sy*lfactor**3
[docs] def getI(self, useX = True, lUnit = 'mm'):
"""
Returns the section's moment of inertia in the units
and direction input.
Parameters
----------
useX : bool, optional
A flag that toggles if the x (strong) or y (weak) axis is used.
The default is True, which uses the strong axis.
lUnit : string, optional
The length units to use for the section. The default is 'mm'.
Returns
-------
float
The section's moment of inertia the direction input.
"""
lfactor = self.lConvert(lUnit)
if useX:
return self.Ix*lfactor**4
else:
return self.Iy*lfactor**4
def _classifySectionType(self):
if 'w' == self.type.lower():
return SteelSectionTypes.w
elif 'hss' == self.type.lower():
return SteelSectionTypes.hss
else:
return SteelSectionTypes.other
class SteelSectionTypes(Enum):
"""
Represents the possible types of steel sections.
w for I beams, hss for square and rectangular hss sections, hssr
and other for any other type of section not listed.
"""
w = 1
hss = 2
hssr = 3
other = 4
class SectionSteelAngle(SectionMonolithic):
"""A class that represents a standard steel W section."""
class SectionDatabase(SectionMonolithic):
"""
A section that is defined from a database. Generally used for steel or more
complex shapes where section geometry requires a large number of parameters
to define.
Parameters
----------
mat : MaterialAbstract
The material to use in the section.
sectionDict : dict
A dictionary containing all of the information necessary to define
the section.
lUnit : str, optional
The units for length used in the section. The default is 'mm'.
Returns
-------
None.
"""
def __init__(self, mat:MaterialElastic, sectionDict:dict, lUnit='mm'):
self.__dict__.update(sectionDict)
self._initMat(mat)
self._initUnits(lUnit)