"""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 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)