feat: initial otko import
Some checks failed
CI / lint (push) Has been cancelled
CI / test (macos-latest, 3.10) (push) Has been cancelled
CI / test (macos-latest, 3.11) (push) Has been cancelled
CI / test (macos-latest, 3.12) (push) Has been cancelled
CI / test (ubuntu-latest, 3.10) (push) Has been cancelled
CI / test (ubuntu-latest, 3.11) (push) Has been cancelled
CI / test (ubuntu-latest, 3.12) (push) Has been cancelled
CI / test (windows-latest, 3.10) (push) Has been cancelled
CI / test (windows-latest, 3.11) (push) Has been cancelled
CI / test (windows-latest, 3.12) (push) Has been cancelled

This commit is contained in:
smillmorel 2026-09-08 02:12:15 -04:00
commit 612936a00b
540 changed files with 174136 additions and 0 deletions

198
docs/roadmap.md Normal file
View file

@ -0,0 +1,198 @@
# Roadmap
OTKO is built in eight phases. Phases 0–7 ship the core GUI
plus all the post-processing tooling we need for verification work.
Phase 8 layers in the earthquake-engineering primitives that turn the
GUI from "OpenSees frontend" into a usable research tool.
Status legend: ✅ done · 🟡 partial · ⬜ planned · ✂️ deferred / out-of-scope.
## Phase 0 — Scaffolding ✅
- ✅ Repo, `.gitignore`, `pyproject.toml`
- ✅ Pre-commit + ruff + mypy
- ✅ GitHub Actions CI (Linux/Mac/Win × Py 3.10–3.12)
- ✅ `python -m otko` opens a `MainWindow` with PyVista 3D
viewport, model-tree dock, property dock, console dock, working-plane
toolbar, and a full menu bar (File / Edit / Define / Assign /
Analyze / Display / View / Options / Help)
- 🟡 Application icon and About dialog — wordmark logo done; native
OS icon (`.ico` / `.icns`) still pending
## Phase 1 — Core Data Model ✅
- ✅ `core.geometry`: `Node`, `Element`, `TrussElement`, `CorotTrussElement`,
`ElasticBeamColumn`, `ForceBeamColumn`, `DispBeamColumn`,
`ZeroLengthElement`, `ZeroLengthSectionElement`, `BeamWithHingesElement`,
`QuadElement`, plus `GridSystem` / `CoordinateSystem`
- ✅ `core.materials`: `ElasticIsotropic`, `ElasticUniaxial`, `ElasticPP`,
`Steel01`, `Steel02`, `Concrete01`, `Concrete02`, `HystereticMaterial`
- ✅ `core.sections`: `ElasticSection`, `FiberSection` with rectangular
/ circular patches and straight rebar layers, `SectionAggregator`
- ✅ `core.loads`: `NodalLoad`, `UniformElementLoad`, `LinearTimeSeries`,
`ConstantTimeSeries`, `PathTimeSeries`, `PlainLoadPattern`,
`UniformExcitationPattern`, `ResponseSpectrum`
- ✅ `core.analysis`: `StaticCase`, `ModalCase`, `TransientCase`,
`PushoverCase`, `ResponseSpectrumCase` — including chained preload
via `preload_case_ids` and pattern removal for free-vibration runs
- ✅ `core.constraints`: `EqualDOFConstraint` (multi-point constraints)
- ✅ `core.project.Project` aggregator with id allocation, validation,
`validate_references()`
- ✅ `services.persistence`: `.osmodel` (Pydantic JSON) load/save with
round-trip-clean assertion in every example script
## Phase 2 — OpenSees Service ✅
- ✅ `services.opensees_runner.OpenSeesRunner` emits commands in the
canonical order documented in [`architecture.md`](architecture.md)
- ✅ Verified examples (matched analytically or against the OpenSees
Wiki Tcl reference): cantilever (point + UDL), portal frame, basic
truss, SDOF pushover, RC frame gravity / pushover / earthquake,
Examples 1–4 family, two-storey shear / one-bay frames, simply
supported beam with quad elements
- ✅ `AnalysisWorker(QObject)` runnable inside a `QThread` with
`progress(int)` / `log(str)` / `finished(ResultsHandle)` signals
## Phase 3 — 3D Viewport ✅
- ✅ `views.canvas3d.ModelCanvas` (subclass of `QtInteractor` from pyvistaqt)
- ✅ Grid plane, world axes triad, view-cube-style preset buttons
(Isometric / Top XY / Front XZ / Right YZ), parallel projection toggle
- ✅ Node rendering as glyphs; element rendering as tubes (frames /
trusses) and shells (quads); supports rendered as gizmos
- ✅ Mouse picking → `nodePicked` / `elementPicked` signals; pixel-space
grid snap (rejects clicks more than 15 px from an intersection)
- ✅ Selection highlighting with in-place colour updates
## Phase 4 — Modeling Tools ✅
- ✅ Grid system dialog (X / Y / Z spacing, generates nodes); SAP2000-style
table editor; off-grid clicks rejected
- ✅ Working-plane filter — grid + snap restricted to the active level
- ✅ Draw Node / Draw Frame / Draw Truss tools with hover snap highlight
- ✅ Inline element editing from the Properties dock (truss area,
any scalar field)
- ✅ Assign Support tool (Free / Pin / Roller / Fix + custom 6-DOF dialog)
- ✅ Assign Load: nodal loads, distributed beam loads, ground motions
- ✅ Assign EqualDOF (multi-point constraints) from the UI
- ✅ Show Extruded Sections toolbar shortcut
- ✅ Undo / Redo via `QUndoStack` for every model mutation
- 🟡 Replicate / Mirror / Move / Extrude — basic copy works; story-extrude
and mirror still pending
## Phase 5 — Properties ✅
- ✅ Material library dialog (CRUD)
- ✅ Section library dialog (incl. `FiberSection` rows that previously
crashed are now handled)
- ✅ Property editor dock — context-aware, multi-selection assignment,
inline mass editor
- 🟡 Fiber-section visual editor — exists; some UI polish still needed
## Phase 6 — Analysis Pipeline ✅
- ✅ Analysis case manager dialog with case-type factories
- ✅ Run dialog with progress + log + cancel
- ✅ Per-run Rayleigh damping override (no project mutation)
- ✅ Results stored to `<project>.osresults.h5`
- 🟡 Convergence diagnostics view (residuals per step) — partial info
in run log; dedicated diagnostics dock pending
## Phase 7 — Post-processing ✅
- ✅ Deformed shape with scale-factor slider
- ✅ Mode-shape animator (1-indexed; play / scrub / scale)
- ✅ Element force diagrams (axial, shear, moment) with auto-pick of
the largest-magnitude component on dock open, numerical labels at
global min/max ends
- ✅ Time-history plotter (pyqtgraph) with displacement / velocity /
acceleration switching
- ✅ Hysteresis plotter — node DOF orbits and element local-force loops
- ✅ Pushover curve view in display units
- ✅ Response-spectrum view (Sa-T curve with modal-period markers and a
mass-participation table)
- ✅ Snapshot / video export (mode shapes + time histories) via
`imageio[ffmpeg]`
- ⬜ **Render performance pass** — collapse per-entity actors into glyphed
PolyData (single draw call), in-place colour updates for selection,
AA, lower-tessellation spheres. Target: 10k nodes / 20k frames @ 30 fps
## Phase 8 — Earthquake Engineering 🟡
- ✅ `HystereticMaterial`, `BeamWithHinges`, `FiberSection` → all
flowing into the runner, end-to-end pushover example
- ✅ Response spectrum generator + SRSS / CQC modal combination
- ✅ Ground-motion import via `PathTimeSeries` + `UniformExcitationPattern`,
with an example wired up against the OpenSees A10000 record
- ✅ `ZeroLengthSectionElement` for moment-curvature workflows; closed-form
verification example shipped
- ✅ `Concrete04` (Popovics) end-to-end: model → runner → UI form → tests →
fiber-section cantilever example
- ✅ **Material Tester service** (`services/material_tester.py`) — headless,
Qt-free; runs any uniaxial material through a monotonic or cyclic strain
protocol in an isolated single-element model and returns the full
stress–strain history. Verified: Elastic linearity, ElasticPP plateau,
Steel01 hysteresis energy (EPP formula, <1%), Concrete04 Popovics C1
continuity; state-cleanup and interleave proofs.
- ⬜ **Material Tester dialog** — Qt front-end for the service above; live
stress–strain plot with strain-amplitude and step controls
- ⬜ Seismic isolators: `elastomericBearing*`, `frictionPendulumBearing`,
`singleFPBearing`, `TripleFrictionPendulum`
- ⬜ Ground-motion library (PEER-style record set + scaling tools)
- ⬜ IDA (Incremental Dynamic Analysis) batch runner
- 🟡 Fiber-section editor — exists for rectangular / circular sections;
confined / unconfined visual presets pending
## Out-of-scope (for now)
- ✂️ Code-checking (TBDY-2018, ASCE 41, Eurocode 8)
- ✂️ Soil-structure interaction GUI
- ✂️ Cloud / collaborative editing
- ✂️ Native shell-element rendering / pre-processing (quads exist as a
primitive, but a proper shell workflow is its own phase)
## Next sessions — backlog (Sept 2026 cooldown session)
Session handoff first: ~60 files of uncommitted work in the tree
(Table dock, extrusion shapes, exporter, pattern_factors, all audit
fixes). Commit per Conventional Commits on `develop` before new work
(`feat:`/`fix:` split per lane), then `ruff check src tests &&
ruff format src tests`, `mypy`, `pytest -m "not slow"`.
Requested (user-ordered):
1. ⬜ Toolbar button icons — `resources/icons/` exists; wire `QIcon`s
in `menu_builder.py` toolbar builders (`@designer` lane: layout,
hierarchy, affordances). Include OS icon (`.ico`/`.icns`, Phase 0 🟡).
2. ⬜ Shell objects — analysis first: `QuadElement` today is continuum
(plane stress/strain). Scope OpenSees `ShellMITC4`/`ShellDKGQ` +
shell sections/materials, then core element + `_emit` + renderer
quad→shell + section dialog. Keep solver-source untouched
(emit `-factor`-style floats only). (`@oracle` for the scope call.)
3. ⬜ Input-dialog layout/usability pass — continue the Lane C pattern:
`QFormLayout` consistency, prefill from selection (done for assign
dialogs), inline validation messages instead of silent reverts,
units-aware labels. (`@designer` for layout, orchestrator for copy.)
4. ⬜ Hover tooltips — two halves: (a) canvas entity hover (node/element
id + key values via existing picking signals); (b) widget tooltip
audit (every toolbar button/dialog field documents itself).
5. ⬜ Load visibility filter — show only loads of the selected pattern /
case; hide the rest. Renderer load-overlay filter + selector combo
(builds on the Table Loads tabs' pattern filter). Natural home:
View toolbar next to Show Local Axes.
Identified this session (audit + build leftovers):
6. ⬜ Named load combinations (deferred phase 3) — `pattern_factors`
covers per-case factoring; add a reusable named-combo entity only
if one combo must be shared across many cases.
7. ⬜ Per-row Run + status in Table Analyses tab — run control lives
only in the Run dialog today; add per-case Run button + last-run
status (converged/failed/when). No overlap: the tab lists cases,
this operates them.
8. ⬜ Case-manager edit preservation — `modelMutated` while the manager
is open rebuilds the form and discards in-progress edits (audit C2).
9. ⬜ Table dock phase-4 polish — CSV copy/paste, column visibility
(deferred from the Table plan).
10. ⬜ Display-settings persistence — extruded-sections / local-axes /
parallel-projection toggles reset per project; persist viewport
prefs in `QSettings` (no `DisplaySettings` module exists yet).
11. ⬜ GUI test coverage under xvfb — `views/*` omitted from coverage;
lanes verified via offscreen smoke only. Add pytest-qt tests for:
dock toggles, Level refresh, post-state teardown, Table edits,
factor spins, local-axes overlay.
12. ⬜ Pin ruff version — local ruff (0.15.x) flags pre-existing drift
(UP037/RUF001/RUF003/E702) that repo CI doesn't; pin in
`pyproject.toml` or baseline-allowlist so `ruff check` is green.
13. ⬜ Exported-Tcl round trip — `.py` export is solver-verified;
add an equivalent exec-and-compare test for the `.tcl` renderer.