# Roadmap Eight phases. 0–7 are the core GUI plus post-processing. Phase 8 is the earthquake-engineering primitives β€” the part that makes it a research tool instead of a model viewer. 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 `.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.