Curved Beam#
|
Modelling a curved beam subjected to eccentric out-of-plane loading and evaluating its deflection:
Keywords:
curved beam arc line nodal support nodal load force eccentricity torsion deflection |
from dlubal.api import rfem, common
from math import inf, pi, cos, sin
# -------------------------------------------------------
# This example demonstrates how to model a quarter-circle
# beam with a rectangular cross-section which is loaded by
# means of an eccentric out-of-plane force.
# While neglecting self-weight, the maximum total
# deflection of the curved beam is retrieved.
# -------------------------------------------------------
# Editable parameters (SI units)
MODEL_NAME = "curved_beam"
MATERIAL = 'S235'
BEAM_RADIUS = 1.0 # R [m]
CROSS_SECTION_WIDTH = 0.025 # b [m]
CROSS_SECTION_HEIGHT = 0.050 # h [m]
LOAD_FZ = 1000.0 # F [N] = 1 kN, out of the beam's plane
def define_structure() -> list:
"""Define and return a list of structural objects."""
return [
rfem.structure_core.Material(
no=1,
name=MATERIAL,
),
# Cross-Sections
rfem.structure_core.CrossSection(
no=1,
material=1,
type=rfem.structure_core.CrossSection.TYPE_PARAMETRIC_MASSIVE_I,
b=CROSS_SECTION_WIDTH,
h=CROSS_SECTION_HEIGHT,
),
# Nodes
rfem.structure_core.Node(
no=1,
coordinate_1=0.0,
coordinate_2=0.0,
),
rfem.structure_core.Node(
no=2,
coordinate_1=BEAM_RADIUS,
coordinate_2=BEAM_RADIUS,
),
# Lines
# The arc control point is a third point ON the arc, at 135 deg. With the
# ends at 180 deg and 90 deg it fixes a quarter circle of radius
# BEAM_RADIUS centred on (BEAM_RADIUS, 0).
rfem.structure_core.Line(
no=1,
type=rfem.structure_core.Line.TYPE_ARC,
definition_nodes=[1, 2],
arc_control_point=common.Vector3d(
x=BEAM_RADIUS + BEAM_RADIUS*cos(3*pi/4),
y=BEAM_RADIUS*sin(3*pi/4),
z=0
),
),
# Members
rfem.structure_core.Member(
no=1,
line=1,
cross_section_start=1,
rotation_specification_type=rfem.structure_core.Member.ROTATION_SPECIFICATION_TYPE_INSIDE,
),
# Nodal Supports
# Fully fixed. Note that a support restrained in every direction is
# invariant to the orientation of its axes, so there is no reason to
# rotate them here.
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=inf, z=inf),
),
]
def define_loading() -> list:
"""Define and return a list of loading objects."""
return [
# Static Analysis Settings
rfem.loading.StaticAnalysisSettings(
no=1,
),
# Load Cases
rfem.loading.LoadCase(
no=1,
static_analysis_settings=1,
self_weight_active=False,
),
# Nodal Loads | LC1
# The force acts out of the beam's plane, offset by one radius. That
# eccentricity lands its line of action on the arc centre and is what
# twists the beam - without it the member would only bend.
rfem.loads.NodalLoad(
no=1,
load_type=rfem.loads.NodalLoad.LOAD_TYPE_COMPONENTS,
nodes=[2],
components_force=common.Vector3d(x=0, y=0, z=LOAD_FZ),
load_case=1,
force_eccentricity_enabled = True,
force_eccentricity=common.Vector3d(x=0, y=-BEAM_RADIUS, z=0)
),
]
# Connect to the RFEM application
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)
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_deformation_df = rfem_app.get_results(
results_type=rfem.results.STATIC_ANALYSIS_MEMBERS_LOCAL_DEFORMATIONS
).data
if "u_abs" not in member_deformation_df.columns:
raise RuntimeError(
"Expected column 'u_abs' not found. "
f"Available columns: {list(member_deformation_df.columns)}"
)
# Maximum total deflection.
# u_abs is the resultant of the three components. For this model it equals
# |u_z|, because a purely out-of-plane load leaves u_x and u_y at zero.
max_u = member_deformation_df["u_abs"].abs().max()
print(f"Max |u|: {max_u} m ({max_u * 1000:.2f} mm)")
using Google.Protobuf;
using System.Globalization;
using System.Linq;
using Common = Dlubal.Api.Common;
using Rfem = Dlubal.Api.Rfem;
// -------------------------------------------------------
// This example demonstrates how to model a
// quarter-circle beam with a rectangular cross-section
// loaded by an eccentric out-of-plane force.
// While neglecting self-weight, the maximum total
// deflection of the curved beam is retrieved.
// -------------------------------------------------------
// Editable parameters (SI units)
const string MODEL_NAME = "curved_beam";
const string MATERIAL = "S235";
const double BEAM_RADIUS = 1.0;
const double CROSS_SECTION_WIDTH = 0.025;
const double CROSS_SECTION_HEIGHT = 0.050;
const double LOAD_FZ = 1000.0;
static List<IMessage> DefineStructure()
{
return new List<IMessage>
{
new Rfem.StructureCore.Material
{
No = 1,
Name = MATERIAL,
},
new Rfem.StructureCore.CrossSection
{
No = 1,
Type = Rfem.StructureCore.CrossSection.Types.Type.ParametricMassiveI,
B = CROSS_SECTION_WIDTH,
H = CROSS_SECTION_HEIGHT,
Material = 1,
},
new Rfem.StructureCore.Node
{
No = 1,
Coordinate1 = 0.0,
Coordinate2 = 0.0,
},
new Rfem.StructureCore.Node
{
No = 2,
Coordinate1 = BEAM_RADIUS,
Coordinate2 = BEAM_RADIUS,
},
// The arc control point is a third point ON the arc, at 135 deg. With the
// ends at 180 deg and 90 deg it fixes a quarter circle of radius
// BEAM_RADIUS centred on (BEAM_RADIUS, 0). Type must be set to Arc:
// without it the line stays a straight chord and the control point is
// ignored, which the Inside rotation below then fails the calculation on.
new Rfem.StructureCore.Line
{
No = 1,
Type = Rfem.StructureCore.Line.Types.Type.Arc,
DefinitionNodes = { 1, 2 },
ArcControlPoint = new Common.Vector3d
{
X = BEAM_RADIUS + BEAM_RADIUS * Math.Cos(3 * Math.PI / 4),
Y = BEAM_RADIUS * Math.Sin(3 * Math.PI / 4),
Z = 0.0,
},
},
new Rfem.StructureCore.Member
{
No = 1,
Line = 1,
CrossSectionStart = 1,
RotationSpecificationType = Rfem.StructureCore.Member.Types.RotationSpecificationType.Inside,
},
// Fully fixed. Note that a support restrained in every direction is
// invariant to the orientation of its axes, so there is no reason to
// rotate them here.
new Rfem.TypesForNodes.NodalSupport
{
No = 1,
Nodes = { 1 },
Spring = new Common.Vector3d { X = double.PositiveInfinity, Y = double.PositiveInfinity, Z = double.PositiveInfinity },
RotationalRestraint = new Common.Vector3d { X = double.PositiveInfinity, Y = double.PositiveInfinity, Z = double.PositiveInfinity },
},
};
}
static List<IMessage> DefineLoading()
{
return new List<IMessage>
{
new Rfem.Loading.StaticAnalysisSettings
{
No = 1,
},
new Rfem.Loading.LoadCase
{
No = 1,
StaticAnalysisSettings = 1,
SelfWeightActive = false,
},
new Rfem.Loads.NodalLoad
{
No = 1,
LoadType = Rfem.Loads.NodalLoad.Types.LoadType.Components,
Nodes = { 2 },
ComponentsForce = new Common.Vector3d { X = 0.0, Y = 0.0, Z = LOAD_FZ },
ForceEccentricityEnabled = true,
ForceEccentricity = new Common.Vector3d { X = 0.0, Y = -BEAM_RADIUS, Z = 0.0 },
LoadCase = 1,
},
};
}
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;
}
ApplicationRfem? rfemApp = null;
try
{
rfemApp = new ApplicationRfem();
var appInfo = rfemApp.get_application_info();
Console.WriteLine($"\nApplication Info:\n{appInfo}");
rfemApp.close_all_models(saveChanges: false);
rfemApp.create_model(name: MODEL_NAME);
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 memberDeformation = rfemApp.get_results(
resultsType: Rfem.Results.ResultsType.StaticAnalysisMembersLocalDeformations
);
if (!memberDeformation.Data.Columns.Any(c => c.Name == "u_abs"))
{
var available = string.Join(", ", memberDeformation.Data.Columns.Select(c => c.Name));
throw new InvalidOperationException(
$"Expected column 'u_abs' not found. Available columns: {available}"
);
}
// u_abs is the resultant of the three components. For this model it equals
// |u_z|, because a purely out-of-plane load leaves u_x and u_y at zero.
var maxAbsU = memberDeformation.Data.Rows
.Select(row => ParseDoubleInvariant(row["u_abs"]))
.Where(v => !double.IsNaN(v))
.Select(Math.Abs)
.DefaultIfEmpty(double.NaN)
.Max();
Console.WriteLine($"Max |u|: {maxAbsU} m ({maxAbsU * 1000.0:F2} mm)");
}
catch (Exception ex)
{
Console.WriteLine($"Error: {ex.Message}");
}
finally
{
if (rfemApp != null) rfemApp.close_connection();
}