Skip to content
Open
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
4 changes: 3 additions & 1 deletion structuralcodes/codes/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
import types
import typing as t

from . import ec2_2004, ec2_2023, mc2010, mc2020
from . import aci318, ec2_2004, ec2_2023, mc2010, mc2020

__all__ = [
'aci318',
'mc2010',
'mc2020',
'ec2_2023',
Expand All @@ -23,6 +24,7 @@

# Design code registry
_DESIGN_CODES = {
'aci318': aci318,
'mc2010': mc2010,
'mc2020': mc2020,
'ec2_2004': ec2_2004,
Expand Down
37 changes: 37 additions & 0 deletions structuralcodes/codes/aci318/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
"""ACI 318-19."""

import typing as t

from ._concrete_material_properties import (
Ec,
alpha1,
beta1,
eps_cu,
fct,
fr,
lambda_factor,
)
from ._reinforcement_material_properties import (
Es,
epsyd,
fy_design,
reinforcement_grade_props,
)

__all__ = [
'Ec',
'Es',
'alpha1',
'beta1',
'eps_cu',
'epsyd',
'fct',
'fr',
'fy_design',
'lambda_factor',
'reinforcement_grade_props',
]

__title__: str = 'ACI 318-19'
__year__: str = '2019'
__materials__: t.Tuple[str] = ('concrete', 'reinforcement')
164 changes: 164 additions & 0 deletions structuralcodes/codes/aci318/_concrete_material_properties.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
"""Concrete material properties according to ACI 318-19."""

from __future__ import annotations

import math
import typing as t

LAMBDA_FACTORS = {
'normalweight': 1.0,
'sand-lightweight': 0.85,
'all-lightweight': 0.75,
}


def Ec(fc: float, wc: float = 2320.0) -> float:
"""The modulus of elasticity of concrete.

ACI 318-19, Table 19.2.2.1.

Args:
fc (float): The specified compressive strength of concrete in
MPa.

Keyword Args:
wc (float): The unit weight of concrete in kg/m3.
Default is 2320 kg/m3 (normalweight concrete).

Returns:
float: The modulus of elasticity in MPa.

Raises:
ValueError: If fc is not positive.
ValueError: If wc is outside the range 1440-2560 kg/m3.
"""
if fc <= 0:
raise ValueError(f'fc={fc} must be positive')
if wc < 1440 or wc > 2560:
raise ValueError(f'wc={wc} must be between 1440 and 2560 kg/m3')
return wc**1.5 * 0.043 * math.sqrt(fc)


def fr(fc: float, lambda_s: float = 1.0) -> float:
"""The modulus of rupture of concrete.

ACI 318-19, Eq. 19.2.3.1.

Args:
fc (float): The specified compressive strength of concrete in
MPa.

Keyword Args:
lambda_s (float): The modification factor for lightweight
concrete. Default is 1.0 (normalweight).

Returns:
float: The modulus of rupture in MPa.

Raises:
ValueError: If fc is not positive.
ValueError: If lambda_s is not in (0, 1].
"""
if fc <= 0:
raise ValueError(f'fc={fc} must be positive')
if lambda_s <= 0 or lambda_s > 1.0:
raise ValueError(f'lambda_s={lambda_s} must be in the range (0, 1]')
return 0.62 * lambda_s * math.sqrt(fc)


def beta1(fc: float) -> float:
"""The Whitney stress block depth factor.

ACI 318-19, Table 22.2.2.4.3.

Args:
fc (float): The specified compressive strength of concrete in
MPa.

Returns:
float: The stress block depth factor (dimensionless).

Raises:
ValueError: If fc is not positive.
"""
if fc <= 0:
raise ValueError(f'fc={fc} must be positive')
if fc <= 28:
return 0.85
if fc >= 55:
return 0.65
return 0.85 - 0.05 * (fc - 28) / 7


def eps_cu() -> float:
"""The maximum usable strain at the extreme concrete compression fiber.

ACI 318-19, Section 22.2.2.1.

Returns:
float: The ultimate concrete strain (dimensionless).
"""
return 0.003


def lambda_factor(
concrete_type: t.Literal[
'normalweight', 'sand-lightweight', 'all-lightweight'
],
) -> float:
"""The modification factor for lightweight concrete.

ACI 318-19, Table 19.2.4.2.

Args:
concrete_type (str): The concrete type. One of
'normalweight', 'sand-lightweight', or 'all-lightweight'.

Returns:
float: The lightweight modification factor (dimensionless).

Raises:
ValueError: If concrete_type is not recognized.
"""
result = LAMBDA_FACTORS.get(concrete_type.lower())
if result is None:
raise ValueError(
f'Unknown concrete type: {concrete_type}. '
f'Valid types: {list(LAMBDA_FACTORS.keys())}'
)
return result


def fct(fc: float, lambda_s: float = 1.0) -> float:
"""The approximate splitting tensile strength of concrete.

ACI 318-19, Section 19.2.4.3.

Args:
fc (float): The specified compressive strength of concrete in
MPa.

Keyword Args:
lambda_s (float): The modification factor for lightweight
concrete. Default is 1.0 (normalweight).

Returns:
float: The splitting tensile strength in MPa.

Raises:
ValueError: If fc is not positive.
"""
if fc <= 0:
raise ValueError(f'fc={fc} must be positive')
return 0.56 * lambda_s * math.sqrt(fc)


def alpha1() -> float:
"""The ratio of equivalent rectangular stress block intensity.

ACI 318-19, Section 22.2.2.4.1.

Returns:
float: The stress block intensity factor (dimensionless).
"""
return 0.85
100 changes: 100 additions & 0 deletions structuralcodes/codes/aci318/_reinforcement_material_properties.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
"""Reinforcement material properties according to ACI 318-19."""

from __future__ import annotations

import typing as t

REINFORCEMENT_GRADES = {
'40': {'fy': 280.0, 'fu': 420.0},
'60': {'fy': 420.0, 'fu': 550.0},
'80': {'fy': 550.0, 'fu': 690.0},
'100': {'fy': 690.0, 'fu': 860.0},
}


def Es() -> float:
"""The modulus of elasticity of reinforcement.

ACI 318-19, Section 20.2.2.2.

Returns:
float: The modulus of elasticity in MPa.
"""
return 200000.0


def fy_design(fy: float, phi: float = 1.0) -> float:
"""The design yield strength of reinforcement.

ACI 318-19 applies strength reduction factors (phi) at the
member capacity level, not the material level. The default
phi=1.0 returns the unreduced yield strength, which is the
standard ACI convention for material properties.

Args:
fy (float): The specified yield strength in MPa.

Keyword Args:
phi (float): Optional strength reduction factor.
Default is 1.0 (no reduction).

Returns:
float: The design yield strength in MPa.

Raises:
ValueError: If fy is not positive.
ValueError: If phi is not in (0, 1].
"""
if fy <= 0:
raise ValueError(f'fy={fy} must be positive')
if phi <= 0 or phi > 1.0:
raise ValueError(f'phi={phi} must be in the range (0, 1]')
return phi * fy


def epsyd(fy: float, _Es: float = 200000.0) -> float:
"""The yield strain of reinforcement.

Args:
fy (float): The specified yield strength in MPa.

Keyword Args:
_Es (float): The modulus of elasticity in MPa.
Default is 200000 MPa.

Returns:
float: The yield strain (dimensionless).

Raises:
ValueError: If fy is not positive.
"""
if fy <= 0:
raise ValueError(f'fy={fy} must be positive')
return fy / _Es


def reinforcement_grade_props(
grade: t.Literal['40', '60', '80', '100'],
) -> t.Dict[str, float]:
"""Return the minimum specified properties for a reinforcement grade.

ACI 318-19, Table 20.2.2.4a (SI equivalents).

Args:
grade (str): The ASTM reinforcement grade designation.
One of '40', '60', '80', or '100'.

Returns:
Dict[str, float]: A dict with keys 'fy' (yield strength in
MPa) and 'fu' (ultimate strength in MPa).

Raises:
ValueError: If the grade is not recognized.
"""
props = REINFORCEMENT_GRADES.get(str(grade))
if props is None:
raise ValueError(
f'Unknown reinforcement grade: {grade}. '
f'Valid grades: {list(REINFORCEMENT_GRADES.keys())}'
)
return dict(props)
3 changes: 3 additions & 0 deletions structuralcodes/materials/concrete/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,22 @@
from structuralcodes.codes import _use_design_code

from ._concrete import Concrete
from ._concreteACI318 import ConcreteACI318
from ._concreteEC2_2004 import ConcreteEC2_2004
from ._concreteEC2_2023 import ConcreteEC2_2023
from ._concreteMC2010 import ConcreteMC2010

__all__ = [
'create_concrete',
'Concrete',
'ConcreteACI318',
'ConcreteMC2010',
'ConcreteEC2_2023',
'ConcreteEC2_2004',
]

CONCRETES: t.Dict[str, Concrete] = {
'ACI 318-19': ConcreteACI318,
'fib Model Code 2010': ConcreteMC2010,
'EUROCODE 2 1992-1-1:2004': ConcreteEC2_2004,
'EUROCODE 2 1992-1-1:2023': ConcreteEC2_2023,
Expand Down
Loading
Loading