Semi-Rigid Hinge#

../../../../../_images/steel_joint_semi_rigid_hinge.png

Generating a semi-rigid hinge from a steel joint’s initial stiffness and comparing its effect on the beam deflection:

  • Build a beam to column connection model

  • Calculate the referenceds rigid-connection beam deflection

  • Create end-plate steel joint with two column stiffeners

  • Enable initial-stiffness hinge generation in the global model

  • Recalculate the beam deflection for semi-rigid connection

  • Read the joint rotational stiffness results

Keywords:
steel joint semi-rigid hinge stiffness analysis initial stiffness rotational stiffness beam deflection
from math import inf

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

# -------------------------------------------------------
# This example demonstrates how a steel joint stiffness analysis affects
# the structural response of a beam-to-column connection in RFEM.
#
# Step 1:
#   Build the base model WITHOUT a steel joint (rigid connection) and
#   calculate the beam deflection for the ULS design situation.
#
# Step 2 (this version):
#   Add the steel joint (end plate + stiffeners) with the stiffness analysis
#   extension: the Beam component gets the stiffness analysis direction My, and
#   the stiffness analysis configuration is set to generate a hinge in the
#   global model using the joint's initial rotational stiffness.
#   The model is recalculated and the new beam deflection is compared against
#   the rigid reference.
# -------------------------------------------------------


# Editable parameters (SI units)

COLUMN_CROSS_SECTION = "HEA 300"
BEAM_CROSS_SECTION = "IPE 400"
STEEL_GRADE = "S355"

PLATE_THICKNESS = "0.014"
STIFFENER_THICKNESS = "0.014"


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,
            name=COLUMN_CROSS_SECTION,
        ),
        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,
            type=rfem.structure_core.Node.TYPE_ON_MEMBER,
            on_member_reference_member=1,
            distance_from_start_is_defined_as_relative=False,
            distance_from_start_absolute=1.0,
        ),
        rfem.structure_core.Node(
            no=3,
            coordinate_1=1.0,
            coordinate_2=0.0,
            coordinate_3=-1.0,
        ),
        rfem.structure_core.Node(
            no=4,
            coordinate_1=0.0,
            coordinate_2=0.0,
            coordinate_3=-2.0,
        ),

        # Lines
        rfem.structure_core.Line(
            no=1,
            definition_nodes=[1, 4],
        ),
        rfem.structure_core.Line(
            no=3,
            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=3,
            line=3,
            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="Nodal force",
            static_analysis_settings=1,
            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="CO1 - 1.0 * LC1",
            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="1.0*LC1",
        ),
        rfem.loads.NodalLoad(
            no=1,
            nodes=[3],
            load_case=1,
            force_magnitude=70000,
            load_direction=rfem.loads.NodalLoad.LOAD_DIRECTION_GLOBAL_Z_OR_USER_DEFINED_W_TRUE_LENGTH,
        ),
        rfem.loads.NodalLoad(
            no=2,
            nodes=[4],
            load_case=1,
            components_force=common.Vector3d(z=20000),
            components_moment=common.Vector3d(y=25000),
            load_type=rfem.loads.NodalLoad.LOAD_TYPE_COMPONENTS
        ),
    ]


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

    The Beam component (member 3) is given the stiffness analysis direction My,
    so the stiffness analysis evaluates its rotational stiffness about the
    major axis.
    """

    return rfem.steel_joints_objects.SteelJoint.MembersTable(
        rows=[
            rfem.steel_joints_objects.SteelJoint.MembersRow(
                no=1,
                is_active=True,
                members_no=[1],
                status="Column",
                end_type=rfem.steel_joints_objects.SteelJoint.MembersRow.EndType.END_TYPE_MEMBER_CONTINUOUS,
                supported=True,
            ),
            rfem.steel_joints_objects.SteelJoint.MembersRow(
                no=2,
                is_active=True,
                members_no=[3],
                status="Beam",
                end_type=rfem.steel_joints_objects.SteelJoint.MembersRow.EndType.END_TYPE_MEMBER_ENDED,
                # Stiffness analysis direction for the Beam: My.
                stiffness_analysis_directions=[
                    rfem.steel_joints_objects.SteelJoint.MembersRow.StiffnessAnalysisDirections.STIFFNESS_ANALYSIS_DIRECTIONS_MY,
                ],
                supported=False,
            ),
        ]
    )


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

    joint_components = [
        (
            rfem.steel_joints_objects.SteelJoint.ComponentsRow.Type.TYPE_END_PLATE,
            "End Plate 1",
            [
                ("connected_member_1", "Beam"),
                ("reference_member", "Column"),
                ("plate_material_1", 1),
                ("plate_shape_1", 0),
                ("plate_thickness_1", PLATE_THICKNESS),
                ("plate_definition_type_1", 0),
                ("plate_top_offset_1", 0.01),
                ("plate_bottom_offset_1", 0.01),
                ("plate_left_offset_1", 0.005),
                ("plate_right_offset_1", 0.005),
                ("bolt_size", "M16"),
                ("bolt_strength_grade", "8.8"),
                ("bolt_horizontal_count", 2),
                ("bolt_horizontal_spacing", "0.0450 0.0900 0.0450"),
                ("bolt_vertical_count", 3),
                ("bolt_vertical_spacing", "0.0600 0.0500 0.1500 0.0600"),
                ("bolt_prestressed_bolts", False),
                ("bolt_shear_plane_in_thread", True),
                ("plate_1_bolt_is_active_1", True),
                ("plate_1_bolt_is_active_2", True),
                ("plate_1_bolt_is_active_3", True),
                ("plate_1_bolt_is_active_4", True),
                ("plate_1_bolt_is_active_5", True),
                ("plate_1_bolt_is_active_6", True),
                ("weld_is_active_1", True),
                ("weld_is_active_2", True),
                ("weld_is_active_3", True),
                ("weld_type_1", 2),
                ("weld_type_2", 2),
                ("weld_type_3", 2),
                ("weld_material_1", "Double fillet weld"),
                ("weld_material_2", "Double fillet weld"),
                ("weld_material_3", "Double fillet weld"),
                ("weld_size_1", 0.003),
                ("weld_size_2", 0.003),
                ("weld_size_3", 0.003),
            ],
        ),
        (
            rfem.steel_joints_objects.SteelJoint.ComponentsRow.Type.TYPE_STIFFENER,
            "Stiffener 1",
            [
                ("stiffened_member", "Column"),
                ("reference_member", "Beam"),
                ("plate_material", 1),
                ("plate_thickness", STIFFENER_THICKNESS),
                ("plate_count", 1),
                ("position", 4),
                ("reference_member_plate", "Flange 1"),
                ("direction", 0),
                ("location_offset", "0.0000"),
                ("side", 2),
                ("inclination", 0.0),
                ("width_offset", 0.0),
                ("height_offset", 0.0),
                ("chamfer", 0.025),
                ("weld_is_active_1", True),
                ("weld_is_active_2", True),
                ("weld_is_active_3", True),
                ("weld_type_1", 2),
                ("weld_type_2", 2),
                ("weld_type_3", 2),
                ("weld_material_1", 1),
                ("weld_material_2", 1),
                ("weld_material_3", 1),
                ("weld_size_1", 0.003),
                ("weld_size_2", 0.003),
                ("weld_size_3", 0.003),
            ],
        ),
        (
            rfem.steel_joints_objects.SteelJoint.ComponentsRow.Type.TYPE_STIFFENER,
            "Stiffener 2",
            [
                ("stiffened_member", "Column"),
                ("reference_member", "Beam"),
                ("plate_material", 1),
                ("plate_thickness", STIFFENER_THICKNESS),
                ("plate_count", 1),
                ("position", 4),
                ("reference_member_plate", "Flange 2"),
                ("direction", 1),
                ("location_offset", "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", 2),
                ("weld_type_2", 2),
                ("weld_type_3", 2),
                ("weld_material_1", 1),
                ("weld_material_2", 1),
                ("weld_material_3", 1),
                ("weld_size_1", 0.003),
                ("weld_size_2", 0.003),
                ("weld_size_3", 0.003),
            ],
        ),
    ]

    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 / stiffness configurations."""

    return [
        rfem.steel_joints_design_addon_objects.JointUlsConfiguration(
            no=1,
            name="ULS Configuration",
        ),
        rfem.steel_joints_design_addon_objects.JointStiffnessAnalysisConfiguration(
            no=1,
            name="Stiffness Analysis 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",
            ultimate_configuration=1,
            stiffness_analysis_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_semi_rigid_hinge')

    # 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()

    # --- Step 1: Rigid Connection (no Steel Joint) ---
    rfem_app.create_object_list(
        define_structure() +
        define_loading()
    )

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

    # Retrieve beam deflection of the rigid connection
    member_deformation_df: common.Table = rfem_app.get_results(
        results_type=rfem.results.ResultsType.STATIC_ANALYSIS_MEMBERS_LOCAL_DEFORMATIONS,
        filters=[
            rfem.results.ResultsFilter(
                column_id="loading",
                filter_expression="DS1",
            ),
            rfem.results.ResultsFilter(
                column_id="member_no",
                filter_expression="3",
            ),
        ],
    ).data

    rigid_deflection = member_deformation_df["u_z"].abs().max()
    print("Beam deflection - ULS design situation (DS1):")
    print(f"Rigid connection (no steel joint): max |u_z| = {rigid_deflection * 1000:.3f} mm")

    # --- Step 2: Steel Joint with initial stiffness ---

    # Create the steel joint
    rfem_app.create_object_list(
        define_steel_joint()
    )

    # Active hinge in the global model using the joint's initial stiffness
    settings_tree = rfem_app.get_object(
        obj=rfem.steel_joints_design_addon_objects.JointStiffnessAnalysisConfiguration(no=1)
    ).settings_ec3

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

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

    # Recalculate with the joint hinge active
    rfem_app.calculate_all(skip_warnings=True)

    # Beam deflection with the semi-rigid joint hinge
    member_deformation_df: common.Table = rfem_app.get_results(
        results_type=rfem.results.ResultsType.STATIC_ANALYSIS_MEMBERS_LOCAL_DEFORMATIONS,
        filters=[
            rfem.results.ResultsFilter(
                column_id="loading",
                filter_expression="DS1",
            ),
            rfem.results.ResultsFilter(
                column_id="member_no",
                filter_expression="3",
            ),
        ],
    ).data
    joint_deflection = member_deformation_df["u_z"].abs().max()
    print(f"Steel joint (initial stiffness hinge): max |u_z| = {joint_deflection * 1000:.3f} mm")


    # Read the joint's rotational stiffness (S_My) from the stiffness analysis results
    stiffness_df: common.Table = rfem_app.get_result_table(
        table=rfem.results.ResultTable.STEEL_JOINTS_STIFFNESS_ANALYSIS_RESULTS_TABLE,
        loading=rfem.ObjectId(
            no=1,
            object_type=rfem.OBJECT_TYPE_DESIGN_SITUATION,
        ),
    ).data

    beam_row = stiffness_df.loc[stiffness_df["status"] == "beam"].iloc[0]

    s_my_positive = float(beam_row["rotational_stiffness_y_positive"])
    s_my_negative = float(beam_row["rotational_stiffness_y_negative"])

    print("\nSteel joint stiffness analysis results (Beam):")
    print(f"Rotational stiffness S_My+ = {s_my_positive / 1e6:.1f} MNm/rad")
    print(f"Rotational stiffness S_My- = {s_my_negative / 1e6:.1f} MNm/rad")