Skip to main content

Overview

After solving your model, milcapy stores all results in Results objects that you can query to extract displacements, reactions, internal forces, stresses, and strains.

Getting Results

Retrieve the Results object for a specific load pattern:
model.solve()

# Get results for a specific load pattern
results = model.get_results("Dead Load")

Model-Level Results

Get global displacement and reaction vectors for the entire model:
# Global displacement vector (length = 3 * number_of_nodes)
displacements = results.get_model_displacements()

# Global reaction vector (length = 3 * number_of_nodes)
reactions = results.get_model_reactions()
The global vectors are organized as [Ux1, Uy1, Rz1, Ux2, Uy2, Rz2, ...] where subscripts indicate node numbers.

Node Results

Extract displacements and reactions at individual nodes:
# Get displacements for node 5
node_disp = results.get_node_displacements(node_id=5)
# Returns: np.array([Ux, Uy, Rz])

# Get reactions for node 1
node_react = results.get_node_reactions(node_id=1)
# Returns: np.array([Rx, Ry, Mz])

Example: Node Results

from milcapy import SystemModel

model = SystemModel()
# ... define model ...
model.solve()

results = model.get_results("Dead Load")

# Check displacement at node 3
disp = results.get_node_displacements(3)
print(f"Node 3 - Ux: {disp[0]:.6f}, Uy: {disp[1]:.6f}, Rz: {disp[2]:.6f}")

# Check reactions at support (node 1)
react = results.get_node_reactions(1)
print(f"Node 1 - Rx: {react[0]:.2f}, Ry: {react[1]:.2f}, Mz: {react[2]:.2f}")

Member Results

For frame and beam elements, extract detailed results including forces and diagrams:

End Forces and Displacements

# Get member end displacements [Uxi, Uyi, Rzi, Uxj, Uyj, Rzj]
member_disp = results.get_member_displacements(member_id=2)

# Get member end forces [Ni, Vi, Mi, Nj, Vj, Mj]
member_forces = results.get_member_internal_forces(member_id=2)

Force Diagrams Along Member

# Get axial force diagram
N = results.get_member_axial_force(member_id=2)

# Get shear force diagram
V = results.get_member_shear_force(member_id=2)

# Get bending moment diagram
M = results.get_member_bending_moment(member_id=2)

# Get x-coordinates for diagrams
x_vals = results.get_member_x_val(member_id=2)

Displacement Diagrams

# Get deflection (transverse displacement)
deflection = results.get_member_deflection(member_id=2)

# Get slope (rotation)
slope = results.get_member_slope(member_id=2)

# Get axial displacement
axial_disp = results.get_member_axial_displacement(member_id=2)

Complete Member Results Dictionary

# Get all results for a member
member_results = results.get_results_member(member_id=2)
# Returns a dict with keys: 'displacements', 'internal_forces', 
# 'axial_forces', 'shear_forces', 'bending_moments', 
# 'deflections', 'slopes', 'axial_displacements', 'x_val'

Truss Results

For truss elements:
# Get truss end displacements [Uxi, Uxj]
truss_disp = results.get_truss_displacements(truss_id=10)

# Get truss internal forces [Ni, Nj]
truss_forces = results.get_truss_internal_forces(truss_id=10)

# Get axial force diagram
truss_axial = results.get_truss_axial_force(truss_id=10)

# Get axial displacement diagram
truss_axial_disp = results.get_truss_axial_displacement(truss_id=10)

# Get all truss results
truss_results = results.get_results_truss(truss_id=10)

Finite Element Results (Membranes)

CST Elements (Constant Strain Triangle)

# Get nodal displacements [Ux1, Uy1, Ux2, Uy2, Ux3, Uy3]
cst_disp = results.get_cst_displacements(cst_id=15)

# Get strains [εx, εy, γxy]
cst_strains = results.get_cst_strains(cst_id=15)

# Get stresses [σx, σy, τxy]
cst_stresses = results.get_cst_stresses(cst_id=15)

Membrane Q6/Q6I Elements

# For Q6 elements (3 DOF per node)
q6_disp = results.get_membrane_q3dof_displacements(membrane_q3dof_id=20)
# Returns: [Ux1, Uy1, Rz1, Ux2, Uy2, Rz2, Ux3, Uy3, Rz3, Ux4, Uy4, Rz4]

# For Q6I/Q4/Q8 elements (2 DOF per node)
q6i_disp = results.get_membrane_q2dof_displacements(membrane_q2dof_id=21)
# Returns: [Ux1, Uy1, Ux2, Uy2, Ux3, Uy3, Ux4, Uy4]

Exporting Results to DataFrames

Convert results to pandas DataFrames for easy export and analysis:
import pandas as pd

model.solve()
results = model.get_results("Dead Load")

# Get node and element results as DataFrames
df_nodes, df_elements = results.get_dataframes()

# Node DataFrame columns:
# ['node_id', 'Ux', 'Uy', 'Rz', 'ReacFx', 'ReacFy', 'ReacMz']
print(df_nodes.head())

# Element DataFrame columns:
# ['ele_id', 'Uxi', 'Uyi', 'Rzi', 'Uxj', 'Uyj', 'Rzj',
#  'Ni', 'Vi', 'Mi', 'Nj', 'Vj', 'Mj']
print(df_elements.head())

# Export to CSV
df_nodes.to_csv("node_results.csv", index=False)
df_elements.to_csv("element_results.csv", index=False)

Complete Example

from milcapy import SystemModel, BeamTheoriesType
import numpy as np

model = SystemModel()

# Build model
model.add_material("steel", modulus_elasticity=2e8, poisson_ratio=0.3)
model.add_rectangular_section("beam", "steel", base=0.2, height=0.4)

model.add_node(1, 0, 0)
model.add_node(2, 5, 0)
model.add_node(3, 10, 0)

model.add_member(1, 1, 2, "beam")
model.add_member(2, 2, 3, "beam")

model.add_restraint(1, ux=True, uy=True, rz=True)
model.add_restraint(3, ux=False, uy=True, rz=False)

model.add_load_pattern("Load")
model.add_point_load(2, "Load", fy=-50)
model.add_distributed_load(1, "Load", load_start=-10, load_end=-10)

# Solve and extract results
model.solve()
results = model.get_results("Load")

# Node results
print("\n=== NODE RESULTS ===")
for node_id in [1, 2, 3]:
    disp = results.get_node_displacements(node_id)
    react = results.get_node_reactions(node_id)
    print(f"Node {node_id}:")
    print(f"  Displacement: Ux={disp[0]:.6f}, Uy={disp[1]:.6f}, Rz={disp[2]:.6f}")
    print(f"  Reactions: Rx={react[0]:.2f}, Ry={react[1]:.2f}, Mz={react[2]:.2f}")

# Member results
print("\n=== MEMBER RESULTS ===")
for member_id in [1, 2]:
    forces = results.get_member_internal_forces(member_id)
    print(f"Member {member_id}:")
    print(f"  Node i: N={forces[0]:.2f}, V={forces[1]:.2f}, M={forces[2]:.2f}")
    print(f"  Node j: N={forces[3]:.2f}, V={forces[4]:.2f}, M={forces[5]:.2f}")
    
    # Max moment
    M_diagram = results.get_member_bending_moment(member_id)
    M_max = np.max(np.abs(M_diagram))
    print(f"  Max moment: {M_max:.2f}")

Results Object Structure

The Results class stores data in the following structure:
results.model = {
    "displacements": np.ndarray,  # Global displacement vector
    "reactions": np.ndarray       # Global reaction vector
}

results.nodes = {
    node_id: {
        "displacements": np.ndarray,  # [Ux, Uy, Rz]
        "reactions": np.ndarray       # [Rx, Ry, Mz]
    }
}

results.members = {
    member_id: {
        "displacements": np.ndarray,        # [Uxi, Uyi, Rzi, Uxj, Uyj, Rzj]
        "internal_forces": np.ndarray,      # [Ni, Vi, Mi, Nj, Vj, Mj]
        "x_val": np.ndarray,                # x-coordinates
        "axial_forces": np.ndarray,         # N(x)
        "shear_forces": np.ndarray,         # V(x)
        "bending_moments": np.ndarray,      # M(x)
        "deflections": np.ndarray,          # y(x)
        "slopes": np.ndarray,               # θ(x)
        "axial_displacements": np.ndarray   # u(x)
    }
}

results.trusses = {
    truss_id: {
        "displacements": np.ndarray,
        "internal_forces": np.ndarray,
        "axial_forces": np.ndarray,
        "axial_displacements": np.ndarray
    }
}

results.CST = {
    cst_id: {
        "displacements": np.ndarray,
        "strains": np.ndarray,
        "stresses": np.ndarray
    }
}

Next Steps

Visualization

Visualize results with interactive plots

Model Building

Learn more about building structural models

Build docs developers (and LLMs) love