Objects to Design and Exclude#

../../../../../_images/cantilever.png

This example demonstrates how to read and modify the two input tables which every design add-on uses to narrow down what is designed:

  • Create a two-span beam loaded in two load combinations and activate the Steel Design add-on.

  • Read the Objects to Design table, which holds one row per object type and role.

  • Remove member 2 from the design by addressing the row by object type and role.

  • Read the Objects to Exclude table, which holds one row per case object - design situation or load combination.

  • Exclude member 1 from load combination CO2 by addressing the row by its case object.

  • Calculate and review the design ratios, where only member 1 in CO1 is left.

Keywords:
objects to design objects to exclude design add-on steel design load combination design situation

Note

Both tables are common to all design add-ons - the add-on is selected with the addon argument of get_objects_to_design() / get_objects_to_exclude().

Add-ons which design whole model objects (Steel Joints, Component Design, Craneway Design, Concrete Foundations) have no Objects to Design table; there the selection is an attribute of the object itself (SteelJoint.to_design, Craneway.to_design, …).

The add-on has to be active in the base data, otherwise both methods report that it is not active.

from dlubal.api import rfem, common
from math import inf
import pandas


# -------------------------------------------------------
# This example demonstrates how to read and modify the two
# input tables of a design add-on:
#   Objects to Design  - which objects the add-on designs,
#                        one row per object type and role
#   Objects to Exclude - which objects are excluded from the
#                        design of a design situation or a
#                        load combination, one row per case object
#
# Add-ons which design whole model objects (Steel Joints,
# Component Design, Craneway Design, Concrete Foundations) have no
# Objects to Design table - there the selection is an attribute of
# the object itself (SteelJoint.to_design, Craneway.to_design, ...).
#
# The model is a two-span beam (members 1 and 2) loaded in two load
# combinations (CO1 and CO2), so all four member/combination pairs could
# be designed. Both tables narrow this down step by step:
#   Objects to Design  - member 2 is removed from the design
#   Objects to Exclude - member 1 is excluded from CO2
# After the calculation only member 1 in CO1 has design results.
# -------------------------------------------------------

ADDON = rfem.DesignAddons.STEEL_DESIGN

DISTRIBUTED_LOAD = 10000.0  # N/m


def define_structure_objects() -> list:

    # Two-span beam, 2 x 5 m: pinned at the left end, rollers at the middle
    # support and at the right end.

    return [
        rfem.structure_core.Material(no=1, name="S235 | EN 1993-1-1:2005-05"),
        rfem.structure_core.CrossSection(no=1, name="IPE 200", material=1),

        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=5.0, coordinate_2=0.0, coordinate_3=0.0),
        rfem.structure_core.Node(no=3, coordinate_1=10.0, coordinate_2=0.0, coordinate_3=0.0),

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

        rfem.structure_core.Member(no=1, line=1, cross_section_start=1),
        rfem.structure_core.Member(no=2, line=2, cross_section_start=1),

        rfem.types_for_nodes.NodalSupport(
            no=1,
            nodes=[1],
            spring=common.Vector3d(x=inf, y=inf, z=inf),
            rotational_restraint=common.Vector3d(x=inf, y=0.0, z=0.0),
        ),
        rfem.types_for_nodes.NodalSupport(
            no=2,
            nodes=[2, 3],
            spring=common.Vector3d(x=0.0, y=inf, z=inf),
            rotational_restraint=common.Vector3d(x=inf, y=0.0, z=0.0),
        ),
    ]


def define_loading_objects() -> list:

    # One load case with a uniform load on both spans, evaluated in two load
    # combinations. CO2 is the governing one - unless the member is excluded
    # from it further below.

    return [
        rfem.loading.StaticAnalysisSettings(no=1),

        rfem.loading.LoadCase(
            no=1,
            name="LC1",
            static_analysis_settings=1,
            self_weight_active=False,
        ),

        rfem.loading.DesignSituation(
            no=1,
            user_defined_name_enabled=True,
            name="ULS - Permanent and transient",
            design_situation_type=rfem.loading.DesignSituation.DESIGN_SITUATION_TYPE_STR_PERMANENT_AND_TRANSIENT_6_10,
        ),

        rfem.loading.LoadCombination(no=1, design_situation=1, name="CO1",
                                     static_analysis_settings=1, combination_rule_str="LC1"),
        rfem.loading.LoadCombination(no=2, design_situation=1, name="CO2",
                                     static_analysis_settings=1, combination_rule_str="1.35*LC1"),

        rfem.loads.MemberLoad(
            no=1,
            members=[1, 2],
            load_case=1,
            magnitude=DISTRIBUTED_LOAD,
        ),
    ]


def define_steel_design_objects() -> list:

    # delete_all_objects() removes the default configurations as well, so the
    # add-on needs at least the ULS configuration to design anything.

    return [
        rfem.steel_design_objects.SteelDesignUlsConfiguration(
            no=1,
            assigned_to_all_members=True,
        ),
    ]


# Connect to the RFEM application
with rfem.Application() as rfem_app:

    rfem_app.close_all_models(save_changes=False)
    rfem_app.create_model(name="objects_to_design_and_exclude")

    # Activate the add-on, otherwise both methods report that it is not active
    base_data = rfem_app.get_base_data()
    base_data.addons.steel_design_active = True
    rfem_app.set_base_data(base_data=base_data)

    rfem_app.delete_all_objects()

    rfem_app.create_object_list(
        objs=
            define_structure_objects() +
            define_loading_objects() +
            define_steel_design_objects()
    )

    # --- Objects to Design ---

    objects_to_design = rfem_app.get_objects_to_design(addon=ADDON)
    print(f"\nOBJECTS TO DESIGN:\n{objects_to_design}")

    # A row is addressed by its key: the object type and the role. The table has a row only for
    # object types which exist in the model, and Timber/Glass Design have two rows of the same
    # object type distinguished by the role.
    rfem_app.set_objects_to_design(
        addon=ADDON,
        objects_to_design=rfem.ObjectsToDesignTable(rows=[
            rfem.ObjectsToDesignRow(
                object_type=rfem.ObjectType.OBJECT_TYPE_MEMBER,
                role=rfem.ObjectsToDesignRow.Role.ROLE_DEFAULT,
                design_all=False,
                selected_objects=[1, 2],
                removed_from_design=[2],
                comment="set through the API",
            ),
        ]),
    )

    # Only the rows contained in the request are modified. 'to_design' and 'not_valid_deactivated'
    # are results of the selection and are read only. Member 2 is selected but removed again,
    # so 'to_design' contains member 1 only.
    objects_to_design = rfem_app.get_objects_to_design(addon=ADDON)
    print(f"\nOBJECTS TO DESIGN AFTER THE CHANGE:\n{objects_to_design}")

    # --- Objects to Exclude ---

    objects_to_exclude = rfem_app.get_objects_to_exclude(addon=ADDON)
    print(f"\nOBJECTS TO EXCLUDE:\n{objects_to_exclude}")

    # A row is addressed by its case object - the design situation or the load combination the row
    # belongs to. Every object type of the add-on has its own column with the excluded objects.
    co2_row = next(
        row for row in objects_to_exclude.rows
        if row.case_object.object_type == rfem.ObjectType.OBJECT_TYPE_LOAD_COMBINATION
        and row.case_object.no == 2
    )

    rfem_app.set_objects_to_exclude(
        addon=ADDON,
        objects_to_exclude=rfem.ObjectsToExcludeTable(rows=[
            rfem.ObjectsToExcludeRow(
                case_object=co2_row.case_object,
                members=[1],
                comment="excluded through the API",
            ),
        ]),
    )

    objects_to_exclude = rfem_app.get_objects_to_exclude(addon=ADDON)
    print(f"\nOBJECTS TO EXCLUDE AFTER THE CHANGE:\n{objects_to_exclude}")


    calculation_info = rfem_app.calculate_all(skip_warnings=True)

    if not calculation_info.succeeded:
        errors_and_warnings = rfem_app.get_result_table(
            table=rfem.results.ResultTable.ERRORS_AND_WARNINGS_TABLE,
            loading=None,
        ).data
        print(f"\nCALCULATION FAILED:\n{errors_and_warnings}")
    else:
        pandas.set_option("display.max_columns", None)
        pandas.set_option("display.width", 200)

        # Member 2 is not designed at all and member 1 is designed for CO1 only,
        # so one out of the four member/combination pairs is left in the results.
        design_ratios = rfem_app.get_result_table(
            table=rfem.results.ResultTable.STEEL_DESIGN_MEMBERS_DESIGN_RATIOS_BY_MEMBER_TABLE,
            loading=None,
        ).data
        print(f"\nSTEEL DESIGN | DESIGN RATIOS BY MEMBER:\n{design_ratios}")