Objects to Design and Exclude#

../../../../../_images/objects_to_design_and_exclude.png

Reading and modifying the two input tables design add-ons use to narrow down what is designed:

  • Build a two-span beam evaluated in two load combinations, so that four member/combination pairs could be designed

  • Activate the Steel Design add-on, without which both methods report that it is not active

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

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

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

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

  • Calculate and read 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
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
#
# Both tables are common to all design add-ons. The add-on is
# selected with the addon argument of get_objects_to_design()
# and get_objects_to_exclude(), and it has to be active in the
# base data, otherwise both methods report that it is not active.
#
# 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.
# -------------------------------------------------------

# Editable parameters (SI units)
MODEL_NAME = 'objects_to_design_and_exclude'
ADDON = rfem.DesignAddons.STEEL_DESIGN

SPAN = 5.0                         # L [m], each of the two spans
MATERIAL = 'S235 | EN 1993-1-1:2005-05'
CROSS_SECTION = 'IPE 200'

DISTRIBUTED_LOAD = 10000.0         # g [N/m], uniform on both spans


def define_structure() -> list:
    """Define and return a list of structural objects.

    Two-span beam, 2 x SPAN: pinned at the left end, rollers at the middle
    support and at the right end.
    """

    return [
        rfem.structure_core.Material(no=1, name=MATERIAL),
        rfem.structure_core.CrossSection(no=1, name=CROSS_SECTION, 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=SPAN, coordinate_2=0.0, coordinate_3=0.0),
        rfem.structure_core.Node(no=3, coordinate_1=2 * SPAN, 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() -> list:
    """Define and return a list of loading objects.

    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() -> list:
    """Define and return a list of steel design objects.

    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,
        ),
    ]


with rfem.Application() as rfem_app:

    app_info = rfem_app.get_application_info()
    print(f"\nApplication Info:\n{app_info}")

    # Modelling
    rfem_app.close_all_models(save_changes=False)
    rfem_app.create_model(name=MODEL_NAME)

    # 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(define_structure() + define_loading() + define_steel_design())

    # 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
    calculation_info = rfem_app.calculate_all(skip_warnings=True)

    # Results
    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}")