API Reference

Note

The API reference is incomplete as I am beginning to learn how to do this correctly. Any suggestionss or help are greatly appreciated.

Materials

Concrete

Concrete dataclass

Concrete

Returns

Concrete Concrete object

Source code in src/rcdesign/is456/concrete.py
@dataclass
class Concrete:
    """Concrete

    Returns
    -------
    Concrete
        Concrete object
    """

    label: str
    fck: float
    gamma_m: float = 1.5
    density: float = 25.0

    def __repr__(self) -> str:
        s = f"fck = {self.fck:.2f} N/mm^2, fd = {self.fd:.2f} N/mm^2"
        return s

    @property
    def Ec(self) -> float:
        return 5000 * sqrt(self.fck)

    @property
    def fd(self) -> float:
        return 0.67 * self.fck / self.gamma_m

    def tauc(self, pt: float) -> float:
        if pt < 0.15:
            pt = 0.15
        if pt > 3:
            pt = 3.0
        beta = max(1.0, (0.8 * self.fck) / (6.89 * pt))
        num = 0.85 * sqrt(0.8 * self.fck) * (sqrt(1 + 5 * beta) - 1)
        den = 6 * beta
        return num / den

    def tauc_max(self):
        tauc = np.array([[15, 20, 25, 30, 35, 40], [2.5, 2.8, 3.1, 3.5, 3.7, 4.0]])
        if self.fck < 15:
            return 0.0
        elif self.fck >= tauc[0, -1]:
            return tauc[1, -1]
        else:
            for i in range(1, tauc.shape[1]):
                if self.fck <= tauc[0, i]:
                    if self.fck == tauc[0, i]:
                        return tauc[1, i]
                    else:
                        x1 = tauc[0, i - 1]
                        y1 = tauc[1, i - 1]
                        x2 = tauc[0, i]
                        y2 = tauc[1, i]
                        print(x1, x2, y1, y2)
                        return y1 + (y2 - y1) / (x2 - x1) * (self.fck - x1)

Rebar

Classes to represent reinforcement bars, layers of reinforcement bars and groups of reinforcement layers

Rebar dataclass

Bases: ABC

Rebar object represents a reinforcment bar.

Parameters

ABC : type description

Returns

Rebar description

Source code in src/rcdesign/is456/rebar.py
@dataclass
class Rebar(ABC):  # pragma: no cover
    """Rebar object represents a reinforcment bar.

    Parameters
    ----------
    ABC : _type_
        _description_

    Returns
    -------
    Rebar
        _description_
    """
    label: str
    fy: float
    gamma_m: float = 1.15
    density: float = 78.5
    Es: float = 2e5
    rebar_type: RebarType = RebarType.REBAR_HYSD

    @property
    def fd(self) -> float:
        return self.fy / self.gamma_m

    def es_min(self) -> float:
        return self.fd / self.Es + 0.002

    @abstractmethod
    def fs(self, es: float) -> float:
        pass

Section

Class to represent reinforced concrete cross sections

DesignForceType

Bases: Enum

DesignForceType object is an enumeration

Source code in src/rcdesign/is456/section.py
class DesignForceType(Enum):
    """DesignForceType object is an enumeration"""

    BEAM = 1
    COLUMN = 2
    SLAB = 3
    SHEARWALL = 4

RectBeamSection dataclass

RectBeamSection object represnts a rectangular beam section subjected to bending and shear.

Returns

RectBeamSection description

Source code in src/rcdesign/is456/section.py
@dataclass
class RectBeamSection:
    """RectBeamSection object represnts a rectangular beam section subjected to bending and shear.

    Returns
    -------
    RectBeamSection
        _description_
    """

    b: float
    D: float
    csb: LSMStressBlock
    conc: Concrete
    long_steel: RebarGroup
    shear_steel: ShearRebarGroup
    clear_cover: float

    def __post_init__(self):
        self.design_force_type = DesignForceType.BEAM
        self.calc_xc()

    def calc_xc(self) -> None:
        self.long_steel.calc_xc(self.D)
        return None

    def get_stress_type(self, xu: float) -> None:
        self.calc_xc()
        self.long_steel.get_stress_type(xu)

    def C(self, xu: float, ecmax: float = ecu) -> Tuple[float, float]:
        Fc, Mc, _, _ = self.F_M(xu, ecmax)
        return Fc, Mc

    def T(self, xu: float, ecmax: float) -> Tuple[float, float]:
        _, _, Ft, Mt = self.F_M(xu, ecmax)
        return Ft, Mt

    def C_T(self, xu: float, ecmax: float = ecu) -> float:
        self.get_stress_type(xu)
        C, _, T, _ = self.F_M(xu, ecmax)
        return C - T

    def F_M(self, xu: float, ecmax: float = ecu) -> Tuple[float, float, float, float]:
        # sb = LSMStressBlock("LSM Flexure")
        self.get_stress_type(xu)
        Fc = Mc = Ft = Mt = 0.0
        # Compression force - concrete
        k = xu / self.D
        Fcc = self.csb.C(0, k, k, ecmax) * self.conc.fd * self.b * self.D
        Mcc = self.csb.M(0, k, k, ecmax) * self.conc.fd * self.b * self.D**2
        # Compression force - compression steel
        Fsc, Msc, Fst, Mst = self.long_steel.force_moment(xu, self.csb, self.conc, ecmax)
        # Tension force in tension steel
        Ft, Mt = self.long_steel.force_tension(xu, ecmax)
        Fc = Fcc + Fsc
        Mc = Mcc + Msc
        return Fc, Mc, Ft, Mt

    def xu(self, ecmax: float = ecu) -> Union[float, Any]:
        dc_max = 10

        x1, x2 = rootsearch(self.C_T, dc_max, self.D, 10, ecmax)
        x = brent(self.C_T, x1, x2, ecmax)
        # x = brentq(self.C_T, x1, x2, args=(ecmax,))
        return x

    def Mu(self, xu: float, ecmax: float = ecu) -> float:
        # Assuming area of tension steel to be such as to produce a tension force equal to C
        _, Mc = self.C(xu, ecmax)
        _, Mt = self.T(xu, ecmax)
        M = Mc + Mt
        return M

    def tauc(self, xu: float) -> float:
        return self.conc.tauc(self.pt(xu))

    def __repr__(self) -> str:
        ecmax = self.csb.ecu
        xu = self.xu(ecmax)
        return self.report(xu, ecmax)

    def has_compr_steel(self, xu: float) -> bool:
        for L in self.long_steel.layers:
            if L._xc < xu:
                return True
        return False

    def report(self, xu: float, ecmax: float = ecu) -> str:  # pragma: no cover
        self.calc_xc()
        self.get_stress_type(xu)
        k = xu / self.D
        ecy = self.csb.ecy
        hdr0 = f"RECTANGULAR BEAM SECTION: {self.b} x {self.D}"
        s = f"{header(hdr0, '~')}\n"
        s += f"{header('FLEXURE', '=')}\nEquilibrium NA = {xu:.2f} (k = {k:.2f}) (ec_max = {ecmax:.6f})\n\n"
        fcc = self.csb._fc_(ecmax) * self.conc.fd
        Fc = self.b * self.csb.C(0, k, k, ecmax) * self.conc.fd * self.D
        Mc = self.csb.M(0, k, k) * self.conc.fd * self.b * self.D**2
        hdr1 = f"{'fck':>6} {' ':>8} {' ':>12} {'ec_max':>12} {'Type':>4} "
        hdr1 += f"{' ':>8} {'f_c':>6} {'F (kN)':>8} {'M (kNm)':>8}"
        s += hdr1 + "\n" + underline(hdr1) + "\n"
        s += f"{self.conc.fck:6.2f} {' ':>8} {' ':>12} {ecmax:12.8f} {'C':>4} {' ':>8} {fcc:6.2f} "
        s += f"{Fc / 1e3:8.2f} {Mc / 1e6:8.2f}\n{underline(hdr1)}\n\n"
        Ft = 0.0
        Mt = 0.0
        hdr2 = f"{'fy':>6} {'Bars':>12} {'xc':>8} {'Strain':>12} {'Type':>4} {'f_s':>8} {'f_c':>6}"
        hdr2 += f" {'F (kN)':>8} {'M (kNm)':>8}"
        s += f"{hdr2}\n{underline(hdr2)}\n"
        for L in sorted(self.long_steel.layers):
            z = k - (L._xc / self.D)
            esc = self.csb.ec(z, k) * ecy
            stress_type = L.stress_type(xu)
            fsc = L.rebar.fs(esc)
            s += f"{L.rebar.fy:6.0f} {L.bar_list():>12} {L._xc:8.2f} {esc:12.8f} "
            s += f"{StressLabel[stress_type][0]:>4} {fsc:8.2f} "
            if stress_type == StressType.STRESS_COMPRESSION:
                fcc = self.csb.fc(z, k, ecmax) * self.conc.fd
                c = L.area * (fsc - fcc)
                s += f"{fcc:6.2f} "
            elif L._stress_type == StressType.STRESS_TENSION:
                c = L.area * fsc
                s += f"{' ':>6} "
            else:
                c = 0.0

            m = c * (k * self.D - L._xc)
            s += f"{c / 1e3:8.2f} {m / 1e6:8.2f}\n"
            Ft += c
            Mt += m
        s += f"{underline(hdr2)}\n"
        if len(self.long_steel.layers) > 1:
            C_M = f"{Ft / 1e3:8.2f} {Mt / 1e6:8.2f}"
            s += f"{' ' * 62} {C_M}\n{' ' * 62} {underline(C_M, '=')}\n"
        F = 0.0 if isclose(Fc + Ft, 0, abs_tol=1e-10) else Fc + Ft
        C_M = f"{F / 1e3:8.2f} {(Mc + Mt) / 1e6:8.2f}"
        s += f"{' ':>62} {C_M}\n"
        s += f"{header('SHEAR', '=')}\n"
        tauc = self.conc.tauc(self.pt(xu))
        area = self.b * self.eff_d(xu)
        vuc = area * tauc
        hdr3 = f"{'Type':>14} {' ':>14} {'tau_c':>6} {'Area (mm^2)':>16} {' ':>8} {' ':>8} {'V_uc (kN)':>8}"
        s += f"{header(hdr3)}\n"
        s += f"{'Concrete':>14} {' ':>14} {tauc:6.2f} {area:16.2f} {' ':>8} {' ':>8} {vuc / 1e3:8.2f}\n"
        s += f"{underline(hdr3)}\n"
        hdr4 = f"{'Type':>14} {'Variant':>14} {'f_y':>6} {'Bars':>16} {'s_v':>8} {'A_sv':>8} {'V_us (kN)':>8}"
        s += f"{header(hdr4)}\n"
        vus = 0.0
        for sh_rein in self.shear_steel.shear_reinforcement:
            data = sh_rein.report(self.eff_d(xu))
            s += f"{data['label']:>14} {data['type']:>14} {data['fy']:6} "
            if data["sh_type"] in [
                ShearRebarType.SHEAR_REBAR_VERTICAL_STIRRUP,
                ShearRebarType.SHEAR_REBAR_INCLINED_STIRRUP,
            ]:
                bar_info = f"{data['legs']}-{data['bar_dia']}#"
            else:
                bar_info = f"{data['bars']}"
            s += f"{bar_info:>16} {data['sv']:8.1f} {data['Asv']:8.2f} {data['Vus'] / 1e3:8.2f}\n"
            vus += data["Vus"]
        vu = f"{(vuc + vus) / 1e3:8.2f}"
        s += f"{' ':>71} {underline(vu, '=')}\n{' ':>71} {vu}\n"
        s += f"{header('CAPACITY', '=')}\n{'Mu = ':>5}{self.Mu(xu, ecmax) / 1e6:.2f} kNm\n"
        Vuc, Vus = self.Vu(xu)
        Vu = Vuc + sum(Vus)
        s += f"{'Vu = ':>5}{Vu / 1e3:.2f} kN\n"
        return s

    def eff_d(self, xu: float) -> float:
        _, ct = self.long_steel.centroid(xu)
        return ct

    def pt(self, xu: float) -> float:
        ast = 0.0
        for L in sorted(self.long_steel.layers):
            if L._xc > xu:
                ast += L.area
        d = self.eff_d(xu)
        pt = ast / (self.b * d) * 100
        return pt

    def Vu(self, xu: float) -> Tuple[float, List[float]]:
        # print("\nstart::RectBeamSection.Vu(xu)", xu)
        pt = self.pt(xu)
        # print("stop::RectBeamSection.Vu(xu)\n")
        tauc = self.conc.tauc(pt)
        d = self.eff_d(xu)
        vuc = tauc * self.b * d
        vus = self.shear_steel.Vus(d)
        return vuc, vus

    def analyse(self, ecmax: float = ecu) -> Tuple[float, float]:
        xu = self.xu(ecmax)
        Mu = self.Mu(xu, ecmax)
        return xu, Mu

    def design_singly(self, bar_dia: float, Mu: float) -> Tuple[float, float]:
        beam = LSMBeam()
        fck = self.conc.fck
        bottom_layer = self.long_steel.layers[-1]
        fy = bottom_layer.rebar.fy
        fd = bottom_layer.rebar.fd
        d = self.D - self.clear_cover - bar_dia / 2
        dc = self.clear_cover + bar_dia / 2
        Mulim = beam.Mulim_const(fy) * fck * self.b * d**2
        if Mu < Mulim:
            ast = beam.reqd_Ast(fck, fy, self.b, d, Mu)
            asc = 0.0
        else:
            ast1 = beam.reqd_Ast(fck, fy, self.b, d, Mulim)
            Mu2 = Mu - Mulim
            ast2 = Mu2 / (fd * (d - dc))
            ast = ast1 + ast2
            xu = beam.xumax_d(fy) * d
            esc = self.csb.ecu / xu * (xu - dc)
            fsc = bottom_layer.rebar.fs(esc)
            fcc = self.csb._fc_(esc) * self.conc.fd
            asc = ast2 * fd / (fsc - fcc)
            print("---", xu, d, esc, fsc, fcc, ast1, ast2, ast, asc)
        return ast, asc

Stress Block

Utilities