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).
90 lines
2.7 KiB
Python
90 lines
2.7 KiB
Python
"""Load-combination integration: 1.2×D + 1.6×L by superposition == one combined run."""
|
||
|
||
from __future__ import annotations
|
||
|
||
import math
|
||
|
||
import pytest
|
||
|
||
ops = pytest.importorskip("openseespy.opensees") # skip if OpenSeesPy not installed
|
||
|
||
from otko.core import (
|
||
ElasticBeamColumn,
|
||
ElasticSection,
|
||
LinearTimeSeries,
|
||
LoadCombination,
|
||
LoadCombinationItem,
|
||
NodalLoad,
|
||
Node,
|
||
PlainLoadPattern,
|
||
Project,
|
||
StaticCase,
|
||
)
|
||
from otko.services import OpenSeesRunner, evaluate_combination
|
||
from otko.services.results import StaticResults
|
||
|
||
pytestmark = pytest.mark.slow
|
||
|
||
|
||
def _two_pattern_cantilever() -> Project:
|
||
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=(5.0, 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), LinearTimeSeries(id=2)],
|
||
load_patterns=[
|
||
PlainLoadPattern(
|
||
id=1,
|
||
name="Dead",
|
||
time_series_id=1,
|
||
nodal_loads=[NodalLoad(node_id=2, forces=(0.0, -1000.0, 0.0, 0.0, 0.0, 0.0))],
|
||
),
|
||
PlainLoadPattern(
|
||
id=2,
|
||
name="Live",
|
||
time_series_id=2,
|
||
nodal_loads=[NodalLoad(node_id=2, forces=(0.0, -500.0, 0.0, 0.0, 0.0, 0.0))],
|
||
),
|
||
],
|
||
analyses=[
|
||
StaticCase(id=1, name="Dead", pattern_ids=[1]),
|
||
StaticCase(id=2, name="Live", pattern_ids=[2]),
|
||
],
|
||
)
|
||
|
||
|
||
def test_superposition_matches_combined_run() -> None:
|
||
"""1.2*Dead + 1.6*Live via evaluate_combination == single StaticCase run."""
|
||
proj = _two_pattern_cantilever()
|
||
dead = OpenSeesRunner(proj).run(proj.analyses[0])
|
||
live = OpenSeesRunner(proj).run(proj.analyses[1])
|
||
combo = LoadCombination(
|
||
id=1,
|
||
name="1.2D+1.6L",
|
||
kind="Linear",
|
||
items=[
|
||
LoadCombinationItem(case_id=1, factor=1.2),
|
||
LoadCombinationItem(case_id=2, factor=1.6),
|
||
],
|
||
)
|
||
combined = evaluate_combination({1: dead, 2: live}, combo)
|
||
assert isinstance(combined, StaticResults)
|
||
# Single run with both patterns factored identically.
|
||
direct = OpenSeesRunner(proj).run(
|
||
StaticCase(id=3, name="direct", pattern_ids=[1, 2], pattern_factors={1: 1.2, 2: 1.6})
|
||
)
|
||
assert math.isclose(
|
||
combined.disp(node_id=2, dof=2), direct.disp(node_id=2, dof=2), rel_tol=1e-9
|
||
)
|