Some checks failed
CI / lint (pull_request) Has been cancelled
CI / test (macos-latest, 3.10) (pull_request) Has been cancelled
CI / test (macos-latest, 3.11) (pull_request) Has been cancelled
CI / test (macos-latest, 3.12) (pull_request) Has been cancelled
CI / test (ubuntu-latest, 3.10) (pull_request) Has been cancelled
CI / test (ubuntu-latest, 3.11) (pull_request) Has been cancelled
CI / test (ubuntu-latest, 3.12) (pull_request) Has been cancelled
CI / test (windows-latest, 3.10) (pull_request) Has been cancelled
CI / test (windows-latest, 3.11) (pull_request) Has been cancelled
CI / test (windows-latest, 3.12) (pull_request) Has been cancelled
80 lines
3.7 KiB
Markdown
80 lines
3.7 KiB
Markdown
# Architecture
|
|
|
|
## Layering
|
|
|
|
OTKO uses a strict **MVVM + service layer** architecture. Dependencies
|
|
flow in **one direction only**: outer layers may depend on inner layers, never
|
|
the reverse.
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────────┐
|
|
│ views/ Qt widgets, dialogs, 3D canvas — PySide6 only │
|
|
│ ▲ │
|
|
│ │ signals/slots, viewmodel binding │
|
|
│ viewmodels/ Qt-aware adapters, QUndoStack, selection state │
|
|
│ ▲ │
|
|
│ │ pure Python calls │
|
|
│ services/ OpenSeesRunner, PersistenceService, Results │
|
|
│ ▲ │
|
|
│ │ │
|
|
│ core/ Project, Node, Element, Material — pure Python │
|
|
│ NO Qt imports. NO openseespy imports. │
|
|
└─────────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
### Why this matters
|
|
|
|
- `core` tests without a display server, without OpenSees, without Qt.
|
|
CI runs `pytest tests/unit/` in milliseconds.
|
|
- Swapping solvers (e.g. `xara`, a future fork) touches
|
|
`services/opensees_runner.py` and nothing else.
|
|
- A future CLI or notebook front-end reuses `core` and `services` as-is.
|
|
|
|
## Package map
|
|
|
|
| Package | Responsibility | Allowed imports |
|
|
|---|---|---|
|
|
| `core` | Domain entities and invariants | stdlib, numpy, pydantic |
|
|
| `services` | I/O, solver invocation, persistence | core + stdlib + h5py + openseespy |
|
|
| `viewmodels` | Bridge core ↔ Qt; expose Qt signals; manage undo/redo | core, services, PySide6 |
|
|
| `views` | Pure UI; no business logic | PySide6, pyvistaqt, viewmodels |
|
|
| `commands` | `QUndoCommand` subclasses; mutate model via services | services, viewmodels |
|
|
|
|
## Threading
|
|
|
|
The Qt main thread owns all widgets. Heavy computation happens elsewhere:
|
|
|
|
- **OpenSees analysis** runs in a `QThread` worker (`services.opensees_runner.AnalysisWorker`).
|
|
- The worker emits `progress(int)`, `log(str)`, `finished(ResultsHandle)` signals.
|
|
- The worker checks `QThread.currentThread().isInterruptionRequested()` between
|
|
analysis steps so the user can cancel.
|
|
- Results are written to HDF5; only a lightweight `ResultsHandle` (file path +
|
|
metadata) crosses the thread boundary.
|
|
|
|
## Persistence
|
|
|
|
- Project files: `*.osmodel` — a JSON document validated by Pydantic models.
|
|
Human-readable, diff-able, version-controllable.
|
|
- Results files: `*.osresults.h5` — HDF5; one group per analysis case; datasets
|
|
for displacements, reactions, element forces, stresses.
|
|
|
|
## OpenSeesPy command sequencing
|
|
|
|
`OpenSeesRunner` always emits commands in this order; the model layer enforces
|
|
that all required pieces exist before a run can be requested:
|
|
|
|
1. `wipe()` and `model('basic', '-ndm', ndm, '-ndf', ndf)`
|
|
2. `node(...)` for every node
|
|
3. `fix(...)` for every restrained DOF
|
|
4. `uniaxialMaterial(...)` / `nDMaterial(...)`
|
|
5. `section(...)` (if used)
|
|
6. `geomTransf(...)` for frame elements
|
|
7. `element(...)` for every element
|
|
8. `timeSeries(...)`
|
|
9. `pattern(...)` with nested `load(...)`
|
|
10. `recorder(...)`
|
|
11. `system / numberer / constraints / integrator / algorithm / analysis`
|
|
12. `analyze(...)`
|
|
|
|
Any deviation from this order is a runtime error in OpenSees. The runner
|
|
asserts the order at the service boundary; the UI never has to think about it.
|