Collar Beam Roof#
|
Modelling a collar roof subjected to 3 loads and evaluating the internal forces:
Keywords:
collar beam member hinge design situation internal forces ULS |
from dlubal.api import rfem, common
from math import inf, sqrt
# -------------------------------------------------------
# This example demonstrates how to modelling a
# collar roof consists of two inclined beams which are
# connected by a hinge at the top and by pin supports at
# the bottom. A horizontal collar beam is connected to
# both beams by hinges. While neglecting
# self-weight, the maximum bending moment due to the
# ULS combination is retrieved.
# -------------------------------------------------------
# Editable parameters (SI units)
CROSS_SECTION_WIDTH = 6
CROSS_SECTION_HEIGHT = 18
SYSTEM_LENGTH = 12.0 # L [m]
COLLAR_BEAM_LENGTH = 4.5 # b [m]
SYSTEM_HEIGHT = 4.0 # H [m]
HEIGHT_TO_COLLAR_BEAM = 2.5 # hu [m]
HEIGHT_FROM_COLLAR_BEAM = 1.5 # ho [m]
DISTRIBUTED_LOAD_RAFTER = 5000.0 # g [N/m] = 5 kN/m
DISTRIBUTED_LOAD_COLLAR = 5000.0 # gk [N/m] = 5 kN/m
DISTRIBUTED_LOAD_WIND = 5000.0 # gw [N/m] = 5 kN/m
def define_structure() -> list:
"""Define and return structural model objects created only once."""
half_span = SYSTEM_LENGTH / 2.0
apex_x = half_span
apex_z = -SYSTEM_HEIGHT
left_rafter_rel = HEIGHT_TO_COLLAR_BEAM / SYSTEM_HEIGHT
right_rafter_rel = HEIGHT_FROM_COLLAR_BEAM / SYSTEM_HEIGHT
rafter_length = sqrt(half_span ** 2 + SYSTEM_HEIGHT ** 2)
left_rafter_abs = left_rafter_rel * rafter_length
right_rafter_abs = right_rafter_rel * rafter_length
return [
rfem.structure_core.Material(
no=1,
name="C24",
),
rfem.structure_core.CrossSection(
no=1,
type=rfem.structure_core.CrossSection.TYPE_STANDARDIZED_TIMBER,
material=1,
b=CROSS_SECTION_WIDTH,
h=CROSS_SECTION_HEIGHT,
shear_stiffness_deactivated=True,
),
# Main truss nodes
rfem.structure_core.Node(no=1),
rfem.structure_core.Node(no=2, coordinate_1=SYSTEM_LENGTH),
rfem.structure_core.Node(no=3, coordinate_1=apex_x, coordinate_3=apex_z),
# Collar beam nodes as points on rafters
rfem.structure_core.Node(
no=6,
type=rfem.structure_core.Node.TYPE_ON_MEMBER,
on_member_reference_member=1,
distance_from_start_relative=left_rafter_rel,
distance_from_start_absolute=left_rafter_abs,
),
rfem.structure_core.Node(
no=7,
type=rfem.structure_core.Node.TYPE_ON_MEMBER,
on_member_reference_member=2,
distance_from_start_relative=right_rafter_rel,
distance_from_start_absolute=right_rafter_abs,
),
# Truss lines
rfem.structure_core.Line(no=1, definition_nodes=[1, 3]),
rfem.structure_core.Line(no=2, definition_nodes=[3, 2]),
rfem.structure_core.Line(no=4, definition_nodes=[6, 7]),
# Members
rfem.structure_core.Member(no=1, line=1, cross_section_start=1, member_hinge_end=1),
rfem.structure_core.Member(no=2, line=2, cross_section_start=1),
rfem.structure_core.Member(no=3, line=4, cross_section_start=1, member_hinge_start=1, member_hinge_end=1),
# Supports and hinge
rfem.types_for_nodes.NodalSupport(
no=1,
user_defined_name_enabled=True,
name="Gelenkig",
nodes=[1, 2],
spring=common.Vector3d(x=inf, y=0, z=inf),
),
rfem.types_for_members.MemberHinge(
no=1,
axial_release_n=inf,
axial_release_vz=inf,
moment_release_my=0,
),
]
def define_loading() -> list:
"""Define separate load cases acting on one shared collar-roof structure."""
return [
rfem.loading.LoadCase(
no=1,
name="Distributed load rafter (g)",
static_analysis_settings=1,
self_weight_active=False,
),
rfem.loading.LoadCase(
no=2,
name="Distributed load collar beam (gk)",
static_analysis_settings=1,
self_weight_active=False,
),
rfem.loading.LoadCase(
no=3,
name="Distributed load wind (gw)",
static_analysis_settings=1,
self_weight_active=False,
),
rfem.loads.MemberLoad(
no=1,
members=[1, 2],
load_case=1,
load_direction=rfem.loads.MemberLoad.LOAD_DIRECTION_GLOBAL_Z_OR_USER_DEFINED_W_PROJECTED_LENGTH,
magnitude=DISTRIBUTED_LOAD_RAFTER,
),
rfem.loads.MemberLoad(
no=2,
members=[3],
load_case=2,
magnitude=DISTRIBUTED_LOAD_COLLAR,
),
rfem.loads.MemberLoad(
no=3,
members=[1],
load_case=3,
coordinate_system=common.CoordinateSystemRepresentation(
type=common.CoordinateSystemRepresentation.COORDINATE_SYSTEM_TYPE_LOCAL
),
magnitude=DISTRIBUTED_LOAD_WIND,
),
rfem.loading.StaticAnalysisSettings(
no=1
),
rfem.loading.CombinationWizard(
no=1,
static_analysis_settings=1
),
rfem.loading.DesignSituation(
no=1,
name="ULS (STR/GEO) - Permanent and transient - Eq. 6.10",
design_situation_type=rfem.loading.DesignSituation.DESIGN_SITUATION_TYPE_STR_PERMANENT_AND_TRANSIENT_6_10,
combination_wizard=1,
)
]
with rfem.Application() as rfem_app:
app_info = rfem_app.get_application_info()
print(f"\nApplication Info:\n{app_info}")
# Modelling
rfem_app.create_model(name='collar_beam_roof')
base_data = rfem_app.get_base_data()
base_data.combinations_settings.combination_wizard_active = True
base_data.main.model_type = rfem.BaseData.Main.MODEL_TYPE_2D_XZ_PLANE_STRESS
rfem_app.set_base_data(base_data=base_data)
rfem_app.delete_all_objects()
rfem_app.create_object_list(define_structure() + define_loading())
# Calculation
calculation_info = rfem_app.calculate_all(skip_warnings=True)
print(f"\nCalculation Info:\n{calculation_info}")
# Results
member_internal_forces_df = rfem_app.get_results(
results_type=rfem.results.STATIC_ANALYSIS_MEMBERS_INTERNAL_FORCES,
).data.copy()
idx_max_abs_m_y = member_internal_forces_df["m_y"].abs().idxmax()
row = member_internal_forces_df.loc[idx_max_abs_m_y]
print(f"Max |m_y|:\n{row}")
using Google.Protobuf;
using System.Globalization;
using System.Linq;
using Common = Dlubal.Api.Common;
using Rfem = Dlubal.Api.Rfem;
// -------------------------------------------------------
// This example demonstrates how to modelling a
// collar roof consists of two inclined beams which are
// connected by a hinge at the top and by pin supports at
// the bottom. A horizontal collar beam is connected to
// both beams by hinges. While neglecting
// self-weight, the maximum bending moment due to the
// ULS combination is retrieved.
// -------------------------------------------------------
// Editable parameters (SI units)
const string MODEL_NAME = "collar_beam_roof";
const double CROSS_SECTION_WIDTH = 6;
const double CROSS_SECTION_HEIGHT = 18;
const double SYSTEM_LENGTH = 12.0; // L [m]
const double COLLAR_BEAM_LENGTH = 4.5; // b [m]
const double SYSTEM_HEIGHT = 4.0; // H [m]
const double HEIGHT_TO_COLLAR_BEAM = 2.5; // hu [m]
const double HEIGHT_FROM_COLLAR_BEAM = 1.5; // ho [m]
const double DISTRIBUTED_LOAD_RAFTER = 5000.0; // g [N/m] = 5 kN/m
const double DISTRIBUTED_LOAD_COLLAR = 5000.0; // gk [N/m] = 5 kN/m
const double DISTRIBUTED_LOAD_WIND = 5000.0; // gw [N/m] = 5 kN/m
static double ParseDoubleInvariant(object? value)
{
if (value is null) return double.NaN;
if (value is double d) return d;
return double.TryParse(
Convert.ToString(value, CultureInfo.InvariantCulture),
NumberStyles.Any,
CultureInfo.InvariantCulture,
out var parsed
)
? parsed
: double.NaN;
}
static List<IMessage> DefineStructure()
{
double halfSpan = SYSTEM_LENGTH / 2.0;
double apexX = halfSpan;
double apexZ = -SYSTEM_HEIGHT;
double leftRafterRel = HEIGHT_TO_COLLAR_BEAM / SYSTEM_HEIGHT;
double rightRafterRel = HEIGHT_FROM_COLLAR_BEAM / SYSTEM_HEIGHT;
double rafterLength = Math.Sqrt(Math.Pow(halfSpan, 2) + Math.Pow(SYSTEM_HEIGHT, 2));
double leftRafterAbs = leftRafterRel * rafterLength;
double rightRafterAbs = rightRafterRel * rafterLength;
return new List<IMessage>
{
new Rfem.StructureCore.Material
{
No = 1,
Name = "C24 | EN 338:2016-04",
},
new Rfem.StructureCore.CrossSection
{
No = 1,
Type = Rfem.StructureCore.CrossSection.Types.Type.StandardizedTimber,
Material = 1,
B = CROSS_SECTION_WIDTH,
H = CROSS_SECTION_HEIGHT,
ShearStiffnessDeactivated = true,
},
// Main truss nodes
new Rfem.StructureCore.Node { No = 1 },
new Rfem.StructureCore.Node { No = 2, Coordinate1 = SYSTEM_LENGTH },
new Rfem.StructureCore.Node { No = 3, Coordinate1 = apexX, Coordinate3 = apexZ },
// Collar beam nodes as points on rafters
new Rfem.StructureCore.Node
{
No = 6,
Type = Rfem.StructureCore.Node.Types.Type.OnMember,
OnMemberReferenceMember = 1,
DistanceFromStartRelative = leftRafterRel,
DistanceFromStartAbsolute = leftRafterAbs,
},
new Rfem.StructureCore.Node
{
No = 7,
Type = Rfem.StructureCore.Node.Types.Type.OnMember,
OnMemberReferenceMember = 2,
DistanceFromStartRelative = rightRafterRel,
DistanceFromStartAbsolute = rightRafterAbs,
},
// Truss lines
new Rfem.StructureCore.Line { No = 1, DefinitionNodes = { 1, 3 } },
new Rfem.StructureCore.Line { No = 2, DefinitionNodes = { 3, 2 } },
new Rfem.StructureCore.Line { No = 4, DefinitionNodes = { 6, 7 } },
// Members
new Rfem.StructureCore.Member { No = 1, Line = 1, CrossSectionStart = 1, MemberHingeEnd = 1 },
new Rfem.StructureCore.Member { No = 2, Line = 2, CrossSectionStart = 1 },
new Rfem.StructureCore.Member { No = 3, Line = 4, CrossSectionStart = 1, MemberHingeStart = 1, MemberHingeEnd = 1 },
// Supports and hinge
new Rfem.TypesForNodes.NodalSupport
{
No = 1,
UserDefinedNameEnabled = true,
Name = "Gelenkig",
Nodes = { 1, 2 },
Spring = new Common.Vector3d
{
X = double.PositiveInfinity,
Y = 0,
Z = double.PositiveInfinity,
},
},
new Rfem.TypesForMembers.MemberHinge
{
No = 1,
AxialReleaseN = double.PositiveInfinity,
AxialReleaseVz = double.PositiveInfinity,
},
};
}
static List<IMessage> DefineLoading()
{
return new List<IMessage>
{
new Rfem.Loading.LoadCase
{
No = 1,
Name = "Distributed load rafter (g)",
StaticAnalysisSettings = 1,
SelfWeightActive = false,
},
new Rfem.Loading.LoadCase
{
No = 2,
Name = "Distributed load collar beam (gk)",
StaticAnalysisSettings = 1,
SelfWeightActive = false,
},
new Rfem.Loading.LoadCase
{
No = 3,
Name = "Distributed load wind (gw)",
StaticAnalysisSettings = 1,
SelfWeightActive = false,
},
new Rfem.Loads.MemberLoad
{
No = 1,
Members = { 1, 2 },
LoadCase = 1,
LoadDirection = Rfem.Loads.MemberLoad.Types.LoadDirection.GlobalZOrUserDefinedWProjectedLength,
Magnitude = DISTRIBUTED_LOAD_RAFTER,
},
new Rfem.Loads.MemberLoad
{
No = 2,
Members = { 3 },
LoadCase = 2,
Magnitude = DISTRIBUTED_LOAD_COLLAR,
},
new Rfem.Loads.MemberLoad
{
No = 3,
Members = { 1 },
LoadCase = 3,
CoordinateSystem = new Common.CoordinateSystemRepresentation
{
Type = Common.CoordinateSystemRepresentation.Types.CoordinateSystemType.Local,
},
Magnitude = DISTRIBUTED_LOAD_WIND,
},
new Rfem.Loading.StaticAnalysisSettings
{
No = 1,
},
new Rfem.Loading.CombinationWizard
{
No = 1,
StaticAnalysisSettings = 1,
},
new Rfem.Loading.DesignSituation
{
No = 1,
Name = "ULS (STR/GEO) - Permanent and transient - Eq. 6.10",
DesignSituationType = Rfem.Loading.DesignSituation.Types.DesignSituationType.StrPermanentAndTransient610,
CombinationWizard = 1,
},
};
}
ApplicationRfem? rfemApp = null;
try
{
rfemApp = new ApplicationRfem();
var appInfo = rfemApp.get_application_info();
Console.WriteLine($"\nApplication Info:\n{appInfo}");
rfemApp.create_model(name: MODEL_NAME);
var baseData = rfemApp.get_base_data();
baseData.CombinationsSettings.CombinationWizardActive = true;
baseData.Main.ModelType = Rfem.BaseData.Types.Main.Types.ModelType._2DXzPlaneStress;
rfemApp.set_base_data(baseData: baseData);
rfemApp.delete_all_objects();
rfemApp.create_object_list(DefineStructure().Concat(DefineLoading()).ToList());
var calculationInfo = rfemApp.calculate_all(skipWarnings: true);
Console.WriteLine($"\nCalculation Info:\n{calculationInfo}");
var memberInternalForces = rfemApp.get_results(
resultsType: Rfem.Results.ResultsType.StaticAnalysisMembersInternalForces
);
bool hasMy = memberInternalForces.Data.Columns.Any(c => c.Name == "m_y");
bool hasN = memberInternalForces.Data.Columns.Any(c => c.Name == "n");
if (!hasMy || !hasN)
{
var available = string.Join(", ", memberInternalForces.Data.Columns.Select(c => c.Name));
throw new InvalidOperationException(
$"Expected columns 'm_y' and 'n' not found. Available columns: {available}"
);
}
var myCol = memberInternalForces.Data.Columns["m_y"];
var nCol = memberInternalForces.Data.Columns["n"];
long maxRowIndex = -1;
double maxAbsMy = double.NegativeInfinity;
for (long i = 0; i < myCol.Length; i++)
{
double my = ParseDoubleInvariant(myCol[i]);
if (double.IsNaN(my))
continue;
double absMy = Math.Abs(my);
if (absMy > maxAbsMy)
{
maxAbsMy = absMy;
maxRowIndex = i;
}
}
if (maxRowIndex < 0)
{
throw new InvalidOperationException("No valid 'm_y' values found in member internal forces.");
}
double myAtMax = ParseDoubleInvariant(myCol[maxRowIndex]);
double nAtMax = ParseDoubleInvariant(nCol[maxRowIndex]);
object? memberNo = memberInternalForces.Data.Columns.Any(c => c.Name == "member_no")
? memberInternalForces.Data.Columns["member_no"][maxRowIndex]
: null;
object? locationX = memberInternalForces.Data.Columns.Any(c => c.Name == "location_x")
? memberInternalForces.Data.Columns["location_x"][maxRowIndex]
: null;
object? loading = memberInternalForces.Data.Columns.Any(c => c.Name == "loading")
? memberInternalForces.Data.Columns["loading"][maxRowIndex]
: null;
Console.WriteLine(
$"Max |m_y|: {Math.Abs(myAtMax)} " +
$"(m_y = {myAtMax}, n = {nAtMax}, member = {memberNo}, x = {locationX}, loading = {loading})"
);
}
catch (Exception ex)
{
Console.WriteLine($"Error: {ex.Message}");
}
finally
{
if (rfemApp != null) rfemApp.close_connection();
}