Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rectangular reinforced cross section (including visualisation) #351

Merged
merged 69 commits into from
Nov 6, 2024
Merged
Show file tree
Hide file tree
Changes from 46 commits
Commits
Show all changes
69 commits
Select commit Hold shift + click to select a range
8313137
correct error catching
egarciamendez Jul 31, 2024
17945cd
m to mm unit conversion
egarciamendez Jul 31, 2024
66e74b8
mm2/m type alias
egarciamendez Jul 31, 2024
97bf9d5
stirrups added
egarciamendez Jul 31, 2024
6dac915
m3/m type alias
egarciamendez Jul 31, 2024
d5f1585
Merge branch 'refs/heads/main' into adding_reinforcement_configurations
egarciamendez Jul 31, 2024
1729392
main reinforcement configurations
egarciamendez Aug 2, 2024
13c0579
docs
egarciamendez Aug 2, 2024
6aa6c60
stirrups formed by a polygon
egarciamendez Aug 12, 2024
10720e8
base for all reinforcement cross-sections
egarciamendez Aug 12, 2024
8b5f4e7
moving shapes to a more logical place
egarciamendez Aug 12, 2024
6de7ff2
empty file deleted
egarciamendez Aug 12, 2024
e98d1ac
import fixed
egarciamendez Aug 12, 2024
82a392e
error message
egarciamendez Aug 12, 2024
fbfa7e7
Merge branch 'refs/heads/main' into adding_reinforcement_configurations
egarciamendez Aug 24, 2024
316359e
fixing tests
egarciamendez Aug 24, 2024
fd8ec92
testing to_rebars method
egarciamendez Aug 24, 2024
e856cd4
fail early when checking for start/end
egarciamendez Aug 24, 2024
954ef1f
add stirrups tests
egarciamendez Aug 24, 2024
c031ea4
add rectangular concrete cover info
egarciamendez Aug 24, 2024
529e6a5
Stirrup -> StirrupConfiguration | to better reflect what it does
egarciamendez Aug 24, 2024
9d22f7d
Stirrup -> StirrupConfiguration | to better reflect what it does
egarciamendez Aug 24, 2024
f20f21d
Stirrup -> StirrupConfiguration | to better reflect what it does
egarciamendez Aug 24, 2024
41e0321
make sure that the geometry of a stirrup is always correctly oriented
egarciamendez Aug 24, 2024
410672a
check that the outside edge of a stirrup configuration is fully insid…
egarciamendez Aug 24, 2024
15523fd
docs
egarciamendez Aug 24, 2024
a4a8285
docs
egarciamendez Aug 24, 2024
598477f
yagni
egarciamendez Aug 24, 2024
716e9fb
check needs to be the other way around off course
egarciamendez Sep 4, 2024
9a2b59f
cross section contains rebar
egarciamendez Sep 4, 2024
96de70b
get stirrups and present steel materials in rcs
egarciamendez Sep 4, 2024
8e4516f
flexible way to add reinforcement configurations
egarciamendez Sep 4, 2024
8ff1ced
Merge branch 'refs/heads/main' into adding_reinforcement_configurations
egarciamendez Sep 4, 2024
18e9e54
Rectangular reinforced cross-section
egarciamendez Sep 4, 2024
f96bee9
Rectangular RCS plotter work in progress
egarciamendez Sep 4, 2024
0dc06f5
Merge branch 'refs/heads/main' into rectangular_rcs_plotter
egarciamendez Sep 5, 2024
55bde17
Merge remote-tracking branch 'refs/remotes/origin/main' into adding_r…
egarciamendez Sep 8, 2024
ab7010e
Merge branch 'refs/heads/rectangular_rcs_plotter' into adding_reinfor…
egarciamendez Sep 8, 2024
b52eca7
RectangularCS plotter
egarciamendez Sep 8, 2024
ad7c61b
example added to docs
egarciamendez Sep 8, 2024
62200d2
cover tests added
egarciamendez Sep 8, 2024
63ab483
tests RectangularReinforcedCrossSection
egarciamendez Sep 8, 2024
927b580
tests RectangularReinforcedCrossSection
egarciamendez Sep 8, 2024
0215611
covers can not be negative
egarciamendez Sep 8, 2024
9013ccd
Merge branch 'refs/heads/main' into adding_reinforcement_configurations
egarciamendez Sep 16, 2024
e396e6d
Merge branch 'main' into adding_reinforcement_configurations
egarciamendez Oct 4, 2024
d58a361
Update blueprints/structural_sections/concrete/reinforced_concrete_se…
egarciamendez Oct 16, 2024
9cb48b8
let it go....let it gooo
egarciamendez Oct 16, 2024
b821328
kiss
egarciamendez Oct 16, 2024
ab40f3a
check is not necessary as this has been done when setting
egarciamendez Oct 16, 2024
964a20e
covers as an object
egarciamendez Oct 16, 2024
880c043
explaining things
egarciamendez Oct 16, 2024
b5c009a
literalinclude is awesome
egarciamendez Oct 16, 2024
c959053
already default
egarciamendez Oct 16, 2024
f83b4a0
docs readme
egarciamendez Oct 16, 2024
ca17b29
missing parameter
egarciamendez Oct 16, 2024
30a2ed4
update style instead
egarciamendez Oct 16, 2024
472372c
legend text public
egarciamendez Oct 16, 2024
6c4d822
pythonic
egarciamendez Oct 16, 2024
77be54d
extend example with third layer
egarciamendez Oct 16, 2024
8f9331c
needed for the case where custom configurations are added to the RCS
egarciamendez Oct 16, 2024
3916a11
custom configurations are added to the RCS
egarciamendez Oct 16, 2024
a6b64d0
kiss
egarciamendez Oct 16, 2024
ef80139
custom rcs example
egarciamendez Oct 16, 2024
1bdd73a
fix reference line
egarciamendez Nov 6, 2024
72da258
rectangular reinforced cross section example
egarciamendez Nov 6, 2024
2525c49
Merge branch 'main' into adding_reinforcement_configurations
egarciamendez Nov 6, 2024
a7647da
testing RectangularReinforcedCrossSection
egarciamendez Nov 6, 2024
68f6ee7
testing RectangularReinforcedCrossSection
egarciamendez Nov 6, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 0 additions & 8 deletions blueprints/geometry/line.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
"""Line module."""

from enum import Enum
from typing import Literal

import numpy as np
Expand All @@ -12,13 +11,6 @@
from blueprints.unit_conversion import RAD_TO_DEG


class Reference(Enum):
"""Enum of the reference options start/end."""

START = 0
END = 1


class Line:
"""Represents a line in a 3D modelling space.

Expand Down
57 changes: 57 additions & 0 deletions blueprints/structural_sections/concrete/covers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
"""Module with the representation of the covers for cross-sections."""

from dataclasses import dataclass

from blueprints.type_alias import MM
from blueprints.validations import raise_if_negative

DEFAULT_COVER = 50 # mm


@dataclass
egarciamendez marked this conversation as resolved.
Show resolved Hide resolved
class CoversRectangular:
"""Representation of the covers of a rectangular cross-section."""

upper: MM = DEFAULT_COVER
right: MM = DEFAULT_COVER
lower: MM = DEFAULT_COVER
left: MM = DEFAULT_COVER

def __post_init__(self) -> None:
"""Post initialization of the covers."""
self.validate()

def get_covers_info(self) -> str:
"""Return a string with the covers of the cross-section."""
text = "Cover:"

all_equal = bool(len({self.upper, self.lower, self.right, self.left}) == 1)
if all_equal:
return f"Cover: {self.upper:.0f} mm"

covers = {cover: "" for cover in list({self.upper, self.lower, self.right, self.left})}
covers[self.upper] = "upper"

if covers[self.lower]:
egarciamendez marked this conversation as resolved.
Show resolved Hide resolved
covers[self.lower] += "|lower"
else:
covers[self.lower] = "lower"

if covers[self.left]:
covers[self.left] += "|left"
else:
covers[self.left] = "left"

if covers[self.right]:
covers[self.right] += "|right"
else:
covers[self.right] = "right"

for cover, names in covers.items():
text += f"\n {names}: {cover:.0f} mm"

return text
egarciamendez marked this conversation as resolved.
Show resolved Hide resolved

def validate(self) -> None:
"""Validate the covers."""
raise_if_negative(upper=self.upper, right=self.right, lower=self.lower, left=self.left)
egarciamendez marked this conversation as resolved.
Show resolved Hide resolved
6 changes: 5 additions & 1 deletion blueprints/structural_sections/concrete/rebar.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from dataclasses import dataclass

from blueprints.materials.reinforcement_steel import ReinforcementSteelMaterial
from blueprints.structural_sections.concrete.reinforced_concrete_sections.cross_section_shapes import CircularCrossSection
from blueprints.structural_sections.cross_section_shapes import CircularCrossSection
from blueprints.type_alias import KG_M, RATIO
from blueprints.unit_conversion import MM2_TO_M2

Expand All @@ -17,6 +17,10 @@ class Rebar(CircularCrossSection):
----------
diameter : MM
Diameter of the bar (for example: ⌀12, ⌀16, ⌀20, etc.) [mm]
x : MM
x-coordinate in the cross-section [mm]
y : MM
y-coordinate in the cross-section [mm]
material : ReinforcementSteelMaterial
Representation of the properties of reinforcement steel suitable for use with NEN-EN 1992-1-1.
relative_start_position: RATIO
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
"""Base class of all reinforced cross-sections."""

from abc import ABC
from functools import partial
from typing import Callable

from shapely import LineString

from blueprints.materials.concrete import ConcreteMaterial
from blueprints.materials.reinforcement_steel import ReinforcementSteelMaterial
from blueprints.structural_sections.concrete.rebar import Rebar
from blueprints.structural_sections.concrete.reinforced_concrete_sections.reinforcement_configurations import (
ReinforcementConfiguration,
)
from blueprints.structural_sections.concrete.stirrups import StirrupConfiguration
from blueprints.structural_sections.cross_section_shapes import CrossSection
from blueprints.type_alias import KG_M, KG_M3, M3_M, MM2_M
from blueprints.unit_conversion import M_TO_MM, MM3_TO_M3


class ReinforcedCrossSection(ABC):
"""Base class of all reinforced cross-sections."""

def __init__(
self,
cross_section: CrossSection,
concrete_material: ConcreteMaterial,
) -> None:
"""Initialize the reinforced cross-section.

Parameters
----------
cross_section : CrossSection
Cross-section of the reinforced concrete section.
concrete_material : ConcreteMaterial
Material properties of the concrete.
"""
self.cross_section = cross_section
self.concrete_material = concrete_material
self._reinforcement_configurations: list[tuple[LineString | Callable[..., LineString], ReinforcementConfiguration]] = []
self._single_longitudinal_rebars: list[Rebar] = []
self._stirrups: list[StirrupConfiguration] = []

@property
def longitudinal_rebars(self) -> list[Rebar]:
"""Return a list of all longitudinal rebars."""
rebars: list[Rebar] = []

# add the single longitudinal rebars
rebars.extend(self._single_longitudinal_rebars)

# add the rebars from the reinforcement configurations
for line, configuration in self._reinforcement_configurations:
if callable(line):
rebars.extend(configuration.to_rebars(line=line()))
egarciamendez marked this conversation as resolved.
Show resolved Hide resolved
egarciamendez marked this conversation as resolved.
Show resolved Hide resolved
else:
rebars.extend(configuration.to_rebars(line=line))

# check if all rebars are inside the cross-section
for rebar in rebars:
if not self.cross_section.geometry.contains(other=rebar.geometry):
msg = f"Rebar (diameter={rebar.diameter}, x={rebar.x}, y={rebar.y}) is not (fully) inside the cross-section."
raise ValueError(msg)
egarciamendez marked this conversation as resolved.
Show resolved Hide resolved

return rebars

@property
def stirrups(self) -> list[StirrupConfiguration]:
"""Return a list of all stirrups."""
return self._stirrups

@property
def reinforcement_weight_longitudinal_bars(self) -> KG_M:
"""Total mass of the longitudinal reinforcement in the cross-section per meter length [kg/m]."""
return sum(rebar.weight_per_meter for rebar in self.longitudinal_rebars)

@property
def reinforcement_weight_stirrups(self) -> KG_M:
"""Total mass of the stirrups' reinforcement in the cross-section per meter length [kg/m]."""
return sum(stirrup.weight_per_meter for stirrup in self._stirrups)

@property
def reinforcement_weight(self) -> KG_M:
"""Total mass of the reinforcement in the cross-section per meter length [kg/m]."""
return self.reinforcement_weight_longitudinal_bars + self.reinforcement_weight_stirrups

@property
def reinforcement_area_longitudinal_bars(self) -> MM2_M:
"""Total area of the longitudinal reinforcement in the cross-section per meter length [mm²/m]."""
return sum(rebar.area for rebar in self.longitudinal_rebars)

@property
def concrete_volume(self) -> M3_M:
"""Total volume of the reinforced cross-section per meter length [m³/m]."""
length = M_TO_MM
return self.cross_section.area * length * MM3_TO_M3

@property
def weight_per_volume(self) -> KG_M3:
"""Total mass of the cross-section per meter length (concrete_checks+reinforcement) [kg/m³]."""
return self.reinforcement_weight / self.concrete_volume

def get_present_steel_materials(self) -> list[ReinforcementSteelMaterial]:
"""Return a list of all present steel materials in the cross-section."""
materials = [rebar.material for rebar in self.longitudinal_rebars]
materials.extend(stirrup.material for stirrup in self._stirrups)
return list(set(materials))

def add_longitudinal_rebar(
self,
rebar: Rebar,
) -> Rebar:
"""Adds a single reinforcement bar to the cross-section.

Parameters
----------
rebar : Rebar
Rebar to be added to the cross-section.

Raises
------
ValueError
If the rebar is not fully inside the cross-section.

Returns
-------
Rebar
Newly created Rebar
"""
# check if given diameter/coordinates are fully inside the cross-section
if not rebar.geometry.within(self.cross_section.geometry):
msg = f"Rebar (diameter={rebar.diameter}, x={rebar.x}, y={rebar.y}) is not (fully) inside the cross-section."
raise ValueError(msg)

# add the rebar to the list of longitudinal rebars
self._single_longitudinal_rebars.append(rebar)

return rebar

def add_stirrup_configuration(self, stirrup: StirrupConfiguration) -> StirrupConfiguration:
"""Add a stirrup configuration to the cross-section.

Parameters
----------
stirrup : StirrupConfiguration
Configuration of stirrup reinforcement in the cross-section.

Returns
-------
StirrupConfiguration
Newly created Stirrup

Raises
------
ValueError
If the stirrup is not fully inside the cross-section.
"""
# check if the stirrup is inside the cross-section
stirrup_outside_edge = stirrup.geometry.buffer(distance=stirrup.diameter / 2)
if not self.cross_section.geometry.contains(stirrup_outside_edge):
msg = "Stirrup is not (fully) inside the cross-section."
raise ValueError(msg)

# add the stirrup to the list
self._stirrups.append(stirrup)

return stirrup

def add_reinforcement_configuration(
self,
line: LineString | Callable[..., LineString],
configuration: ReinforcementConfiguration,
*args,
**kwargs,
) -> None:
"""Add a reinforcement configuration to the cross-section.

Parameters
----------
line : LineString | Callable[..., LineString]
Representing the path of the reinforcement in the cross-section.
Start of the line defines the first rebar of the configuration, end of the line defines the last rebar.
If a callable is given, it should return a LineString. The callable can take additional arguments.
Arguments can be passed to the callable using the *args and **kwargs.
configuration : ReinforcementConfiguration
Configuration of the reinforcement.
args : Any
Additional arguments for the callable line. If line is not a callable, these arguments are ignored.
kwargs : Any
Additional keyword arguments for the callable line. If line is not a callable, these arguments are ignored.

"""
# check if the line is a callable and wrap it with the given arguments
if callable(line):
line = partial(line, *args, **kwargs) # type: ignore[misc]

# add the reinforcement configuration to the list
self._reinforcement_configurations.append((line, configuration))
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Default plotters for Blueprint's reinforced concrete sections."""
Loading