1
+ from typing import Union , Optional
1
2
import numpy as np
2
3
from shapely .geometry import Polygon
3
4
import sectionproperties .pre .pre as pre
@@ -106,53 +107,40 @@ def concrete_rectangular_section(
106
107
x_i_side_right = b - x_i_side_left
107
108
spacing_side = (d - 2 * cover - dia_top / 2 - dia_bot / 2 ) / (n_side + 1 )
108
109
110
+ if area_top is None :
111
+ area_top = np .pi * dia_top ** 2 / 4
112
+ if area_bot is None :
113
+ area_bot = np .pi * dia_bot ** 2 / 4
114
+ if area_side is None and dia_side is not None :
115
+ area_side = np .pi * dia_side ** 2 / 4
116
+
109
117
# add top bars
110
118
for i in range (n_top ):
111
- if area_top :
112
- bar = primitive_sections .circular_section_by_area (
113
- area = area_top , n = n_circle , material = steel_mat
114
- )
115
- else :
116
- bar = primitive_sections .circular_section (
117
- d = dia_top , n = n_circle , material = steel_mat
118
- )
119
-
119
+ bar = primitive_sections .circular_section_by_area (
120
+ area = area_top , n = n_circle , material = steel_mat
121
+ )
120
122
bar = bar .shift_section (
121
123
x_offset = x_i_top + spacing_top * i , y_offset = d - cover - dia_top / 2
122
124
)
123
-
124
125
geom = (geom - bar ) + bar
125
126
126
127
# add bot bars
127
128
for i in range (n_bot ):
128
- if area_bot :
129
- bar = primitive_sections .circular_section_by_area (
130
- area = area_bot , n = n_circle , material = steel_mat
131
- )
132
- else :
133
- bar = primitive_sections .circular_section (
134
- d = dia_bot , n = n_circle , material = steel_mat
135
- )
136
-
129
+ bar = primitive_sections .circular_section_by_area (
130
+ area = area_bot , n = n_circle , material = steel_mat
131
+ )
137
132
bar = bar .shift_section (
138
133
x_offset = x_i_bot + spacing_bot * i , y_offset = cover + dia_bot / 2
139
134
)
140
-
141
135
geom = (geom - bar ) + bar
142
136
143
137
# add side bars if specified
144
138
if n_side != 0 :
145
139
for i in range (n_side ):
146
- if area_side :
147
- bar_left = primitive_sections .circular_section_by_area (
148
- area = area_side , n = n_circle , material = steel_mat
149
- )
150
- bar_right = bar_left
151
- else :
152
- bar_left = primitive_sections .circular_section (
153
- d = dia_side , n = n_circle , material = steel_mat
154
- )
155
- bar_right = bar_left
140
+ bar_left = primitive_sections .circular_section_by_area (
141
+ area = area_side , n = n_circle , material = steel_mat
142
+ )
143
+ bar_right = bar_left
156
144
157
145
bar_left = bar_left .shift_section (
158
146
x_offset = x_i_side_left ,
@@ -168,6 +156,129 @@ def concrete_rectangular_section(
168
156
return geom
169
157
170
158
159
+ def concrete_column_section (
160
+ b : float ,
161
+ d : float ,
162
+ cover : float ,
163
+ n_bars_b : int ,
164
+ n_bars_d : int ,
165
+ dia_bar : float ,
166
+ bar_area : Optional [float ] = None ,
167
+ conc_mat : pre .Material = pre .DEFAULT_MATERIAL ,
168
+ steel_mat : pre .Material = pre .DEFAULT_MATERIAL ,
169
+ filled : bool = False ,
170
+ n_circle : int = 4 ,
171
+ ) -> geometry .CompoundGeometry :
172
+ """Constructs a concrete rectangular section of width *b* and depth *d*, with
173
+ steel bar reinforcing organized as an *n_bars_b* by *n_bars_d* array, discretised
174
+ with *n_circle* points with equal sides and top/bottom *cover* to the steel which
175
+ is taken as the clear cover (edge of bar to edge of concrete).
176
+
177
+ :param float b: Concrete section width, parallel to the x-axis
178
+ :param float d: Concrete section depth, parallel to the y-axis
179
+ :param float cover: Clear cover, calculated as distance from edge of reinforcing bar to edge of section.
180
+ :param int n_bars_b: Number of bars placed across the width of the section, minimum 2.
181
+ :param int n_bars_d: Number of bars placed across the depth of the section, minimum 2.
182
+ :param float dia_bar: Diameter of reinforcing bars. Used for calculating bar placement and,
183
+ optionally, for calculating the bar area for section capacity calculations.
184
+ :param Optional[float] bar_area: Area of reinforcing bars. Used for section capacity calculations.
185
+ If not provided, then dia_bar will be used to calculate the bar area.
186
+ :param Optional[sectionproperties.pre.pre.Material] conc_mat: Material to
187
+ associate with the concrete
188
+ :param Optional[sectionproperties.pre.pre.Material] steel_mat: Material to
189
+ associate with the reinforcing steel
190
+ :param bool filled: When True, will populate the concrete section with an equally
191
+ spaced 2D array of reinforcing bars numbering 'n_bars_b' by 'n_bars_d'.
192
+ When False, only the bars around the perimeter of the array will be present.
193
+ :param int n_circle: The number of points used to discretize the circle of the reinforcing
194
+ bars. The bars themselves will have an exact area of 'bar_area' regardless of the
195
+ number of points used in the circle. Useful for making the reinforcing bars look
196
+ more circular when plotting the concrete section.
197
+
198
+ :raises ValueError: If the number of bars in either 'n_bars_b' or 'n_bars_d' is not greater
199
+ than or equal to 2.
200
+
201
+ The following example creates a 600D x 300W concrete column with 25 mm diameter
202
+ reinforcing bars each with 500 mm**2 area and 35 mm cover in a 3x6 array without
203
+ the interior bars being filled::
204
+
205
+ from sectionproperties.pre.library.concrete_sections import concrete_column_section
206
+ from sectionproperties.pre.pre import Material
207
+
208
+ concrete = Material(
209
+ name='Concrete', elastic_modulus=30.1e3, poissons_ratio=0.2, yield_strength=32,
210
+ density=2.4e-6, color='lightgrey'
211
+ )
212
+ steel = Material(
213
+ name='Steel', elastic_modulus=200e3, poissons_ratio=0.3, yield_strength=500,
214
+ density=7.85e-6, color='grey'
215
+ )
216
+
217
+ geometry = concrete_column_section(
218
+ b=300, d=600, dia_bar=25, bar_area=500, cover=35, n_bars_b=3, n_bars_d=6,
219
+ conc_mat=concrete, steel_mat=steel, filled=False, n_circle=4
220
+ )
221
+ geometry.create_mesh(mesh_sizes=[500])
222
+
223
+ .. figure:: ../images/sections/concrete_rectangular_section_geometry.png
224
+ :align: center
225
+ :scale: 50 %
226
+
227
+ Concrete rectangular section geometry.
228
+
229
+ .. figure:: ../images/sections/concrete_rectangular_section_mesh.png
230
+ :align: center
231
+ :scale: 50 %
232
+
233
+ Mesh generated from the above geometry.
234
+ """
235
+ concrete_geometry = primitive_sections .rectangular_section (b , d , material = conc_mat )
236
+ bar_extents = concrete_geometry .offset_perimeter (
237
+ - cover - dia_bar / 2
238
+ ).calculate_extents ()
239
+ bar_x_min , bar_x_max , bar_y_min , bar_y_max = bar_extents
240
+
241
+ b_edge_bars_x = np .linspace (bar_x_min , bar_x_max , n_bars_b )
242
+ d_edge_bars_y = np .linspace (bar_y_min , bar_y_max , n_bars_d )
243
+
244
+ if not filled :
245
+ b_edge_bars_y1 = [bar_y_min ] * n_bars_b
246
+ b_edge_bars_y2 = [bar_y_max ] * n_bars_b
247
+
248
+ d_edge_bars_x1 = [bar_x_min ] * n_bars_d
249
+ d_edge_bars_x2 = [bar_x_max ] * n_bars_d
250
+
251
+ b_edge_bars_top = list (zip (b_edge_bars_x , b_edge_bars_y2 ))
252
+ b_edge_bars_bottom = list (zip (b_edge_bars_x , b_edge_bars_y1 ))
253
+ d_edge_bars_right = list (zip (d_edge_bars_x2 , d_edge_bars_y ))
254
+ d_edge_bars_left = list (zip (d_edge_bars_x1 , d_edge_bars_y ))
255
+
256
+ all_bar_coords = list (
257
+ set (
258
+ b_edge_bars_top
259
+ + b_edge_bars_bottom
260
+ + d_edge_bars_right
261
+ + d_edge_bars_left
262
+ )
263
+ )
264
+ if filled :
265
+ xy = np .meshgrid (b_edge_bars_x , d_edge_bars_y )
266
+ all_bar_coords = np .append (xy [0 ].reshape (- 1 , 1 ), xy [1 ].reshape (- 1 , 1 ), axis = 1 )
267
+
268
+ if bar_area is None :
269
+ bar_area = np .pi * dia_bar ** 2 / 4
270
+ for bar_coord in all_bar_coords :
271
+ concrete_geometry = add_bar (
272
+ concrete_geometry ,
273
+ area = bar_area ,
274
+ material = steel_mat ,
275
+ x = bar_coord [0 ],
276
+ y = bar_coord [1 ],
277
+ n = n_circle ,
278
+ )
279
+ return concrete_geometry
280
+
281
+
171
282
def concrete_tee_section (
172
283
b : float ,
173
284
d : float ,
@@ -261,38 +372,29 @@ def concrete_tee_section(
261
372
spacing_top = (b_f - 2 * cover - dia_top ) / (n_top - 1 )
262
373
spacing_bot = (b - 2 * cover - dia_bot ) / (n_bot - 1 )
263
374
375
+ if area_top is None :
376
+ area_top = np .pi * dia_top ** 2 / 4
377
+ if area_bot is None :
378
+ area_bot = np .pi * dia_bot ** 2 / 4
379
+
264
380
# add top bars
265
381
for i in range (n_top ):
266
- if area_top :
267
- bar = primitive_sections .circular_section_by_area (
268
- area = area_top , n = n_circle , material = steel_mat
269
- )
270
- else :
271
- bar = primitive_sections .circular_section (
272
- d = dia_top , n = n_circle , material = steel_mat
273
- )
274
-
382
+ bar = primitive_sections .circular_section_by_area (
383
+ area = area_top , n = n_circle , material = steel_mat
384
+ )
275
385
bar = bar .shift_section (
276
386
x_offset = x_i_top + spacing_top * i , y_offset = d - cover - dia_top / 2
277
387
)
278
-
279
388
geom = (geom - bar ) + bar
280
389
281
390
# add bot bars
282
391
for i in range (n_bot ):
283
- if area_bot :
284
- bar = primitive_sections .circular_section_by_area (
285
- area = area_bot , n = n_circle , material = steel_mat
286
- )
287
- else :
288
- bar = primitive_sections .circular_section (
289
- d = dia_bot , n = n_circle , material = steel_mat
290
- )
291
-
392
+ bar = primitive_sections .circular_section_by_area (
393
+ area = area_bot , n = n_circle , material = steel_mat
394
+ )
292
395
bar = bar .shift_section (
293
396
x_offset = x_i_bot + spacing_bot * i , y_offset = cover + dia_bot / 2
294
397
)
295
-
296
398
geom = (geom - bar ) + bar
297
399
298
400
return geom
@@ -380,20 +482,41 @@ def concrete_circular_section(
380
482
r = d / 2 - cover - dia / 2
381
483
d_theta = 2 * np .pi / n_bar
382
484
485
+ if area_bar is None :
486
+ area_bar = np .pi * dia ** 2 / 4
383
487
for i in range (n_bar ):
384
- if area_bar :
385
- bar = primitive_sections .circular_section_by_area (
386
- area = area_bar , n = n_circle , material = steel_mat
387
- )
388
- else :
389
- bar = primitive_sections .circular_section (
390
- d = dia , n = n_circle , material = steel_mat
391
- )
392
-
488
+ bar = primitive_sections .circular_section_by_area (
489
+ area = area_bar , n = n_circle , material = steel_mat
490
+ )
393
491
bar = bar .shift_section (
394
492
x_offset = r * np .cos (i * d_theta ), y_offset = r * np .sin (i * d_theta )
395
493
)
396
-
397
494
geom = (geom - bar ) + bar
398
495
399
496
return geom
497
+
498
+
499
+ def add_bar (
500
+ geometry : Union [geometry .Geometry , geometry .CompoundGeometry ],
501
+ area : float ,
502
+ material : pre .DEFAULT_MATERIAL ,
503
+ x : float ,
504
+ y : float ,
505
+ n : int = 4 ,
506
+ ) -> geometry .CompoundGeometry :
507
+ """Adds a reinforcing bar to a *sectionproperties* geometry.
508
+ Bars are discretised by four points by default.
509
+ :param geometry: Reinforced concrete geometry to which the new bar will be added
510
+ :param area: Bar cross-sectional area
511
+ :param material: Material object for the bar
512
+ :param x: x-position of the bar
513
+ :param y: y-position of the bar
514
+ :param n: Number of points to discretise the bar circle
515
+ :return: Reinforced concrete geometry with added bar
516
+ """
517
+
518
+ bar = primitive_sections .circular_section_by_area (
519
+ area = area , n = n , material = material # type: ignore
520
+ ).shift_section (x_offset = x , y_offset = y )
521
+
522
+ return (geometry - bar ) + bar
0 commit comments