from typing import Union, Optional
import numpy as np
import sectionproperties.pre.pre as pre
import sectionproperties.pre.geometry as geometry
import sectionproperties.pre.library.primitive_sections as primitive_sections
[docs]def concrete_rectangular_section(
b: float,
d: float,
dia_top: float,
n_top: int,
dia_bot: float,
n_bot: int,
n_circle: int,
cover: float,
dia_side: Optional[float] = None,
n_side: int = 0,
area_top: Optional[float] = None,
area_bot: Optional[float] = None,
area_side: Optional[float] = None,
conc_mat: pre.Material = pre.DEFAULT_MATERIAL,
steel_mat: pre.Material = pre.DEFAULT_MATERIAL,
) -> geometry.CompoundGeometry:
"""Constructs a concrete rectangular section of width *b* and depth *d*, with
*n_top* top steel bars of diameter *dia_top*, *n_bot* bottom steel bars of diameter
*dia_bot*, *n_side* left & right side steel bars of diameter *dia_side* discretised
with *n_circle* points with equal side and top/bottom *cover* to the steel.
:param float b: Concrete section width
:param float d: Concrete section depth
:param float dia_top: Diameter of the top steel reinforcing bars
:param int n_top: Number of top steel reinforcing bars
:param float dia_bot: Diameter of the bottom steel reinforcing bars
:param int n_bot: Number of bottom steel reinforcing bars
:param int n_circle: Number of points discretising the steel reinforcing bars
:param float cover: Side and bottom cover to the steel reinforcing bars
:param float dia_side: If provided, diameter of the side steel reinforcing bars
:param int n_side: If provided, number of side bars either side of the section
:param float area_top: If provided, constructs top reinforcing bars based on their
area rather than diameter (prevents the underestimation of steel area due to
circle discretisation)
:param float area_bot: If provided, constructs bottom reinforcing bars based on
their area rather than diameter (prevents the underestimation of steel area due
to circle discretisation)
:param float area_side: If provided, constructs side reinforcing bars based on
their area rather than diameter (prevents the underestimation of steel area due
to circle discretisation)
:param conc_mat: Material to associate with the concrete
:param steel_mat: Material to associate with the steel
:raises ValueError: If the number of bars is not greater than or equal to 2 in an
active layer
The following example creates a 600D x 300W concrete beam with 3N20 bottom steel
reinforcing bars and 30 mm cover::
from sectionproperties.pre.library.concrete_sections import concrete_rectangular_section
from sectionproperties.pre.pre import Material
concrete = Material(
name='Concrete', elastic_modulus=30.1e3, poissons_ratio=0.2, yield_strength=32,
density=2.4e-6, color='lightgrey'
)
steel = Material(
name='Steel', elastic_modulus=200e3, poissons_ratio=0.3, yield_strength=500,
density=7.85e-6, color='grey'
)
geometry = concrete_rectangular_section(
b=300, d=600, dia_top=20, n_top=0, dia_bot=20, n_bot=3, n_circle=24, cover=30,
conc_mat=concrete, steel_mat=steel
)
geometry.create_mesh(mesh_sizes=[500])
.. figure:: ../images/sections/concrete_rectangular_section_geometry.png
:align: center
:scale: 50 %
Concrete rectangular section geometry.
.. figure:: ../images/sections/concrete_rectangular_section_mesh.png
:align: center
:scale: 50 %
Mesh generated from the above geometry.
"""
if n_top == 1 or n_bot == 1:
raise ValueError("If adding a reinforcing layer, provide 2 or more bars.")
# create rectangular concrete geometry
geom = primitive_sections.rectangular_section(b=b, d=d, material=conc_mat)
# calculate reinforcing bar dimensions for top and bottom layers
x_i_top = cover + dia_top / 2
x_i_bot = cover + dia_bot / 2
spacing_top = (b - 2 * cover - dia_top) / (n_top - 1)
spacing_bot = (b - 2 * cover - dia_bot) / (n_bot - 1)
# calculate reinforcing bar dimensions for side layers if specified
if n_side != 0:
x_i_side_left = cover + dia_side / 2
x_i_side_right = b - x_i_side_left
spacing_side = (d - 2 * cover - dia_top / 2 - dia_bot / 2) / (n_side + 1)
if area_top is None:
area_top = np.pi * dia_top**2 / 4
if area_bot is None:
area_bot = np.pi * dia_bot**2 / 4
if area_side is None and dia_side is not None:
area_side = np.pi * dia_side**2 / 4
# add top bars
for i in range(n_top):
bar = primitive_sections.circular_section_by_area(
area=area_top, n=n_circle, material=steel_mat
)
bar = bar.shift_section(
x_offset=x_i_top + spacing_top * i, y_offset=d - cover - dia_top / 2
)
geom = (geom - bar) + bar
# add bot bars
for i in range(n_bot):
bar = primitive_sections.circular_section_by_area(
area=area_bot, n=n_circle, material=steel_mat
)
bar = bar.shift_section(
x_offset=x_i_bot + spacing_bot * i, y_offset=cover + dia_bot / 2
)
geom = (geom - bar) + bar
# add side bars if specified
if n_side != 0:
for i in range(n_side):
bar_left = primitive_sections.circular_section_by_area(
area=area_side, n=n_circle, material=steel_mat
)
bar_right = bar_left
bar_left = bar_left.shift_section(
x_offset=x_i_side_left,
y_offset=cover + dia_bot / 2 + spacing_side * (i + 1),
)
bar_right = bar_right.shift_section(
x_offset=x_i_side_right,
y_offset=cover + dia_bot / 2 + spacing_side * (i + 1),
)
geom = (geom - bar_left - bar_right) + bar_left + bar_right
return geom
[docs]def concrete_column_section(
b: float,
d: float,
cover: float,
n_bars_b: int,
n_bars_d: int,
dia_bar: float,
bar_area: Optional[float] = None,
conc_mat: pre.Material = pre.DEFAULT_MATERIAL,
steel_mat: pre.Material = pre.DEFAULT_MATERIAL,
filled: bool = False,
n_circle: int = 4,
) -> geometry.CompoundGeometry:
"""Constructs a concrete rectangular section of width *b* and depth *d*, with
steel bar reinforcing organized as an *n_bars_b* by *n_bars_d* array, discretised
with *n_circle* points with equal sides and top/bottom *cover* to the steel which
is taken as the clear cover (edge of bar to edge of concrete).
:param float b: Concrete section width, parallel to the x-axis
:param float d: Concrete section depth, parallel to the y-axis
:param float cover: Clear cover, calculated as distance from edge of reinforcing bar to edge of section.
:param int n_bars_b: Number of bars placed across the width of the section, minimum 2.
:param int n_bars_d: Number of bars placed across the depth of the section, minimum 2.
:param float dia_bar: Diameter of reinforcing bars. Used for calculating bar placement and,
optionally, for calculating the bar area for section capacity calculations.
:param float bar_area: Area of reinforcing bars. Used for section capacity calculations.
If not provided, then dia_bar will be used to calculate the bar area.
:param sectionproperties.pre.pre.Material conc_mat: Material to
associate with the concrete
:param sectionproperties.pre.pre.Material steel_mat: Material to
associate with the reinforcing steel
:param bool filled: When True, will populate the concrete section with an equally
spaced 2D array of reinforcing bars numbering 'n_bars_b' by 'n_bars_d'.
When False, only the bars around the perimeter of the array will be present.
:param int n_circle: The number of points used to discretize the circle of the reinforcing
bars. The bars themselves will have an exact area of 'bar_area' regardless of the
number of points used in the circle. Useful for making the reinforcing bars look
more circular when plotting the concrete section.
:raises ValueError: If the number of bars in either 'n_bars_b' or 'n_bars_d' is not greater
than or equal to 2.
The following example creates a 600D x 300W concrete column with 25 mm diameter
reinforcing bars each with 500 mm**2 area and 35 mm cover in a 3x6 array without
the interior bars being filled::
from sectionproperties.pre.library.concrete_sections import concrete_column_section
from sectionproperties.pre.pre import Material
concrete = Material(
name='Concrete', elastic_modulus=30.1e3, poissons_ratio=0.2, yield_strength=32,
density=2.4e-6, color='lightgrey'
)
steel = Material(
name='Steel', elastic_modulus=200e3, poissons_ratio=0.3, yield_strength=500,
density=7.85e-6, color='grey'
)
geometry = concrete_column_section(
b=300, d=600, dia_bar=25, bar_area=500, cover=35, n_bars_b=3, n_bars_d=6,
conc_mat=concrete, steel_mat=steel, filled=False, n_circle=4
)
geometry.create_mesh(mesh_sizes=[500])
"""
concrete_geometry = primitive_sections.rectangular_section(b, d, material=conc_mat)
bar_extents = concrete_geometry.offset_perimeter(
-cover - dia_bar / 2
).calculate_extents()
bar_x_min, bar_x_max, bar_y_min, bar_y_max = bar_extents
b_edge_bars_x = np.linspace(bar_x_min, bar_x_max, n_bars_b)
d_edge_bars_y = np.linspace(bar_y_min, bar_y_max, n_bars_d)
if not filled:
b_edge_bars_y1 = [bar_y_min] * n_bars_b
b_edge_bars_y2 = [bar_y_max] * n_bars_b
d_edge_bars_x1 = [bar_x_min] * n_bars_d
d_edge_bars_x2 = [bar_x_max] * n_bars_d
b_edge_bars_top = list(zip(b_edge_bars_x, b_edge_bars_y2))
b_edge_bars_bottom = list(zip(b_edge_bars_x, b_edge_bars_y1))
d_edge_bars_right = list(zip(d_edge_bars_x2, d_edge_bars_y))
d_edge_bars_left = list(zip(d_edge_bars_x1, d_edge_bars_y))
all_bar_coords = list(
set(
b_edge_bars_top
+ b_edge_bars_bottom
+ d_edge_bars_right
+ d_edge_bars_left
)
)
if filled:
xy = np.meshgrid(b_edge_bars_x, d_edge_bars_y)
all_bar_coords = np.append(xy[0].reshape(-1, 1), xy[1].reshape(-1, 1), axis=1)
if bar_area is None:
bar_area = np.pi * dia_bar**2 / 4
for bar_coord in all_bar_coords:
concrete_geometry = add_bar(
concrete_geometry,
area=bar_area,
material=steel_mat,
x=bar_coord[0],
y=bar_coord[1],
n=n_circle,
)
return concrete_geometry
[docs]def concrete_tee_section(
b: float,
d: float,
b_f: float,
d_f: float,
dia_top: float,
n_top: int,
dia_bot: float,
n_bot: int,
n_circle: int,
cover: float,
area_top: Optional[float] = None,
area_bot: Optional[float] = None,
conc_mat: pre.Material = pre.DEFAULT_MATERIAL,
steel_mat: pre.Material = pre.DEFAULT_MATERIAL,
) -> geometry.CompoundGeometry:
"""Constructs a concrete tee section of width *b*, depth *d*, flange width *b_f*
and flange depth *d_f*, with *n_top* top steel bars of diameter *dia_top*, *n_bot*
bottom steel bars of diameter *dia_bot*, discretised with *n_circle* points with
equal side and top/bottom *cover* to the steel.
:param float b: Concrete section width
:param float d: Concrete section depth
:param float b_f: Concrete section flange width
:param float d_f: Concrete section flange depth
:param float dia_top: Diameter of the top steel reinforcing bars
:param int n_top: Number of top steel reinforcing bars
:param float dia_bot: Diameter of the bottom steel reinforcing bars
:param int n_bot: Number of bottom steel reinforcing bars
:param int n_circle: Number of points discretising the steel reinforcing bars
:param float cover: Side and bottom cover to the steel reinforcing bars
:param float area_top: If provided, constructs top reinforcing bars based on their
area rather than diameter (prevents the underestimation of steel area due to
circle discretisation)
:param float area_bot: If provided, constructs bottom reinforcing bars based on
their area rather than diameter (prevents the underestimation of steel area due
to circle discretisation)
:param conc_mat: Material to associatewith the concrete
:param steel_mat: Material toassociate with the steel
:raises ValueErorr: If the number of bars is not greater than or equal to 2 in an
active layer
The following example creates a 900D x 450W concrete beam with a 1200W x 250D
flange, with 5N24 steel reinforcing bars and 30 mm cover::
from sectionproperties.pre.library.concrete_sections import concrete_tee_section
from sectionproperties.pre.pre import Material
concrete = Material(
name='Concrete', elastic_modulus=30.1e3, poissons_ratio=0.2, yield_strength=32,
density=2.4e-6, color='lightgrey'
)
steel = Material(
name='Steel', elastic_modulus=200e3, poissons_ratio=0.3, yield_strength=500,
density=7.85e-6, color='grey'
)
geometry = concrete_tee_section(
b=450, d=900, b_f=1200, d_f=250, dia_top=24, n_top=0, dia_bot=24, n_bot=5,
n_circle=24, cover=30, conc_mat=concrete, steel_mat=steel
)
geometry.create_mesh(mesh_sizes=[500])
.. figure:: ../images/sections/concrete_tee_section_geometry.png
:align: center
:scale: 50 %
Concrete tee section geometry.
.. figure:: ../images/sections/concrete_tee_section_mesh.png
:align: center
:scale: 50 %
Mesh generated from the above geometry.
"""
if n_top == 1 or n_bot == 1:
raise ValueError("If adding a reinforcing layer, provide 2 or more bars.")
# generate tee-section
geom = primitive_sections.rectangular_section(b=b, d=d - d_f, material=conc_mat)
flange = primitive_sections.rectangular_section(b=b_f, d=d_f, material=conc_mat)
geom += flange.align_center(align_to=geom).align_to(other=geom, on="top")
# calculate reinforcing bar dimensions
x_i_top = cover + dia_top / 2 + 0.5 * (b - b_f)
x_i_bot = cover + dia_bot / 2
spacing_top = (b_f - 2 * cover - dia_top) / (n_top - 1)
spacing_bot = (b - 2 * cover - dia_bot) / (n_bot - 1)
if area_top is None:
area_top = np.pi * dia_top**2 / 4
if area_bot is None:
area_bot = np.pi * dia_bot**2 / 4
# add top bars
for i in range(n_top):
bar = primitive_sections.circular_section_by_area(
area=area_top, n=n_circle, material=steel_mat
)
bar = bar.shift_section(
x_offset=x_i_top + spacing_top * i, y_offset=d - cover - dia_top / 2
)
geom = (geom - bar) + bar
# add bot bars
for i in range(n_bot):
bar = primitive_sections.circular_section_by_area(
area=area_bot, n=n_circle, material=steel_mat
)
bar = bar.shift_section(
x_offset=x_i_bot + spacing_bot * i, y_offset=cover + dia_bot / 2
)
geom = (geom - bar) + bar
return geom
[docs]def concrete_circular_section(
d: float,
n: int,
dia: float,
n_bar: int,
n_circle: int,
cover: float,
area_conc: Optional[float] = None,
area_bar: Optional[float] = None,
conc_mat: pre.Material = pre.DEFAULT_MATERIAL,
steel_mat: pre.Material = pre.DEFAULT_MATERIAL,
) -> geometry.CompoundGeometry:
"""Constructs a concrete circular section of diameter *d* discretised with *n*
points, with *n_bar* steel bars of diameter *dia*, discretised with *n_circle*
points with equal side and bottom *cover* to the steel.
:param float d: Concrete diameter
:param float n: Number of points discretising the concrete section
:param float dia: Diameter of the steel reinforcing bars
:param int n_bar: Number of steel reinforcing bars
:param int n_circle: Number of points discretising the steel reinforcing bars
:param float cover: Side and bottom cover to the steel reinforcing bars
:param float area_conc: If provided, constructs the concrete based on its area
rather than diameter (prevents the underestimation of concrete area due to
circle discretisation)
:param float area_bar: If provided, constructs reinforcing bars based on their area
rather than diameter (prevents the underestimation of steel area due to
:param conc_mat: Material to associate with the concrete
:param steel_mat: Material to associate with the steel
:raises ValueErorr: If the number of bars is not greater than or equal to 2
The following example creates a 450DIA concrete column with with 6N20 steel
reinforcing bars and 45 mm cover::
from sectionproperties.pre.library.concrete_sections import concrete_circular_section
from sectionproperties.pre.pre import Material
concrete = Material(
name='Concrete', elastic_modulus=30.1e3, poissons_ratio=0.2, yield_strength=32,
density=2.4e-6, color='lightgrey'
)
steel = Material(
name='Steel', elastic_modulus=200e3, poissons_ratio=0.3, yield_strength=500,
density=7.85e-6, color='grey'
)
geometry = concrete_circular_section(
d=450, n=64, dia=20, n_bar=6, n_circle=24, cover=45, conc_mat=concrete, steel_mat=steel
)
geometry.create_mesh(mesh_sizes=[500])
.. figure:: ../images/sections/concrete_circular_section_geometry.png
:align: center
:scale: 50 %
Concrete circular section geometry.
.. figure:: ../images/sections/concrete_circular_section_mesh.png
:align: center
:scale: 50 %
Mesh generated from the above geometry.
"""
if n_bar < 2:
raise ValueError("Please provide 2 or more steel reinforcing bars.")
# create circular geometry
if area_conc:
geom = primitive_sections.circular_section_by_area(
area=area_conc, n=n, material=conc_mat
)
else:
geom = primitive_sections.circular_section(d=d, n=n, material=conc_mat)
# calculate bar geometry
r = d / 2 - cover - dia / 2
d_theta = 2 * np.pi / n_bar
if area_bar is None:
area_bar = np.pi * dia**2 / 4
for i in range(n_bar):
bar = primitive_sections.circular_section_by_area(
area=area_bar, n=n_circle, material=steel_mat
)
bar = bar.shift_section(
x_offset=r * np.cos(i * d_theta), y_offset=r * np.sin(i * d_theta)
)
geom = (geom - bar) + bar
return geom
[docs]def add_bar(
geometry: Union[geometry.Geometry, geometry.CompoundGeometry],
area: float,
material: pre.DEFAULT_MATERIAL,
x: float,
y: float,
n: int = 4,
) -> geometry.CompoundGeometry:
"""Adds a reinforcing bar to a *sectionproperties* geometry.
Bars are discretised by four points by default.
:param geometry: Reinforced concrete geometry to which the new bar will be added
:param area: Bar cross-sectional area
:param material: Material object for the bar
:param x: x-position of the bar
:param y: y-position of the bar
:param n: Number of points to discretise the bar circle
:return: Reinforced concrete geometry with added bar
"""
bar = primitive_sections.circular_section_by_area(
area=area, n=n, material=material # type: ignore
).shift_section(x_offset=x, y_offset=y)
return (geometry - bar) + bar