Skip to main content
This example shows how to create and analyze a planar truss structure using milcapy’s add_truss() method for axial-only elements.

Overview

In this example, you’ll build a simple 2D truss consisting of:
  • 5 nodes forming a trapezoidal geometry
  • 8 bar elements with two different cross-sectional areas
  • Fixed and roller supports at the base
  • Concentrated loads at the top chord

Complete Example

1

Import milcapy

Import the required classes from milcapy:
from milcapy import SystemModel
2

Create model and define materials

Initialize the model and add materials:
model = SystemModel()

# Add steel material
model.add_material(
    name="steel",
    modulus_elasticity=2.1e6,  # tonf/m²
    poisson_ratio=0.3
)
3

Define sections

Create two different sections for different member types:
# Section for diagonal and vertical members
model.add_generic_section(
    name="section1",
    material_name="steel",
    area=0.12,      # m² (0.3 × 0.4)
    inertia=0.001,  # Not used in trusses
    k_factor=1.0
)

# Section for horizontal members
model.add_generic_section(
    name="section2",
    material_name="steel",
    area=0.16,      # m² (0.4 × 0.4)
    inertia=0.001,
    k_factor=1.0
)
For truss elements, only the area matters. The inertia and k_factor are not used in axial-only analysis.
4

Add nodes

Define the truss geometry with 5 nodes:
model.add_node(1, 0, 0)  # Left support
model.add_node(2, 3, 0)  # Right support
model.add_node(3, 5, 3)  # Right top
model.add_node(4, 3, 3)  # Center top
model.add_node(5, 0, 3)  # Left top
This creates a trapezoidal truss with a 3m height.
5

Add truss members

Connect nodes with truss elements:
# Diagonal and vertical members (section1)
model.add_truss(1, 2, 1, "section1")  # Bottom right diagonal
model.add_truss(2, 3, 2, "section1")  # Right vertical
model.add_truss(3, 4, 3, "section1")  # Top right diagonal
model.add_truss(4, 4, 5, "section1")  # Top horizontal
model.add_truss(5, 5, 1, "section1")  # Left vertical

# Horizontal members (section2) - heavier section
model.add_truss(6, 2, 4, "section2")  # Center diagonal
model.add_truss(7, 1, 4, "section2")  # Left diagonal
model.add_truss(8, 2, 5, "section2")  # Bottom left diagonal
6

Apply boundary conditions

Add support restraints:
# Fixed support at node 1
model.add_restraint(1, ux=True, uy=True, rz=True)

# Roller support at node 2 (horizontal movement allowed)
model.add_restraint(2, ux=False, uy=True, rz=True)
7

Apply loads

Add concentrated loads at the top nodes:
model.add_load_pattern("Live Load")

# Vertical load at node 3
model.add_point_load(3, "Live Load", fx=0, fy=-6, mz=0)  # 6 tonf downward
8

Solve the model

Run the analysis:
model.solve()
9

Extract results

Get the results and display member forces:
results = model.get_results("Live Load")

# Print axial forces for each member
for i in range(1, 9):
    axial_force = results.get_member_axial_force(i)
    # Axial force is constant along truss members
    force_value = axial_force[0] if len(axial_force) > 0 else 0
    print(f"Member {i}: Axial force = {force_value:.2f} tonf")
    
# Get node displacements
for node_id in [3, 4, 5]:
    disp = results.get_node_displacements(node_id)
    print(f"Node {node_id}: ux={disp[0]:.4f} m, uy={disp[1]:.4f} m")
10

Visualize

View the deformed shape and member forces:
model.show()
The viewer will display:
  • Undeformed geometry
  • Deformed shape with displacement magnification
  • Axial force diagram (tension and compression)
  • Support reactions

Complete Code

Here’s the complete truss analysis example:
from milcapy import SystemModel

# Create model
model = SystemModel()

# Material
model.add_material("steel", modulus_elasticity=2.1e6, poisson_ratio=0.3)

# Sections
model.add_generic_section("section1", "steel", area=0.12, inertia=0.001, k_factor=1.0)
model.add_generic_section("section2", "steel", area=0.16, inertia=0.001, k_factor=1.0)

# Nodes
model.add_node(1, 0, 0)
model.add_node(2, 3, 0)
model.add_node(3, 5, 3)
model.add_node(4, 3, 3)
model.add_node(5, 0, 3)

# Truss members
model.add_truss(1, 2, 1, "section1")
model.add_truss(2, 3, 2, "section1")
model.add_truss(3, 4, 3, "section1")
model.add_truss(4, 4, 5, "section1")
model.add_truss(5, 5, 1, "section1")
model.add_truss(6, 2, 4, "section2")
model.add_truss(7, 1, 4, "section2")
model.add_truss(8, 2, 5, "section2")

# Supports
model.add_restraint(1, ux=True, uy=True, rz=True)
model.add_restraint(2, ux=False, uy=True, rz=True)

# Loads
model.add_load_pattern("Live Load")
model.add_point_load(3, "Live Load", fx=0, fy=-6, mz=0)

# Solve
model.solve()

# Results
results = model.get_results("Live Load")
for i in range(1, 9):
    axial = results.get_member_axial_force(i)
    print(f"Member {i}: {axial[0]:.2f} tonf")

# Visualize
model.show()

Understanding Truss Behavior

  • Positive axial force = Tension (member is being pulled)
  • Negative axial force = Compression (member is being pushed)
Truss elements in milcapy make these assumptions:
  • Members carry only axial forces (no bending or shear)
  • Loads are applied only at joints (nodes)
  • Members are connected with frictionless pins
  • Member weight is negligible or applied at nodes
Use add_truss() when:
  • Members are slender and connected at joints
  • Loads are applied at nodes only
  • You only care about axial forces
Use add_member() (beams) when:
  • Members have bending moments
  • Distributed loads are applied along members
  • Joint connections are rigid (moment-resisting)

Next Steps

Portal Frame

Learn how to model frame structures with beams

Membrane Analysis

Explore 2D plane stress elements

API Reference

View the SystemModel API documentation

Load Patterns

Learn about different loading types

Build docs developers (and LLMs) love