Skip to content

New material module #28

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

Merged
merged 7 commits into from
Aug 5, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
178 changes: 93 additions & 85 deletions concreteproperties/analysis_section.py

Large diffs are not rendered by default.

798 changes: 437 additions & 361 deletions concreteproperties/concrete_section.py

Large diffs are not rendered by default.

52 changes: 36 additions & 16 deletions concreteproperties/design_codes.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

from copy import deepcopy
from math import inf
from typing import TYPE_CHECKING, List, Optional, Tuple
from multiprocessing.sharedctypes import Value
from typing import TYPE_CHECKING, List, Tuple

import numpy as np
from rich.live import Live
Expand All @@ -12,7 +13,7 @@
import concreteproperties.results as res
import concreteproperties.stress_strain_profile as ssp
import concreteproperties.utils as utils
from concreteproperties.material import Concrete, Steel
from concreteproperties.material import Concrete, SteelBar

if TYPE_CHECKING:
from concreteproperties.concrete_section import ConcreteSection
Expand Down Expand Up @@ -60,8 +61,8 @@ def create_steel_material(
self,
yield_strength: float,
colour: str = "grey",
) -> Steel:
"""Returns a steel material object.
) -> SteelBar:
"""Returns a steel bar material object.

List assumptions of material properties here...

Expand All @@ -76,7 +77,7 @@ def create_steel_material(
def get_gross_properties(
self,
**kwargs,
) -> res.ConcreteProperties:
) -> res.GrossProperties:
"""Returns the gross section properties of the reinforced concrete section.

:param kwargs: Keyword arguments passed to
Expand All @@ -90,7 +91,7 @@ def get_gross_properties(
def get_transformed_gross_properties(
self,
**kwargs,
) -> res.TransformedConcreteProperties:
) -> res.TransformedGrossProperties:
"""Transforms gross section properties.

:param kwargs: Keyword arguments passed to
Expand Down Expand Up @@ -232,7 +233,13 @@ def calculate_ultimate_stress(


class AS3600(DesignCode):
"""Design code class for Australian standard AS 3600:2018."""
"""Design code class for Australian standard AS 3600:2018.

Note that this design code only supports :class:`~concreteproperties.pre.Concrete`
and :class:`~concreteproperties.pre.SteelBar` material objects. Meshed
:class:`~concreteproperties.pre.Steel` material objects are **not** supported
as this falls under the composite structures design code.
"""

def __init__(
self,
Expand All @@ -252,11 +259,22 @@ def assign_concrete_section(

self.concrete_section = concrete_section

# check to make sure there are no meshed reinforcement regions
if self.concrete_section.reinf_geometries_meshed:
raise ValueError(
"Meshed reinforcement is not supported in this design code."
)

# determine reinforcement class
self.reinforcement_class = "N"

for steel_geom in self.concrete_section.steel_geometries:
if steel_geom.material.stress_strain_profile.fracture_strain < 0.05:
for steel_geom in self.concrete_section.reinf_geometries_lumped:
if (
abs(
steel_geom.material.stress_strain_profile.get_ultimate_tensile_strain()
)
< 0.05
):
self.reinforcement_class = "L"

# calculate squash and tensile load
Expand Down Expand Up @@ -343,8 +361,8 @@ def create_steel_material(
yield_strength: float = 500,
ductility_class: str = "N",
colour: str = "grey",
) -> Steel:
r"""Returns a steel material object.
) -> SteelBar:
r"""Returns a steel bar material object.

| **Material assumptions:**
| - *Density*: 7850 kg/m\ :sup:`3`
Expand All @@ -367,7 +385,7 @@ def create_steel_material(
else:
raise ValueError("ductility_class must be N or L.")

return Steel(
return SteelBar(
name=f"{yield_strength:.0f} MPa Steel (AS 3600:2018)",
density=7.85e-6,
stress_strain_profile=ssp.SteelElasticPlastic(
Expand Down Expand Up @@ -406,7 +424,7 @@ def squash_tensile_load(
squash_load += force_c

# loop through all steel geometries
for steel_geom in self.concrete_section.steel_geometries:
for steel_geom in self.concrete_section.reinf_geometries_lumped:
# calculate area and centroid
area = steel_geom.calculate_area()

Expand All @@ -415,7 +433,9 @@ def squash_tensile_load(
strain=0.025
)

force_t = -area * steel_geom.material.stress_strain_profile.yield_strength
force_t = (
-area * steel_geom.material.stress_strain_profile.get_yield_strength()
)

# add to totals
squash_load += force_c
Expand Down Expand Up @@ -500,10 +520,10 @@ def get_n_ub(
# get compressive strain at extreme fibre
eps_cu = self.concrete_section.gross_properties.conc_ultimate_strain

# 4) calculate d_n at balanced load
# calculate d_n at balanced load
d_nb = d_0 * (eps_cu) / (eps_sy + eps_cu)

# 5) calculate axial force at balanced load
# calculate axial force at balanced load
balanced_res = self.concrete_section.calculate_ultimate_section_actions(
d_n=d_nb, ultimate_results=res.UltimateBendingResults(theta=theta)
)
Expand Down
99 changes: 69 additions & 30 deletions concreteproperties/material.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,35 @@
from __future__ import annotations

from dataclasses import dataclass, field
from typing import TYPE_CHECKING

from concreteproperties.stress_strain_profile import (
ConcreteServiceProfile,
ConcreteUltimateProfile,
SteelProfile,
)
import concreteproperties.stress_strain_profile as ssp


@dataclass(eq=True)
class Concrete:
@dataclass
class Material:
"""Generic class for a *concreteproperties* material.

:param name: Material name
:param density: Material density (mass per unit volume)
:param stress_strain_profile: Material stress-strain profile
:param colour: Colour of the material for rendering
:param meshed: If set to True, the entire material region is meshed; if set to
False, the material region is treated as a lumped circular mass at its centroid
"""

name: str
density: float
stress_strain_profile: ssp.StressStrainProfile
colour: str
meshed: bool

def __post_init__(self):
# set elastic modulus
self.elastic_modulus = self.stress_strain_profile.get_elastic_modulus()


@dataclass
class Concrete(Material):
"""Class for a concrete material.

:param name: Concrete material name
Expand All @@ -27,45 +45,66 @@ class Concrete:

name: str
density: float
stress_strain_profile: ConcreteServiceProfile
ultimate_stress_strain_profile: ConcreteUltimateProfile
stress_strain_profile: ssp.ConcreteServiceProfile
ultimate_stress_strain_profile: ssp.ConcreteUltimateProfile
alpha_squash: float
flexural_tensile_strength: float
colour: str
meshed: bool = field(default=True, init=False)

def __post_init__(self):
self.elastic_modulus = self.stress_strain_profile.get_elastic_modulus()
super().__post_init__()

if not isinstance(self.stress_strain_profile, ConcreteServiceProfile):
raise ValueError(
"Concrete stress_strain_profile must be a ConcreteServiceProfile object"
)
if not isinstance(self.stress_strain_profile, ssp.ConcreteServiceProfile):
msg = "Concrete stress_strain_profile must be a "
msg += "ConcreteServiceProfile object."
raise ValueError(msg)

if not isinstance(self.ultimate_stress_strain_profile, ConcreteUltimateProfile):
raise ValueError(
"Concrete ultimate_stress_strain_profile must be a ConcreteUltimateProfile object"
)
if not isinstance(
self.ultimate_stress_strain_profile, ssp.ConcreteUltimateProfile
):
msg = "Concrete ultimate_stress_strain_profile must be a "
msg += "ConcreteUltimateProfile object."
raise ValueError(msg)


@dataclass(eq=True)
class Steel:
"""Class for a steel material.
@dataclass
class Steel(Material):
"""Class for a steel material with the entire region meshed to allow for strain
variation across the section, e.g. structural steel profiles.

:param name: Steel material name
:param density: Steel density (mass per unit volume)
:param stress_strain_profile: Ultimate steel stress-strain profile
:param stress_strain_profile: Steel stress-strain profile
:param colour: Colour of the material for rendering
"""

name: str
density: float
stress_strain_profile: SteelProfile
stress_strain_profile: ssp.StressStrainProfile
colour: str
meshed: bool = field(default=True, init=False)


@dataclass
class SteelBar(Steel):
"""Class for a steel bar material, treated as a lumped circular mass with a constant
strain.

:param name: Steel bar material name
:param density: Steel bar density (mass per unit volume)
:param stress_strain_profile: Steel bar stress-strain profile
:param colour: Colour of the material for rendering
"""

name: str
density: float
stress_strain_profile: ssp.StressStrainProfile
colour: str
meshed: bool = field(default=False, init=False)

def __post_init__(self):
self.elastic_modulus = self.stress_strain_profile.get_elastic_modulus()

if not isinstance(self.stress_strain_profile, SteelProfile):
raise ValueError(
"Steel stress_strain_profile must be a SteelProfile object"
)
# @dataclass
# class SteelStrand(Steel):
# # placeholder
# pass
4 changes: 0 additions & 4 deletions concreteproperties/post.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,10 @@
from typing import TYPE_CHECKING, Optional, Tuple, Union

import matplotlib.pyplot as plt
import numpy as np

if TYPE_CHECKING:
import matplotlib

from concreteproperties.analysis_section import AnalysisSection
from concreteproperties.concrete_section import ConcreteSection


@contextlib.contextmanager
def plotting_context(
Expand Down
Loading