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
84 lines
2.5 KiB
Python
84 lines
2.5 KiB
Python
"""GUI tests for analysis case forms."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import pytest
|
|
|
|
pytest.importorskip("PySide6")
|
|
|
|
from otko.core import ( # noqa: E402
|
|
NodalLoad,
|
|
PlainLoadPattern,
|
|
StaticCase,
|
|
TransientCase,
|
|
)
|
|
from otko.views.dialogs.case_forms import TransientCaseForm # noqa: E402
|
|
|
|
|
|
def _patterns(): # type: ignore[no-untyped-def]
|
|
return [
|
|
PlainLoadPattern(
|
|
id=1,
|
|
name="Gravity",
|
|
time_series_id=1,
|
|
nodal_loads=[NodalLoad(node_id=1, forces=(0.0, -1.0, 0.0, 0.0, 0.0, 0.0))],
|
|
),
|
|
PlainLoadPattern(
|
|
id=2,
|
|
name="EQ",
|
|
time_series_id=1,
|
|
nodal_loads=[NodalLoad(node_id=1, forces=(1.0, 0.0, 0.0, 0.0, 0.0, 0.0))],
|
|
),
|
|
]
|
|
|
|
|
|
@pytest.mark.gui
|
|
def test_transient_case_form_round_trips_preload_and_damping(qtbot) -> None: # type: ignore[no-untyped-def]
|
|
analyses = [
|
|
StaticCase(id=1, name="Gravity", pattern_ids=[1], n_steps=10),
|
|
StaticCase(id=2, name="Wind", pattern_ids=[2], n_steps=5),
|
|
]
|
|
form = TransientCaseForm(_patterns(), analyses)
|
|
qtbot.addWidget(form)
|
|
|
|
case = TransientCase(
|
|
id=3,
|
|
name="Earthquake",
|
|
pattern_ids=[2],
|
|
preload_case_ids=[1],
|
|
remove_patterns=[1],
|
|
dt=0.01,
|
|
n_steps=3995,
|
|
rayleigh_alpha_m=0.01,
|
|
rayleigh_beta_k=2.5e-4,
|
|
rayleigh_mode1_damping=0.02,
|
|
)
|
|
form.populate(case)
|
|
|
|
rebuilt = form.read()
|
|
assert rebuilt.pattern_ids == [2]
|
|
assert rebuilt.preload_case_ids == [1]
|
|
assert rebuilt.remove_patterns == [1]
|
|
assert rebuilt.dt == pytest.approx(0.01)
|
|
assert rebuilt.n_steps == 3995
|
|
assert rebuilt.rayleigh_alpha_m == pytest.approx(0.01)
|
|
assert rebuilt.rayleigh_beta_k == pytest.approx(2.5e-4)
|
|
assert rebuilt.rayleigh_mode1_damping == pytest.approx(0.02)
|
|
|
|
|
|
@pytest.mark.gui
|
|
def test_transient_case_form_zero_mode1_damping_reads_as_none(qtbot) -> None: # type: ignore[no-untyped-def]
|
|
form = TransientCaseForm(_patterns(), [StaticCase(id=1, name="Gravity", pattern_ids=[1])])
|
|
qtbot.addWidget(form)
|
|
|
|
form._name_edit.setText("Transient")
|
|
form._dt.setValue(0.02)
|
|
form._n_steps.setValue(100)
|
|
form._mode1_damping.setValue(0.0)
|
|
form._beta_k.setValue(1.0e-4)
|
|
form._patterns_picker.item(1).setSelected(True)
|
|
|
|
rebuilt = form.read(case_id=2)
|
|
assert rebuilt.pattern_ids == [2]
|
|
assert rebuilt.rayleigh_beta_k == pytest.approx(1.0e-4)
|
|
assert rebuilt.rayleigh_mode1_damping is None
|