feat: named case-result load combinations with full GUI support
Snapshots the current development tree, headlined by proper load combinations (user request): a reusable LoadCombination entity of weighted completed static-case results (e.g. 1.2xDead + 1.6xLive). - core: LoadCombination/LoadCombinationItem entities, Project integration (lookup, unique ids, reference validation) - services: combinations.py (linear superposition + envelope), exported via services __init__ - commands: undoable Add/Delete/Update for combinations - GUI: Load Combinations manager dialog, Run-dialog evaluation, envelope display in Results panel, Combinations tab in Table dock - tests: unit coverage (validation, math, error paths) + integration superposition check vs a single factored run
This commit is contained in:
commit
f361fee969
560 changed files with 178701 additions and 0 deletions
65
tests/integration/test_pattern_factors.py
Normal file
65
tests/integration/test_pattern_factors.py
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
"""Pattern-factor integration: scaled static load doubles the tip displacement."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import math
|
||||
|
||||
import pytest
|
||||
|
||||
ops = pytest.importorskip("openseespy.opensees") # skip if OpenSeesPy not installed
|
||||
|
||||
from otko.core import ( # noqa: E402
|
||||
ElasticBeamColumn,
|
||||
ElasticSection,
|
||||
LinearTimeSeries,
|
||||
NodalLoad,
|
||||
Node,
|
||||
PlainLoadPattern,
|
||||
Project,
|
||||
StaticCase,
|
||||
)
|
||||
from otko.services import OpenSeesRunner # noqa: E402
|
||||
|
||||
pytestmark = pytest.mark.slow
|
||||
|
||||
|
||||
def _cantilever() -> Project:
|
||||
length = 5.0
|
||||
load = 1000.0
|
||||
elastic_mod = 200e9
|
||||
area = 0.01
|
||||
inertia = 8.333e-6
|
||||
return Project(
|
||||
ndm=2,
|
||||
ndf=3,
|
||||
nodes=[
|
||||
Node(
|
||||
id=1,
|
||||
coords=(0.0, 0.0, 0.0),
|
||||
restraint=(True, True, False, False, False, True),
|
||||
),
|
||||
Node(id=2, coords=(length, 0.0, 0.0)),
|
||||
],
|
||||
sections=[ElasticSection(id=1, E=elastic_mod, A=area, Iz=inertia)],
|
||||
elements=[ElasticBeamColumn(id=1, nodes=(1, 2), section_id=1)],
|
||||
time_series=[LinearTimeSeries(id=1)],
|
||||
load_patterns=[
|
||||
PlainLoadPattern(
|
||||
id=1,
|
||||
time_series_id=1,
|
||||
nodal_loads=[NodalLoad(node_id=2, forces=(0.0, -load, 0.0, 0.0, 0.0, 0.0))],
|
||||
)
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
def test_pattern_factor_doubles_tip_disp() -> None:
|
||||
"""StaticCase pattern_factors={1: 2.0} must double the tip displacement."""
|
||||
base = OpenSeesRunner(_cantilever()).run(StaticCase(id=1, name="base", pattern_ids=[1]))
|
||||
scaled = OpenSeesRunner(_cantilever()).run(
|
||||
StaticCase(id=1, name="scaled", pattern_ids=[1], pattern_factors={1: 2.0})
|
||||
)
|
||||
d_base = base.disp(node_id=2, dof=2)
|
||||
d_scaled = scaled.disp(node_id=2, dof=2)
|
||||
assert d_base != 0.0
|
||||
assert math.isclose(d_scaled, 2.0 * d_base, rel_tol=1e-9)
|
||||
Loading…
Reference in a new issue