Base Plate#
|
Creating a column base-plate steel joint and reading its governing design checks:
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))
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using Common = Dlubal.Api.Common;
using Google.Protobuf;
using Microsoft.Data.Analysis;
using Rfem = Dlubal.Api.Rfem;
// -------------------------------------------------------
// This example demonstrates how to design a steel column base plate in RFEM.
// It creates a fixed-base steel 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)
const string MODEL_NAME = "base_plate_design";
const string STEEL_GRADE = "S235";
const string CONCRETE_GRADE = "C20/25"; // base-plate concrete block
const string COLUMN_CROSS_SECTION = "I 0.24/0.24/0.01/0.017/0";
// Load cases as nodal forces/moments at node 2: (no, name, force x/y/z, moment x/y/z) in N / Nm.
List<(int No, string Name, double ForceX, double ForceY, double ForceZ, double MomentX, double MomentY, double MomentZ)> LOAD_CASES = new()
{
(1, "Compression", 0.0, 0.0, 1564000.0, 0.0, 0.0, 0.0),
(2, "Moment-Major", 0.0, 0.0, 0.0, 0.0, -41000.0, 0.0),
(3, "Moment-Minor", 0.0, 0.0, 0.0, -37000.0, 0.0, 0.0),
(4, "Moment-Major+Compression+Shear", 0.0, 105000.0, 1520000.0, 0.0, -41000.0, 0.0),
(5, "Moment-Minor+Compression", 0.0, 0.0, 1500000.0, -37000.0, 0.0, 0.0),
(6, "Tension", 0.0, 0.0, -250000.0, 0.0, 0.0, 0.0),
};
// Base-plate settings (key -> value). RFEM auto-generates the derived plates,
// concrete block, member cut, welds and anchor bolts from these.
List<(string Key, object Value)> BASE_PLATE = new()
{
("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),
};
static List<IMessage> DefineStructure()
{
// Define the base RFEM model: materials, cross-section, column, and support.
return new List<IMessage>
{
// Materials
new Rfem.StructureCore.Material
{
No = 1,
Name = STEEL_GRADE,
},
new Rfem.StructureCore.Material
{
No = 2,
Name = CONCRETE_GRADE,
},
// Cross-Sections
new Rfem.StructureCore.CrossSection
{
No = 1,
Material = 1,
Type = Rfem.StructureCore.CrossSection.Types.Type.ParametricThinWalled,
ManufacturingType = Rfem.StructureCore.CrossSection.Types.ManufacturingType.Welded,
ParametrizationType = Rfem.StructureCore.CrossSection.Types.ParametrizationType.ParametricThinWalledISectionI,
Name = COLUMN_CROSS_SECTION,
},
// Nodes: node 2 (z=0) up to node 1 (z=1.25)
new Rfem.StructureCore.Node
{
No = 1,
Coordinate3 = 1.25,
},
new Rfem.StructureCore.Node
{
No = 2,
Coordinate3 = 0.0,
},
// Lines
new Rfem.StructureCore.Line
{
No = 1,
DefinitionNodes = { 2, 1 },
},
// Members
new Rfem.StructureCore.Member
{
No = 1,
Line = 1,
Type = Rfem.StructureCore.Member.Types.Type.Beam,
CrossSectionStart = 1,
},
// Nodal Supports
new Rfem.TypesForNodes.NodalSupport
{
No = 1,
Nodes = { 1 },
SpringX = double.PositiveInfinity,
SpringY = double.PositiveInfinity,
SpringZ = double.PositiveInfinity,
RotationalRestraintX = double.PositiveInfinity,
RotationalRestraintY = double.PositiveInfinity,
RotationalRestraintZ = double.PositiveInfinity,
},
};
}
static List<IMessage> DefineLoading(List<(int No, string Name, double ForceX, double ForceY, double ForceZ, double MomentX, double MomentY, double MomentZ)> loadCases)
{
// Define one load case, design situation, combination, and nodal load per entry in loadCases.
var objects = new List<IMessage>
{
new Rfem.Loading.StaticAnalysisSettings { No = 1 },
};
foreach (var loadCase in loadCases)
{
objects.Add(new Rfem.Loading.LoadCase
{
No = loadCase.No,
Name = loadCase.Name,
StaticAnalysisSettings = 1,
ActionCategory = Rfem.Loading.LoadCase.Types.ActionCategory.PermanentG,
SelfWeightActive = false,
});
objects.Add(new Rfem.Loading.DesignSituation
{
No = loadCase.No,
UserDefinedNameEnabled = true,
Name = loadCase.Name,
DesignSituationType = Rfem.Loading.DesignSituation.Types.DesignSituationType.StrPermanentAndTransient610,
ActiveForSteelJoints = true,
});
objects.Add(new Rfem.Loading.LoadCombination
{
No = loadCase.No,
DesignSituation = loadCase.No,
UserDefinedNameEnabled = true,
Name = loadCase.Name,
StaticAnalysisSettings = 1,
CombinationRuleStr = $"0.50 * LC{loadCase.No}",
});
objects.Add(new Rfem.Loads.NodalLoad
{
No = 1,
Nodes = { 2 },
LoadCase = loadCase.No,
LoadType = Rfem.Loads.NodalLoad.Types.LoadType.Components,
ComponentsForceX = loadCase.ForceX,
ComponentsForceY = loadCase.ForceY,
ComponentsForceZ = loadCase.ForceZ,
ComponentsMomentX = loadCase.MomentX,
ComponentsMomentY = loadCase.MomentY,
ComponentsMomentZ = loadCase.MomentZ,
});
}
return objects;
}
static Rfem.SteelJointsObjects.SteelJoint.Types.MembersTable DefineJointMembers()
{
// Members assigned inside the Steel Joint add-on table.
return new Rfem.SteelJointsObjects.SteelJoint.Types.MembersTable
{
Rows =
{
new Rfem.SteelJointsObjects.SteelJoint.Types.MembersRow
{
No = 1,
IsActive = true,
MembersNo = { 1 },
Status = "Column 1",
EndType = Rfem.SteelJointsObjects.SteelJoint.Types.MembersRow.Types.EndType.MemberEnded,
Supported = false,
},
},
};
}
static Common.Value WrapValue(object value)
{
// Create a generic Common.Value from a plain value, mirroring the Python
// wrap_value() helper (bool / int / double / string oneof).
return value switch
{
bool b => new Common.Value { BoolValue = b },
int i => new Common.Value { IntValue = i },
double d => new Common.Value { DoubleValue = d },
string s => new Common.Value { StringValue = s },
_ => new Common.Value { StringValue = value?.ToString() ?? string.Empty },
};
}
static Rfem.SteelJointsObjects.SteelJoint.Types.ComponentsTable DefineJointComponents(List<(string Key, object Value)> basePlateSettings)
{
// Define the base-plate component and its RFEM setting keys.
var jointComponents = new List<(
Rfem.SteelJointsObjects.SteelJoint.Types.ComponentsRow.Types.Type Type,
string Name,
List<(string Key, object Value)> Settings)>
{
(
Rfem.SteelJointsObjects.SteelJoint.Types.ComponentsRow.Types.Type.BasePlate,
"Base Plate 1",
basePlateSettings
),
};
var componentsTable = new Rfem.SteelJointsObjects.SteelJoint.Types.ComponentsTable();
int componentNo = 1;
foreach (var (type, name, settings) in jointComponents)
{
var settingsTable = new Rfem.SteelJointsObjects.SteelJoint.Types.ComponentsRow.Types.SettingsTable();
int settingNo = 1;
foreach (var (key, value) in settings)
{
settingsTable.Rows.Add(new Rfem.SteelJointsObjects.SteelJoint.Types.ComponentsRow.Types.SettingsTableRow
{
No = settingNo,
Key = key,
Value = WrapValue(value),
});
settingNo++;
}
componentsTable.Rows.Add(new Rfem.SteelJointsObjects.SteelJoint.Types.ComponentsRow
{
No = componentNo,
IsActive = true,
Type = type,
Name = name,
Settings = settingsTable,
});
componentNo++;
}
return componentsTable;
}
static List<IMessage> DefineSteelJoint(List<(string Key, object Value)> basePlateSettings)
{
// Define the base-plate steel joint and its design configurations.
return new List<IMessage>
{
new Rfem.SteelJointsDesignAddonObjects.JointUlsConfiguration
{
No = 1,
Name = "Default",
},
new Rfem.SteelJointsDesignAddonObjects.JointStiffnessAnalysisConfiguration
{
No = 1,
Name = "Default",
},
new Rfem.SteelJointsObjects.SteelJoint
{
No = 1,
Nodes = { 1 },
ToDesign = true,
UltimateConfiguration = 1,
StiffnessAnalysisConfiguration = 1,
Members = DefineJointMembers(),
Components = DefineJointComponents(basePlateSettings),
},
};
}
static List<DataFrameRow> GetGoverningDesignRatios(Common.Table ratios)
{
// 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.
return ratios.Data.Rows
.GroupBy(row => (
JointNo: Convert.ToString(row["joint_no"], CultureInfo.InvariantCulture),
DesignCheckType: Convert.ToString(row["design_check_type"], CultureInfo.InvariantCulture)
))
.Select(group => group
.OrderByDescending(row => Convert.ToDouble(row["design_ratio"], CultureInfo.InvariantCulture))
.First())
.OrderBy(row => Convert.ToString(row["joint_no"], CultureInfo.InvariantCulture), StringComparer.Ordinal)
.ThenBy(row => Convert.ToString(row["design_check_type"], CultureInfo.InvariantCulture), StringComparer.Ordinal)
.ToList();
}
// -------------------------------------------------------
// MAIN SCRIPT
// -------------------------------------------------------
ApplicationRfem? rfemApp = null;
try
{
rfemApp = new ApplicationRfem();
// Initialize model
rfemApp.close_all_models(saveChanges: false);
rfemApp.create_model(name: MODEL_NAME);
// Edit base data
var baseData = rfemApp.get_base_data();
baseData.Addons.SteelJointsActive = true;
rfemApp.set_base_data(baseData: baseData);
// Create model
rfemApp.delete_all_objects();
rfemApp.create_object_list(
DefineStructure()
.Concat(DefineLoading(LOAD_CASES))
.Concat(DefineSteelJoint(BASE_PLATE))
.ToList()
);
// Calculate design
rfemApp.calculate_all(skipWarnings: true);
// Governing (maximum) design ratio per joint and check type
var ratios = rfemApp.get_results(
resultsType: Rfem.Results.ResultsType.SteelJointsDesignRatiosByJoint
);
var governing = GetGoverningDesignRatios(ratios);
var columns = new[]
{
"joint_no", "node_no", "design_check_description",
"design_situation_no", "loading", "design_ratio", "is_valid",
};
Console.WriteLine($"\nModel '{MODEL_NAME}' - steel joint design ratios (governing per check type):");
Console.WriteLine(string.Join("\t", columns));
foreach (var row in governing)
{
Console.WriteLine(string.Join("\t", columns.Select(c => row[c]?.ToString() ?? string.Empty)));
}
}
catch (Exception ex)
{
Console.WriteLine($"Error: {ex.Message}");
}
finally
{
if (rfemApp != null) rfemApp.close_connection();
}