Profile
Back to NewsBack
GitHub Trending 5 min
Reader Mode
JorgeDeLosSantos/nusa: A Python library for structural analysis using the finite element method

JorgeDeLosSantos/nusa: A Python library for structural analysis using the finite element method

8 hours ago

NuSA

A Python library for structural analysis using the finite element method, designed for academic purposes.

!PyPI !Python !License

Releases

  • 0.1.0 (16/11/2016)
  • 0.2.0 (14/07/2019)
  • 0.3.0a1 First alpha release (20/09/2026)
  • 0.3.0b1 Beta release (21/09/2026)
  • 0.3.0rc1 Release candidate (22/09/2026)
  • 0.3.0rc2 Release candidate (22/09/2026)
  • 0.3.0 Stable release (23/09/2026)
  • 0.4.0 Stable release (06/10/2026)
  • 0.5.0 Stable release (12/10/2026)

Requirements

NuSA requires Python 3.10 or newer and installs NumPy, Matplotlib, tabulate, and meshio as Python dependencies.

The nusa.mesh helpers can read triangular meshes immediately after installing NuSA. Generating new meshes from geometry additionally requires the external Gmsh executable to be installed and available on PATH.

Installation

Install the current PyPI release:

pip install nusa

Mesh-file support through meshio is included in the default installation. The historical nusa[mesh] extra remains accepted as a compatibility alias, but is no longer required.

To generate meshes, install Gmsh separately and verify that NuSA can discover it:

gmsh --version

Install the current development branch directly from GitHub:

pip install "nusa @ git+https://github.com/JorgeDeLosSantos/nusa.git@develop"

For local development:

git clone https://github.com/JorgeDeLosSantos/nusa.git
cd nusa
git checkout develop
python -m pip install -e ".[test]"
python -m pytest

Analysis workflow

NuSA 0.4 separates finite-element problem definition from solved state:

from nusa import LinearStaticAnalysis, solve

result = solve(model)

Equivalent explicit form:

result = LinearStaticAnalysis().solve(model)

Model contains topology, loads, and prescribed displacements. A solve returns an independent StaticResult snapshot containing displacements, reactions, nodal forces, and canonical element results.

Physical properties in NuSA 0.5

NuSA 0.5 uses reusable Material and Section objects for Bar, Truss, and Beam, while LinearTriangle takes a Material and explicit thickness. The examples below require NuSA 0.5.0 or newer (or the current develop branch). If upgrading from 0.4.0, consult the 0.4 → 0.5 migration guide.

Supported element types

  • Spring
  • Bar
  • Truss
  • Beam
  • Linear triangle (plane stress formulation)

Mini-Demos

Linear Triangle Element

import numpy as np

from nusa import LinearTriangle, LinearTriangleModel, Material, Node, plot_model import nusa.mesh as nmsh

md = nmsh.Modeler() a = md.add_rectangle((0,0),(1,1), esize=0.1) b = md.add_circle((0.5,0.5), 0.1, esize=0.05) md.subtract_surfaces(a,b) nc, ec = md.generate_mesh() x,y = nc[:,0], nc[:,1]

nodes = [] elements = []

for k,nd in enumerate(nc): cn = Node((x[k],y[k])) nodes.append(cn) material = Material(E=200e9, nu=0.3)

for elm in ec: i, j, k = int(elm[0]), int(elm[1]), int(elm[2]) ni, nj, nk = nodes[i], nodes[j], nodes[k] ce = LinearTriangle((ni, nj, nk), material=material, thickness=0.1) elements.append(ce)

model = LinearTriangleModel() for node in nodes: model.add_node(node) for elm in elements: model.add_element(elm)

Boundary conditions and loads

minx, maxx = min(x), max(x) miny, maxy = min(y), max(y)

for node in nodes: if np.isclose(node.x, minx): model.add_constraint(node, ux=0, uy=0) if np.isclose(node.x, maxx): model.add_force(node, (10e3,0))

plot_model(model) result = model.solve() result.plot_nodal_field("von_mises_stress")

Spring element

Example 01. For the spring assemblage with arbitrarily numbered nodes shown in the figure, obtain (a) the displacements of nodes 3 and 4, (b) the reaction forces at nodes 1 and 2, and (c) the forces in each spring. A force of 5000 lb is applied at node 4 in the x direction. The spring constants are given in the figure. Nodes 1 and 2 are fixed.

# NuSA Demo
from nusa import Node, Spring, SpringModel
    
def test1():
    """
    Logan, D. (2007). A first course in the finite element analysis.
    Example 2.1, pp. 42.
    """
    P = 5000.0

# Model m1 = SpringModel("2D Model")

# Nodes n1 = Node((0,0)) n2 = Node((0,0)) n3 = Node((0,0)) n4 = Node((0,0))

# Elements e1 = Spring((n1,n3),1000.0) e2 = Spring((n3,n4),2000.0) e3 = Spring((n4,n2),3000.0)

# Adding elements and nodes to the model for nd in (n1,n2,n3,n4): m1.add_node(nd) for el in (e1,e2,e3): m1.add_element(el)

m1.add_force(n4, (P,)) m1.add_constraint(n1, ux=0) m1.add_constraint(n2, ux=0) result = m1.solve() return result

if __name__ == '__main__': test1()

Beam element

Example 02. For the beam and loading shown, determine the deflection at point C. Use E = 29 x 106 psi.

"""
Beer & Johnston. (2012) Mechanics of materials. 
Problem 9.13 , pp. 568.
"""
from nusa import Beam, BeamModel, Material, Node, Section

Input data

E = 29e6 I = 291 # W14x30 P = 35e3 material = Material(E=E) section = Section(I=I) L1 = 5*12 # in L2 = 10*12 #in

Model

m1 = BeamModel("Beam Model")

Nodes

n1 = Node((0,0)) n2 = Node((L1,0)) n3 = Node((L1+L2,0))

Elements

e1 = Beam((n1,n2), material=material, section=section) e2 = Beam((n2,n3), material=material, section=section)

Add elements and nodes

for nd in (n1,n2,n3): m1.add_node(nd) for el in (e1,e2): m1.add_element(el) m1.add_force(n2, (-P,)) m1.add_constraint(n1, uy=0) # pin m1.add_constraint(n3, uy=0) # roller result = m1.solve()

Displacement at C point

print(result.displacement(n2)["uy"])

GUIs based on NuSA

Documentation and Examples

You can view the online documentation at the following link: https://jorgedelossantos.github.io/nusa/.

The repository also contains historical Jupyter notebooks under docs/nusa-info/. Some of those notebooks predate the 0.3.0 API and are retained as archival material; the executable scripts under examples/ and the current Sphinx documentation are the recommended references for the current API.

About...

Developer: Pedro Jorge De Los Santos E-mail: [email protected]

Chat with me