Steel Hall#
|
This example demonstrates how to model a parametric steel hall using manipulation functions like
|
from dlubal.api import rfem, common
import math
# -------------------------------------------------------
# This example demonstrates how to modelling parametric
# steel hall with help of manipulation functions like move
# or rotate including the copy option. The idea is to reduce
# manual modeling by leveraging symmetry and transformations.
# -------------------------------------------------------
# Editable parameters (SI units)
FRAME_SPACING = 5.0
FRAME_COUNT = 5
FRAME_WIDTH = 11.0
FRAME_HEIGHT_MIN = 4.5
FRAME_HEIGHT_MAX = 6.0
RAFTER_SLOPE_LENGTH = 0.75
PURLIN_FIELDS = 4
PURLIN_OFFSET_ON_TOP = 0.25
STEEL_GRADE = "S235 | EN 10025-2:2004-11"
CROSS_SECTION_COLUMN = "IPE 300"
CROSS_SECTION_RAFTER = "I 0.3/0.11/0.006/0.014/0/0/H"
CROSS_SECTION_RAFTER_TAPPERED = "I 0.6/0.11/0.006/0.014/0/0/H"
CROSS_SECTION_PURLINS = "CHC 139.7x8.0"
CROSS_SECTION_BRACING = "R 20"
def build_half_portal_frame() -> list:
inf = float('inf')
portal_frame = [
rfem.structure_core.Material(no=1, name=STEEL_GRADE),
rfem.structure_core.CrossSection(no=1, name=CROSS_SECTION_COLUMN, material=1),
rfem.structure_core.CrossSection(no=2, name=CROSS_SECTION_RAFTER, material=1),
rfem.structure_core.CrossSection(no=3, name=CROSS_SECTION_RAFTER_TAPPERED, material=1),
]
portal_frame.append(rfem.structure_core.Node(no=1))
portal_frame.append(rfem.structure_core.Node(no=2, coordinate_3=-FRAME_HEIGHT_MIN))
node_no = 3
rafter_length = math.sqrt((FRAME_HEIGHT_MAX - FRAME_HEIGHT_MIN)**2 + (FRAME_WIDTH / 2)**2)
purlin_offset = (rafter_length - PURLIN_OFFSET_ON_TOP) / PURLIN_FIELDS
for j in range(1, PURLIN_FIELDS+1):
portal_frame.append(
rfem.structure_core.Node(
no=node_no,
type=rfem.structure_core.Node.TYPE_ON_MEMBER,
on_member_reference_member=2,
distance_from_start_is_defined_as_relative=False,
distance_from_start_absolute=purlin_offset*j,
)
)
node_no += 1
portal_frame.append(rfem.structure_core.Node(no=node_no, coordinate_1=FRAME_WIDTH/2, coordinate_3=-FRAME_HEIGHT_MAX))
# Lines
portal_frame.append(rfem.structure_core.Line(no=1, definition_nodes=[1, 2]))
portal_frame.append(rfem.structure_core.Line(no=2, definition_nodes=[2, node_no]))
# Members
portal_frame.append(rfem.structure_core.Member(
no=1, line=1, cross_section_start=1,
type=rfem.structure_core.Member.TYPE_BEAM))
portal_frame.append(rfem.structure_core.Member(
no=2, line=2, cross_section_start=3,
type=rfem.structure_core.Member.TYPE_BEAM,
))
# Nodal support (hinge)
portal_frame.append(rfem.types_for_nodes.NodalSupport(
no=1, nodes=[1],
spring_x=inf, spring_y=inf, spring_z=inf,
rotational_restraint_z=inf
))
return portal_frame
def enhance_rafters_with_tapering() -> list:
tapered_members = []
for rafter_no in (2, 4):
tapered_members.append(
rfem.structure_core.Member(
no=rafter_no,
cross_section_end=2,
cross_section_distribution_type=rfem.structure_core.Member.CROSS_SECTION_DISTRIBUTION_TYPE_TAPERED_AT_START_OF_MEMBER,
cross_section_distance_from_start_is_defined_as_relative=False,
section_distance_from_start_absolute=RAFTER_SLOPE_LENGTH
)
)
return tapered_members
def build_purlins_in_first_bay_half() -> list:
nodes_per_frame = 7 + 2* (PURLIN_FIELDS)
purlins = [
rfem.structure_core.CrossSection(no=4, name=CROSS_SECTION_PURLINS, material=1),
]
for purlin in range(1, PURLIN_FIELDS+2):
purlin_line_no = (4 * FRAME_COUNT) + purlin
purlin_node_start = 2 + (purlin - 1)
purlin_node_end = 2 + (purlin - 1) + nodes_per_frame
purlins.append(rfem.structure_core.Line(
no=purlin_line_no, definition_nodes=[purlin_node_start, purlin_node_end])
)
purlins.append(rfem.structure_core.Member(
no=purlin_line_no, line=purlin_line_no, cross_section_start=4,
type=rfem.structure_core.Member.TYPE_TRUSS)
)
return purlins
def build_bracing_in_first_bay_half() -> list:
nodes_per_frame = 7 + 2* (PURLIN_FIELDS)
bracing_no = (4 * FRAME_COUNT) + 2*(PURLIN_FIELDS+1)*(FRAME_COUNT-1) + 1
bracing = [
rfem.structure_core.CrossSection(no=5, name=CROSS_SECTION_BRACING, material=1)
]
for i in range(1, PURLIN_FIELDS + 2):
for j in range(2):
bracing.append(rfem.structure_core.Line(
no=bracing_no + j, definition_nodes=[i + j, nodes_per_frame + i - j + 1]
))
bracing.append(rfem.structure_core.Member(
no=bracing_no + j, line=bracing_no + j, cross_section_start=5,
type=rfem.structure_core.Member.TYPE_TRUSS_ONLY_N
))
bracing_no += 2
return bracing
def get_members_by_type(rfem_app, member_type) -> list:
member_list = rfem_app.get_object_list(
objs=[
rfem.structure_core.Member()
]
)
member_list_filtered = []
for member in member_list:
if member.type is member_type:
member_list_filtered.append(member)
return member_list_filtered
# --- MAIN SCRIPT ---
# Connect to the RFEM application
with rfem.Application() as rfem_app:
rfem_app.close_all_models(save_changes=False)
model_id = rfem_app.create_model(name='steel_hall_parametric')
rfem_app.delete_all_objects()
# Build the half of the portal frame
portal_frame = build_half_portal_frame()
rfem_app.create_object_list(
objs=portal_frame
)
# Rotate the half of the portal frame as copy to its mirrored position
rfem_app.rotate_objects(
objs=portal_frame,
rotation_angle=math.pi,
point_1=common.Vector3d(x=FRAME_WIDTH/2,y=0,z=-FRAME_HEIGHT_MAX),
axis=rfem.manipulation.COORDINATE_AXIS_Z,
rotation_axis=rfem.manipulation.ROTATION_AXIS_SPECIFICATION_TYPE_POINT_AND_PARALLEL_AXIS,
create_copy=True,
number_of_steps=1
)
# Enhance the rafters with tapering
tapered_rafter = enhance_rafters_with_tapering()
rfem_app.update_object_list(
objs=tapered_rafter
)
# Move the frame to create multiple frames by applying a vector displacement
rfem_app.move_objects(
objs=rfem_app.get_object_list(
objs=[
rfem.structure_core.Node(),
rfem.structure_core.Member(),
]
),
create_copy=True,
number_of_steps=FRAME_COUNT-1,
direction_through=rfem.manipulation.DIRECTION_THROUGH_DISPLACEMENT_VECTOR,
displacement_vector=common.Vector3d(x=0.0, y=FRAME_SPACING, z=0.0)
)
# Model purlins between the first two frames, on one symmetric half of the hall
purlins = build_purlins_in_first_bay_half()
rfem_app.create_object_list(objs=purlins)
# Rotate purlins to symmetric half of the hall
rfem_app.rotate_objects(
objs=purlins,
rotation_angle=math.pi - 2*math.atan((FRAME_HEIGHT_MAX - FRAME_HEIGHT_MIN) / (FRAME_WIDTH / 2)),
point_1=common.Vector3d(x=FRAME_WIDTH/2,y=0,z=-FRAME_HEIGHT_MAX),
axis=rfem.manipulation.COORDINATE_AXIS_Y,
rotation_axis=rfem.manipulation.ROTATION_AXIS_SPECIFICATION_TYPE_POINT_AND_PARALLEL_AXIS,
create_copy=True,
number_of_steps=1
)
# Copy the purlins parallel to the axis for the remaining bays
rfem_app.move_objects(
objs=get_members_by_type(
rfem_app, rfem.structure_core.Member.TYPE_TRUSS
),
create_copy=True,
number_of_steps=FRAME_COUNT-2,
direction_through=rfem.manipulation.DIRECTION_THROUGH_PARALLEL_TO_AXIS,
axis=rfem.manipulation.COORDINATE_AXIS_Y,
spacing=FRAME_SPACING
)
# Model bracing between the first two frames, on one symmetric half of the hall
bracing = build_bracing_in_first_bay_half()
rfem_app.create_object_list(objs=bracing)
# Mirror the bracing to symetric half of the hall
rfem_app.rotate_objects(
objs=get_members_by_type(
rfem_app, rfem.structure_core.Member.TYPE_TRUSS_ONLY_N
),
rotation_angle=math.pi,
point_1=common.Vector3d(x=FRAME_WIDTH/2,y=FRAME_SPACING/2,z=-FRAME_HEIGHT_MAX),
axis=rfem.manipulation.COORDINATE_AXIS_Z,
rotation_axis=rfem.manipulation.ROTATION_AXIS_SPECIFICATION_TYPE_POINT_AND_PARALLEL_AXIS,
create_copy=True,
number_of_steps=1
)
/**
Parametric steel hall example using manipulation functions.
**/
using Rfem = Dlubal.Api.Rfem;
using Common = Dlubal.Api.Common;
using Google.Protobuf;
using System.Threading.Tasks;
// Editable parameters (SI units)
const double FRAME_SPACING = 5.0;
const int FRAME_COUNT = 5;
const double FRAME_WIDTH = 11.0;
const double FRAME_HEIGHT_MIN = 4.5;
const double FRAME_HEIGHT_MAX = 6.0;
const double RAFTER_SLOPE_LENGTH = 0.75;
const int PURLIN_FIELDS = 4;
const double PURLIN_OFFSET_ON_TOP = 0.25;
const string STEEL_GRADE = "S235 | EN 10025-2:2004-11";
const string CROSS_SECTION_COLUMN = "IPE 300";
const string CROSS_SECTION_RAFTER = "I 0.3/0.11/0.006/0.014/0/0/H";
const string CROSS_SECTION_RAFTER_TAPPERED = "I 0.6/0.11/0.006/0.014/0/0/H";
const string CROSS_SECTION_PURLIN = "CHC 139.7x8.0";
const string CROSS_SECTION_BRACING = "R 20";
static List<IMessage> BuildHalfPortalFrame()
{
double inf = double.PositiveInfinity;
var portalFrame = new List<IMessage>
{
// Material
new Rfem.StructureCore.Material{No=1, Name=STEEL_GRADE},
// Cross-section
new Rfem.StructureCore.CrossSection{No=1, Name=CROSS_SECTION_COLUMN, Material=1},
new Rfem.StructureCore.CrossSection{No=2, Name=CROSS_SECTION_RAFTER, Material=1},
new Rfem.StructureCore.CrossSection{No=3, Name=CROSS_SECTION_RAFTER_TAPPERED, Material=1},
};
// Nodes
portalFrame.Add(new Rfem.StructureCore.Node{No=1});
portalFrame.Add(new Rfem.StructureCore.Node{No=2, Coordinate3=-FRAME_HEIGHT_MIN});
var nodeNo = 3;
var rafterLength = Math.Sqrt(Math.Pow(FRAME_HEIGHT_MAX - FRAME_HEIGHT_MIN, 2) + Math.Pow(FRAME_WIDTH / 2, 2));
var purlinOffset = (rafterLength - PURLIN_OFFSET_ON_TOP) / PURLIN_FIELDS;
for (int j = 1; j <= PURLIN_FIELDS; j++)
{
var node = new Rfem.StructureCore.Node
{
No = nodeNo,
Type = Rfem.StructureCore.Node.Types.Type.OnMember,
OnMemberReferenceMember = 2,
DistanceFromStartIsDefinedAsRelative = false,
DistanceFromStartAbsolute = purlinOffset * j
};
portalFrame.Add(node);
nodeNo++;
}
portalFrame.Add(new Rfem.StructureCore.Node{No=nodeNo, Coordinate1=FRAME_WIDTH/2, Coordinate3=-FRAME_HEIGHT_MAX});
// Lines
portalFrame.Add(new Rfem.StructureCore.Line{No=1, DefinitionNodes={1, 2}});
portalFrame.Add(new Rfem.StructureCore.Line{No=2, DefinitionNodes={2, nodeNo}});
// Members
portalFrame.Add(new Rfem.StructureCore.Member{
No=1, Line=1, CrossSectionStart=1,
Type=Rfem.StructureCore.Member.Types.Type.Beam
});
portalFrame.Add(new Rfem.StructureCore.Member{
No=2, Line=2, CrossSectionStart=3,
Type=Rfem.StructureCore.Member.Types.Type.Beam
});
// Nodal support (hinge)
portalFrame.Add(new Rfem.TypesForNodes.NodalSupport{
No=1, Nodes={ 1 },
SpringX=inf, SpringY=inf, SpringZ=inf,
RotationalRestraintZ=inf
});
return portalFrame;
}
static List<IMessage> EnhanceRaftersWithTapering()
{
var taperedMembers = new List<IMessage>();
foreach (int rafterNo in new int[] { 2, 4 })
{
var member = new Rfem.StructureCore.Member
{
No = rafterNo,
CrossSectionEnd = 2,
CrossSectionDistributionType = Rfem.StructureCore.Member.Types.CrossSectionDistributionType.TaperedAtStartOfMember,
CrossSectionDistanceFromStartIsDefinedAsRelative = false,
SectionDistanceFromStartAbsolute = RAFTER_SLOPE_LENGTH
};
taperedMembers.Add(member);
}
return taperedMembers;
}
static List<IMessage> BuildPurlinsInFirstBayHalf()
{
int nodesPerFrame = 7 + 2 * PURLIN_FIELDS;
var purlins = new List<IMessage>
{
new Rfem.StructureCore.CrossSection
{
No = 4,
Name = CROSS_SECTION_PURLIN,
Material = 1
}
};
for (int purlin = 1; purlin <= PURLIN_FIELDS + 1; purlin++)
{
int purlinLineNo = (4 * FRAME_COUNT) + purlin;
int purlinNodeStart = 2 + (purlin - 1);
int purlinNodeEnd = purlinNodeStart + nodesPerFrame;
purlins.Add(new Rfem.StructureCore.Line
{
No = purlinLineNo,
DefinitionNodes =
{
purlinNodeStart,
purlinNodeEnd
}
});
purlins.Add(new Rfem.StructureCore.Member
{
No = purlinLineNo,
Line = purlinLineNo,
CrossSectionStart = 4,
Type = Rfem.StructureCore.Member.Types.Type.Truss
});
}
return purlins;
}
static List<IMessage> BuildBracingInFirstBayHalf()
{
int nodesPerFrame = 7 + 2 * PURLIN_FIELDS;
int bracingNo =
(4 * FRAME_COUNT)
+ 2 * (PURLIN_FIELDS + 1) * (FRAME_COUNT - 1)
+ 1;
var bracing = new List<IMessage>
{
new Rfem.StructureCore.CrossSection
{
No = 5,
Name = CROSS_SECTION_BRACING,
Material = 1
}
};
for (int i = 1; i <= PURLIN_FIELDS + 1; i++)
{
for (int j = 0; j < 2; j++)
{
int currentNo = bracingNo + j;
bracing.Add(new Rfem.StructureCore.Line
{
No = currentNo,
DefinitionNodes =
{
i + j,
nodesPerFrame + i - j + 1
}
});
bracing.Add(new Rfem.StructureCore.Member
{
No = currentNo,
Line = currentNo,
CrossSectionStart = 5,
Type = Rfem.StructureCore.Member.Types.Type.TrussOnlyN
});
}
bracingNo += 2;
}
return bracing;
}
static async Task<List<IMessage>> GetMembersByType(
ApplicationRfem rfemApp,
Rfem.StructureCore.Member.Types.Type memberType)
{
var result = new List<IMessage>();
var objects = await rfemApp.get_object_list(
objs: new List<IMessage>{
new Rfem.StructureCore.Member{}
}
);
foreach (var obj in objects)
{
if (obj is Rfem.StructureCore.Member member &&
member.Type == memberType)
{
result.Add(member);
}
}
return result;
}
ApplicationRfem? rfemApp = null;
try
{
rfemApp = new ApplicationRfem();
await rfemApp.close_all_models(saveChanges: false);
await rfemApp.create_model("steel_hall_parametric");
await rfemApp.delete_all_objects();
// Build the half of the portal frame
var portalFrame = BuildHalfPortalFrame();
await rfemApp.create_object_list(objs: portalFrame);
// Rotate the half of the portal frame as copy to its mirrored position
await rfemApp.rotate_objects(
objs: portalFrame,
rotationAngle: Math.PI,
point1: new Common.Vector3d{X=FRAME_WIDTH/2,Y=0,Z=-FRAME_HEIGHT_MAX},
axis: Rfem.Manipulation.CoordinateAxis.Z,
rotationAxis: Rfem.Manipulation.RotationAxisSpecificationType.PointAndParallelAxis,
createCopy: true,
numberOfSteps: 1
);
// Enhance the rafters with tapering
var taperedRafterObjs = EnhanceRaftersWithTapering();
await rfemApp.update_object_list(
objs: taperedRafterObjs
);
// Copy the frame by vector
await rfemApp.move_objects(
objs: await rfemApp.get_object_list(
objs: new List<IMessage> {
new Rfem.StructureCore.Node {},
new Rfem.StructureCore.Member {}
}
),
createCopy: true,
numberOfSteps: FRAME_COUNT - 1,
directionThrough: Rfem.Manipulation.DirectionThrough.DisplacementVector,
displacementVector: new Common.Vector3d{X=0.0, Y=FRAME_SPACING, Z=0.0},
spacing:FRAME_SPACING
);
// Model purlins between the first two frames, on one symmetric half of the hall
var purlins = BuildPurlinsInFirstBayHalf();
await rfemApp.create_object_list(objs: purlins);
// Rotate purlins to symmetric half of the hall
await rfemApp.rotate_objects(
objs: purlins,
rotationAngle: Math.PI - 2*Math.Atan((FRAME_HEIGHT_MAX - FRAME_HEIGHT_MIN) / (FRAME_WIDTH / 2)),
point1: new Common.Vector3d{X=FRAME_WIDTH/2,Y=0,Z=-FRAME_HEIGHT_MAX},
axis: Rfem.Manipulation.CoordinateAxis.Y,
rotationAxis: Rfem.Manipulation.RotationAxisSpecificationType.PointAndParallelAxis,
createCopy: true,
numberOfSteps: 1
);
// Copy the purlins parallel to the axis for the remaining bays
await rfemApp.move_objects(
objs: await GetMembersByType(
rfemApp, Rfem.StructureCore.Member.Types.Type.Truss
),
createCopy: true,
numberOfSteps: FRAME_COUNT-2,
directionThrough: Rfem.Manipulation.DirectionThrough.ParallelToAxis,
axis: Rfem.Manipulation.CoordinateAxis.Y,
spacing: FRAME_SPACING
);
// Model bracing between the first two frames, on one symmetric half of the hall
var bracing = BuildBracingInFirstBayHalf();
await rfemApp.create_object_list(objs: bracing);
// Mirror the bracing to symetric half of the hall
await rfemApp.rotate_objects(
objs: await GetMembersByType(
rfemApp, Rfem.StructureCore.Member.Types.Type.TrussOnlyN
),
rotationAngle: Math.PI,
point1: new Common.Vector3d{X=FRAME_WIDTH/2,Y=FRAME_SPACING/2,Z=-FRAME_HEIGHT_MAX},
axis: Rfem.Manipulation.CoordinateAxis.Z,
rotationAxis: Rfem.Manipulation.RotationAxisSpecificationType.PointAndParallelAxis,
createCopy: true,
numberOfSteps: 1
);
}
catch (Exception ex)
{
Console.WriteLine($"Error: {ex.Message}");
}
finally
{
if (rfemApp != null) await rfemApp.close_connection();
}