示例#1
0
def design_rc_frame(fb, hz, design_drift=0.02, **kwargs):
    """
    Displacement-based design of a reinforced concrete frame building.

    :param fb: sfsimodels.FrameBuilding
    :param hz:
    :param design_drift:
    :param kwargs:
    :return:
    """

    df = em.DesignedRCFrame(fb, hz)
    df.design_drift = design_drift
    verbose = kwargs.get('verbose', df.verbose)

    for i in range(100):
        mu_reduction_factor = 1.0 - float(i) / 100
        theta_c = df.design_drift * mu_reduction_factor
        displacements = dt.displacement_profile_frame(theta_c, df.heights,
                                                      df.hm_factor)
        df.delta_d, df.mass_eff, df.height_eff = dt.equivalent_sdof(
            df.storey_mass_p_frame, displacements, df.heights)
        df.theta_y = dt.conc_frame_yield_drift(df.fye, df.concrete.e_mod_steel,
                                               df.av_bay, df.av_beam)
        delta_y = dt.yield_displacement(df.theta_y, df.height_eff)
        df.mu = dt.ductility(df.delta_d, delta_y)
        df.xi = dt.equivalent_viscous_damping(df.mu,
                                              mtype="concrete",
                                              btype="frame")
        df.eta = dt.reduction_factor(df.xi)
        df.t_eff = dt.effective_period(df.delta_d, df.eta, df.hz.corner_disp,
                                       df.hz.corner_period)

        if verbose > 1:
            print('Delta_D: ', df.delta_d)
            print('Effective mass: ', df.mass_eff)
            print('Effective height: ', df.height_eff)
            print('Mu: ', df.mu)
            print('theta yield', df.theta_y)
            print('xi: ', df.xi)
            print('Reduction Factor: ', df.eta)
            print('t_eff', df.t_eff)

        if df.t_eff > 0:
            break
        else:
            if verbose > 1:
                print("drift %.2f is not compatible" % theta_c)
    k_eff = dt.effective_stiffness(df.mass_eff, df.t_eff)
    df.v_base = dt.design_base_shear(k_eff, df.delta_d)
    df.storey_forces = dt.calculate_storey_forces(df.storey_mass_p_frame,
                                                  displacements,
                                                  df.v_base,
                                                  btype='frame')
    return df
示例#2
0
def design_rc_frame_w_sfsi_via_millen_et_al_2020(fb,
                                                 hz,
                                                 sl,
                                                 fd,
                                                 design_drift=0.02,
                                                 found_rot=0.00001,
                                                 found_rot_tol=0.02,
                                                 found_rot_iterations=20,
                                                 **kwargs):
    import geofound as gf
    df = em.DesignedSFSIRCFrame(fb, hz, sl, fd)
    df.design_drift = design_drift
    verbose = kwargs.get('verbose', df.verbose)
    df.static_values()
    psi = 0.75 * np.tan(df.sl.phi_r)

    # add foundation to heights and masses
    heights, storey_masses = dt.add_foundation(df.heights, df.storey_masses,
                                               df.fd.height, df.fd.mass)
    df.storey_mass_p_frame = storey_masses / df.n_seismic_frames

    # initial estimate of foundation shear
    # for iteration in range(found_rot_iterations):  # iterate the foundation rotation
    #     df.delta_fshear = 0
    disp_compatible = False
    fd_compatible = False
    for i in range(100):
        fd_compatible = False
        mu_reduction_factor = 1.0 - float(i) / 100
        theta_c = df.design_drift * mu_reduction_factor
        temp_found_rot = found_rot
        temp_delta_fshear = 0
        for iteration in range(
                found_rot_iterations):  # iterate the foundation rotation

            displacements = dt.displacement_profile_frame(
                theta_c,
                heights,
                df.hm_factor,
                foundation=True,
                fd_height=df.fd.height,
                theta_f=temp_found_rot)
            df.delta_d, df.mass_eff, df.height_eff = dt.equivalent_sdof(
                df.storey_mass_p_frame, displacements, heights)
            df.theta_y = dt.conc_frame_yield_drift(df.fye,
                                                   df.concrete.e_mod_steel,
                                                   df.av_bay, df.av_beam)
            delta_y = dt.yield_displacement(df.theta_y,
                                            df.height_eff - df.fd.height)

            df.delta_frot = df.theta_f * df.height_eff
            df.delta_f = df.delta_frot + temp_delta_fshear
            df.delta_ss = df.delta_d - df.delta_f

            df.mu = dt.ductility(df.delta_ss, delta_y)
            if df.mu < 0:
                raise DesignError('foundation rotation to large, Mu < 0.0')
            eta_fshear = nf.foundation_shear_reduction_factor()
            xi_ss = dt.equivalent_viscous_damping(df.mu)
            eta_ss = dt.reduction_factor(xi_ss)

            norm_rot = temp_found_rot / df.theta_pseudo_up
            bhr = (df.fd.width / df.height_eff)
            cor_norm_rot = nf.calculate_corrected_normalised_rotation(
                norm_rot, bhr)
            eta_frot = nf.foundation_rotation_reduction_factor(cor_norm_rot)
            if verbose >= 1:
                print("mu: ", df.mu)
                print('DRF_ss: ', eta_ss)
                print('DRF_frot: ', eta_frot)

            eta_sys = nf.system_reduction_factor(df.delta_ss, df.delta_frot,
                                                 temp_delta_fshear, eta_ss,
                                                 eta_frot, eta_fshear)

            df.eta = eta_sys
            df.xi = dt.damping_from_reduction_factor(eta_sys)
            df.t_eff = dt.effective_period(df.delta_d, df.eta,
                                           df.hz.corner_disp,
                                           df.hz.corner_period)

            if verbose > 1:
                print('Delta_D: ', df.delta_d)
                print('Effective mass: ', df.mass_eff)
                print('Effective height: ', df.height_eff)
                print('Mu: ', df.mu)
                print('theta yield', df.theta_y)
                print('xi: ', df.xi)
                print('Reduction Factor: ', df.eta)
                print('t_eff', df.t_eff)

            if df.t_eff > 0:
                disp_compatible = True
                k_eff = dt.effective_stiffness(df.mass_eff, df.t_eff)
                v_base_dynamic = dt.design_base_shear(k_eff, df.delta_d)
                v_base_p_delta = dt.p_delta_base_shear(df.mass_eff, df.delta_d,
                                                       df.height_eff,
                                                       v_base_dynamic)
                df.v_base = v_base_dynamic + v_base_p_delta
                prev_delta_fshear = temp_delta_fshear
                temp_delta_fshear = df.v_base / (0.5 * df.k_f0_shear)
                df.storey_forces = dt.calculate_storey_forces(
                    df.storey_mass_p_frame,
                    displacements,
                    df.v_base,
                    btype='frame')
                n_ult = df.fd_bearing_capacity
                moment_f = df.v_base * df.height_eff
                hf = df.height_eff
                prev_found_rot = temp_found_rot

                temp_found_rot = calc_fd_rot_via_millen_et_al_2020(
                    df.k_f_0, df.fd.length, df.total_weight, n_ult, psi,
                    moment_f, df.height_eff)
                if abs(prev_delta_fshear -
                       temp_delta_fshear) / df.delta_d < 0.01 and abs(
                           prev_found_rot -
                           temp_found_rot) * hf / df.delta_d < 0.01:
                    fd_compatible = True
                    break
                else:
                    fd_compatible = False

            else:
                break

        if disp_compatible:
            break
    if not fd_compatible:
        print(i, iteration)
        raise DesignError(
            f'Foundation displacements not compatible in design (prev: {prev_found_rot}, last: {found_rot})'
        )
    if not disp_compatible:
        raise DesignError('System displacements not compatible in design')

    found_rot = temp_found_rot
    df.theta_f = temp_found_rot
    df.delta_fshear = temp_delta_fshear

    df.theta_f = found_rot

    if fd.type == 'pad_foundation':
        assert isinstance(fd, sm.PadFoundation)
        ip_axis = 'length'
        mom_ratio = 0.6
        moment_beams_cl, moment_column_bases, axial_seismic = moment_equilibrium.assess(
            df, df.storey_forces, mom_ratio)
        # TODO: need to account for minimum column base moment which shifts mom_ratio
        h_eff = df.interstorey_heights[0] * mom_ratio + fd.height
        pad = df.fd.pad
        pad.n_ult = df.soil_q * pad.area
        col_loads = df.get_column_vert_loads()
        ext_nloads = max(col_loads[0])
        int_nloads = np.max(col_loads[1:-1])

        m_foot_int = np.max(
            moment_column_bases[1:-1]) * h_eff / df.interstorey_heights[0]
        pad.n_load = int_nloads
        tie_beams = getattr(fd, f'tie_beam_in_{ip_axis}_dir')
        tb_length = (fd.length -
                     (fd.pad_length * fd.n_pads_l)) / (fd.n_pads_l - 1)
        tie_beams = None
        if hasattr(fd, f'tie_beam_in_{ip_axis}_dir'):
            tie_beams = getattr(fd, f'tie_beam_in_{ip_axis}_dir')
        if tie_beams is not None:
            tb_sect = getattr(fd, f'tie_beam_in_{ip_axis}_dir').s[0]
            assert isinstance(tb_sect, sm.sections.RCBeamSection)
            # See supporting_docs/tie-beam-stiffness-calcs.pdf
            k_ties = (6 * tb_sect.i_rot_ww_cracked *
                      tb_sect.mat.e_mod_conc) / tb_length
        else:
            k_ties = 0
        l_in = getattr(pad, ip_axis)
        k_f_0_pad = gf.stiffness.calc_rotational_via_gazetas_1991(
            sl, pad, ip_axis=ip_axis)
        rot_ipad = calc_fd_rot_via_millen_et_al_2020_w_tie_beams(
            k_f_0_pad, l_in, int_nloads, pad.n_ult, psi, m_foot_int, h_eff,
            2 * k_ties)
        # Exterior footings
        if rot_ipad is None:  # First try moment ratio of 0.5
            # m_cap = pad.n_load * getattr(pad, ip_axis) / 2 * (1 - pad.n_load / pad.n_ult)
            m_cap = calc_moment_capacity_via_millen_et_al_2020(
                l_in, pad.n_load, pad.n_ult, psi, h_eff)
            raise DesignError(
                f"Design failed - interior footing moment demand ({m_foot_int/1e3:.3g})"
                f" kNm exceeds capacity (~{m_cap/1e3:.3g} kNm)")
        m_foot_ext = np.max(moment_column_bases[np.array(
            [0, -1])]) * h_eff / df.interstorey_heights[0]
        pad.n_load = ext_nloads
        # rot_epad = check_local_footing_rotations(sl, pad, m_foot_ext, h_eff, ip_axis=ip_axis, k_ties=k_ties)
        rot_epad = calc_fd_rot_via_millen_et_al_2020_w_tie_beams(
            k_f_0_pad, l_in, ext_nloads, pad.n_ult, psi, m_foot_ext, h_eff,
            k_ties)
        if rot_epad is None:
            m_cap = pad.n_load * getattr(
                pad, ip_axis) / 2 * (1 - pad.n_load / pad.n_ult)
            raise DesignError(
                f"Design failed - interior footing moment demand ({m_foot_ext/1e3:.3g})"
                f" kNm exceeds capacity (~{m_cap/1e3:.3g} kNm)")
        if max([rot_ipad, rot_epad]) - found_rot > theta_c - df.theta_y:
            # footing should be increased or design drift increased
            pad_rot = max([rot_ipad, rot_epad])
            plastic_rot = theta_c - df.theta_y
            raise DesignError(
                f"Design failed - footing rotation ({pad_rot:.3g}) "
                f"exceeds plastic rotation (~{plastic_rot:.3g})")

    return df
示例#3
0
def design_rc_wall_via_millen_et_al_2020(wb,
                                         hz,
                                         sl,
                                         fd,
                                         design_drift=0.025,
                                         **kwargs):
    """
    Displacement-based design of a concrete wall.

    :param wb: WallBuilding object
    :param hz: Hazard Object
    :param design_drift: Design drift
    :param kwargs:
    :return: DesignedWall object
    """
    dw = em.DesignedSFSIRCWall(wb, hz, sl, fd)
    dw.design_drift = design_drift
    verbose = kwargs.get('verbose', dw.verbose)
    dw.static_dbd_values()
    print("udw: ", dw.sl.unit_dry_weight)
    dw.static_values()

    # add foundation to heights and masses
    heights, storey_masses = dt.add_foundation(dw.heights, dw.storey_masses,
                                               dw.fd.height, dw.fd.mass)
    dw.storey_mass_p_wall = storey_masses / dw.n_walls

    # k = min(0.2 * (fu / fye - 1), 0.08)  # Eq 4.31b
    k = min(0.15 * (dw.fu / dw.fye - 1), 0.06)  # Eq 6.5a from DDBD code
    l_c = dw.max_height
    long_db = dw.preferred_bar_diameter
    l_sp = 0.022 * dw.fye * long_db / 1.0e6  # Eq 4.30
    l_p = max(k * l_c + l_sp + 0.1 * dw.wall_depth, 2 * l_sp)
    phi_y = dt.yield_curvature(dw.epsilon_y, dw.wall_depth, btype="wall")
    delta_y = dt.yield_displacement_wall(phi_y, heights, dw.max_height)
    phi_p = dw.phi_material - phi_y
    # determine whether code limit or material strain governs
    theta_ss_code = design_drift
    dw.theta_y = dw.epsilon_y * dw.max_height / dw.wall_depth
    theta_p_code = (theta_ss_code - dw.theta_y)
    theta_p = min(theta_p_code, phi_p * l_p)

    # Assume no torsional effects
    increments = theta_p + dw.theta_y
    for i in range(20):
        reduced_theta_p = theta_p - increments * float(i) / 20
        if reduced_theta_p > 0.0:
            non_linear = 1

            delta_p = reduced_theta_p * (dw.heights - (0.5 * l_p - l_sp))
            delta_p = np.insert(delta_p, 0,
                                0)  # no plastic deformation at foundation
            if verbose > 2:
                print('reduced_theta_p: ', reduced_theta_p)
                print('delta_p: ', delta_p)

            delta_st = delta_y + delta_p
        else:
            raise DesignError('can not handle linear design, resize footing')

        dw.design_drift = reduced_theta_p + dw.theta_y

        delta_ls = delta_st

        displacements = delta_ls * dw.hm_factor

        dw.delta_d, dw.mass_eff, dw.height_eff = dt.equivalent_sdof(
            dw.storey_mass_p_wall, displacements, heights)
        delta_y = dt.yield_displacement_wall(phi_y, dw.height_eff,
                                             dw.max_height)
        dw.mu = dt.ductility(dw.delta_d, delta_y)
        dw.xi = dt.equivalent_viscous_damping(dw.mu,
                                              mtype="concrete",
                                              btype="wall")
        dw.eta = dt.reduction_factor(dw.xi)
        dw.t_eff = dt.effective_period(dw.delta_d, dw.eta, dw.hz.corner_disp,
                                       dw.hz.corner_period)

        if verbose > 1:
            print('Delta_D: ', dw.delta_d)
            print('Effective mass: ', dw.mass_eff)
            print('Effective height: ', dw.height_eff)
            print('Mu: ', dw.mu)
            print('theta yield', dw.theta_y)
            print('xi: ', dw.xi)
            print('Reduction Factor: ', dw.eta)
            print('t_eff', dw.t_eff)

        if dw.t_eff > 0:
            break
        else:
            if verbose > 1:
                print("drift %.2f is not compatible" % reduced_theta_p)
    k_eff = dt.effective_stiffness(dw.mass_eff, dw.t_eff)
    dw.v_base = dt.design_base_shear(k_eff, dw.delta_d)
    moment_f = dw.v_base * dw.height_eff
    psi = 0.75 * np.tan(dw.sl.phi_r)
    theta_f = calc_fd_rot_via_millen_et_al_2020(dw.k_f_0, dw.fd.length,
                                                dw.total_weight,
                                                dw.bearing_capacity, psi,
                                                moment_f, dw.height_eff)
    print("theta_f: ", theta_f)

    # TODO: ADD calculation of rotation

    dw.storey_forces = dt.calculate_storey_forces(dw.storey_mass_p_wall,
                                                  displacements,
                                                  dw.v_base,
                                                  btype='wall')
    return dw
示例#4
0
def design_rc_wall(wb, hz, design_drift=0.025, **kwargs):
    """
    Displacement-based design of a reinforced concrete wall.

    :param wb: WallBuilding object
    :param hz: Hazard Object
    :param design_drift: Design drift
    :param kwargs:
    :return: DesignedWall object
    """

    dw = em.DesignedRCWall(wb, hz)
    dw.design_drift = design_drift
    verbose = kwargs.get('verbose', dw.verbose)
    dw.static_dbd_values()
    # k = min(0.2 * (fu / fye - 1), 0.08)  # Eq 4.31b
    k = min(0.15 * (dw.fu / dw.fye - 1), 0.06)  # Eq 6.5a from DDBD code
    l_c = dw.max_height
    long_db = dw.preferred_bar_diameter
    l_sp = 0.022 * dw.fye * long_db / 1.0e6  # Eq 4.30
    l_p = max(k * l_c + l_sp + 0.1 * dw.wall_depth, 2 * l_sp)
    phi_y = dt.yield_curvature(dw.epsilon_y, dw.wall_depth, btype="wall")
    delta_y = dt.yield_displacement_wall(phi_y, dw.heights, dw.max_height)
    phi_p = dw.phi_material - phi_y
    # determine whether code limit or material strain governs
    theta_ss_code = design_drift
    dw.theta_y = dw.epsilon_y * dw.max_height / dw.wall_depth
    theta_p_code = (theta_ss_code - dw.theta_y)
    theta_p = min(theta_p_code, phi_p * l_p)

    # Assume no torsional effects
    increments = theta_p + dw.theta_y
    for i in range(20):
        reduced_theta_p = theta_p - increments * float(i) / 20
        if reduced_theta_p > 0.0:
            non_linear = 1

            delta_p = reduced_theta_p * (dw.heights - (0.5 * l_p - l_sp))
            if verbose > 2:
                print('reduced_theta_p: ', reduced_theta_p)
                print('delta_p: ', delta_p)

            delta_st = delta_y + delta_p
        else:
            raise DesignError('can not handle linear design, resize footing')

        dw.design_drift = reduced_theta_p + dw.theta_y

        delta_ls = delta_st

        displacements = delta_ls * dw.hm_factor

        dw.delta_d, dw.mass_eff, dw.height_eff = dt.equivalent_sdof(
            dw.storey_mass_p_wall, displacements, dw.heights)
        delta_y = dt.yield_displacement_wall(phi_y, dw.height_eff,
                                             dw.max_height)
        dw.mu = dt.ductility(dw.delta_d, delta_y)
        dw.xi = dt.equivalent_viscous_damping(dw.mu,
                                              mtype="concrete",
                                              btype="wall")
        dw.eta = dt.reduction_factor(dw.xi)
        dw.t_eff = dt.effective_period(dw.delta_d, dw.eta, dw.hz.corner_disp,
                                       dw.hz.corner_period)

        if verbose > 1:
            print('Delta_D: ', dw.delta_d)
            print('Effective mass: ', dw.mass_eff)
            print('Effective height: ', dw.height_eff)
            print('Mu: ', dw.mu)
            print('theta yield', dw.theta_y)
            print('xi: ', dw.xi)
            print('Reduction Factor: ', dw.eta)
            print('t_eff', dw.t_eff)

        if dw.t_eff > 0:
            break
        else:
            if verbose > 1:
                print("drift %.2f is not compatible" % reduced_theta_p)
    k_eff = dt.effective_stiffness(dw.mass_eff, dw.t_eff)
    dw.v_base = dt.design_base_shear(k_eff, dw.delta_d)
    dw.storey_forces = dt.calculate_storey_forces(dw.storey_mass_p_wall,
                                                  displacements,
                                                  dw.v_base,
                                                  btype='wall')
    return dw
示例#5
0
def design_rc_frame_w_sfsi_via_millen_et_al_2018(fb,
                                                 hz,
                                                 sl,
                                                 fd,
                                                 design_drift=0.02,
                                                 found_rot=0.00001,
                                                 found_rot_tol=0.02,
                                                 found_rot_iterations=20,
                                                 **kwargs):

    df = em.DesignedSFSIRCFrame(fb, hz, sl, fd)
    df.design_drift = design_drift
    df.theta_f = found_rot
    verbose = kwargs.get('verbose', df.verbose)
    df.static_values()

    # add foundation to heights and masses
    heights, storey_masses = dt.add_foundation(df.heights, df.storey_masses,
                                               df.fd.height, df.fd.mass)
    df.storey_mass_p_frame = storey_masses / df.n_seismic_frames

    # initial estimate of foundation shear
    for iteration in range(
            found_rot_iterations):  # iterate the foundation rotation
        df.delta_fshear = 0

        for i in range(100):
            mu_reduction_factor = 1.0 - float(i) / 100
            theta_c = df.design_drift * mu_reduction_factor
            displacements = dt.displacement_profile_frame(
                theta_c,
                heights,
                df.hm_factor,
                foundation=True,
                fd_height=df.fd.height,
                theta_f=df.theta_f)
            df.delta_d, df.mass_eff, df.height_eff = dt.equivalent_sdof(
                df.storey_mass_p_frame, displacements, heights)
            df.theta_y = dt.conc_frame_yield_drift(df.fye,
                                                   df.concrete.e_mod_steel,
                                                   df.av_bay, df.av_beam)
            delta_y = dt.yield_displacement(df.theta_y,
                                            df.height_eff - df.fd.height)

            df.delta_frot = df.theta_f * df.height_eff
            df.delta_f = df.delta_frot + df.delta_fshear
            df.delta_ss = df.delta_d - df.delta_f

            df.mu = dt.ductility(df.delta_ss, delta_y)
            if df.mu < 0:
                raise DesignError('foundation rotation to large, Mu < 0.0')
            eta_fshear = nf.foundation_shear_reduction_factor()
            xi_ss = dt.equivalent_viscous_damping(df.mu)
            eta_ss = dt.reduction_factor(xi_ss)

            norm_rot = found_rot / df.theta_pseudo_up
            bhr = (df.fd.width / df.height_eff)
            cor_norm_rot = nf.calculate_corrected_normalised_rotation(
                norm_rot, bhr)
            eta_frot = nf.foundation_rotation_reduction_factor(cor_norm_rot)
            if verbose >= 1:
                print("mu: ", df.mu)
                print('DRF_ss: ', eta_ss)
                print('DRF_frot: ', eta_frot)

            eta_sys = nf.system_reduction_factor(df.delta_ss, df.delta_frot,
                                                 df.delta_fshear, eta_ss,
                                                 eta_frot, eta_fshear)

            df.eta = eta_sys
            df.xi = dt.damping_from_reduction_factor(eta_sys)
            df.t_eff = dt.effective_period(df.delta_d, df.eta,
                                           df.hz.corner_disp,
                                           df.hz.corner_period)

            if verbose > 1:
                print('Delta_D: ', df.delta_d)
                print('Effective mass: ', df.mass_eff)
                print('Effective height: ', df.height_eff)
                print('Mu: ', df.mu)
                print('theta yield', df.theta_y)
                print('xi: ', df.xi)
                print('Reduction Factor: ', df.eta)
                print('t_eff', df.t_eff)

            if df.t_eff > 0:
                break
            else:
                if verbose > 1:
                    print("drift %.2f is not compatible" % theta_c)
        k_eff = dt.effective_stiffness(df.mass_eff, df.t_eff)
        v_base_dynamic = dt.design_base_shear(k_eff, df.delta_d)
        v_base_p_delta = dt.p_delta_base_shear(df.mass_eff, df.delta_d,
                                               df.height_eff, v_base_dynamic)
        df.v_base = v_base_dynamic + v_base_p_delta
        df.storey_forces = dt.calculate_storey_forces(df.storey_mass_p_frame,
                                                      displacements,
                                                      df.v_base,
                                                      btype='frame')

        stiffness_ratio = nf.foundation_rotation_stiffness_ratio(cor_norm_rot)
        k_f_eff = df.k_f_0 * stiffness_ratio
        temp_found_rot = found_rot
        moment_f = df.v_base * df.height_eff
        found_rot = moment_f / k_f_eff
        df.delta_fshear = df.v_base / (0.5 * df.k_f0_shear)

        iteration_diff = (abs(temp_found_rot - found_rot) / found_rot)
        if iteration_diff < found_rot_tol:
            if verbose:
                print('found_rot_i-1: ', temp_found_rot)
                print('found_rot_i: ', found_rot)
                print('n_iterations: ', iteration)
            break
        elif iteration == found_rot_iterations - 1:
            print('found_rot_i-1: ', temp_found_rot)
            print('found_rot_i: ', found_rot)
            print('iteration difference: ', iteration_diff)
            df.mu = -1
            raise DesignError('Could not find convergence')

        df.theta_f = found_rot
    return df
示例#6
0
def test_effective_stiffness():
    assert isclose(dt.effective_stiffness(300, 2.0), 2959.76, rel_tol=0.0001)
    assert isclose(dt.effective_stiffness(200, 1.0), 7892.7048, rel_tol=0.0001)
    assert isclose(dt.effective_stiffness(100., 2.0), 986.588, rel_tol=0.0001), dt.effective_stiffness(100., 2.0)