Plate Buckling#

../../../../../_images/steel_joint_plate_buckling.png

Creating a beam-to-beam steel joint and running its ULS design including the plate buckling check:

  • Create a welded I-section column and an IPE 500 beam meeting at one node

  • Activate the Steel Joints add-on and add two member cuts and a stiffener

  • Apply a bending moment and define the ULS design situation and load combination

  • Enable the buckling analysis in the ULS configuration

  • Calculate the model and print the maximum plate design ratio

  • Read back the buckling critical load factors for each mode shape

Keywords:
steel joint beam to beam member cut stiffener buckling analysis critical load factor design ratios
from math import inf

from dlubal.api import rfem, common
from dlubal.api.common.packing import wrap_value

# -------------------------------------------------------
# This example creates a beam-to-beam steel joint and runs its ULS design
# including the buckling design check of the joint.
#
# A welded I-section column (member 1) meets an IPE 500 beam (member 2) at
# node 2. The joint connects them with two member cuts and one stiffener. The
# buckling analysis is enabled in the ULS configuration, and both the design
# ratios and the buckling critical load factors are read back.
# -------------------------------------------------------

# Editable parameters (SI units)

BEAM_CROSS_SECTION = "IPE 500"
STEEL_GRADE = "S235"
STIFFENER_THICKNESS = 0.016

# Welded parametric I-section for member 1: h/b/t_w/t_f in metres -> "I 840/250/4/10/0/0/H"
COLUMN_SECTION_H = 0.84
COLUMN_SECTION_B = 0.25
COLUMN_SECTION_TW = 0.004
COLUMN_SECTION_TF = 0.01

def define_structure() -> list:
    """Define the base RFEM model (column + beam) used for the analysis."""

    return [
        # Materials
        rfem.structure_core.Material(
            no=1,
            name=STEEL_GRADE,
        ),

        # Cross-Sections
        rfem.structure_core.CrossSection(
            no=1,
            material=1,
            type=rfem.structure_core.CrossSection.TYPE_PARAMETRIC_THIN_WALLED,
            parametrization_type=rfem.structure_core.CrossSection.PARAMETRIZATION_TYPE_PARAMETRIC_THIN_WALLED__I_SECTION__I,
            h=COLUMN_SECTION_H,
            b=COLUMN_SECTION_B,
            t_w=COLUMN_SECTION_TW,
            t_f=COLUMN_SECTION_TF,
            r_1=0.0,
            r_2=0.0,
        ),
        rfem.structure_core.CrossSection(
            no=2,
            material=1,
            name=BEAM_CROSS_SECTION,
        ),

        # Nodes
        rfem.structure_core.Node(
            no=1,
            coordinate_1=0.0,
            coordinate_2=0.0,
            coordinate_3=0.0,
        ),
        rfem.structure_core.Node(
            no=2,
            coordinate_1=0.0,
            coordinate_2=0.0,
            coordinate_3=-1.35,
        ),
        rfem.structure_core.Node(
            no=3,
            coordinate_1=1.045,
            coordinate_2=0.0,
            coordinate_3=-1.35,
        ),

        # Lines
        rfem.structure_core.Line(
            no=1,
            definition_nodes=[1, 2],
        ),
        rfem.structure_core.Line(
            no=2,
            definition_nodes=[2, 3],
        ),

        # Members
        rfem.structure_core.Member(
            no=1,
            line=1,
            type=rfem.structure_core.Member.TYPE_BEAM,
            cross_section_start=1,
        ),
        rfem.structure_core.Member(
            no=2,
            line=2,
            type=rfem.structure_core.Member.TYPE_BEAM,
            cross_section_start=2,
        ),

        # Nodal Supports
        rfem.types_for_nodes.NodalSupport(
            no=1,
            nodes=[1],
            spring_x=inf,
            spring_y=inf,
            spring_z=inf,
            rotational_restraint_x=inf,
            rotational_restraint_y=inf,
            rotational_restraint_z=inf,
        ),
    ]

def define_loading() -> list:
    """Define a load case, the ULS design situation and one load combination."""

    return [
        rfem.loading.StaticAnalysisSettings(
            no=1,
        ),
        rfem.loading.LoadCase(
            no=1,
            name="Moment",
            static_analysis_settings=1,
            action_category=rfem.loading.LoadCase.ACTION_CATEGORY_PERMANENT_G,
            self_weight_active=False,
        ),
        rfem.loading.DesignSituation(
            no=1,
            name="ULS (STR/GEO) - Permanent and transient - Eq. 6.10",
            design_situation_type=rfem.loading.DesignSituation.DESIGN_SITUATION_TYPE_STR_PERMANENT_AND_TRANSIENT_6_10,
            active_for_steel_joints=True,
        ),
        rfem.loading.LoadCombination(
            no=1,
            design_situation=1,
            name="Moment",
            static_analysis_settings=1,
            items=rfem.loading.LoadCombination.ItemsTable(
                rows=[
                    rfem.loading.LoadCombination.ItemsRow(
                        no=1,
                        factor=1.0,
                        load_case=1,
                    ),
                ]
            ),
            combination_rule_str="LC1",
        ),
        # Bending moment about the global Y axis at the free beam end (node 3)
        rfem.loads.NodalLoad(
            no=1,
            nodes=[3],
            load_case=1,
            load_type=rfem.loads.NodalLoad.LOAD_TYPE_MOMENT,
            moment_magnitude=-239190,
            load_direction=rfem.loads.NodalLoad.LOAD_DIRECTION_GLOBAL_Y_OR_USER_DEFINED_V_TRUE_LENGTH,
        ),
    ]

def define_joint_members():
    """Define members assigned inside the Steel Joint add-on table."""

    return rfem.steel_joints_objects.SteelJoint.MembersTable(
        rows=[
            rfem.steel_joints_objects.SteelJoint.MembersRow(
                no=1,
                is_active=True,
                members_no=[1],
                status="Member 1",
                end_type=rfem.steel_joints_objects.SteelJoint.MembersRow.EndType.END_TYPE_MEMBER_ENDED,
                supported=True,
            ),
            rfem.steel_joints_objects.SteelJoint.MembersRow(
                no=2,
                is_active=True,
                members_no=[2],
                status="Member 2",
                end_type=rfem.steel_joints_objects.SteelJoint.MembersRow.EndType.END_TYPE_MEMBER_ENDED,
                supported=False,
            ),
        ]
    )

def define_joint_components():
    """Define top-level Steel Joint components and their RFEM setting keys.

    Only the user-defined components are created here (two member cuts that
    connect the members plus one stiffener). RFEM auto-generates the derived
    plates, plate cuts and welds from these.
    """

    joint_components = [
        (
            rfem.steel_joints_objects.SteelJoint.ComponentsRow.Type.TYPE_MEMBER_CUT,
            "Member Cut 1",
            [
                ("member_to_cut", "Member 1"),
                ("type_of_cut", 0),
                ("cut_by", "Member 2"),
                ("cutting_method", 0),
                ("cutting_plane", 1),
                ("direction", 0),
                ("offset", 0.0),
            ],
        ),
        (
            rfem.steel_joints_objects.SteelJoint.ComponentsRow.Type.TYPE_MEMBER_CUT,
            "Member Cut 2",
            [
                ("member_to_cut", "Member 2"),
                ("type_of_cut", 0),
                ("cut_by", "Member 1"),
                ("cutting_method", 0),
                ("cutting_plane", 0),
                ("direction", 0),
                ("offset", 0.0),
                ("weld_is_active_1", True),
                ("weld_is_active_2", True),
                ("weld_is_active_3", True),
                ("weld_type_1", 3),
                ("weld_type_2", 3),
                ("weld_type_3", 3),
            ],
        ),
        (
            rfem.steel_joints_objects.SteelJoint.ComponentsRow.Type.TYPE_STIFFENER,
            "Stiffener 1",
            [
                ("stiffened_member", "Member 1"),
                ("reference_member", "Member 2"),
                ("plate_material", 1),
                ("plate_thickness", STIFFENER_THICKNESS),
                ("plate_count", 2),
                ("position", 2),
                ("direction", 1),
                ("location_offset", "0.0000 0.0000"),
                ("side", 2),
                ("inclination", 0.0),
                ("width_offset", 0.0),
                ("height_offset", 0.0),
                ("chamfer", 0.0),
                ("weld_is_active_1", True),
                ("weld_is_active_2", True),
                ("weld_is_active_3", True),
                ("weld_type_1", 3),
                ("weld_type_2", 3),
                ("weld_type_3", 3),
            ],
        ),
    ]

    joint_component_rows = []

    for component_no, joint_component in enumerate(joint_components, start=1):
        component_type, component_name, component_settings = joint_component
        setting_rows = []

        for setting_no, setting in enumerate(component_settings, start=1):
            setting_key, setting_value = setting

            setting_rows.append(
                rfem.steel_joints_objects.SteelJoint.ComponentsRow.SettingsTableRow(
                    no=setting_no,
                    key=setting_key,
                    value=wrap_value(setting_value),
                )
            )

        joint_component_rows.append(
            rfem.steel_joints_objects.SteelJoint.ComponentsRow(
                no=component_no,
                is_active=True,
                type=component_type,
                name=component_name,
                settings=rfem.steel_joints_objects.SteelJoint.ComponentsRow.SettingsTable(
                    rows=setting_rows,
                ),
            )
        )

    return rfem.steel_joints_objects.SteelJoint.ComponentsTable(
        rows=joint_component_rows,
    )

def define_steel_joint() -> list:
    """Define the steel joint and its design configuration."""

    return [
        rfem.steel_joints_design_addon_objects.JointUlsConfiguration(
            no=1,
            name="ULS Configuration",
        ),
        rfem.steel_joints_objects.SteelJoint(
            no=1,
            nodes=[2],
            user_defined_name_enabled=True,
            name="Nodes : 2 | Created via API",
            comment="Created via API",
            to_design=True,
            ultimate_configuration=1,
            members=define_joint_members(),
            components=define_joint_components(),
        ),
    ]

# -------------------------------------------------------
# MAIN SCRIPT
# -------------------------------------------------------

with rfem.Application() as rfem_app:

    # Initialize model
    rfem_app.close_all_models(save_changes=False)
    rfem_app.create_model(name='steel_joint_buckling_analysis')

    # Activate the Steel Joints add-on
    base_data = rfem_app.get_base_data()
    base_data.addons.steel_joints_active = True
    rfem_app.set_base_data(base_data=base_data)
    rfem_app.delete_all_objects()

    # Create structure, loading and the steel joint
    rfem_app.create_object_list(
        define_structure() +
        define_loading() +
        define_steel_joint()
    )

    # Enable the buckling analysis in the ULS configuration
    # (a freshly created configuration has it switched off by default)
    settings_tree = rfem_app.get_object(
        obj=rfem.steel_joints_design_addon_objects.JointUlsConfiguration(no=1)
    ).settings_ec3

    common.tree_table.set_values_by_key(settings_tree, "perform_buckling_analysis", values=[True])

    rfem_app.update_object(
        obj=rfem.steel_joints_design_addon_objects.JointUlsConfiguration(
            no=1,
            settings_ec3=settings_tree,
        )
    )

    # Calculate the ULS design situation
    rfem_app.calculate_all(skip_warnings=True)

    # --- Steel joint design checks (max ratios) ---
    design_ratios_df: common.Table = rfem_app.get_results(
        results_type=rfem.results.ResultsType.STEEL_JOINTS_DESIGN_RATIOS,
    ).data

    plate_ratio = design_ratios_df.loc[
        design_ratios_df["design_check_type"] == "UL1000.00", "design_ratio"
    ].dropna().max()

    print("Steel joint design check summary (max ratios):")
    print(f"Plates (UL1000.00): {plate_ratio:.3f}")

    # --- Steel joint buckling analysis (critical load factors) ---
    # Only available when perform_buckling_analysis is enabled.
    # design_check_type ST2000.00 -> "Buckling analysis"; f = critical load factor.
    buckling_df: common.Table = rfem_app.get_results(
        results_type=rfem.results.ResultsType.STEEL_JOINTS_BUCKLING_DESIGN_RATIOS,
    ).data

    print("\nSteel joint buckling analysis (critical load factors):")
    for row in buckling_df.itertuples():
        print(f"Mode {row.mode_shape_no}: f = {row.critical_load_factor:.3f}")

    lowest_factor = buckling_df["critical_load_factor"].dropna().min()
    print(f"Lowest critical load factor: {lowest_factor:.3f}")