Skip to content

ch3_api_reference.md

nathan-carmichael edited this page Mar 11, 2026 · 1 revision

Chapter 3: API Reference

This chapter documents every public class, method, and function in the toolkit. Private and internal methods are omitted; consult the source code for implementation details.

All indices (node IDs, element IDs, DOF numbers) are 0-based.


StructureGeometry

Stores topology, material properties, boundary conditions, and DOF mappings. Properties that depend on thickness or node positions are kept in sync through dedicated setter methods.

Constructor

from feaopt import StructureGeometry

geom = StructureGeometry(nodes, connectivity, props, constraints)
Argument Type / Shape Description
nodes (N, 2) array Node coordinates [x, y] in metres.
connectivity (M, 2) int array Element connectivity [start, end], 0-based.
props dict Material/section properties (see below).
constraints (C, 3) array or list of Constraint Boundary conditions [node_id, dof, value].

The props dict accepts the following keys. Scalar values are automatically expanded to (M,) arrays.

Key Units Required Description
'E' Pa Yes Elastic modulus.
'thickness' m Yes Element thickness.
'width' m Yes Out-of-plane width.
'ultimate' Pa No Ultimate tensile strength (default 0).
'rho' kg/m³ No Density (default 7850).
'is_rigid' bool No Rigid element flag (default False).

Mutators

geom.update_thickness(new_t)          # (M,) thickness array (m)
geom.update_node_positions(new_xy)    # (N, 2) node coordinates (m)

Both methods automatically recompute all dependent quantities (A, I, L, θ₀).

Key Query Methods

n1, n2 = geom.get_member_nodes(i)    # node IDs for element i
dofs   = geom.get_member_dof(i)      # (6,) global DOF indices
xy     = geom.get_node_coords(i)     # (2,) coordinates
dofs   = geom.get_node_dof(i)        # (3,) global DOF indices
tf     = geom.is_dof_constrained(d)  # True if DOF is fixed
mass   = geom.get_total_mass()       # total structure mass (kg)

Key Properties

Property Shape Description
nodes (N, 2) Node coordinates.
connectivity (M, 2) Element connectivity.
num_nodes int Number of nodes.
num_members int Number of elements.
num_dof_total int Total DOFs (3 × N).
num_dof_free int Number of unconstrained DOFs.
E, thickness, width, A, I (M,) Material and section properties.
L, theta0 (M,) Element lengths and initial orientations.
is_rigid (M,) bool Rigid element flags.
dof_map DOFMap Contains free_dof and fixed_dof index arrays.
assembly_map AssemblyMap Contains member_dof array of shape (M, 6).

ElementMatrices

Manages pre-computed stiffness and transformation matrices for every element. All matrices are stored as (M, 6, 6) NumPy arrays and rebuilt vectorised.

Constructor

from feaopt.element_matrices import ElementMatrices

em = ElementMatrices(geometry)

Computes all local, transformation, and global matrices from the initial geometry.

Key Methods

# Retrieval
k  = em.get_local_matrix(i)          # (6, 6) local stiffness
K  = em.get_global_matrix(i)         # (6, 6) global stiffness
T  = em.get_transformation(i)        # (6, 6) transformation matrix
th = em.get_current_angle(i)         # current orientation (rad)
L  = em.get_current_length(i)        # current length (m)

# Geometry updates (Newton-Raphson)
em.update_member_geometry(i, new_L, new_theta)
em.update_all_member_geometry(lengths, thetas)    # vectorised batch update

# Assembly
K_sparse = em.assemble_global_stiffness_matrix(geometry)  # returns scipy.sparse.csr_matrix

# Reset
em.reset_to_initial_configuration()

# Rigid stiffness
em.set_rigid_stiffness_factor(1e4)

# Vectorised force computation
f_int = em.compute_internal_forces_vectorized(u, geometry)
f_local, f_global = em.compute_member_forces_vectorized(u, geometry)

AnalysisState

Mutable container for displacement, force, and residual vectors during analysis.

Constructor

from feaopt.analysis_state import AnalysisState

state = AnalysisState(geometry)     # zero-initialised

Key Properties

Property Shape Description
u (D,) Full displacement vector.
f_external (D,) External force vector.
f_internal (D,) Internal (restoring) force vector.
u_free (F,) Free-DOF displacements.
residual (F,) f_ext − f_int on free DOFs.
residual_norm float ‖residual‖.
member_forces_local (M, 6) Element end forces (local).
member_forces_global (M, 6) Element end forces (global).
member_displ_local (M, 6) Element displacements (local).
member_displ_global (M, 6) Element displacements (global).

Key Methods

state.reset()                                     # zero everything
state.copy_from(other_state)                      # deep copy
state.update_displacements(u_free)                # set free DOFs, map to full
state.compute_internal_forces(elem_matrices)      # assemble f_int from K*u
state.compute_residual()                          # R = f_ext - f_int
state.apply_increment(delta_u)                    # u += delta_u
state.extract_member_displacements(elem_matrices) # populate member_displ_*
state.compute_member_forces(elem_matrices)        # populate member_forces_*
d = state.get_max_displacement()                  # max translational displacement
state.display_summary()                           # print summary to console

FEAAnalysis

Main analysis controller.

Constructor

from feaopt import FEAAnalysis

analysis = FEAAnalysis(geometry)
analysis = FEAAnalysis(geometry, verbose=True, max_iterations=1000)

Solver Settings

Property Type Default Description
verbose bool True Print iteration info.
max_iterations int 1000 Max N-R iterations per step.
force_tolerance float 10⁻² Normalised force residual.
displacement_tolerance float 10⁻⁶ Normalised displacement increment.
energy_tolerance float 10⁻⁶ |Rᵀ Δu|.

Analysis Methods

results = analysis.run_linear_analysis(load_case)
results = analysis.solve_large_deflection(load_case, num_steps)
stress  = analysis.perform_stress_analysis()

Results Dicts

The results dict returned by both analysis methods contains:

Key Description
'displacements' (D,) full displacement vector.
'displacements_free' (F,) free-DOF displacements.
'max_displacement' Maximum translational displacement magnitude.
'external_forces' (D,) applied force vector.
'nodes_deformed' (N, 2) deformed node coordinates.

The nonlinear results dict additionally contains:

Key Description
'member_rotations' (M,) element rotation increments.
'load_history' List of load factors.
'displacement_history' (num_steps,) max displacement at each step.
'state_history' List of converged AnalysisState snapshots.

The stress dict from perform_stress_analysis contains:

Key Description
'stresses''axial' (M, 2) axial stress at each node (Pa).
'stresses''bending' (M, 2) bending stress (Pa).
'stresses''shear' (M, 2) shear stress (Pa).
'stresses''von_mises' (M, 2) von Mises stress (Pa).
'stresses''max_stress' (M,) max von Mises per element (Pa).
'stresses''critical_member' Element index with highest stress.
'FOS''member_FOS' (M,) factor of safety per element.
'FOS''min_FOS' Global minimum FOS.
'FOS''critical_member' Element index with lowest FOS.

Utility Methods

analysis.reset_analysis()
coords = analysis.get_deformed_coordinates(scale=1.0)   # (N, 2) array

LoadCase

Manages nodal loads and load-factor scaling.

from feaopt import LoadCase

lc = LoadCase(geometry)
lc.add_nodal_load(node_id, fx, fy, mz, 'description')
lc.set_load_factor(1.0)
lc.clear_loads()

P  = lc.get_scaled_load()              # (D,) current load vector
Pf = lc.get_free_dof_loads()           # (F,) free-DOF loads
lc.apply_to_state(state)               # write loads into an AnalysisState

factors = lc.generate_load_steps(10, 'linear')
lc.display_loads()

Key Properties

Property Type Description
P_ref (D,) array Reference (unscaled) load vector.
P_current (D,) array Scaled load vector (P_ref × λ).
lambda_ float Current load factor.
load_records list of LoadRecord All defined loads.

StructurePlotter

Visualisation utilities. Elements are drawn as filled rectangles matching their physical thickness using matplotlib's PatchCollection and PolyCollection for efficient batch rendering.

from feaopt import StructurePlotter

plotter = StructurePlotter(geometry)
plotter = StructurePlotter(geometry, analysis)

Drawing Methods

All drawing methods require a matplotlib Axes object as the first argument.

import matplotlib.pyplot as plt

fig, ax = plt.subplots()

# Structure drawing
plotter.draw_structure(ax)                                    # undeformed, default colour
plotter.draw_structure(ax, nodes=deformed, color=(0.8, 0.2, 0.2))
sm = plotter.draw_stress(ax, stress_values=stress_mpa)        # returns ScalarMappable
plt.colorbar(sm, ax=ax)

# Supports and loads
plotter.plot_supports(ax)
plotter.plot_loads(ax, load_case, scale=None)

Module-Level Functions

The structure_plotter module also exposes two standalone batch drawing functions:

from feaopt.structure_plotter import draw_beams_batch, draw_beams_stress

draw_beams_batch(ax, nodes, connectivity, thickness, color)
sm = draw_beams_stress(ax, nodes, connectivity, thickness, stress_values)

optimize_thickness

Standalone function implementing stress-ratio thickness optimisation.

from feaopt import optimize_thickness

geometry, results = optimize_thickness(geometry, analysis, load_case, options)

In-place mutation: The geometry object is modified in place. The returned geometry is the same object. If you need to preserve the original, create a deep copy before calling this function.

Options

Key Type Default Description
'alpha' float 0.4 Stress-ratio exponent.
'max_iterations' int 100 Iteration cap.
'convergence_tol' float 0.01 Max relative Δt for convergence.
'move_limit' float 0.2 Per-iteration change fraction.
't_min' float 0.001 Minimum thickness (m).
't_max' float 0.020 Maximum thickness (m).
'safety_factor' float 1.5 Divisor on σ_ult.
'use_nonlinear' bool False Use large-deflection analysis.
'num_load_steps' int 2 Load steps for nonlinear.
'verbose' bool True Print progress table.

Results Dict

Key Description
'converged' True if converged within iteration limit.
'iterations' Number of iterations performed.
'thickness_initial' (M,) starting thicknesses.
'thickness_final' (M,) final thicknesses.
'thickness_history' (M, iters) thickness at each iteration.
'mass_initial' Starting mass (kg).
'mass_final' Final mass (kg).
'mass_reduction' Percentage mass reduction.
'mass_history' (iters,) mass at each iteration.
'final_stress_results' Stress dict from final analysis.
'stress_uniformity' Coefficient of variation of element stresses.

subdivide_truss

from feaopt import subdivide_truss

new_nodes, new_conn, member_map = subdivide_truss(nodes, conn, num_sub)

Replaces every member with a chain of num_sub smaller elements. Original joint nodes are preserved; intermediate nodes are inserted at uniform spacing along each member.

Argument Type / Shape Description
nodes (N, 2) array Original node coordinates.
conn (M, 2) int array Original connectivity, 0-based.
num_sub int ≥ 1 Sub-elements per member.
Return Type / Shape Description
new_nodes (N2, 2) array Expanded node array.
new_conn (M2, 2) int array Expanded connectivity.
member_map (M2,) int array Original member index for each sub-element.

Importers

from feaopt import import_csv_curve, import_igs_curve

result = import_csv_curve(filename, num_elements=250, scale=1.0,
                          flip=False, plot=True, verbose=True)

result = import_igs_curve(filename, num_elements=250, scale=1.0,
                          samples_per_entity=300, flip=False,
                          plot=True, verbose=True)

Both return a dict with keys: 'nodes', 'connectivity', 'num_nodes', 'num_elements', 'arc_length', 'raw_points', 'start_tangent', 'end_tangent', 'start_angle', 'end_angle'.

The IGES importer additionally returns 'raw_entities'.

Supported IGES Entities

Type Name Notes
110 Line Straight segment.
100 Circular Arc CCW arc in the XY plane.
104 Conic Arc Simplified as a straight line between endpoints.
106 Copious Data Point sequences (flags 1, 2, 3).
112 Parametric Spline Cubic polynomial segments.
126 B-Spline Rational B-spline (NURBS) — most common for SolidWorks exports.

Entity 124 (Transformation Matrix) is not applied. Control points are read as 2-D (X, Y) in the entity's local coordinate system, matching the original MATLAB behaviour.


export_profile

from feaopt import export_profile

profile = export_profile(geometry, options)

Rasterises the structure into a binary image, extracts boundary contours, fits smoothing splines, and exports each loop as a SolidWorks-compatible text file. See Chapter 5: Profile Export Pipeline for a detailed description of the algorithm.

Options

Key Type Default Description
'num_spline_points' int 1000 Points per loop.
'smoothing' float 0.9999999 Spline smoothing factor.
'scale_to_mm' float 1000 Coordinate multiplier for export.
'resolution' float 50000 Pixels per metre.
'min_thickness_frac' float 0 Filter thin elements (0 = no filter).
'export_filename' str None Base name for output files.
'plot' bool True Show diagnostic figure.
'verbose' bool True Print summary.

Performance note: For small geometries, increase resolution to get a usable image size. For large geometries or thick elements, the morphological closing disk radius is capped to prevent excessive computation times.

Return Value

The returned profile dict contains:

Key Description
'loops' List of loop dicts, each with 'x', 'y', 'xs', 'ys', 'is_hole', 'arc_length'.
'num_loops' Number of boundary loops found.
'image' (H, W) bool array — the rasterised binary image.
'export_files' List of file paths written.