NuSA
A Python library for structural analysis using the finite element method, designed for academic purposes.
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)
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.
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, 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)
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), 200e9, 0.3, 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, Node
# Input data
E = 29e6
I = 291 # W14x30
P = 35e3
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),E,I)
e2 = Beam((n2,n3),E,I)
# 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: delossantosmfq@gmail.com
Metadata
Release files for nusa 0.4.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| nusa-0.4.0.tar.gz | 56.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| nusa-0.4.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 88.4 kB
Release files / nusa-0.4.0.tar.gz
| Download URL | nusa-0.4.0.tar.gz |
|---|---|
| Size | 56.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
6eb856989a1e38772c4af462fcf012812950f5a573b932aad6c8af2579116bfb
|
|
BLAKE2b-256 checksum How to use checksums |
27239a15064474900a4ef5e75497172e866440cf37d52874b82e69b3191742f4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 7, 2026.
Transparency logRelease files / nusa-0.4.0-py3-none-any.whl
| Download URL | nusa-0.4.0-py3-none-any.whl |
|---|---|
| Size | 32.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
501cb7b42eae6cf828e4e68a78b4452f0fcac54254eb8ee0b5ac2bc522c4dcc7
|
|
BLAKE2b-256 checksum How to use checksums |
f67ebf40f9b780b59e7a77d94b93c1116d8f9958d35b51bafcf978d3cf6ad85d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 7, 2026.
Transparency log