Skip to main content

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 (17/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: delossantosmfq@gmail.com

Metadata

Release files for nusa 0.5.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for nusa 0.5.0
File Size Uploaded Provenance Actions
nusa-0.5.0.tar.gz 60.6 kB With provenance Details for nusa-0.5.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for nusa 0.5.0
File Interpreter ABI Platform Actions
nusa-0.5.0-py3-none-any.whl Python 3 none any Details for nusa-0.5.0-py3-none-any.whl

Total release size: 95.2 kB

Release files / nusa-0.5.0.tar.gz

Download URL nusa-0.5.0.tar.gz
Size 60.6 kB
Tags Source
SHA-256 checksum
How to use checksums
280f0fc93bdf9932c679afa944bd4c458a75b37dca1e32cfafba3074aa894e26
BLAKE2b-256 checksum
How to use checksums
7bd8d00ff42260104ffb013cfdb36383e6570f1617209f1b52b53df7a6f6969a
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 17, 2026.

Transparency log

Release files / nusa-0.5.0-py3-none-any.whl

Download URL nusa-0.5.0-py3-none-any.whl
Size 34.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
2ff7a3a873268cf4e6943631703572aaed85c047d5c1bfad859d3ef93afac97a
BLAKE2b-256 checksum
How to use checksums
9e1b1f9bd39ef8174d079cf913235fb42adf5dc2ebb51100204f764826f6cf7e
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 17, 2026.

Transparency log

Security for nusa 0.5.0

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.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for nusa-0.5.0.tar.gz

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 17, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page