Some checks failed
CI / lint (pull_request) Has been cancelled
CI / type (pull_request) Has been cancelled
CI / test-headless (macos-latest, 3.10) (pull_request) Has been cancelled
CI / test-headless (macos-latest, 3.11) (pull_request) Has been cancelled
CI / test-headless (macos-latest, 3.12) (pull_request) Has been cancelled
CI / test-headless (ubuntu-latest, 3.10) (pull_request) Has been cancelled
CI / test-headless (ubuntu-latest, 3.11) (pull_request) Has been cancelled
CI / test-headless (ubuntu-latest, 3.12) (pull_request) Has been cancelled
CI / test-headless (windows-latest, 3.10) (pull_request) Has been cancelled
CI / test-headless (windows-latest, 3.11) (pull_request) Has been cancelled
CI / test-headless (windows-latest, 3.12) (pull_request) Has been cancelled
CI / test-gui (pull_request) Has been cancelled
CI / test-integration (macos-latest) (pull_request) Has been cancelled
CI / test-integration (ubuntu-latest) (pull_request) Has been cancelled
CI / test-integration (windows-latest) (pull_request) Has been cancelled
Auto-fixes (UP037, UP038, F401, I001, SIM105, RUF100) plus hand-fixes: drop the now-unused `Union` imports, annotate mutable class attributes with ClassVar, raise ValidationError instead of blind Exception in the zero-length test, delete two dead locals, and bind the per-iteration grid-builder closures to their loop variables (B023).
76 lines
2.4 KiB
Python
76 lines
2.4 KiB
Python
"""Regression test: pure-truss models with ndf=3 must refuse to solve.
|
|
|
|
OpenSees silently returns the load vector as 'displacement' when the
|
|
stiffness matrix is singular on rotational DOFs. The runner now
|
|
pre-validates DOF coverage and raises a descriptive error instead.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import pytest
|
|
|
|
pytest.importorskip("openseespy")
|
|
|
|
from otko.core import (
|
|
ElasticUniaxial,
|
|
LinearTimeSeries,
|
|
NodalLoad,
|
|
Node,
|
|
PlainLoadPattern,
|
|
Project,
|
|
StaticCase,
|
|
TrussElement,
|
|
)
|
|
from otko.services.opensees_runner import OpenSeesRunner
|
|
|
|
pytestmark = pytest.mark.slow
|
|
|
|
|
|
def _make_truss_project(ndf: int) -> Project:
|
|
return Project(
|
|
ndm=2,
|
|
ndf=ndf,
|
|
nodes=[
|
|
Node(id=1, coords=(0, 0, 0), restraint=(True, True, False, False, False, False)),
|
|
Node(id=2, coords=(3, 0, 0), restraint=(True, True, False, False, False, False)),
|
|
Node(id=3, coords=(1.5, 2, 0)),
|
|
],
|
|
materials=[ElasticUniaxial(id=1, E=200e9)],
|
|
elements=[
|
|
TrussElement(id=1, nodes=(1, 3), area=1e-3, material_id=1),
|
|
TrussElement(id=2, nodes=(2, 3), area=1e-3, material_id=1),
|
|
],
|
|
time_series=[LinearTimeSeries(id=1, name="R")],
|
|
load_patterns=[
|
|
PlainLoadPattern(
|
|
id=1,
|
|
time_series_id=1,
|
|
nodal_loads=[NodalLoad(node_id=3, forces=(1e3, -5e3, 0, 0, 0, 0))],
|
|
)
|
|
],
|
|
analyses=[StaticCase(id=1, name="Static", pattern_ids=[1], n_steps=1)],
|
|
)
|
|
|
|
|
|
def test_truss_with_ndf_3_is_rejected_clearly() -> None:
|
|
"""A pure-truss project declared with ndf=3 must fail before the solve."""
|
|
proj = _make_truss_project(ndf=3)
|
|
with pytest.raises(RuntimeError) as excinfo:
|
|
OpenSeesRunner(proj).run(proj.analyses[0])
|
|
message = str(excinfo.value)
|
|
assert "Singular stiffness matrix" in message
|
|
# Every unrestrained Rz should be listed.
|
|
assert "Rz" in message
|
|
# Helpful hint steering the user to the right menu item.
|
|
assert "New 2D Truss" in message
|
|
|
|
|
|
def test_truss_with_ndf_2_runs_to_completion() -> None:
|
|
"""The same truss with ndf=2 solves fine."""
|
|
proj = _make_truss_project(ndf=2)
|
|
result = OpenSeesRunner(proj).run(proj.analyses[0])
|
|
assert 3 in result.node_disp
|
|
# Sanity: displacement must be non-zero and finite.
|
|
ux, uy = result.node_disp[3][-1]
|
|
assert abs(ux) > 0 or abs(uy) > 0
|
|
assert ux == ux and uy == uy # NaN check
|