First-Order: Bar Deflection#

Determining the vertical displacement at the free end of a cantilever beam

In this example, the same cantilever beam as in “First-Order: Bending Moment” is analyzed, but the focus is shifted from internal forces to nodal displacements. A point load acts at the free end, and the resulting deformation of the beam is computed using first-order (linear) structural analysis.

This example demonstrates:

  • Defining a cross-section from polygon geometry

  • Modeling a beam with a node load

  • Extracting bar deformations from the calculation results

  • Reading the vertical displacement at the free end

  • Plotting the displacement distribution

This serves as a minimal introduction to the basic workflow of sStatics. You can find the example as an executable Python file here.

System Description#

  • Beam length: 3 m

  • Material: Timber C24, (E = 11000000 \(\frac{kN}{m^2}\))

  • Cross-section: width / height = 10 cm / 20 cm

  • Support: fixed at the left end (Node 1)

  • Load: 1 kN vertical point load at the free end (Node 2)

⚠️ Note: All values are converted into meters (m) and kilonewtons (kN) for consistent units.

Define the Structural System#

In this section, the static system is modeled. For a detailed step-by-step workflow, refer to the “Getting Started” example.

[1]:
# 1. Import required modules
from sstatics.core.preprocessing import (
    Bar, CrossSection, Polygon, Material, Node, NodePointLoad, System
)
from sstatics.core.calc_methods import FirstOrder
from sstatics.core.postprocessing.graphic_objects import ObjectRenderer, SystemGeo


# 2. Define the cross-section using polygon geometry
cross_sec = CrossSection(
    geometry=[Polygon([(0, 0), (0.1, 0), (0.1, 0.2), (0, 0.2), (0, 0)])]
)

# 3. Define material (E = 11,000,000 kN/m²)
material = Material(11000000, 0.1, 0.1, 0.1)

# 4. Define nodes
n1 = Node(0, 0, u='fixed', w='fixed', phi='fixed')  # fully fixed support
n2 = Node(3, 0, loads=NodePointLoad(z=1))  # free end with vertical load

# 5. Define the bar connecting the two nodes
bar_1 = Bar(n1, n2, cross_sec, material)

# 6. Build the structural system
system = System([bar_1])

# Show system graphic
ObjectRenderer(SystemGeo(system), 'mpl').show()
../../_images/examples_02_firstorder_02_bar_deflection_2_0.png

Perform the Structural Analysis#

Next, we assemble the bar into a structural system and perform a first-order analysis.

The FirstOrder class differs from the standard Solver in that it accepts the structural system directly, rather than a pre-defined mesh. The computational mesh is generated automatically during the analysis, so you can focus on defining the model and loads.

This approach simplifies the workflow and allows you to quickly compute internal forces, support reactions and other results without manually creating the mesh.

Perform the Structural Analysis#

Next, we assemble the bar into a structural system and perform a first-order analysis.

The FirstOrder class differs from the standard Solver in that it accepts the structural system directly, rather than a pre-defined mesh. The computational mesh is generated automatically during the analysis, so you can focus on defining the model and loads.

This approach simplifies the workflow and allows you to quickly compute internal forces, support reactions and other results without manually creating the mesh.

[2]:
from sstatics.core.preprocessing import System
from sstatics.core.calc_methods import FirstOrder

# Create system
system = System([bar_1])

# Perform calculation
solution = FirstOrder(system)

# Get bar deformations
print(solution.bar_deform_total)
[array([[ 0.        ],
       [ 0.        ],
       [ 0.        ],
       [ 0.        ],
       [ 0.01227273],
       [-0.00613636]])]

Get the Bar Deformations#

The bar deformations can be accessed using the function bar_deform_total.

Side Note: The total bar deformations are composed of three contributions:

  • bar_deform: deformations caused by the transformation of nodal deformations (node_deform) into the bar local system

  • bar_deform_hinge: relative deformations that occur at hinges or joints

  • bar_deform_displacements: displacements induced by support movements (NodeDisplacement) transformed into the bar coordinate system

All deformations are stored as a list of 6×1 vectors, with one vector per bar.

To retrieve the deformation vector for the first bar, use index [0].

[3]:
# 8. Extract bar deformations
bar_deform = solution.bar_deform_total
print("Bar deformations of all bars:\n", bar_deform)

# Each entry is a 6×1 vector of bar deformations:
# [u'_i, w'_i, phi'_i, u'_j, w'_j, phi'_j]^T
bar_deform_1 = bar_deform[0]
Bar deformations of all bars:
 [array([[ 0.        ],
       [ 0.        ],
       [ 0.        ],
       [ 0.        ],
       [ 0.01227273],
       [-0.00613636]])]

Explanation of results:

  • The array contains 6 values:

    • First 3 values = displacements \((u, w, \varphi)\) at the start node (Node 1)

    • Last 3 values = displacements \((u, w, \varphi)\) at the end node (Node 2)

  • Interpretation for our case:

    • Node 1 is fixed → all values = 0

    • Node 2 has:

      • Horizontal displacement \(u = 0\)

      • Vertical displacement w = 12.27 mm

      • Rotation \(\varphi = -0.0061\> rad\)

To access the vertical displacement at the end of the bar, use index ``[4]``, since Python uses 0-based indexing.

Plot of the vertical displacement distribution#

The vertical displacement distribution can be visualized directly using the plot method from the FirstOrder class.

To display the vertical displacement diagram, set the parameter kind='w'

You can choose different visualization options, such as using Matplotlib or Plotly, and whether to show the modeled system, user-defined subdivisions, or the computational mesh.

[4]:
# 9. Plot vertical displacement distribution
solution.plot(kind='w')
../../_images/examples_02_firstorder_02_bar_deflection_10_0.png

Summary#

The analysis of this cantilever beam shows that the vertical bar displacement at the free end (end node) is \(w = 12.27\ \text{mm}\).