Пример #1
0
def test_ele_load_uniform():
    osi = o3.OpenSeesInstance(ndm=2, state=3)
    ele_len = 2.0
    coords = [[0, 0], [ele_len, 0]]
    ele_nodes = [o3.node.Node(osi, *coords[x]) for x in range(len(coords))]
    transf = o3.geom_transf.Linear2D(osi, [])
    ele = o3.element.ElasticBeamColumn2D(osi,
                                         ele_nodes=ele_nodes,
                                         area=1.0,
                                         e_mod=1.0,
                                         iz=1.0,
                                         transf=transf,
                                         mass=1.0,
                                         c_mass="string")

    for i, node in enumerate(ele_nodes):
        if i == 0:
            o3.Fix3DOF(osi, node, o3.cc.FIXED, o3.cc.FIXED, o3.cc.FIXED)
        else:
            o3.Fix3DOF(osi, node, o3.cc.FREE, o3.cc.FIXED, o3.cc.FIXED)

    ts_po = o3.time_series.Linear(osi, factor=1)
    o3.pattern.Plain(osi, ts_po)
    udl = 10.
    o3.EleLoad2DUniform(osi, ele, w_y=-udl)

    tol = 1.0e-4
    o3.constraints.Plain(osi)
    o3.numberer.RCM(osi)
    o3.system.BandGeneral(osi)
    o3.test_check.NormDispIncr(osi, tol, 6)
    o3.algorithm.Newton(osi)
    n_steps_gravity = 1
    d_gravity = 1. / n_steps_gravity
    o3.integrator.LoadControl(osi, d_gravity, num_iter=10)
    o3.analysis.Static(osi)
    o3.analyze(osi, n_steps_gravity)
    opy.reactions()
    ele_loads = o3.get_ele_response(osi, ele, 'force')
    assert np.isclose(ele_loads[0], 0.0)
    assert np.isclose(ele_loads[1], udl * ele_len / 2)
    assert np.isclose(ele_loads[2], udl * ele_len**2 / 12)
    assert np.isclose(ele_loads[3], 0.0)
    assert np.isclose(ele_loads[4], udl * ele_len / 2)
    assert np.isclose(ele_loads[5], -udl * ele_len**2 / 12)
    assert np.isclose(o3.get_node_reaction(osi, ele_nodes[0], o3.cc.Y),
                      udl * ele_len / 2)
def run(use_pload):
    # If pload=true then apply point load at end, else apply distributed load along beam

    osi = o3.OpenSeesInstance(ndm=2, state=3)

    ele_len = 4.0

    # Establish nodes
    left_node = o3.node.Node(osi, 0, 0)
    right_node = o3.node.Node(osi, ele_len, 0)

    # Fix bottom node
    o3.Fix3DOF(osi, left_node, o3.cc.FIXED, o3.cc.FIXED, o3.cc.FIXED)
    o3.Fix3DOF(osi, right_node, o3.cc.FREE, o3.cc.FREE, o3.cc.FREE)
    e_mod = 200.0e2
    i_sect = 0.1
    area = 0.5
    lp_i = 0.1
    lp_j = 0.1

    elastic = 0

    if elastic:
        left_sect = o3.section.Elastic2D(osi, e_mod, area, i_sect)
    else:
        m_cap = 14.80
        b = 0.05
        phi = m_cap / (e_mod * i_sect)
        # mat_flex = o3.uniaxial_material.Steel01(osi, m_cap, e0=e_mod * i_sect, b=b)
        mat_flex = o3.uniaxial_material.ElasticBilin(osi, e_mod * i_sect,
                                                     e_mod * i_sect * b, phi)
        mat_axial = o3.uniaxial_material.Elastic(osi, e_mod * area)
        left_sect = o3.section.Aggregator(osi,
                                          mats=[[mat_axial, o3.cc.P],
                                                [mat_flex, o3.cc.M_Z],
                                                [mat_flex, o3.cc.M_Y]])
    right_sect = o3.section.Elastic2D(osi, e_mod, area, i_sect)
    centre_sect = o3.section.Elastic2D(osi, e_mod, area, i_sect)
    integ = o3.beam_integration.HingeMidpoint(osi, left_sect, lp_i, right_sect,
                                              lp_j, centre_sect)
    beam_transf = o3.geom_transf.Linear2D(osi, )
    ele = o3.element.ForceBeamColumn(osi, [left_node, right_node], beam_transf,
                                     integ)

    w_gloads = 1
    if w_gloads:
        # Apply gravity loads
        pload = 1.0 * ele_len
        udl = 2.0
        ts_po = o3.time_series.Linear(osi, factor=1)
        o3.pattern.Plain(osi, ts_po)
        if use_pload:
            o3.Load(osi, right_node, [0, -pload, 0])
        else:
            o3.EleLoad2DUniform(osi, ele, -udl)

        tol = 1.0e-3
        o3.constraints.Plain(osi)
        o3.numberer.RCM(osi)
        o3.system.BandGeneral(osi)
        n_steps_gravity = 10
        o3.integrator.LoadControl(osi, 1. / n_steps_gravity, num_iter=10)
        o3.test_check.NormDispIncr(osi, tol, 10)
        o3.algorithm.Linear(osi)
        o3.analysis.Static(osi)
        o3.analyze(osi, n_steps_gravity)
        o3.gen_reactions(osi)
        print('reactions: ', o3.get_ele_response(osi, ele, 'force')[:3])
        end_disp = o3.get_node_disp(osi, right_node, dof=o3.cc.Y)
        print(f'end_disp: {end_disp}')
        if use_pload:
            disp_expected = pload * ele_len**3 / (3 * e_mod * i_sect)
            print(f'v_expected: {pload}')
            print(f'm_expected: {pload * ele_len}')
            print(f'disp_expected: {disp_expected}')
        else:
            v_expected = udl * ele_len
            m_expected = udl * ele_len**2 / 2
            disp_expected = udl * ele_len**4 / (8 * e_mod * i_sect)
            print(f'v_expected: {v_expected}')
            print(f'm_expected: {m_expected}')
            print(f'disp_expected: {disp_expected}')

        # o3.extensions.to_py_file(osi, 'temp4.py')
    disp_load = 1
    if disp_load:
        # start displacement controlled
        d_inc = -0.01

        # opy.wipeAnalysis()
        o3.numberer.RCM(osi)
        o3.system.BandGeneral(osi)
        o3.test_check.NormUnbalance(osi, 2, max_iter=10, p_flag=0)
        # o3.test_check.FixedNumIter(osi, max_iter=10)
        # o3.test_check.NormDispIncr(osi, 0.002, 10, p_flag=0)
        o3.algorithm.Newton(osi)
        o3.integrator.DisplacementControl(osi, right_node, o3.cc.Y, d_inc)
        o3.analysis.Static(osi)
        ts_po = o3.time_series.Linear(osi, factor=1)
        o3.pattern.Plain(osi, ts_po)
        o3.Load(osi, right_node, [0.0, 1.0, 0])
        ok = o3.analyze(osi, 10)
        end_disp = o3.get_node_disp(osi, right_node, dof=o3.cc.Y)
        print(f'end_disp: {end_disp}')
        r = o3.get_ele_response(osi, ele, 'force')[:3]
        print('reactions: ', r)
        k = r[1] / -end_disp
        print('k: ', k)
        k_elastic_expected = 1. / (ele_len**3 / (3 * e_mod * i_sect))
        print('k_elastic_expected: ', k_elastic_expected)
def get_inelastic_response(fb,
                           roof_drift_ratio=0.05,
                           elastic=False,
                           w_sfsi=False,
                           out_folder=''):
    """
    Run seismic analysis of a nonlinear FrameBuilding

    Units: Pa, N, m, s

    Parameters
    ----------
    fb: sfsimodels.Frame2DBuilding object
    xi

    Returns
    -------

    """
    osi = o3.OpenSeesInstance(ndm=2, state=3)

    q_floor = 7.0e3  # Pa
    trib_width = fb.floor_length
    trib_mass_per_length = q_floor * trib_width / 9.8

    # Establish nodes and set mass based on trib area
    # Nodes named as: C<column-number>-S<storey-number>, first column starts at C1-S0 = ground level left
    nd = OrderedDict()
    col_xs = np.cumsum(fb.bay_lengths)
    col_xs = np.insert(col_xs, 0, 0)
    n_cols = len(col_xs)
    sto_ys = fb.heights
    sto_ys = np.insert(sto_ys, 0, 0)
    for cc in range(1, n_cols + 1):
        for ss in range(fb.n_storeys + 1):
            nd[f"C{cc}-S{ss}"] = o3.node.Node(osi, col_xs[cc - 1], sto_ys[ss])

            if ss != 0:
                if cc == 1:
                    node_mass = trib_mass_per_length * fb.bay_lengths[0] / 2
                elif cc == n_cols:
                    node_mass = trib_mass_per_length * fb.bay_lengths[-1] / 2
                else:
                    node_mass = trib_mass_per_length * (
                        fb.bay_lengths[cc - 2] + fb.bay_lengths[cc - 1] / 2)
                o3.set_node_mass(osi, nd[f"C{cc}-S{ss}"], node_mass, 0., 0.)

    # Set all nodes on a storey to have the same displacement
    for ss in range(0, fb.n_storeys + 1):
        for cc in range(2, n_cols + 1):
            o3.set_equal_dof(osi, nd[f"C1-S{ss}"], nd[f"C{cc}-S{ss}"], o3.cc.X)

    # Fix all base nodes
    for cc in range(1, n_cols + 1):
        o3.Fix3DOF(osi, nd[f"C{cc}-S0"], o3.cc.FIXED, o3.cc.FIXED, o3.cc.FIXED)

    # Define material
    e_conc = 30.0e9  # kPa
    i_beams = 0.4 * fb.beam_widths * fb.beam_depths**3 / 12
    i_columns = 0.5 * fb.column_widths * fb.column_depths**3 / 12
    a_beams = fb.beam_widths * fb.beam_depths
    a_columns = fb.column_widths * fb.column_depths
    ei_beams = e_conc * i_beams
    ei_columns = e_conc * i_columns
    eps_yield = 300.0e6 / 200e9
    phi_y_col = calc_yield_curvature(fb.column_depths, eps_yield)
    phi_y_beam = calc_yield_curvature(fb.beam_depths, eps_yield)

    # Define beams and columns
    # Columns named as: C<column-number>-S<storey-number>, first column starts at C1-S0 = ground floor left
    # Beams named as: B<bay-number>-S<storey-number>, first beam starts at B1-S1 = first storey left (foundation at S0)

    md = OrderedDict()  # material dict
    sd = OrderedDict()  # section dict
    ed = OrderedDict()  # element dict

    for ss in range(fb.n_storeys):

        # set columns
        lp_i = 0.4
        lp_j = 0.4  # plastic hinge length
        col_transf = o3.geom_transf.Linear2D(
            osi, )  # d_i=[0.0, lp_i], d_j=[0.0, -lp_j]
        for cc in range(1, fb.n_cols + 1):

            ele_str = f"C{cc}-S{ss}S{ss + 1}"

            if elastic:
                top_sect = o3.section.Elastic2D(osi, e_conc,
                                                a_columns[ss][cc - 1],
                                                i_columns[ss][cc - 1])
                bot_sect = o3.section.Elastic2D(osi, e_conc,
                                                a_columns[ss][cc - 1],
                                                i_columns[ss][cc - 1])
            else:
                m_cap = ei_columns[ss][cc - 1] * phi_y_col[ss][cc - 1]
                mat = o3.uniaxial_material.ElasticBilin(
                    osi, ei_columns[ss][cc - 1], 0.05 * ei_columns[ss][cc - 1],
                    1 * phi_y_col[ss][cc - 1])
                mat_axial = o3.uniaxial_material.Elastic(
                    osi, e_conc * a_columns[ss][cc - 1])
                top_sect = o3.section.Aggregator(osi,
                                                 mats=[[mat_axial, o3.cc.P],
                                                       [mat, o3.cc.M_Z]])
                bot_sect = o3.section.Aggregator(osi,
                                                 mats=[[mat_axial, o3.cc.P],
                                                       [mat, o3.cc.M_Z]])

            centre_sect = o3.section.Elastic2D(osi, e_conc,
                                               a_columns[ss][cc - 1],
                                               i_columns[ss][cc - 1])
            sd[ele_str + "T"] = top_sect
            sd[ele_str + "B"] = bot_sect
            sd[ele_str + "C"] = centre_sect

            integ = o3.beam_integration.HingeMidpoint(osi, bot_sect, lp_i,
                                                      top_sect, lp_j,
                                                      centre_sect)

            bot_node = nd[f"C{cc}-S{ss}"]
            top_node = nd[f"C{cc}-S{ss + 1}"]
            ed[ele_str] = o3.element.ForceBeamColumn(osi, [bot_node, top_node],
                                                     col_transf, integ)
            print('mc: ', ei_columns[ss][cc - 1] * phi_y_col[ss][cc - 1])
        # Set beams
        lp_i = 0.4
        lp_j = 0.4
        beam_transf = o3.geom_transf.Linear2D(osi, )
        for bb in range(1, fb.n_bays + 1):

            ele_str = f"C{bb}C{bb + 1}-S{ss + 1}"

            print('mb: ', ei_beams[ss][bb - 1] * phi_y_beam[ss][bb - 1])
            print('phi_b: ', phi_y_beam[ss][bb - 1])

            if elastic:
                left_sect = o3.section.Elastic2D(osi, e_conc,
                                                 a_beams[ss][bb - 1],
                                                 i_beams[ss][bb - 1])
                right_sect = o3.section.Elastic2D(osi, e_conc,
                                                  a_beams[ss][bb - 1],
                                                  i_beams[ss][bb - 1])
            else:
                m_cap = ei_beams[ss][bb - 1] * phi_y_beam[ss][bb - 1]
                # mat_flex = o3.uniaxial_material.ElasticBilin(osi, ei_beams[ss][bb - 1], 0.05 * ei_beams[ss][bb - 1], phi_y_beam[ss][bb - 1])
                mat_flex = o3.uniaxial_material.Steel01(osi,
                                                        m_cap,
                                                        e0=ei_beams[ss][bb -
                                                                        1],
                                                        b=0.05)
                mat_axial = o3.uniaxial_material.Elastic(
                    osi, e_conc * a_beams[ss][bb - 1])
                left_sect = o3.section.Aggregator(osi,
                                                  mats=[[mat_axial, o3.cc.P],
                                                        [mat_flex, o3.cc.M_Z],
                                                        [mat_flex, o3.cc.M_Y]])
                right_sect = o3.section.Aggregator(osi,
                                                   mats=[[mat_axial, o3.cc.P],
                                                         [mat_flex, o3.cc.M_Z],
                                                         [mat_flex,
                                                          o3.cc.M_Y]])

            centre_sect = o3.section.Elastic2D(osi, e_conc,
                                               a_beams[ss][bb - 1],
                                               i_beams[ss][bb - 1])
            integ = o3.beam_integration.HingeMidpoint(osi, left_sect, lp_i,
                                                      right_sect, lp_j,
                                                      centre_sect)

            left_node = nd[f"C{bb}-S{ss + 1}"]
            right_node = nd[f"C{bb + 1}-S{ss + 1}"]
            ed[ele_str] = o3.element.ForceBeamColumn(osi,
                                                     [left_node, right_node],
                                                     beam_transf, integ)

    # Apply gravity loads
    gravity = 9.8 * 1e-2
    # If true then load applied along beam
    g_beams = 0  # TODO: when this is true and analysis is inelastic then failure
    ts_po = o3.time_series.Linear(osi, factor=1)
    o3.pattern.Plain(osi, ts_po)

    for ss in range(1, fb.n_storeys + 1):
        print('ss:', ss)
        if g_beams:
            for bb in range(1, fb.n_bays + 1):
                ele_str = f"C{bb}C{bb + 1}-S{ss}"
                o3.EleLoad2DUniform(osi, ed[ele_str],
                                    -trib_mass_per_length * gravity)
        else:
            for cc in range(1, fb.n_cols + 1):
                if cc == 1 or cc == n_cols:
                    node_mass = trib_mass_per_length * fb.bay_lengths[0] / 2
                elif cc == n_cols:
                    node_mass = trib_mass_per_length * fb.bay_lengths[-1] / 2
                else:
                    node_mass = trib_mass_per_length * (
                        fb.bay_lengths[cc - 2] + fb.bay_lengths[cc - 1] / 2)
                # This works
                o3.Load(osi, nd[f"C{cc}-S{ss}"], [0, -node_mass * gravity, 0])

    tol = 1.0e-3
    o3.constraints.Plain(osi)
    o3.numberer.RCM(osi)
    o3.system.BandGeneral(osi)
    o3.test_check.NormDispIncr(osi, tol, 10)
    o3.algorithm.Newton(osi)
    n_steps_gravity = 10
    d_gravity = 1. / n_steps_gravity
    o3.integrator.LoadControl(osi, d_gravity, num_iter=10)
    o3.analysis.Static(osi)
    o3.analyze(osi, n_steps_gravity)
    o3.gen_reactions(osi)
    print('b1_int: ', o3.get_ele_response(osi, ed['C1C2-S1'], 'force'))
    print('c1_int: ', o3.get_ele_response(osi, ed['C1-S0S1'], 'force'))

    # o3.extensions.to_py_file(osi, 'po.py')
    o3.load_constant(osi, time=0.0)

    # Define the analysis

    # set damping based on first eigen mode
    angular_freq = o3.get_eigen(osi, solver='fullGenLapack', n=1)[0]**0.5
    if isinstance(angular_freq, complex):
        raise ValueError(
            "Angular frequency is complex, issue with stiffness or mass")
    print('angular_freq: ', angular_freq)
    response_period = 2 * np.pi / angular_freq
    print('response period: ', response_period)

    # Run the analysis
    o3r = o3.results.Results2D()
    o3r.cache_path = out_folder
    o3r.dynamic = True
    o3r.pseudo_dt = 0.001  # since analysis is actually static
    o3.set_time(osi, 0.0)
    o3r.start_recorders(osi)
    # o3res.coords = o3.get_all_node_coords(osi)
    # o3res.ele2node_tags = o3.get_all_ele_node_tags_as_dict(osi)
    d_inc = 0.0001

    o3.numberer.RCM(osi)
    o3.system.BandGeneral(osi)
    # o3.test_check.NormUnbalance(osi, 2, max_iter=10, p_flag=2)
    # o3.test_check.FixedNumIter(osi, max_iter=10)
    o3.test_check.NormDispIncr(osi, 0.002, 10, p_flag=0)
    o3.algorithm.Newton(osi)
    o3.integrator.DisplacementControl(osi, nd[f"C1-S{fb.n_storeys}"], o3.cc.X,
                                      d_inc)
    o3.analysis.Static(osi)

    d_max = 0.05 * fb.max_height  # TODO: set to 5%
    print('d_max: ', d_max)
    # n_steps = int(d_max / d_inc)

    print("Analysis starting")
    print('int_disp: ',
          o3.get_node_disp(osi, nd[f"C1-S{fb.n_storeys}"], o3.cc.X))
    # opy.recorder('Element', '-file', 'ele_out.txt', '-time', '-ele', 1, 'force')
    tt = 0
    outputs = {
        'h_disp': [],
        'vb': [],
        'REACT-C1C2-S1': [],
        'REACT-C1-S0S1': [],
    }
    hd = 0
    n_max = 2
    n_cycs = 0
    xs = fb.heights / fb.max_height  # TODO: more sophisticated displacement profile
    ts_po = o3.time_series.Linear(osi, factor=1)
    o3.pattern.Plain(osi, ts_po)
    for i, xp in enumerate(xs):
        o3.Load(osi, nd[f"C1-S{i + 1}"], [xp, 0.0, 0])

    # o3.analyze(osi, 2)
    # n_max = 0
    time = [0]
    while n_cycs < n_max:
        print('n_cycles: ', n_cycs)
        for i in range(2):
            if i == 0:
                o3.integrator.DisplacementControl(osi,
                                                  nd[f"C1-S{fb.n_storeys}"],
                                                  o3.cc.X, d_inc)
            else:
                o3.integrator.DisplacementControl(osi,
                                                  nd[f"C1-S{fb.n_storeys}"],
                                                  o3.cc.X, -d_inc)
            while hd * (-1)**i < d_max:
                ok = o3.analyze(osi, 10)
                time.append(time[len(time) - 1] + 1)
                hd = o3.get_node_disp(osi, nd[f"C1-S{fb.n_storeys}"], o3.cc.X)
                outputs['h_disp'].append(hd)
                o3.gen_reactions(osi)
                vb = 0
                for cc in range(1, fb.n_cols + 1):
                    vb += o3.get_node_reaction(osi, nd[f"C{cc}-S0"], o3.cc.X)
                outputs['vb'].append(-vb)
                outputs['REACT-C1C2-S1'].append(
                    o3.get_ele_response(osi, ed['C1C2-S1'], 'force'))
                outputs['REACT-C1-S0S1'].append(
                    o3.get_ele_response(osi, ed['C1-S0S1'], 'force'))

        n_cycs += 1

    o3.wipe(osi)
    o3r.save_to_cache()
    for item in outputs:
        outputs[item] = np.array(outputs[item])
    print('complete')
    return outputs
def run(apply_diff):
    # If use_pload=true then apply point load at end, else apply distributed load along beam

    osi = o3.OpenSeesInstance(ndm=2, state=3)

    ele_len = 4.0

    # Establish nodes
    left_node = o3.node.Node(osi, 0, 0)
    right_node = o3.node.Node(osi, ele_len, 0)

    # Fix left node
    if apply_diff:
        o3.Fix3DOF(osi, left_node, o3.cc.FIXED, o3.cc.FREE, o3.cc.FREE)
        o3.Fix3DOF(osi, left_node, o3.cc.FREE, o3.cc.FIXED, o3.cc.FIXED)
    else:
        o3.Fix3DOF(osi, left_node, o3.cc.FIXED, o3.cc.FIXED, o3.cc.FIXED)
        o3.Fix3DOF(osi, left_node, o3.cc.FIXED, o3.cc.FIXED, o3.cc.FIXED)
    o3.Fix3DOF(osi, right_node, o3.cc.FREE, o3.cc.FREE, o3.cc.FREE)
    e_mod = 200.0e2
    i_sect = 0.1
    area = 0.5
    lp_i = 0.1
    lp_j = 0.1

    elastic = 0

    if elastic:
        left_sect = o3.section.Elastic2D(osi, e_mod, area, i_sect)
    else:
        m_cap = 14.80
        b = 0.05
        phi = m_cap / (e_mod * i_sect)
        # mat_flex = o3.uniaxial_material.Steel01(osi, m_cap, e0=e_mod * i_sect, b=b)
        mat_flex = o3.uniaxial_material.ElasticBilin(osi, e_mod * i_sect,
                                                     e_mod * i_sect * b, phi)
        mat_axial = o3.uniaxial_material.Elastic(osi, e_mod * area)
        left_sect = o3.section.Aggregator(osi,
                                          mats=[[mat_axial, o3.cc.P],
                                                [mat_flex, o3.cc.M_Z],
                                                [mat_flex, o3.cc.M_Y]])
    right_sect = o3.section.Elastic2D(osi, e_mod, area, i_sect)
    centre_sect = o3.section.Elastic2D(osi, e_mod, area, i_sect)
    integ = o3.beam_integration.HingeMidpoint(osi, left_sect, lp_i, right_sect,
                                              lp_j, centre_sect)
    beam_transf = o3.geom_transf.Linear2D(osi, )
    ele = o3.element.ForceBeamColumn(osi, [left_node, right_node], beam_transf,
                                     integ)
    use_pload = 1
    w_gloads = 1
    if w_gloads:
        # Apply gravity loads
        pload = 1.0 * ele_len
        udl = 2.0
        ts_po = o3.time_series.Linear(osi, factor=1)
        o3.pattern.Plain(osi, ts_po)
        if use_pload:
            o3.Load(osi, right_node, [0, -pload, 0])
        else:
            o3.EleLoad2DUniform(osi, ele, -udl)

        tol = 1.0e-3
        o3.constraints.Plain(osi)
        o3.numberer.RCM(osi)
        o3.system.BandGeneral(osi)
        n_steps_gravity = 10
        o3.integrator.LoadControl(osi, 1. / n_steps_gravity, num_iter=10)
        o3.test_check.NormDispIncr(osi, tol, 10)
        o3.algorithm.Linear(osi)
        o3.analysis.Static(osi)
        o3.analyze(osi, n_steps_gravity)
        o3.gen_reactions(osi)
        print('reactions: ', o3.get_ele_response(osi, ele, 'force')[:3])
        end_disp = o3.get_node_disp(osi, right_node, dof=o3.cc.Y)
        print(f'end_disp: {end_disp}')
        if use_pload:
            disp_expected = pload * ele_len**3 / (3 * e_mod * i_sect)
            print(f'v_expected: {pload}')
            print(f'm_expected: {pload * ele_len}')
            print(f'disp_expected: {disp_expected}')
        else:
            v_expected = udl * ele_len
            m_expected = udl * ele_len**2 / 2
            disp_expected = udl * ele_len**4 / (8 * e_mod * i_sect)
            print(f'v_expected: {v_expected}')
            print(f'm_expected: {m_expected}')
            print(f'disp_expected: {disp_expected}')
        rot_0 = o3.get_ele_response(osi,
                                    ele,
                                    'section',
                                    extra_args=['1', 'deformation'])[1]
        shear_0 = o3.get_ele_response(osi,
                                      ele,
                                      'section',
                                      extra_args=['1', 'deformation'])[2]
        print(
            o3.get_ele_response(osi,
                                ele,
                                'section',
                                extra_args=['2', 'deformation']))
    def run_w_settings(ele_len, e_mod, i_sect, pload, udl, beam_in_parts,
                       use_pload):
        osi = o3.OpenSeesInstance(ndm=2, state=3)

        # Establish nodes
        left_node = o3.node.Node(osi, 0, 0)
        right_node = o3.node.Node(osi, ele_len, 0)

        # Fix bottom node
        o3.Fix3DOF(osi, left_node, o3.cc.FIXED, o3.cc.FIXED, o3.cc.FIXED)
        o3.Fix3DOF(osi, right_node, o3.cc.FREE, o3.cc.FREE, o3.cc.FREE)

        area = 0.5
        lp_i = 0.2
        lp_j = 0.2

        if beam_in_parts:
            elastic = 1

            if elastic:
                left_sect = o3.section.Elastic2D(osi, e_mod, area, i_sect)
            else:
                m_cap = 600.0
                b = 0.05
                phi = m_cap / (e_mod * i_sect)
                # mat_flex = o3.uniaxial_material.Steel01(osi, m_cap, e0=e_mod * i_sect, b=b)
                mat_flex = o3.uniaxial_material.ElasticBilin(
                    osi, e_mod * i_sect, e_mod * i_sect * b, phi)
                mat_axial = o3.uniaxial_material.Elastic(osi, e_mod * area)
                left_sect = o3.section.Aggregator(osi,
                                                  mats=[
                                                      mat_axial.tag, o3.cc.P,
                                                      mat_flex.tag, o3.cc.M_Z,
                                                      mat_flex.tag, o3.cc.M_Y
                                                  ])
            right_sect = o3.section.Elastic2D(osi, e_mod, area, i_sect)
            centre_sect = o3.section.Elastic2D(osi, e_mod, area, i_sect)
            integ = o3.beam_integration.HingeMidpoint(osi, left_sect, lp_i,
                                                      right_sect, lp_j,
                                                      centre_sect)
            beam_transf = o3.geom_transf.Linear2D(osi, )
            ele = o3.element.ForceBeamColumn(osi, [left_node, right_node],
                                             beam_transf, integ)
        else:
            beam_transf = o3.geom_transf.Linear2D(osi)
            ele = o3.element.ElasticBeamColumn2D(osi, [left_node, right_node],
                                                 area, e_mod, i_sect,
                                                 beam_transf)
        # Apply gravity loads

        # If true then load applied along beam

        ts_po = o3.time_series.Linear(osi, factor=1)
        o3.pattern.Plain(osi, ts_po)
        if use_pload:
            o3.Load(osi, right_node, [0, -pload, 0])
        else:
            o3.EleLoad2DUniform(osi, ele, -udl)

        tol = 1.0e-3
        o3.constraints.Plain(osi)
        o3.numberer.RCM(osi)
        o3.system.BandGeneral(osi)
        n_steps_gravity = 10
        o3.integrator.LoadControl(osi, 1. / n_steps_gravity, num_iter=10)
        o3.test_check.NormDispIncr(osi, tol, 10)
        o3.algorithm.Linear(osi)
        o3.analysis.Static(osi)
        o3.analyze(osi, n_steps_gravity)
        o3.gen_reactions(osi)
        end_disp = o3.get_node_disp(osi, right_node, dof=o3.cc.Y)
        return o3.get_ele_response(osi, ele, 'force')[:3], end_disp