Source code for sectionproperties.pre.library.steel_sections

"""Steel sections library."""

from __future__ import annotations

import numpy as np
from shapely import Polygon

import sectionproperties.pre.geometry as geometry
import sectionproperties.pre.library.utils as sp_utils
import sectionproperties.pre.pre as pre


[docs] def circular_hollow_section( d: float, t: float, n: int, material: pre.Material = pre.DEFAULT_MATERIAL, ) -> geometry.Geometry: """Constructs a circular hollow section (CHS). Constructs a circular hollow section (CHS) centered at the origin ``(0, 0)``, with diameter ``d`` and thickness ``t``, using ``n`` points to construct the inner and outer circles. Args: d: Outer diameter of the CHS t: Thickness of the CHS n: Number of points discretising the inner and outer circles material: Material to associate with this geometry Returns: Circular hollow section geometry Example: The following example creates a CHS discretised with 64 points, with a diameter of 48 mm and thickness of 3.2mm: .. plot:: :include-source: True :caption: Circular hollow section geometry from sectionproperties.pre.library import circular_hollow_section circular_hollow_section(d=48, t=3.2, n=64).plot_geometry() """ points_inner = [] points_outer = [] # loop through each point of the CHS for i in range(n): # determine polar angle theta = i * 2 * np.pi * 1.0 / n # calculate location of outer and inner points x_outer = 0.5 * d * np.cos(theta) y_outer = 0.5 * d * np.sin(theta) x_inner = (0.5 * d - t) * np.cos(theta) y_inner = (0.5 * d - t) * np.sin(theta) # append the current points to the points list points_outer.append((x_outer, y_outer)) points_inner.append((x_inner, y_inner)) inner_circle = Polygon(points_inner) outer_circle = Polygon(points_outer) return geometry.Geometry(geom=outer_circle - inner_circle, material=material)
[docs] def elliptical_hollow_section( d_x: float, d_y: float, t: float, n: int, material: pre.Material = pre.DEFAULT_MATERIAL, ) -> geometry.Geometry: """Constructs an elliptical hollow section (EHS). Constructs an elliptical hollow section (EHS) centered at the origin ``(0, 0)``, with outer horizontal diameter ``d_x``, outer vertical diameter ``d_y`` and thickness ``t``, using ``n`` points to construct the inner and outer ellipses. Args: d_x: Diameter of the ellipse in the x-dimension d_y: Diameter of the ellipse in the y-dimension t: Thickness of the EHS n: Number of points discretising the inner and outer ellipses material: Material to associate with this geometry Returns: Elliptical hollow section geometry Example: The following example creates an EHS discretised with 30 points, with an outer horizontal diameter of 50 mm, outer vertical diameter of 25 mm and thickness of 2 mm: .. plot:: :include-source: True :caption: Elliptical hollow section geometry from sectionproperties.pre.library import elliptical_hollow_section elliptical_hollow_section(d_x=50, d_y=25, t=2, n=64).plot_geometry() """ points_inner = [] points_outer = [] # loop through each point of the EHS for i in range(n): # determine polar angle theta = i * 2 * np.pi * 1.0 / n # calculate location of outer and inner points x_outer = 0.5 * d_x * np.cos(theta) y_outer = 0.5 * d_y * np.sin(theta) x_inner = ((0.5 * d_x) - t) * np.cos(theta) y_inner = ((0.5 * d_y) - t) * np.sin(theta) # append the current points to the points list points_outer.append((x_outer, y_outer)) points_inner.append((x_inner, y_inner)) outer = Polygon(points_outer) inner = Polygon(points_inner) return geometry.Geometry(geom=outer - inner, material=material)
[docs] def rectangular_hollow_section( d: float, b: float, t: float, r_out: float, n_r: int, material: pre.Material = pre.DEFAULT_MATERIAL, ) -> geometry.Geometry: """Constructs a rectangular hollow section (RHS). Constructs a rectangular hollow section (RHS) centered at ``(b/2, d/2)``, with depth ``d``, width ``b``, thickness ``t`` and outer radius ``r_out``, using ``n_r`` points to construct the inner and outer radii. If the outer radius is less than the thickness of the RHS, the inner radius is set to zero. Args: d: Depth of the RHS b: Width of the RHS t: Thickness of the RHS r_out: Outer radius of the RHS n_r: Number of points discretising the inner and outer radii material: Material to associate with this geometry Returns: Rectangular hollow section geometry Example: The following example creates an RHS with a depth of 100 mm, a width of 50 mm, a thickness of 6 mm and an outer radius of 9 mm, using 8 points to discretise the inner and outer radii: .. plot:: :include-source: True :caption: Rectangular hollow section geometry from sectionproperties.pre.library import rectangular_hollow_section rectangular_hollow_section(d=100, b=50, t=6, r_out=9, n_r=8).plot_geometry() """ points_inner = [] points_outer = [] # calculate internal radius r_in = max(r_out - t, 0) # construct the outer radius points points_outer += sp_utils.draw_radius((r_out, r_out), r_out, np.pi, n_r) points_outer += sp_utils.draw_radius((b - r_out, r_out), r_out, 1.5 * np.pi, n_r) points_outer += sp_utils.draw_radius((b - r_out, d - r_out), r_out, 0, n_r) points_outer += sp_utils.draw_radius((r_out, d - r_out), r_out, 0.5 * np.pi, n_r) points_inner += sp_utils.draw_radius((t + r_in, t + r_in), r_in, np.pi, n_r) points_inner += sp_utils.draw_radius( (b - t - r_in, t + r_in), r_in, 1.5 * np.pi, n_r ) points_inner += sp_utils.draw_radius((b - t - r_in, d - t - r_in), r_in, 0, n_r) points_inner += sp_utils.draw_radius( (t + r_in, d - t - r_in), r_in, 0.5 * np.pi, n_r ) outer = Polygon(points_outer) inner = Polygon(points_inner) return geometry.Geometry(geom=outer - inner, material=material)
[docs] def polygon_hollow_section( d: float, t: float, n_sides: int, r_in: float = 0.0, n_r: int = 1, rot: float = 0.0, material: pre.Material = pre.DEFAULT_MATERIAL, ) -> geometry.Geometry: """Constructs a regular hollow polygon section. Constructs a regular hollow polygon section centered at ``(0, 0)``, with a pitch circle diameter of bounding polygon ``d``, thickness ``t``, number of sides ``n_sides`` and an optional inner radius ``r_in``, using ``n_r`` points to construct the inner and outer radii (if radii is specified). Args: d: Pitch circle diameter of the outer bounding polygon (i.e. diameter of circle that passes through all vertices of the outer polygon) t: Thickness of the polygon section wall n_sides: Number of sides of the polygon r_in: Inner radius of the polygon corners. By default, if not specified, a polygon with no corner radii is generated. n_r: Number of points discretising the inner and outer radii, ignored if no inner radii is specified rot: Initial counterclockwise rotation in degrees. By default bottom face is aligned with x axis. material: Material to associate with this geometry Raises: ValueError: Number of sides in polygon must be greater than or equal to 3 Returns: Regular hollow polygon section geometry Example: The following example creates an octagonal section (8 sides) with a diameter of 200 mm, a thickness of 6 mm and an inner radius of 20 mm, using 12 points to discretise the inner and outer radii: .. plot:: :include-source: True :caption: Rectangular hollow section geometry from sectionproperties.pre.library import polygon_hollow_section polygon_hollow_section( d=200, t=6, n_sides=8, r_in=20, n_r=12 ).plot_geometry() """ outer_points: list[tuple[float, float]] = [] inner_points: list[tuple[float, float]] = [] if n_sides < 3: msg = "n_sides required to be greater than 3 for polygon_section()" raise ValueError(msg) # initial rotation rot = rot * np.pi / 180 # radians # determine triangular segment angle alpha = 2 * np.pi / n_sides # radians # determine distance from origin to point perpendicular on face of side a_out = d / 2 * np.cos(alpha / 2) a_in = a_out - t # determine side length for outer & inner faces neglecting radii side_length_out = d * np.sin(alpha / 2) side_length_in = a_in / a_out * side_length_out # check limit on internal radii, if exceeded then radii merge to circle if r_in > a_in: r_in = a_in # calculate external radius, if r_in is zero, r_out also is zero if r_in == 0: r_out = 0.0 n_r = 1 else: r_out = r_in + t # equivalent side length of half the corner radii triangular segment c_out = r_out * (side_length_out / 2) / a_out c_in = r_in * (side_length_in / 2) / a_in # determine straight side length between corner radii (if present) side_length_straight_out = side_length_out - (2 * c_out) side_length_straight_in = side_length_in - (2 * c_in) # temp list for repeating geometry outer_base_points: list[tuple[float, float]] = [] inner_base_points: list[tuple[float, float]] = [] # start at bottom face, constructing one corner radii, then rotate by initial # rotation + alpha and repeat for n_side number of times to form full section # perimeter # construct the first radius (bottom right) for i in range(n_r): # determine polar angle theta = 1 / 2 * np.pi + i * 1.0 / max(1, n_r - 1) * alpha # calculate location of inner and outer points x_outer = side_length_straight_out / 2 - r_out * np.cos(theta) y_outer = -a_out + r_out - r_out * np.sin(theta) x_inner = side_length_straight_in / 2 - r_in * np.cos(theta) y_inner = -a_in + r_in - r_in * np.sin(theta) # append the current temporary points to the temporary points list outer_base_points.append((x_outer, y_outer)) inner_base_points.append((x_inner, y_inner)) for i in range(n_sides): for point in outer_base_points: point_new = sp_utils.rotate(point, alpha * i + rot) outer_points.append(point_new) for point in inner_base_points: point_new = sp_utils.rotate(point, alpha * i + rot) inner_points.append(point_new) outer_polygon = Polygon(outer_points) inner_polygon = Polygon(inner_points) return geometry.Geometry(geom=outer_polygon - inner_polygon, material=material)
[docs] def i_section( d: float, b: float, t_f: float, t_w: float, r: float, n_r: int, material: pre.Material = pre.DEFAULT_MATERIAL, ) -> geometry.Geometry: """Constructs an I section. Constructs an I section centered at ``(b/2, d/2)``, with depth ``d``, width ``b``, flange thickness ``t_f``, web thickness ``t_w``, and root radius ``*, using ``n_r`` points to construct the root radius. Args: d: Depth of the I section b: Width of the I section t_f: Flange thickness of the I section t_w: Web thickness of the I section r: Root radius of the I section n_r: Number of points discretising the root radius material: Material to associate with this geometry Returns: I section geometry Example: The following example creates an I section with a depth of 203 mm, a width of 133 mm, a flange thickness of 7.8 mm, a web thickness of 5.8 mm and a root radius of 8.9 mm, using 16 points to discretise the root radius: .. plot:: :include-source: True :caption: I section geometry from sectionproperties.pre.library import i_section i_section(d=203, b=133, t_f=7.8, t_w=5.8, r=8.9, n_r=16).plot_geometry() """ points: list[tuple[float, float]] = [] # add first three points points.append((0, 0)) points.append((b, 0)) points.append((b, t_f)) # construct the bottom right radius pt = b * 0.5 + t_w * 0.5 + r, t_f + r points += sp_utils.draw_radius(pt=pt, r=r, theta=1.5 * np.pi, n=n_r, ccw=False) # construct the top right radius pt = b * 0.5 + t_w * 0.5 + r, d - t_f - r points += sp_utils.draw_radius(pt=pt, r=r, theta=np.pi, n=n_r, ccw=False) # add the next four points points.append((b, d - t_f)) points.append((b, d)) points.append((0, d)) points.append((0, d - t_f)) # construct the top left radius pt = b * 0.5 - t_w * 0.5 - r, d - t_f - r points += sp_utils.draw_radius(pt=pt, r=r, theta=0.5 * np.pi, n=n_r, ccw=False) # construct the bottom left radius pt = b * 0.5 - t_w * 0.5 - r, t_f + r points += sp_utils.draw_radius(pt=pt, r=r, theta=0, n=n_r, ccw=False) # # add the last point points.append((0, t_f)) i_section = Polygon(points) return geometry.Geometry(geom=i_section, material=material)
[docs] def mono_i_section( d: float, b_t: float, b_b: float, t_ft: float, t_fb: float, t_w: float, r: float, n_r: int, material: pre.Material = pre.DEFAULT_MATERIAL, ) -> geometry.Geometry: """Constructs a monosymmetric I section. Constructs a monosymmetric I section centered at ``(max(b_t, b_b)/2, d/2)``, with depth ``d``, top flange width ``b_t``, bottom flange width ``b_b``, top flange thickness ``t_ft``, top flange thickness ``t_fb``, web thickness ``t_w``, and root radius ``r``, using ``n_r`` points to construct the root radius. Args: d: Depth of the I section b_t: Top flange width b_b: Bottom flange width t_ft: Top flange thickness of the I section t_fb: Bottom flange thickness of the I section t_w: Web thickness of the I section r: Root radius of the I section n_r: Number of points discretising the root radius material: Material to associate with this geometry Returns: Monosymmetric I section geometry Example: The following example creates a monosymmetric I section with a depth of 200 mm, a top flange width of 50 mm, a top flange thickness of 12 mm, a bottom flange width of 130 mm, a bottom flange thickness of 8 mm, a web thickness of 6 mm and a root radius of 8 mm, using 16 points to discretise the root radius: .. plot:: :include-source: True :caption: Monosymmetric I section geometry from sectionproperties.pre.library import mono_i_section mono_i_section( d=200, b_t=50, b_b=130, t_ft=12, t_fb=8, t_w=6, r=8, n_r=16 ).plot_geometry() """ points: list[tuple[float, float]] = [] # calculate central axis x_central = max(b_t, b_b) * 0.5 # add first three points points.append((x_central - b_b * 0.5, 0)) points.append((x_central + b_b * 0.5, 0)) points.append((x_central + b_b * 0.5, t_fb)) # construct the bottom right radius pt = x_central + t_w * 0.5 + r, t_fb + r points += sp_utils.draw_radius(pt=pt, r=r, theta=1.5 * np.pi, n=n_r, ccw=False) # construct the top right radius pt = x_central + t_w * 0.5 + r, d - t_ft - r points += sp_utils.draw_radius(pt=pt, r=r, theta=np.pi, n=n_r, ccw=False) # add the next four points points.append((x_central + b_t * 0.5, d - t_ft)) points.append((x_central + b_t * 0.5, d)) points.append((x_central - b_t * 0.5, d)) points.append((x_central - b_t * 0.5, d - t_ft)) # construct the top left radius pt = x_central - t_w * 0.5 - r, d - t_ft - r points += sp_utils.draw_radius(pt=pt, r=r, theta=0.5 * np.pi, n=n_r, ccw=False) # construct the bottom left radius pt = x_central - t_w * 0.5 - r, t_fb + r points += sp_utils.draw_radius(pt=pt, r=r, theta=0, n=n_r, ccw=False) # add the last point points.append((x_central - b_b * 0.5, t_fb)) polygon = Polygon(points) return geometry.Geometry(geom=polygon, material=material)
[docs] def tapered_flange_i_section( d: float, b: float, t_f: float, t_w: float, r_r: float, r_f: float, alpha: float, n_r: int, material: pre.Material = pre.DEFAULT_MATERIAL, ) -> geometry.Geometry: """Constructs a tapered flange I section. Constructs a tapered flange I section centered at ``(b/2, d/2)``, with depth ``d*``, mid-flange thickness ``t_f``, web thickness ``t_w``, root radius ``r_r``, flange radius ``r_f`` and flange angle ``alpha``, using ``n_r`` points to construct the radii. Args: d: Depth of the tapered flange I section b: Width of the tapered flange I section t_f: Mid-flange thickness of the tapered flange I section (measured at the point equidistant from the face of the web to the edge of the flange) t_w: Web thickness of the tapered flange I section r_r: Root radius of the tapered flange I section r_f: Flange radius of the tapered flange I section alpha: Flange angle of the tapered flange I section in degrees n_r: Number of points discretising the radii material: Material to associate with this geometry Returns: Tapered flange I section geometry Example: The following example creates a tapered flange I section with a depth of 588 mm, a width of 191 mm, a mid-flange thickness of 27.2 mm, a web thickness of 15.2 mm, a root radius of 17.8 mm, a flange radius of 8.9 mm and a flange angle of 8°, using 16 points to discretise the radii: .. plot:: :include-source: True :caption: Tapered flange I section geometry from sectionproperties.pre.library import tapered_flange_i_section tapered_flange_i_section( d=588, b=191, t_f=27.2, t_w=15.2, r_r=17.8, r_f=8.9, alpha=8, n_r=16 ).plot_geometry() """ points: list[tuple[float, float]] = [] # calculate alpha in radians alpha_rad = np.pi * alpha / 180 # calculate the height of the flange toe and dimensions of the straight x1 = b * 0.25 - t_w * 0.25 - r_f * (1 - np.sin(alpha_rad)) y1 = x1 * np.tan(alpha_rad) x2 = b * 0.25 - t_w * 0.25 - r_r * (1 - np.sin(alpha_rad)) y2 = x2 * np.tan(alpha_rad) y_t = t_f - y1 - r_f * np.cos(alpha_rad) # add first two points points.append((0, 0)) points.append((b, 0)) # construct the bottom right flange toe radius if r_f == 0: points.append((b, y_t)) else: for i in range(n_r): # determine polar angle theta = i * 1.0 / max(1, n_r - 1) * (np.pi * 0.5 - alpha_rad) # calculate the locations of the radius points x = b - r_f + r_f * np.cos(theta) y = y_t + r_f * np.sin(theta) # append the current points to the points list points.append((x, y)) # construct the bottom right root radius if r_r == 0: points.append((b * 0.5 + t_w * 0.5, t_f + y2)) else: for i in range(n_r): # determine polar angle theta = (3.0 / 2 * np.pi - alpha_rad) - ( i * 1.0 / max(1, n_r - 1) * (np.pi * 0.5 - alpha_rad) ) # calculate the locations of the radius points x = b * 0.5 + t_w * 0.5 + r_r + r_r * np.cos(theta) y = t_f + y2 + r_r * np.cos(alpha_rad) + r_r * np.sin(theta) # append the current points to the points list points.append((x, y)) # construct the top right root radius if r_r == 0: points.append((b * 0.5 + t_w * 0.5, d - t_f - y2)) else: for i in range(n_r): # determine polar angle theta = np.pi - i * 1.0 / max(1, n_r - 1) * (np.pi * 0.5 - alpha_rad) # calculate the locations of the radius points x = b * 0.5 + t_w * 0.5 + r_r + r_r * np.cos(theta) y = d - t_f - y2 - r_r * np.cos(alpha_rad) + r_r * np.sin(theta) # append the current points to the points list points.append((x, y)) # construct the top right flange toe radius if r_f == 0: points.append((b, d - y_t)) else: for i in range(n_r): # determine polar angle theta = (3.0 * np.pi / 2 + alpha_rad) + i * 1.0 / max(1, n_r - 1) * ( np.pi * 0.5 - alpha_rad ) # calculate the locations of the radius points x = b - r_f + r_f * np.cos(theta) y = d - y_t + r_f * np.sin(theta) # append the current points to the points list points.append((x, y)) # add the next two points points.append((b, d)) points.append((0, d)) # construct the top left flange toe radius if r_f == 0: points.append((0, d - y_t)) else: for i in range(n_r): # determine polar angle theta = np.pi + (i * 1.0 / max(1, n_r - 1) * (np.pi * 0.5 - alpha_rad)) # calculate the locations of the radius points x = r_f + r_f * np.cos(theta) y = d - y_t + r_f * np.sin(theta) # append the current points to the points list points.append((x, y)) # construct the top left root radius if r_r == 0: points.append((b * 0.5 - t_w * 0.5, d - t_f - y2)) else: for i in range(n_r): # determine polar angle theta = (np.pi * 0.5 - alpha_rad) - ( i * 1.0 / max(1, n_r - 1) * (np.pi * 0.5 - alpha_rad) ) # calculate the locations of the radius points x = b * 0.5 - t_w * 0.5 - r_r + r_r * np.cos(theta) y = d - t_f - y2 - r_r * np.cos(alpha_rad) + r_r * np.sin(theta) # append the current points to the points list points.append((x, y)) # construct the bottom left root radius if r_r == 0: points.append((b * 0.5 - t_w * 0.5, t_f + y2)) else: for i in range(n_r): # determine polar angle theta = -i * 1.0 / max(1, n_r - 1) * (np.pi * 0.5 - alpha_rad) # calculate the locations of the radius points x = b * 0.5 - t_w * 0.5 - r_r + r_r * np.cos(theta) y = t_f + y2 + r_r * np.cos(alpha_rad) + r_r * np.sin(theta) # append the current points to the points list points.append((x, y)) # construct the bottom left flange toe radius if r_f == 0: points.append((0, y_t)) else: for i in range(n_r): # determine polar angle theta = (np.pi * 0.5 + alpha_rad) + ( i * 1.0 / max(1, n_r - 1) * (np.pi * 0.5 - alpha_rad) ) # calculate the locations of the radius points x = r_f + r_f * np.cos(theta) y = y_t + r_f * np.sin(theta) # append the current points to the points list points.append((x, y)) polygon = Polygon(points) return geometry.Geometry(geom=polygon, material=material)
[docs] def channel_section( d: float, b: float, t_f: float, t_w: float, r: float, n_r: int, material: pre.Material = pre.DEFAULT_MATERIAL, ) -> geometry.Geometry: """Constructs a parallel flange channel (PFC). Constructs a parallel flange channel (PFC) section with the bottom left corner at the origin ``(0, 0)``, with depth ``d``, width ``b``, flange thickness ``t_f``, web thickness ``t_w`` and root radius ``r``, using ``n_r`` points to construct the root radius. Args: d: Depth of the PFC section b: Width of the PFC section t_f: Flange thickness of the PFC section t_w: Web thickness of the PFC section r: Root radius of the PFC section n_r: Number of points discretising the root radius material: Material to associate with this geometry Returns: Parallel flange channel section geometry Example: The following example creates a PFC section with a depth of 250 mm, a width of 90 mm, a flange thickness of 15 mm, a web thickness of 8 mm and a root radius of 12 mm, using 8 points to discretise the root radius: .. plot:: :include-source: True :caption: Parallel flange channel section geometry from sectionproperties.pre.library import channel_section channel_section(d=250, b=90, t_f=15, t_w=8, r=12, n_r=8).plot_geometry() """ points: list[tuple[float, float]] = [] # add first three points points.append((0, 0)) points.append((b, 0)) points.append((b, t_f)) # construct the bottom right radius pt = t_w + r, t_f + r points += sp_utils.draw_radius(pt=pt, r=r, theta=1.5 * np.pi, n=n_r, ccw=False) # construct the top right radius pt = t_w + r, d - t_f - r points += sp_utils.draw_radius(pt=pt, r=r, theta=np.pi, n=n_r, ccw=False) # add last three points points.append((b, d - t_f)) points.append((b, d)) points.append((0, d)) polygon = Polygon(points) return geometry.Geometry(geom=polygon, material=material)
[docs] def tapered_flange_channel( d: float, b: float, t_f: float, t_w: float, r_r: float, r_f: float, alpha: float, n_r: int, material: pre.Material = pre.DEFAULT_MATERIAL, ) -> geometry.Geometry: """Constructs a tapered flange channel section. Constructs a tapered flange channel section with the bottom left corner at the origin ``(0, 0)``, with depth ``d``, width *b*, mid-flange thickness ``t_f``, web thickness ``t_w``, root radius ``r_r``, flange radius ``r_f`` and flange angle ``alpha``, using ``n_r`` points to construct the radii. Args: d: Depth of the tapered flange channel section b: Width of the tapered flange channel section t_f: Mid-flange thickness of the tapered flange channel section (measured at the point equidistant from the face of the web to the edge of the flange) t_w: Web thickness of the tapered flange channel section r_r: Root radius of the tapered flange channel section r_f: Flange radius of the tapered flange channel section alpha: Flange angle of the tapered flange channel section in degrees n_r: Number of points discretising the radii material: Material to associate with this geometry Returns: Tapered flange channel section geometry Example: The following example creates a tapered flange channel section with a depth of 10 in, a width of 3.5 in, a mid-flange thickness of 0.575 in, a web thickness of 0.475 in, a root radius of 0.575 in, a flange radius of 0.4 in and a flange angle of 8°, using 16 points to discretise the radii: .. plot:: :include-source: True :caption: Tapered flange channel section geometry from sectionproperties.pre.library import tapered_flange_channel tapered_flange_channel( d=10, b=3.5, t_f=0.575, t_w=0.475, r_r=0.575, r_f=0.4, alpha=8, n_r=16 ).plot_geometry() """ points: list[tuple[float, float]] = [] # calculate alpha in radians alpha_rad = np.pi * alpha / 180 # calculate the height of the flange toe and dimensions of the straight x1 = b * 0.5 - t_w * 0.5 - r_f * (1 - np.sin(alpha_rad)) y1 = x1 * np.tan(alpha_rad) x2 = b * 0.5 - t_w * 0.5 - r_r * (1 - np.sin(alpha_rad)) y2 = x2 * np.tan(alpha_rad) y_t = t_f - y1 - r_f * np.cos(alpha_rad) # add first two points points.append((0, 0)) points.append((b, 0)) # construct the bottom right flange toe radius if r_f == 0: points.append((b, y_t)) else: for i in range(n_r): # determine polar angle theta = i * 1.0 / max(1, n_r - 1) * (np.pi * 0.5 - alpha_rad) # calculate the locations of the radius points x = b - r_f + r_f * np.cos(theta) y = y_t + r_f * np.sin(theta) # append the current points to the points list points.append((x, y)) # construct the bottom right root radius if r_r == 0: points.append((t_w, t_f + y2)) else: for i in range(n_r): # determine polar angle theta = (3.0 / 2 * np.pi - alpha_rad) - ( i * 1.0 / max(1, n_r - 1) * (np.pi * 0.5 - alpha_rad) ) # calculate the locations of the radius points x = t_w + r_r + r_r * np.cos(theta) y = t_f + y2 + r_r * np.cos(alpha_rad) + r_r * np.sin(theta) # append the current points to the points list points.append((x, y)) # construct the top right root radius if r_r == 0: points.append((t_w, d - t_f - y2)) else: for i in range(n_r): # determine polar angle theta = np.pi - i * 1.0 / max(1, n_r - 1) * (np.pi * 0.5 - alpha_rad) # calculate the locations of the radius points x = t_w + r_r + r_r * np.cos(theta) y = d - t_f - y2 - r_r * np.cos(alpha_rad) + r_r * np.sin(theta) # append the current points to the points list points.append((x, y)) # construct the top right flange toe radius if r_f == 0: points.append((b, d - y_t)) else: for i in range(n_r): # determine polar angle theta = (3.0 * np.pi / 2 + alpha_rad) + ( i * 1.0 / max(1, n_r - 1) * (np.pi * 0.5 - alpha_rad) ) # calculate the locations of the radius points x = b - r_f + r_f * np.cos(theta) y = d - y_t + r_f * np.sin(theta) # append the current points to the points list points.append((x, y)) # add the final two points points.append((b, d)) points.append((0, d)) polygon = Polygon(points) return geometry.Geometry(geom=polygon, material=material)
[docs] def tee_section( d: float, b: float, t_f: float, t_w: float, r: float, n_r: int, material: pre.Material = pre.DEFAULT_MATERIAL, ) -> geometry.Geometry: """Constructs a tee section. Constructs a tee section with the top left corner at ``(0, d)``, with depth ``d``, width ``b``, flange thickness ``t_f``, web thickness ``t_w`` and root radius ``r``, using ``n_r`` points to construct the root radius. Args: d: Depth of the tee section b: Width of the tee section t_f: Flange thickness of the tee section t_w: Web thickness of the tee section r: Root radius of the tee section n_r: Number of points discretising the root radius material: Material to associate with this geometry Returns: Tee section geometry Example: The following example creates a tee section with a depth of 200 mm, a width of 100 mm, a flange thickness of 12 mm, a web thickness of 6 mm and a root radius of 8 mm, using 8 points to discretise the root radius: .. plot:: :include-source: True :caption: Tee section geometry from sectionproperties.pre.library import tee_section tee_section(d=200, b=100, t_f=12, t_w=6, r=8, n_r=8).plot_geometry() """ points: list[tuple[float, float]] = [] # add first two points points.append((b * 0.5 - t_w * 0.5, 0)) points.append((b * 0.5 + t_w * 0.5, 0)) # construct the top right radius pt = b * 0.5 + t_w * 0.5 + r, d - t_f - r points += sp_utils.draw_radius(pt=pt, r=r, theta=np.pi, n=n_r, ccw=False) # add next four points points.append((b, d - t_f)) points.append((b, d)) points.append((0, d)) points.append((0, d - t_f)) # construct the top left radius pt = b * 0.5 - t_w * 0.5 - r, d - t_f - r points += sp_utils.draw_radius(pt=pt, r=r, theta=0.5 * np.pi, n=n_r, ccw=False) polygon = Polygon(points) return geometry.Geometry(geom=polygon, material=material)
[docs] def angle_section( d: float, b: float, t: float, r_r: float, r_t: float, n_r: int, material: pre.Material = pre.DEFAULT_MATERIAL, ) -> geometry.Geometry: """Constructs an angle section. Constructs an angle section with the bottom left corner at the origin ``(0, 0)``, with depth ``d``, width ``b``, thickness ``t``, root radius ``r_r`` and toe radius ``r_t``, using ``n_r`` points to construct the radii. Args: d: Depth of the angle section b: Width of the angle section t: Thickness of the angle section r_r: Root radius of the angle section r_t: Toe radius of the angle section n_r: Number of points discretising the radii material: Material to associate with this geometry Returns: Angle section geometry Raises: ValueError: If the toe radius is larger than the toe thickness Example: The following example creates an angle section with a depth of 150 mm, a width of 100 mm, a thickness of 8 mm, a root radius of 12 mm and a toe radius of 5 mm, using 16 points to discretise the radii: .. plot:: :include-source: True :caption: Angle section geometry from sectionproperties.pre.library import angle_section angle_section(d=150, b=100, t=8, r_r=12, r_t=5, n_r=16).plot_geometry() """ if r_t > t: raise ValueError( "The radius of the toe (r_t) cannot be larger than the toe thickness (t)." ) points: list[tuple[float, float]] = [] # add first two points points.append((0, 0)) points.append((b, 0)) # construct the bottom toe radius pt = b - r_t, t - r_t points += sp_utils.draw_radius(pt=pt, r=r_t, theta=0, n=n_r) # construct the root radius pt = t + r_r, t + r_r points += sp_utils.draw_radius(pt=pt, r=r_r, theta=1.5 * np.pi, n=n_r, ccw=False) # construct the top toe radius pt = t - r_t, d - r_t points += sp_utils.draw_radius(pt=pt, r=r_t, theta=0, n=n_r) # add the next point points.append((0, d)) polygon = Polygon(points) return geometry.Geometry(geom=polygon, material=material)
[docs] def cee_section( d: float, b: float, l: float, t: float, r_out: float, n_r: int, material: pre.Material = pre.DEFAULT_MATERIAL, ) -> geometry.Geometry: """Constructs a cee section. Constructs a cee section (typical of cold-formed steel) with the bottom left corner at the origin ``(0, 0)``, with depth *d*, width ``b``, lip ``l``, thickness ``t`` and outer radius ``r_out``, using ``n_r`` points to construct the radius. If the outer radius is less than the thickness of the Cee Section, the inner radius is set to zero. Args: d: Depth of the cee section b: Width of the cee section l: Lip of the cee section (which can be zero) t: Thickness of the cee section r_out: Outer radius of the cee section n_r: Number of points discretising the outer radius material: Material to associate with this geometry Returns: Cee section geometry Example: The following example creates a cee section with a depth of 125 mm, a width of 30 mm, a lip of 30 mm, a thickness of 1.5 mm and an outer radius of 6 mm, using 8 points to discretise the radius: .. plot:: :include-source: True :caption: Cee section geometry from sectionproperties.pre.library import cee_section cee_section(d=125, b=50, l=30, t=1.5, r_out=6, n_r=8).plot_geometry() """ points: list[tuple[float, float]] = [] # calculate internal radius r_in = max(r_out - t, 0) # construct the outer bottom left radius points += sp_utils.draw_radius(pt=(r_out, r_out), r=r_out, theta=np.pi, n=n_r) # if the lip is longer than the outer radius (curve + straight section if l > r_out: # construct the outer bottom right radius points += sp_utils.draw_radius( pt=(b - r_out, r_out), r=r_out, theta=1.5 * np.pi, n=n_r ) # add next two points points.append((b, l)) points.append((b - t, l)) # construct the inner bottom right radius points += sp_utils.draw_radius( pt=(b - t - r_in, t + r_in), r=r_in, theta=0, n=n_r, ccw=False ) # if the lip is shorter than the outer radius (curve only) elif l > t and l <= r_out: # construct a smaller corner for bottom right if t < l < r_out r_out_l = l r_in_l = max(l - t, 0) points += sp_utils.draw_radius( pt=(b - r_out_l, r_out_l), r=r_out_l, theta=1.5 * np.pi, n=n_r ) points += sp_utils.draw_radius( pt=(b - t - r_in_l, t + r_in_l), r=r_in_l, theta=0, n=n_r, ccw=False ) # if the lip length is less than the section thickness (no lip) elif l <= t: # construct end as two points only points.append((b, 0)) points.append((b, t)) # construct the inner bottom left radius points += sp_utils.draw_radius( pt=(t + r_in, t + r_in), r=r_in, theta=1.5 * np.pi, n=n_r, ccw=False ) # construct the inner top left radius points += sp_utils.draw_radius( pt=(t + r_in, d - t - r_in), r=r_in, theta=np.pi, n=n_r, ccw=False ) # if the lip is longer than the outer radius (curve + straight section) if l > r_out: # construct the inner top right radius points += sp_utils.draw_radius( pt=(b - t - r_in, d - t - r_in), r=r_in, theta=0.5 * np.pi, n=n_r, ccw=False ) # add next two points points.append((b - t, d - l)) points.append((b, d - l)) # construct the outer top right radius points += sp_utils.draw_radius( pt=(b - r_out, d - r_out), r=r_out, theta=0, n=n_r ) # if the lip is shorter than the outer radius (curve only) elif l > t and l <= r_out: # construct a smaller corner for top right if t < l < r_out points += sp_utils.draw_radius( pt=(b - t - r_in_l, d - t - r_in_l), r=r_in_l, theta=0.5 * np.pi, n=n_r, ccw=False, ) points += sp_utils.draw_radius( pt=(b - r_out_l, d - r_out_l), r=r_out_l, theta=0, n=n_r ) # if the lip length is less than the section thickness (no lip) elif l <= t: # construct end as two points only points.append((b, d - t)) points.append((b, d)) # construct the outer top left radius points += sp_utils.draw_radius( pt=(r_out, d - r_out), r=r_out, theta=0.5 * np.pi, n=n_r ) polygon = Polygon(points) return geometry.Geometry(geom=polygon, material=material)
[docs] def zed_section( d: float, b_l: float, b_r: float, l: float, t: float, r_out: float, n_r: int, material: pre.Material = pre.DEFAULT_MATERIAL, ) -> geometry.Geometry: """Constructs a zed section. Constructs a zed section with the bottom left corner at the origin ``(0, 0)``, with depth``*d``, left flange width ``b_l``, right flange width ``b_r``, lip ``l``, thickness ``t`` and outer radius ``r_out``, using ``n_r`` points to construct the radius. If the outer radius is less than the thickness of the Zed Section, the inner radius is set to zero. Args: d: Depth of the zed section b_l: Left flange width of the zed section b_r: Right flange width of the zed section l: Lip of the zed section (which can be zero) t: Thickness of the zed section r_out: Outer radius of the zed section n_r: Number of points discretising the outer radius material: Material to associate with this geometry Returns: Zed section geometry Example: The following example creates a zed section with a depth of 100 mm, a left flange width of 40 mm, a right flange width of 50 mm, a lip of 20 mm, a thickness of 1.2 mm and an outer radius of 5 mm, using 8 points to discretise the radius: .. plot:: :include-source: True :caption: Zed section geometry from sectionproperties.pre.library import zed_section zed_section( d=100, b_l=40, b_r=50, l=20, t=1.2, r_out=5, n_r=8 ).plot_geometry() """ points: list[tuple[float, float]] = [] # calculate internal radius r_in = max(r_out - t, 0) # construct the outer bottom left radius points += sp_utils.draw_radius(pt=(r_out, r_out), r=r_out, theta=np.pi, n=n_r) # if the lip is longer than the outer radius (curve + straight section if l > r_out: # construct the outer bottom right radius points += sp_utils.draw_radius( pt=(b_r - r_out, r_out), r=r_out, theta=1.5 * np.pi, n=n_r ) # add next two points points.append((b_r, l)) points.append((b_r - t, l)) # construct the inner bottom right radius points += sp_utils.draw_radius( pt=(b_r - t - r_in, t + r_in), r=r_in, theta=0, n=n_r, ccw=False ) # if the lip is shorter than the outer radius (curve only) elif l > t and l <= r_out: # construct a smaller corner for bottom right if t < l < r_out r_out_l = l r_in_l = max(l - t, 0) points += sp_utils.draw_radius( pt=(b_r - r_out_l, r_out_l), r=r_out_l, theta=1.5 * np.pi, n=n_r ) points += sp_utils.draw_radius( pt=(b_r - t - r_in_l, t + r_in_l), r=r_in_l, theta=0, n=n_r, ccw=False ) # if the lip length is less than the section thickness (no lip) elif l <= t: # construct end as two points only points.append((b_r, 0)) points.append((b_r, t)) # construct the inner bottom left radius points += sp_utils.draw_radius( pt=(t + r_in, t + r_in), r=r_in, theta=1.5 * np.pi, n=n_r, ccw=False ) # construct the outer top right radius points += sp_utils.draw_radius(pt=(t - r_out, d - r_out), r=r_out, theta=0, n=n_r) # if the lip is longer than the outer radius (curve + straight section if l > r_out: # construct the outer top left radius points += sp_utils.draw_radius( pt=(t - b_l + r_out, d - r_out), r=r_out, theta=0.5 * np.pi, n=n_r ) # add the next two points points.append((t - b_l, d - l)) points.append((t - b_l + t, d - l)) # construct the inner top left radius points += sp_utils.draw_radius( pt=(2 * t - b_l + r_in, d - t - r_in), r=r_in, theta=np.pi, n=n_r, ccw=False ) # if the lip is shorter than the outer radius (curve only) elif l > t and l <= r_out: # construct a smaller corner for top left if t < l < r_out points += sp_utils.draw_radius( pt=(t - b_l + r_out_l, d - r_out_l), r=r_out_l, theta=0.5 * np.pi, n=n_r ) points += sp_utils.draw_radius( pt=(2 * t - b_l + r_in_l, d - t - r_in_l), r=r_in_l, theta=np.pi, n=n_r, ccw=False, ) # if the lip length is less than the section thickness (no lip) elif l <= t: # construct end as two points only points.append((t - b_l, d)) points.append((t - b_l, d - t)) # construct the inner top right radius points += sp_utils.draw_radius( pt=(-r_in, d - t - r_in), r=r_in, theta=0.5 * np.pi, n=n_r, ccw=False ) polygon = Polygon(points) return geometry.Geometry(geom=polygon, material=material)
[docs] def box_girder_section( d: float, b_t: float, b_b: float, t_ft: float, t_fb: float, t_w: float, material: pre.Material = pre.DEFAULT_MATERIAL, ) -> geometry.Geometry: """Constructs a box girder section. Constructs a box girder section centered at at ``(max(b_t, b_b)/2, d/2)``, with depth ``d``, top width ``b_t``, bottom width ``b_b``, top flange thickness ``t_ft``, bottom flange thickness ``t_fb`` and web thickness ``t_w``. Args: d: Depth of the box girder section b_t: Top width of the box girder section b_b: Bottom width of the box girder section t_ft: Top flange thickness of the box girder section t_fb: Bottom flange thickness of the box girder section t_w: Web thickness of the box girder section material: Material to associate with this geometry Returns: Box girder section geometry Example: The following example creates a box girder section with a depth of 1200 mm, a top width of 1200 mm, a bottom width of 400 mm, a top flange thickness of 100 mm, a bottom flange thickness of 80 mm and a web thickness of 50 mm: .. plot:: :include-source: True :caption: Box girder section geometry from sectionproperties.pre.library import box_girder_section box_girder_section( d=1200, b_t=1200, b_b=400, t_ft=100, t_fb=80, t_w=50 ).plot_geometry() """ outer_points: list[tuple[float, float]] = [] inner_points: list[tuple[float, float]] = [] # calculate central axis x_c = max(b_t, b_b) * 0.5 # determine side wall angle if b_t < b_b: phi_b = np.arctan2(d, 0.5 * (b_b - b_t)) phi_t = np.pi - phi_b else: phi_t = np.arctan2(d, 0.5 * (b_t - b_b)) phi_b = np.pi - phi_t # determine inner wall x-offsets x_bot = t_fb / np.tan(np.pi - phi_b) x_top = t_ft / np.tan(np.pi - phi_t) web_x = abs(t_w / np.sin(np.pi - phi_b)) # add outer points outer_points.append((x_c - 0.5 * b_b, 0)) outer_points.append((x_c + 0.5 * b_b, 0)) outer_points.append((x_c + 0.5 * b_t, d)) outer_points.append((x_c - 0.5 * b_t, d)) # add inner points inner_points.append((x_c - 0.5 * b_b - x_bot + web_x, t_fb)) inner_points.append((x_c + 0.5 * b_b + x_bot - web_x, t_fb)) inner_points.append((x_c + 0.5 * b_t + x_top - web_x, d - t_ft)) inner_points.append((x_c - 0.5 * b_t - x_top + web_x, d - t_ft)) outer_polygon = Polygon(outer_points) inner_polygon = Polygon(inner_points) return geometry.Geometry(geom=outer_polygon - inner_polygon, material=material)
[docs] def bulb_section( d: float, b: float, t: float, r: float, n_r: int, d_b: float | None = None, material: pre.Material = pre.DEFAULT_MATERIAL, ) -> geometry.Geometry: """Constructs a bulb section. Constructs a bulb section with the bottom left corner at the point ``(-t / 2, 0)``, with depth ``d``, bulb depth ``d_b``, bulb width``*b``, web thickness ``t`` and radius ``r``, using ``n_r`` points to construct the radius. Args: d: Depth of the section b: Bulb width t: Web thickness r: Bulb radius d_b: Depth of the bulb (automatically calculated for standard sections, if provided the section may have sharp edges) n_r: Number of points discretising the radius material: Material to associate with this geometry Returns: Bulb section geometry Example: The following example creates a bulb section with a depth of 240 mm, a width of 34 mm, a web thickness of 12 mm and a bulb radius of 16 mm, using 16 points to discretise the radius: .. plot:: :include-source: True :caption: Bulb section geometry from sectionproperties.pre.library import bulb_section bulb_section(d=240, b=34, t=12, r=10, n_r=16).plot_geometry() """ if d_b is None: d_b = r * np.cos(np.pi / 3) / np.cos(np.pi / 6) + r + b * np.tan(np.pi / 6) points: list[tuple[float, float]] = [] # add first two points points.append((-t * 0.5, 0)) points.append((t * 0.5, 0)) # test of additional radius if d_b is not None: dc = r / np.sin(2 / 3 * np.pi / 2) ptb0 = (t * 0.5 + dc * np.cos(np.pi / 6), d - d_b - dc * np.cos(np.pi / 3)) points += sp_utils.draw_radius( pt=ptb0, r=r, theta=np.pi, n=n_r, ccw=False, phi=np.pi / 3 ) # end of test of additional radius ptb = b + t * 0.5 - r, d - r # build radius points += sp_utils.draw_radius( pt=ptb, r=r, theta=-np.pi * 1 / 3, n=n_r, ccw=True, phi=np.pi / 3 ) points.pop() # delete duplicate point points += sp_utils.draw_radius(pt=ptb, r=r, theta=0, n=n_r, ccw=True) # build the top part points.append((-t * 0.5, d)) polygon = Polygon(points) return geometry.Geometry(geom=polygon, material=material)