Base Plate#

../../../../../_images/steel_joint_base_plate.png

Creating a column base-plate steel joint and reading its governing design checks:

  • Create a fixed-base steel column model with six ULS load cases

  • Activate the Steel Joints add-on and define ULS and stiffness configurations

  • Add a base plate with a concrete block, anchors, and welds

  • Calculate the model and print the governing design ratio per check type

Keywords:
steel joint base plate anchors concrete block welds design ratios
from math import inf

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

# -------------------------------------------------------
# This example demonstrates how to design a steel column base plate in RFEM.
# It creates a fixed-base column, applies six ULS load cases (compression,
# bending, combined actions, tension), defines a base-plate steel joint with
# anchors and welds, calculates the model, and prints the governing design
# ratio per check type.
# -------------------------------------------------------


# Editable parameters (SI units)

MODEL_NAME = "base_plate_design"
STEEL_GRADE = "S235"
CONCRETE_GRADE = "C20/25"                  # base-plate concrete block
COLUMN_CROSS_SECTION = "I 0.24/0.24/0.01/0.017/0"

# Load cases as nodal forces/moments at node 2: (no, name, components).
# components: components_force_x/y/z in N, components_moment_x/y/z in Nm.
LOAD_CASES = [
    (1, "Compression",                    {"components_force_z": 1564000.0}),
    (2, "Moment-Major",                   {"components_moment_y": -41000.0}),
    (3, "Moment-Minor",                   {"components_moment_x": -37000.0}),
    (4, "Moment-Major+Compression+Shear", {"components_force_y": 105000.0, "components_force_z": 1520000.0, "components_moment_y": -41000.0}),
    (5, "Moment-Minor+Compression",       {"components_force_z": 1500000.0, "components_moment_x": -37000.0}),
    (6, "Tension",                        {"components_force_z": -250000.0}),
]

# Base-plate settings (key -> value). RFEM auto-generates the derived plates,
# concrete block, member cut, welds and anchor bolts from these.
BASE_PLATE = {
    "reference_member": "Column 1",
    "axial_displacement": 0.0,
    "rotation_x": 0.0,
    "rotation_y": 0.0,
    "rotation_z": 0.0,
    # Plate
    "plate_material": 1,
    "plate_shape": 0,
    "plate_thickness": 0.02,
    "plate_definition_type": 0,
    "plate_top_offset": 0.1,
    "plate_bottom_offset": 0.1,
    "plate_left_offset": 0.045,
    "plate_right_offset": 0.045,
    "plate_width": 0.33,
    "plate_height": 0.44,
    # Concrete block
    "block_material": 2,
    "block_thickness": 0.9,
    "block_definition_type": 0,
    "block_top_offset": 0.335,
    "block_bottom_offset": 0.335,
    "block_left_offset": 0.335,
    "block_right_offset": 0.335,
    "block_width": 1.0,
    "block_height": 1.11,
    "is_block_cracked_concrete": True,
    "is_block_edge_reinforcement": True,
    "is_block_dense_reinforcement": False,
    "is_block_reinforcement_resisting_concrete_splitting": True,
    "is_block_grout": True,
    "block_grout_material": 2,
    "block_grout_thickness": 0.02,
    # Shear transfer
    "shear_transfer_type": 0,
    "consider_friction": True,
    # Anchors
    "anchor_size": 4,
    "anchor_strength_grade": 5,
    "anchor_longitudinal_count": 2,
    "anchor_longitudinal_spacing": "0.0500 0.2300 0.0500",
    "anchor_transverse_count": 2,
    "anchor_transverse_spacing": "0.0500 0.3400 0.0500",
    "anchor_shear_plane_in_thread": True,
    "anchor_cut_thread_reduction": True,
    "anchor_effective_length": 0.4,
    "anchor_type": 0,
    "anchor_check_combined_pull_out": False,
    "anchor_is_active_1": True,
    "anchor_is_active_2": True,
    "anchor_is_active_3": True,
    "anchor_is_active_4": True,
    "anchor_coordinates_1": "-0.1150 -0.1700",
    "anchor_coordinates_2": "0.1150 -0.1700",
    "anchor_coordinates_3": "-0.1150 0.1700",
    "anchor_coordinates_4": "0.1150 0.1700",
    # Welds
    "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,
}


def define_structure() -> list:
    """Define the base RFEM model: materials, cross-section, column, and support."""

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

        # Cross-Sections
        rfem.structure_core.CrossSection(
            no=1,
            material=1,
            type=rfem.structure_core.CrossSection.TYPE_PARAMETRIC_THIN_WALLED,
            manufacturing_type=rfem.structure_core.CrossSection.MANUFACTURING_TYPE_WELDED,
            parametrization_type=rfem.structure_core.CrossSection.PARAMETRIZATION_TYPE_PARAMETRIC_THIN_WALLED__I_SECTION__I,
            name=COLUMN_CROSS_SECTION,
        ),

        # Nodes: node 2 (z=0) up to node 1 (z=1.25)
        rfem.structure_core.Node(
            no=1,
            coordinate_3=1.25,
        ),
        rfem.structure_core.Node(
            no=2,
            coordinate_3=0.0,
        ),

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

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

        # 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 one load case, design situation, combination, and nodal load per entry in LOAD_CASES."""

    objects = [rfem.loading.StaticAnalysisSettings(no=1)]

    for no, name, components in LOAD_CASES:
        objects += [
            rfem.loading.LoadCase(
                no=no,
                name=name,
                static_analysis_settings=1,
                action_category=rfem.loading.LoadCase.ACTION_CATEGORY_PERMANENT_G,
                self_weight_active=False,
            ),
            rfem.loading.DesignSituation(
                no=no,
                user_defined_name_enabled=True,
                name=name,
                design_situation_type=rfem.loading.DesignSituation.DESIGN_SITUATION_TYPE_STR_PERMANENT_AND_TRANSIENT_6_10,
                active_for_steel_joints=True,
            ),
            rfem.loading.LoadCombination(
                no=no,
                design_situation=no,
                user_defined_name_enabled=True,
                name=name,
                static_analysis_settings=1,
                combination_rule_str=f"0.50 * LC{no}",
            ),
            rfem.loads.NodalLoad(
                no=1,
                nodes=[2],
                load_case=no,
                load_type=rfem.loads.NodalLoad.LOAD_TYPE_COMPONENTS,
                **components,
            ),
        ]

    return objects


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="Column 1",
                end_type=rfem.steel_joints_objects.SteelJoint.MembersRow.EndType.END_TYPE_MEMBER_ENDED,
                supported=False,
            ),
        ]
    )


def define_joint_components():
    """Define the base-plate component and its RFEM setting keys."""

    joint_components = [
        (
            rfem.steel_joints_objects.SteelJoint.ComponentsRow.Type.TYPE_BASE_PLATE,
            "Base Plate 1",
            list(BASE_PLATE.items()),
        ),
    ]

    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 base-plate steel joint and its design configurations."""

    return [
        rfem.steel_joints_design_addon_objects.JointUlsConfiguration(
            no=1,
            name="Default",
        ),
        rfem.steel_joints_design_addon_objects.JointStiffnessAnalysisConfiguration(
            no=1,
            name="Default",
        ),
        rfem.steel_joints_objects.SteelJoint(
            no=1,
            nodes=[1],
            to_design=True,
            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=MODEL_NAME)

    # Edit base data
    base_data = rfem_app.get_base_data()
    base_data.addons.steel_joints_active = True
    rfem_app.set_base_data(base_data=base_data)

    # Create model
    rfem_app.delete_all_objects()
    rfem_app.create_object_list(
        define_structure() +
        define_loading() +
        define_steel_joint()
    )

    # Calculate design
    rfem_app.calculate_all(skip_warnings=True)

    # Governing (maximum) design ratio per joint and check type. The API returns
    # every individual check, so reduce it to the RFEM "by Steel Joint" table.
    ratios = rfem_app.get_results(
        results_type=rfem.results.ResultsType.STEEL_JOINTS_DESIGN_RATIOS_BY_JOINT,
    ).data
    governing = ratios.loc[
        ratios.groupby(["joint_no", "design_check_type"])["design_ratio"].idxmax()
    ].sort_values(["joint_no", "design_check_type"])

    print(f"\nModel '{MODEL_NAME}' - steel joint design ratios (governing per check type):")
    print(governing[[
        "joint_no", "node_no", "design_check_description",
        "design_situation_no", "loading", "design_ratio", "is_valid",
    ]].to_string(index=False))