Compare commits

...
Sign in to create a new pull request.
Author SHA1 Message Date
7839f05384 Merge pull request 'feat/plotly-canvas' (#5) from feat/plotly-canvas into main
Some checks failed
CI / lint (push) Has been cancelled
CI / type (push) Has been cancelled
CI / test-headless (macos-latest, 3.10) (push) Has been cancelled
CI / test-headless (macos-latest, 3.11) (push) Has been cancelled
CI / test-headless (macos-latest, 3.12) (push) Has been cancelled
CI / test-headless (ubuntu-latest, 3.10) (push) Has been cancelled
CI / test-headless (ubuntu-latest, 3.11) (push) Has been cancelled
CI / test-headless (ubuntu-latest, 3.12) (push) Has been cancelled
CI / test-headless (windows-latest, 3.10) (push) Has been cancelled
CI / test-headless (windows-latest, 3.11) (push) Has been cancelled
CI / test-headless (windows-latest, 3.12) (push) Has been cancelled
CI / test-gui (push) Has been cancelled
CI / test-integration (macos-latest) (push) Has been cancelled
CI / test-integration (ubuntu-latest) (push) Has been cancelled
CI / test-integration (windows-latest) (push) Has been cancelled
Reviewed-on: #5
2026-09-16 20:37:40 -04:00
429ebc0790 docs: repair AGENTS.md NUL corruption and record the canvas contracts
Some checks failed
CI / lint (pull_request) Has been cancelled
CI / type (pull_request) Has been cancelled
CI / test-headless (macos-latest, 3.10) (pull_request) Has been cancelled
CI / test-headless (macos-latest, 3.11) (pull_request) Has been cancelled
CI / test-headless (macos-latest, 3.12) (pull_request) Has been cancelled
CI / test-headless (ubuntu-latest, 3.10) (pull_request) Has been cancelled
CI / test-headless (ubuntu-latest, 3.11) (pull_request) Has been cancelled
CI / test-headless (ubuntu-latest, 3.12) (pull_request) Has been cancelled
CI / test-headless (windows-latest, 3.10) (pull_request) Has been cancelled
CI / test-headless (windows-latest, 3.11) (pull_request) Has been cancelled
CI / test-headless (windows-latest, 3.12) (pull_request) Has been cancelled
CI / test-gui (pull_request) Has been cancelled
CI / test-integration (macos-latest) (pull_request) Has been cancelled
CI / test-integration (ubuntu-latest) (pull_request) Has been cancelled
CI / test-integration (windows-latest) (pull_request) Has been cancelled
The previous AGENTS.md edit wrote 478 NUL bytes instead of the intended
sentence, so git and grep treated the file as binary. Restored the clean
UTF-8 text and documented both Plotly canvas invariants: data-only pushes
must pass preserveView (never re-send the camera), and the hover/snap
marker must only be restyled when its visible state changes.
2026-09-16 20:33:30 -04:00
5262d31e33 fix: stop the Plotly hover handler redrawing on every mouse move
plotly_hover/plotly_unhover fire continuously while the mouse moves, and
the unhover handler restyled the snap marker unconditionally - even with
snapping off and nothing visible. That meant a full Plotly.restyle plus
redraw per mouse event, which re-fired hover until the page died with
'RangeError: Maximum call stack size exceeded' and the canvas froze
(reported live after opening a model).

The marker is now updated only when its visible state actually changes: no
marker when snapping is off, and a restyle only when the snapped point
differs from the one already shown. Deliberately synchronous - timers are
throttled to about a second by WebEngine when the page is not compositing,
which stalled the preview. Measured: 200 mouse-move events went from 200
restyles to 0; 200 hovers on one grid dot cost a single restyle.
2026-09-16 20:33:30 -04:00
7cf323df23 feat: surface the Plotly page console in the Console dock
A plotly failure inside the WebEngine page was invisible from Python - the
react promise just rejected and the canvas looked frozen with no evidence.
PlotlyCanvas now installs a QWebEnginePage that forwards
javaScriptConsoleMessage into the Console dock with the right severity
(error/warning/info), so the next silent failure is diagnosable.
2026-09-16 20:18:23 -04:00
0611153555 fix: stop the Plotly canvas wedging on rapid or overlapping updates
Three defects in the view-preservation path could leave the plot frozen
(no updates, no orbit, stale colours):

1. The merge injected raw _fullLayout objects - including undefined when a
   push landed before the previous react resolved - and plotly validates
   layouts, so one bad value made every later react fail permanently.
   currentView() now deep-copies and validates eye/center/up and each
   range, and mergeView() is wrapped so it can never block an update.
2. Updates were not serialized: overlapping Plotly.react calls on one graph
   div left it unresponsive. otkoUpdate now queues and coalesces (one react
   at a time, latest payload wins), and logs instead of failing silently.
3. A style change re-framed the camera, so re-colouring yanked a view the
   user had orbited. Colour/opacity ride the traces and background/outline
   ride the layout, so set_style is now a non-framing push.

Verified in the browser: a user orbit survives colour changes, 30 rapid
preview updates land on the final value and stay responsive, and deleting
the live camera no longer wedges the plot.
2026-09-16 20:14:05 -04:00
8f7bc3cf4f fix: keep the Plotly camera and axis ranges through data updates
Plotly.react resets any scene attribute the incoming layout omits, so every
selection change snapped the camera back to the default and re-fit the
ranges - the pinned framing was meaningless. Data-only pushes now pass
preserveView and html.py merges the live camera and axis ranges into the
incoming layout; only an explicit re-frame sends computed framing.

Also fixes the ordering bug where the framing flag was consumed before the
not-ready early return, which dropped the very first framing on the floor
(show_project runs before loadFinished).

Verified in the browser: user orbit + zoom survive selection and working
plane updates, while reset_camera re-frames. Regression-tested headlessly
by asserting the emitted preserveView flag.
2026-09-16 20:05:35 -04:00
5f977e9df0 feat: opstool-style scene recipe for the Plotly canvas
Frames the view deterministically: Scene now carries padded per-axis bounds
(opstool's pad_ratio 0.15, with unit slack on degenerate axes) plus
axis_overrides() pinning range + autorange=False, so the model is never
flush against the viewport edge. Adds entity hover templates (Node #n /
Element #n with an empty extra tag), and an optional axis outline (grid +
ticks) - off by default so the SAP2000-like clean viewport is unchanged;
the coloured X/Y/Z axis lines always stay as the orientation cue.

The outline is exposed as a bool in the Plot Properties table, so the
table-driven dialog now builds a checkbox for kind=bool.
2026-09-16 20:05:26 -04:00
bd365be77d feat: Options → Plot Properties dialog with live preview and persistence
Adds a table-driven dialog over RenderStyle.STYLE_FIELDS (colour swatches,
an opacity spin and a label font size), reachable from Options. Edits
preview immediately on every canvas, Cancel restores the style the dialog
opened with, and only OK persists — as JSON under QSettings plot/props,
reloaded on the next launch. Both canvases gain set_style(); the dialog
deliberately exposes plot_style() rather than style() so QWidget.style()
keeps its Qt meaning.
2026-09-16 19:31:38 -04:00
56f1f6c08b feat: route both canvas backends through RenderStyle
Colours that were hard-coded in the renderers now come from the shared
style: nodes, supports, nodal/element loads, section extrusions (+
opacity) and label font size. The PyVista frame LUT becomes a four-slot
palette [beam, truss, link, selected] with the cell scalar carrying the
family slot, so VTK matches the Plotly backend's per-family colouring
that landed earlier. Adds style helpers shared by both backends
(element_family_index, family_palette) and an immutable with_updates().

The style also gains the editable field table (STYLE_FIELDS) the Plot
Properties dialog is built from.
2026-09-16 19:31:30 -04:00
17d2ed21d3 feat: opstool-derived element palette and single-trace frame colours
Ports opstool's per-family element colours and its diverging response
scale; RenderStyle.response_scale_colors now also drives the PyVista
force-diagram colouring instead of a hard-coded "coolwarm".

The frame renderer drops the two-trace normal/selected workaround: my
earlier assumption that plotly cannot colour segments individually was
wrong. Scatter3d.line.color accepts an array mapped through a colorscale,
so one trace now carries per-element colours (family + selection) and is
ready to be coloured by response value later.

Attribution recorded in NOTICE per GPLv3 section 5(a)/(b).
2026-09-16 19:15:55 -04:00
40a673c562 test: isolate QSettings so user preferences cannot fail GUI tests
MainWindow persists preferences (window layout, canvas backend) through
QSettings("OTKO", "OTKO"), so tests constructing it were reading the
developer's real settings: after switching to the Plotly backend the
PyVista-specific viewport-axis tests failed with "PlotlyCanvas has no
attribute renderer". A session fixture now redirects QSettings into a
temp dir and is skipped when Qt is not installed, keeping the headless
job Qt-free.
2026-09-16 19:15:48 -04:00
d09e72e95d chore: clone opstool for visualization reference
opstool v1.0.26 (GPL-3.0) is cloned read-only under
.slim/clonedeps/repos/ to inspect its PyVista/Plotly visualization
settings. GPLv3 section 13 permits combining it with this AGPL-3.0
project. The clone itself is git-ignored; the manifest and the AGENTS.md
pointer are committed.
2026-09-16 19:15:48 -04:00
9a1baa07c2 feat: live canvas backend switching (Options → Canvas Backend)
Both backends share one SelectionState owned by MainWindow and live
side by side in a QStackedWidget — switching is setCurrentWidget, so
no widget is destroyed mid-session (tearing a VTK window down leaves
dangling make-current callbacks). The choice persists in QSettings.
CanvasCapabilities declares per-backend gaps (force diagrams and
video export stay PyVista-only, both are documented and greyed out)
and the UI gates on capabilities rather than the backend name. The
architecture gate now allows the canvas_plotly package.
2026-09-16 18:43:59 -04:00
804bf22f61 feat: plotly.js canvas widget (WebEngine + QWebChannel)
PlotlyCanvas hosts plotly.js in a QWebEngineView driven over
QWebChannel: figures update with Plotly.react (the camera survives
unless a view preset asks for it), and clicks round-trip as
node/element picks or grid-snap clicks. Assets are written to a temp
dir and loaded from file:// because the ~5 MB bundle is past
setHtml's data-URL limit. render() forwards QWidget's overload so
grab() and painting keep working.
2026-09-16 18:43:59 -04:00
fc5971ad3d feat: pure Plotly trace builder for the 3D canvas
Project → plotly.js figure dicts with no Qt/pyvista/plotly import, so
it is unit-tested in the headless job. Mirrors the PyVista renderer's
geometry (grid, nodes, frames, supports, loads, extrusions, local
axes, labels, deformation) while respecting plotly.js's medium:
pixel-sized markers, None-separated line segments, selection as a
second trace (per-segment line colours are impossible), cone traces
for arrows. Pickable traces carry meta.kind + customdata.
2026-09-16 18:43:53 -04:00
f99b3a3efd build: add plotly to the GUI extra
Supplies the offline plotly.js bundle for the new canvas backend. The
GUI CI job now installs the gui extra so the Qt/WebEngine tests run
instead of being import-skipped.
2026-09-16 18:43:53 -04:00
1c8333979f Merge pull request 'chore/adopt-local-tree' (#4) from chore/adopt-local-tree into main
Some checks failed
CI / lint (push) Has been cancelled
CI / type (push) Has been cancelled
CI / test-headless (macos-latest, 3.10) (push) Has been cancelled
CI / test-headless (macos-latest, 3.11) (push) Has been cancelled
CI / test-headless (macos-latest, 3.12) (push) Has been cancelled
CI / test-headless (ubuntu-latest, 3.10) (push) Has been cancelled
CI / test-headless (ubuntu-latest, 3.11) (push) Has been cancelled
CI / test-headless (ubuntu-latest, 3.12) (push) Has been cancelled
CI / test-headless (windows-latest, 3.10) (push) Has been cancelled
CI / test-headless (windows-latest, 3.11) (push) Has been cancelled
CI / test-headless (windows-latest, 3.12) (push) Has been cancelled
CI / test-gui (push) Has been cancelled
CI / test-integration (macos-latest) (push) Has been cancelled
CI / test-integration (ubuntu-latest) (push) Has been cancelled
CI / test-integration (windows-latest) (push) Has been cancelled
Reviewed-on: #4
2026-09-16 15:48:15 -04:00
61b850bf46 style: resolve the remaining ruff findings
Some checks failed
CI / lint (pull_request) Has been cancelled
CI / type (pull_request) Has been cancelled
CI / test-headless (macos-latest, 3.10) (pull_request) Has been cancelled
CI / test-headless (macos-latest, 3.11) (pull_request) Has been cancelled
CI / test-headless (macos-latest, 3.12) (pull_request) Has been cancelled
CI / test-headless (ubuntu-latest, 3.10) (pull_request) Has been cancelled
CI / test-headless (ubuntu-latest, 3.11) (pull_request) Has been cancelled
CI / test-headless (ubuntu-latest, 3.12) (pull_request) Has been cancelled
CI / test-headless (windows-latest, 3.10) (pull_request) Has been cancelled
CI / test-headless (windows-latest, 3.11) (pull_request) Has been cancelled
CI / test-headless (windows-latest, 3.12) (pull_request) Has been cancelled
CI / test-gui (pull_request) Has been cancelled
CI / test-integration (macos-latest) (pull_request) Has been cancelled
CI / test-integration (ubuntu-latest) (pull_request) Has been cancelled
CI / test-integration (windows-latest) (pull_request) Has been cancelled
Auto-fixes (UP037, UP038, F401, I001, SIM105, RUF100) plus hand-fixes:
drop the now-unused `Union` imports, annotate mutable class attributes
with ClassVar, raise ValidationError instead of blind Exception in the
zero-length test, delete two dead locals, and bind the per-iteration
grid-builder closures to their loop variables (B023).
2026-09-16 13:20:36 -04:00
184bb4662b chore: scope ruff ignores to tests, Qt and engineering notation
RUF001-003 are ignored repo-wide: × / ≈ / ² are deliberate in the
engineering docs and formulas, which also makes the scattered inline
noqa suppressions redundant. Tests use engineering symbols (A, I, L, E),
`importorskip` before imports and capitalised test names; Qt requires
camelCase signal names and PascalCase event overrides; OpenSees material
fields (cR1, epsU) mirror the solver verbatim. N806 stays exempt only for
the numeric modules that use L / Iz / Iy as symbols.
2026-09-16 13:20:36 -04:00
1f39cff5b0 ci: split the workflow into lint/type/headless/gui/integration jobs
Reconstructs the workflow stripped during the tree copy to match the
meta-gates: separate type job, headless command over
tests/unit+tests/services, and dedicated GUI / integration jobs.
Tool versions pinned to the pre-commit revisions (ruff 0.4.4,
mypy 1.10.0) so CI and local hooks agree.
2026-09-16 13:08:49 -04:00
ba3cad4eff fix: ElasticSectionForm round-trips the SectionShape union
The form still passed flat b/h/d/tw/tf/diameter fields, which
ElasticSection (extra='forbid') rejects, so reading any elastic
section crashed. Rebuild the display-only hint as a PipeShape /
AngleShape / RectShape member instead; an incomplete shape degrades
to None rather than raising.
2026-09-16 13:08:49 -04:00
ba783718d4 chore: adopt remaining local development state
Catch-all for the intermixed residue of the unpushed otko-development
work ported into this tree: combinations/console-dock/quick-guide wiring
across commands, core, services, views and tests; repo-wide ruff-format
normalization; README/CONTRIBUTING updates; and the toolbar default
(both toolbars now open in the top area, quick guide text updated).

Splitting this further would require hunk-level surgery with low
confidence; the preceding commits in this branch isolate the
self-contained features.
2026-09-16 12:03:22 -04:00
cb4bf8fccd docs: quick guide, docs README, specifications and NOTICE 2026-09-16 12:03:07 -04:00
ff09e38b7c test: meta gates for architecture, CI, docs and packaging 2026-09-16 12:03:07 -04:00
f1d58273b7 feat: shared unit-aware formatting helpers
Pure presentation helpers (labels, number parse/format) shared by docks
and dialogs; no Qt imports.
2026-09-16 12:03:07 -04:00
1d21006281 feat: console log dock 2026-09-16 12:03:07 -04:00
ea352a5de5 feat: load combinations
LoadCombination entity, combination service, manager dialog and
unit/integration coverage.
2026-09-16 12:03:07 -04:00
7093164f75 test: relocate service-layer tests to tests/services/
Mirrors the source layout (core/services split) so unit/ holds core-only
tests and services get their own home.
2026-09-16 12:02:55 -04:00
dd9fa26b52 style: apply ruff format to generated catalog
Mechanical double-quote / line-wrap normalization over the schema-generated
catalog classes; no semantic changes.
2026-09-16 12:02:55 -04:00
12c78ea8cb build: read version from _const.py, drop phantom scipy/pandas deps
Single source of truth for the package + pinned solver versions in
src/otko/_const.py (hatch dynamic version). scipy/pandas were listed in
[gui] but never imported. mypy strict mode rescoped to
core/services/viewmodels; tomli added for tomllib-less Pythons.
2026-09-16 12:02:47 -04:00
4d1b3092f8 Merge pull request 'docs: document Forgejo remote and SSH workflow in AGENTS.md' (#3) from docs/git-remote into main
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
Reviewed-on: #3
2026-09-08 02:52:58 -04:00
9df51ee1a1 Merge pull request 'fix: bump export solver pin to 3.8.0.0, narrow PathTimeSeries in examples' (#2) from fix/export-pinned-version-and-ex1b-series into main
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
Reviewed-on: #2
2026-09-08 02:52:24 -04:00
c3b4eed4b2 docs: document Forgejo remote and SSH workflow in AGENTS.md
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
2026-09-08 02:51:15 -04:00
a243092f03 fix: bump export solver pin to 3.8.0.0, narrow PathTimeSeries in examples
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
2026-09-08 02:43:23 -04:00
319 changed files with 16770 additions and 8815 deletions

View file

@ -14,12 +14,25 @@ jobs:
- uses: actions/setup-python@v5
with:
python-version: "3.11"
- run: pip install ruff mypy
# Pinned to the pre-commit revisions so CI and local hooks agree.
- run: pip install ruff==0.4.4
- run: ruff check src tests
- run: ruff format --check src tests
test:
needs: lint
type:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.11"
# Pinned to the pre-commit revision (see .pre-commit-config.yaml).
- run: pip install mypy==1.10.0 pydantic numpy
- run: pip install -e .
- run: mypy src/otko/core src/otko/services
test-headless:
needs: [lint, type]
strategy:
fail-fast: false
matrix:
@ -31,18 +44,38 @@ jobs:
- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- run: pip install -e ".[dev]"
- run: pytest tests/unit tests/services -m "not slow"
test-gui:
needs: [lint, type]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Install Linux Qt deps
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install -y libegl1 libxkbcommon-x11-0 libxcb-icccm4 \
libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 \
libxcb-shape0 libxcb-sync1 libxcb-xfixes0 libxcb-xinerama0 \
libxcb-cursor0 libdbus-1-3 libgl1 libxkbcommon0 xvfb
- run: pip install -e ".[gui,dev]"
- run: xvfb-run -a pytest tests/gui -m "not slow"
test-integration:
needs: [lint, type]
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.11"
- run: pip install -e ".[dev]"
- name: Run tests (Linux, headless)
if: runner.os == 'Linux'
run: xvfb-run -a pytest --cov --cov-report=xml -m "not slow"
- name: Run tests (Win/Mac)
if: runner.os != 'Linux'
run: pytest --cov --cov-report=xml -m "not slow"
- run: pytest tests/integration -m "not slow"

4
.gitignore vendored
View file

@ -61,3 +61,7 @@ examples/ozan*.osmodel
examples/ozan_results/
/Ex*.csv
/Ex*.png
# BEGIN oh-my-opencode-slim clonedeps
.slim/clonedeps/repos/
# END oh-my-opencode-slim clonedeps

9
.ignore Normal file
View file

@ -0,0 +1,9 @@
# BEGIN oh-my-opencode-slim clonedeps
!.slim/
!.slim/clonedeps.json
!.slim/clonedeps/
!.slim/clonedeps/repos/
!.slim/clonedeps/repos/**
.slim/clonedeps/repos/**/.git/
.slim/clonedeps/repos/**/.git/**
# END oh-my-opencode-slim clonedeps

15
.slim/clonedeps.json Normal file
View file

@ -0,0 +1,15 @@
{
"version": "1.0.0",
"updatedAt": "2026-09-16T17:30:00.000Z",
"dependencies": [
{
"name": "opstool",
"resolvedVersion": "1.0.26",
"repoUrl": "https://github.com/yexiang92/opstool.git",
"ref": "v1.0.26",
"path": ".slim/clonedeps/repos/yexiang92__opstool",
"packagePath": "opstool/vis",
"reason": "Read-only source for evaluating whether to port opstool's PyVista/Plotly visualization settings into otko's canvas backends, or to depend on opstool.vis directly (GPL-3.0, compatible with otko's AGPL-3.0 via GPLv3 section 13)."
}
]
}

View file

@ -5,7 +5,7 @@ Pre-alpha SAP2000-style desktop GUI for OpenSeesPy. Python 3.10+; **Windows requ
## Install
```bash
pip install -e ".[gui,dev]" # desktop: Qt + PyVista + dev tools
pip install -e ".[gui,dev]" # desktop: Qt + PyVista + plotly.js backend + dev tools
pip install -e . # headless: core + services only, no Qt (scripts, notebooks, web backends)
python -m otko # launch GUI (src/otko/app.py:run)
```
@ -19,6 +19,8 @@ Strict one-way MVVM + services: `views → viewmodels → services → core`.
- `core/` (entities: `project.py`, `geometry/`, `materials/`, `sections/`, `loads/`, `analysis/`, `catalog/`): stdlib + numpy + pydantic only. **No Qt, no openseespy. Period.**
- `services/` (`opensees_runner.py`, `persistence.py`, `results.py`, ...): may use core + h5py + openseespy. **No Qt.**
- `views/`: PySide6/pyvistaqt only. **No direct `import openseespy`** — go through a service.
- `views/canvas3d/` (**PyVista/VTK**, default) and `views/canvas_plotly/` (plotly.js in a `QWebEngineView`) are two backends for the same central 3D view. Both satisfy the `CanvasBackend` protocol in `views/canvas_base.py`, share one `SelectionState` owned by `MainWindow`, and are swapped live via **Options → Canvas Backend** (persisted in `QSettings` under `canvas/backend`). `MainWindow._activate_canvas` keeps both widgets in a `QStackedWidget` — never destroy a canvas mid-session (VTK leaves dangling make-current callbacks). Backend-specific gaps are declared by `CanvasCapabilities` (e.g. Plotly has no force-diagram overlay or video export yet); gate UI on `canvas.capabilities`, never on the backend name. `canvas_plotly/trace_builder.py` is pure (no Qt, no pyvista) and unit-tested headless. `PlotlyCanvas` pushes with `Plotly.react`, which resets scene attributes the layout omits: data-only pushes pass `preserveView` so `html.py` carries the live camera and padded axis ranges forward, and the hover/snap marker is restyled only when its visible state changes (a restyle per hover event redraws per mouse move until the stack blows). Regression tests: `tests/gui/test_plotly_view_preservation.py`, `tests/gui/test_plotly_hover.py`.
- `views/canvas3d/style.py` (`RenderStyle`) is the single source of truth for colours/sizes on **both** backends; renderers must read it rather than hard-coding a colour. The `STYLE_FIELDS` subset is user-editable via **Options → Plot Properties…** (`views/dialogs/plot_properties.py`), previews live through `MainWindow.set_plot_style(..., persist=False)`, and persists as JSON in `QSettings` under `plot/props`.
- `viewmodels/` bridges core↔Qt (signals, `QUndoStack`); `commands/` holds `QUndoCommand` subclasses.
- Rules: public functions need type hints + docstring; new domain entities go through Pydantic validation; ops >50 ms run off the GUI thread (`AnalysisWorker` in QThread, cancel via `isInterruptionRequested()`, results cross threads as lightweight `ResultsHandle` to HDF5).
@ -37,8 +39,36 @@ Focused runs: `pytest tests/unit` (pure logic, ms), `pytest tests/gui -k <name>`
Notes: `tests/conftest.py` auto-`ops.wipe()`s the OpenSees domain between tests (lazy import so core tests stay Qt/OpenSees-free). Coverage omits `views/`. Commit style: Conventional Commits (`feat:`, `fix:`, ...). `pre-commit install` runs ruff + mypy (mypy hook scoped to `core|services|viewmodels`).
## Git & Forgejo
Remote is a self-hosted Forgejo, SSH-only:
```bash
git remote add origin ssh://git@smill-home.ddns.net/smill/otko.git
```
- Web UI / HTTPS clone: `https://smill-home.ddns.net/forgejo/smill/otko.git` (note the `/forgejo` subpath — SSH URLs don't have it).
- Forgejo SSH runs through the system sshd on **port 22** (`SSH_PORT = 22` in the server's `app.ini`). If the site ever advertises a `:2222` SSH URL again, that config regressed — push/pull with port 22 anyway and flag it.
- Auth is by SSH key (Forgejo → Settings → SSH Keys). Test: `ssh -T git@smill-home.ddns.net` should answer `Hi there, <user>! ... Forgejo does not provide shell access.`
- Default branch `main`. Work on short-lived branches (`fix/<topic>`, `docs/<topic>`), open a PR against `main`. Never commit directly to `main` from an agent session.
- Repo root is `otko/` itself. (On the dev laptop there is also an empty, commit-less parent repo at `Sync/coding/` — ignore it; all git work happens inside `otko/`.)
## Examples & persistence
- `examples/*.py` are source of truth; `examples/*.osmodel` are generated artifacts (checked in). Never hand-edit `.osmodel` — change the script and regen: `python examples/cantilever.py` (each script saves, reloads, asserts clean round-trip).
- Projects persist as single Pydantic-validated JSON `.osmodel` (diffable); analysis output goes to `*.osresults.h5` (HDF5, one group per case).
- Quick smoke: open `examples/cantilever.osmodel` → run `Tip-Load` → M3 peaks 50 kN·m at fixed end.
## Cloned Dependency Source
Read-only dependency source repositories are available under
`.slim/clonedeps/repos/` for inspection. Do not edit these clones. The
structured manifest is `.slim/clonedeps.json`.
- `.slim/clonedeps/repos/yexiang92__opstool/` — `yexiang92/opstool` at `v1.0.26`; the OpenSeesPy
pre/post-processor whose PyVista and Plotly visualization settings
(`opstool/vis/{pyvista,plotly}/plot_utils.py`, `plot_resp_base.py`, `vis_model.py`) are the
reference for otko's canvas look-and-feel. GPL-3.0, and GPLv3 §13 explicitly permits combining
it with otko's AGPL-3.0. Any code actually ported from it must keep the opstool copyright notice
and record that it was modified (GPLv3 §5a/b) — add that entry to `NOTICE` when the port lands.

View file

@ -1,37 +1,97 @@
# Contributing
Early-stage project. The bar is architecture cleanliness, not feature
count. If your change breaks a layering rule below, it won't merge —
no matter how useful the feature.
Thanks for helping with OTKO — a SAP2000-style desktop GUI for
OpenSeesPy. Early-stage project: the bar is architecture cleanliness, not
feature count. If your change breaks a layering rule below, it won't
merge — no matter how useful the feature.
## Dev setup
```bash
python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
source .venv/bin/activate # Linux / macOS
# .venv\Scripts\activate # Windows
pip install -e ".[gui,dev]"
pre-commit install
```
`pip install -e ".[gui,dev]"` pulls the Qt/PyVista desktop stack plus the
dev tools. For a headless checkout (core + services only, no Qt) use
`pip install -e .` instead. Python 3.10+; on Windows use 3.12+.
Launch the GUI with:
```bash
python -m otko
```
`pre-commit install` wires ruff + mypy into your local git hooks so
obvious issues are caught before a commit. Run it once per clone.
## Before opening a PR
Run the verify commands in this order and make sure they are all clean:
```bash
ruff check src tests
ruff format src tests
ruff format src tests # line-length 100, E501 ignored
mypy src/otko/core src/otko/services
pytest -m "not slow"
pytest -m "not slow" # CI gate: lint → this, on 3.10/3.11/3.12 × ubuntu/windows/macos
```
Focused runs are faster while iterating: `pytest tests/unit` (pure logic,
milliseconds), `pytest tests/gui -k <name>` (pytest-qt, needs a display;
Linux GUI tests want `xvfb-run -a pytest ...`), and
`pytest tests/integration -k <name>` (real OpenSeesPy runs). Single test:
`pytest tests/unit/test_project.py::test_name -q`. Markers: `gui`, `slow`.
## Architectural rules (enforced in review)
1. `core/` may not import Qt or `openseespy`. Period.
2. `services/` may not import Qt.
3. `views/` may not import `openseespy` directly — go through a service.
4. Public functions and methods need type hints and a docstring.
5. New domain entities go through Pydantic validation.
6. Long-running operations (>50 ms) run off the GUI thread.
OTKO uses a strict one-way **MVVM + service** architecture. Dependencies
flow outward-in only:
```
views → viewmodels → services → core
```
`commands` sits alongside the bridge and owns every model mutation.
1. `core/` is pure Python — stdlib + numpy + pydantic. It may **not**
import Qt or `openseespy`. Period.
2. `services/` may use `core` + `h5py` + `openseespy`, but may **not**
import Qt.
3. `views/` (PySide6/pyvistaqt) may **not** import `openseespy` directly —
go through a service. No business logic in `views`.
4. `viewmodels/` bridges `core` ↔ Qt (signals, `QUndoStack`).
5. `commands/` holds the `QUndoCommand` subclasses; all model mutations
go through `commands`, not ad-hoc edits in `views`.
6. Public functions and methods need type hints and a docstring.
7. New domain entities go through Pydantic validation.
8. Long-running operations (>50 ms) run off the GUI thread (`AnalysisWorker`
in a `QThread`, cancelled via `isInterruptionRequested()`; results cross
threads as a lightweight `ResultsHandle` written to HDF5).
The full package map and the fixed OpenSeesPy command order the runner
emits live in [`docs/architecture.md`](docs/architecture.md). Never
reorder the runner's commands.
## Branch model
`main` is the default and integration branch. Work on short-lived topic
branches cut from `main` — `feat/<topic>`, `fix/<topic>`, or
`docs/<topic>` — and open a pull request against `main`. Do not commit
directly to `main` from an agent session. There is no `develop` branch.
## Commit style
Conventional Commits — `feat:`, `fix:`, `refactor:`, `docs:`, `test:`,
`chore:`, `ci:`.
`chore:`, `ci:`. Keep each commit focused; a `feat:` commit should add a
feature, not mix one in with unrelated refactors.
## Documentation
If your change is user-visible, update
[`docs/QUICK_GUIDE.md`](docs/QUICK_GUIDE.md) and the relevant roadmap or
ADR entry. Project model files are `.osmodel` (Pydantic-validated JSON);
regenerate the checked-in `examples/*.osmodel` from their scripts with
`python examples/<name>.py` rather than hand-editing them.

85
NOTICE Normal file
View file

@ -0,0 +1,85 @@
# NOTICE
OTKO
Copyright © 2026 Ozan and contributors.
## OTKO license
OTKO's own source code is licensed under the **GNU Affero General Public
License v3.0** (AGPL-3.0). The full text is in [`LICENSE`](LICENSE). This
`NOTICE` file does not replace or modify that license; where the two
disagree, `LICENSE` governs.
OTKO is **not** an MIT-licensed project. Portions of the codebase were
ported or adapted from an earlier, MIT-licensed prototype called
`otko-development`, so the original MIT notice is reproduced below as
required by that license.
## Ported / adapted code: `otko-development`
Portions of OTKO were ported or adapted from the `otko-development`
project, which is distributed under the MIT License. The MIT
copyright and permission notice is reproduced verbatim below:
```
MIT License
Copyright (c) 2026 OTKO contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
```
## Ported / adapted code: `opstool`
The canvas element colour palette in `src/otko/views/canvas3d/style.py`
(per-family element colours and the diverging response colour scale) and the
resulting diagram colouring in `views/canvas3d/diagram_renderer.py` were
adapted from the `opstool` project, which is distributed under the **GNU
General Public License v3.0**. opstool is Copyright © Yexiang Yan and
contributors.
In accordance with GPLv3 §5(a)/(b) this notice records that the material was
modified and adapted for OTKO. Combining the GPLv3-covered material with
OTKO's AGPL-3.0 code is permitted by GPLv3 §13; the combined work is
conveyed under AGPL-3.0, and the GPLv3 terms continue to apply to the
opstool-derived portions.
## Runtime dependencies
OTKO depends on third-party software that is not covered by OTKO's
AGPL-3.0 license. Each component remains under its own license, and its
license text ships with the corresponding package. The notes below are a
summary for attribution, not a substitute for those license texts.
- **OpenSees / OpenSeesPy** — the finite-element solver invoked by
`otko.services.opensees_runner`. OpenSees is copyright The Regents of
the University of California and is distributed under a BSD-style
license; the notice is shipped inside the `openseespy` package.
- **PySide6** — the Qt 6 bindings used by the desktop GUI. PySide6 is
available under the GNU Lesser General Public License v3 (LGPLv3) or a
commercial license. OTKO links against it dynamically, which keeps the
LGPL relinking obligation satisfiable for redistributors.
- **numpy**, **pydantic**, **h5py**, **pyvista**, **VTK**,
**pyqtgraph**, and **imageio** — each is distributed under its own
license (for example BSD-3-Clause, MIT, and similar permissive terms).
See the license file bundled with each installed package for the exact
terms.
When redistributing OTKO, keep `LICENSE`, this `NOTICE`, and the license
notices of the dependencies above.

View file

@ -82,6 +82,13 @@ views (Qt) → viewmodels → services (OpenSeesRunner, Persistence) → c
Long version in [`docs/architecture.md`](docs/architecture.md),
including the OpenSeesPy command order the runner emits.
## Documentation
Practical, task-first walkthroughs live in
[`docs/QUICK_GUIDE.md`](docs/QUICK_GUIDE.md) — a cantilever build,
modal analysis, report/script export, display units, and undo/redo.
The full index is [`docs/README.md`](docs/README.md).
## Install (development)
**Desktop GUI** (Qt, PyVista, pyqtgraph, imageio):

132
docs/QUICK_GUIDE.md Normal file
View file

@ -0,0 +1,132 @@
# OTKO Quick Guide
A practical, task-first guide to the OTKO desktop GUI. It assumes you
have already installed the desktop extras and can launch the app:
```bash
pip install -e ".[gui,dev]"
python -m otko
```
Project files use the `.osmodel` extension — a single, Pydantic-validated
JSON document that diffs cleanly in Git. Analysis output is written
separately to `*.osresults.h5`.
For the layer map and the OpenSeesPy command order, see
[`architecture.md`](architecture.md). For the feature-by-feature plan, see
[`roadmap.md`](roadmap.md).
## 1. A cantilever walkthrough
This follows the bundled `examples/cantilever.osmodel` model: a 5 m
horizontal beam, fixed at the left end, with a tip load. If you would
rather build it by hand, the steps are below.
1. **Start a project.** **File → New (3D Frame)**. Pick display units in
the bottom-right **Units** combo before typing any values.
2. **Lay out a grid.** **Define → Coordinate System/Grids…** (Ctrl+G).
Define X lines at 0…5 m (say, every 1 m), Y = 0, Z = 0, and set the
grid as the active coordinate system. The 3D canvas will draw it as
reference geometry.
3. **Add nodes.** **Define → Add Node…** (Ctrl+N), or use the **Draw
Node** tool and click on grid intersections at (0,0,0) … (5,0,0).
4. **Define material and section.** **Define → Material Library…**
(Ctrl+Shift+M) then **Define → Section Library…** (Ctrl+Shift+S). The
example uses a steel `ElasticSection` named `W12x40`.
5. **Draw the element.** **Assign/Define → Draw Frame** (F2), then click
from the first node to the last. Assign the section with
**Assign → Frame → Section…**.
6. **Add the support.** Select the node at x = 0 and use
**Assign → Joint → Restraints…** (Ctrl+R); restrain all six DOF. The
support icon confirms the fixed end.
7. **Add the load.** Select the tip node and use **Assign → Joint →
Point Loads…** (Ctrl+L). The example applies -10 kN in Y. Alternatively
build the distributed case with **Assign → Frame → Distributed
Load…**.
8. **Set up and run the case.** **Analyze → Cases…** (Ctrl+Shift+A) to
create or review a Static case, then **Analyze → Run…** (F5). The
bundled file already contains `Tip-Load`, `Uniform-Load`, and a modal
`Modal-3` case.
### Smoke check
Open `examples/cantilever.osmodel`, run the `Tip-Load` static case, then
**Display → Show Force Diagram… → M3**. The moment diagram is linear and
peaks at **50 kN·m at the fixed end**. V2 is a constant -10 kN along the
span. If you see that, the model, runner, and post-processor are wired up
correctly.
## 2. Running a modal analysis
1. Open a model that has mass assigned (the bundled cantilever lumps mass
at every free node so modal works out of the box).
2. **Analyze → Cases…**, add or select a **Modal** case, and set the
number of modes `n_modes` (the example uses 3).
3. **Analyze → Run…** (F5). Results appear in the results/report panel:
periods, frequencies, and participation factors per mode.
4. **Display → Animate Mode Shape** to view each mode. Use the mode
selector and the animation controls, and **Export…** if you want a
video of the mode shape.
5. Modal results also feed the response-spectrum case: define a response
spectrum, then run the SRSS or CQC combination and open
**Display → Show Response Spectrum**.
## 3. Reviewing results and exporting a report or script
After a run, the results/report panel shows a summary for the active case
(static reactions and forces, modal periods, and so on). Use the display
actions to inspect the model visually:
- **Display → Show Deformed Shape** — with a scale slider.
- **Display → Show Force Diagram…** — axial (P), shear (V2/V3), moment
(M2/M3) diagrams.
- **Display → Show Pushover Curve**, **Show Time-History**, **Show
Hysteresis** as applicable.
To hand the analysis to someone else, or to archive exactly what was run,
export a script:
- **File → Export OpenSeesPy (.py)…** — writes the full model, and
optionally a selected analysis case, as a runnable Python script.
- **File → Export Tcl (.tcl)…** — the same model as classic OpenSees Tcl.
The export dialog lets you choose "Model only (no analysis case)" or one
of the configured cases. The generated script follows the runner's fixed
command order (`wipe → model → node → fix → … → analyze`), so it
reproduces the analysis outside the GUI.
## 4. Changing display units
Use either control, they are the same setting:
- The **Units** combo in the bottom-right of the status bar, or
- **Options → Set Display Units…**
Changing units updates how lengths, forces, and moments are formatted in
the UI and plots. It does **not** rescale the underlying model numbers —
pick the right unit system before you type values, and convert
deliberately if you switch later. A set of unit labels is available in the
unit-label tests under `tests/unit/test_unit_labels.py`.
## 5. Undo and redo
Every model mutation goes through the undo stack, so most edits are
reversible:
- **Edit → Undo** (Ctrl+Z)
- **Edit → Redo** (Ctrl+Y / Ctrl+Shift+Z)
Menu text is dynamic — it names the operation, for example "Undo Add 4
Nodes". Compound operations such as drawing a frame (node + element) are
wrapped in a single macro, so one undo removes the whole step. File
loads, analysis runs, and display-only changes are not model mutations and
are not undoable.
## Where to go next
- [`architecture.md`](architecture.md) — MVVM layering and command order.
- [`roadmap.md`](roadmap.md) — what is done and what is planned.
- `examples/` — 20+ verified models, each generated from a checked-in
Python script.
- [`../CONTRIBUTING.md`](../CONTRIBUTING.md) — setup, rules, and verify
commands.

26
docs/README.md Normal file
View file

@ -0,0 +1,26 @@
# OTKO Documentation
Index of the project documentation. Start with the quick guide if you
just want to build and run a model; read the architecture page if you are
changing code.
| Document | What it covers |
| --- | --- |
| [QUICK_GUIDE.md](QUICK_GUIDE.md) | Task-first walkthrough: cantilever model, modal analysis, report and script export, display units, undo/redo. |
| [architecture.md](architecture.md) | MVVM layering, package responsibilities, threading, persistence, and the fixed OpenSeesPy command order. |
| [roadmap.md](roadmap.md) | Phase-by-phase feature status, from scaffolding through the earthquake-engineering primitives. |
| [adr/](adr/) | Architecture Decision Records — the "why" behind individual design choices. |
| [screenshots/](screenshots/) | Screenshots referenced by the docs and README. |
## Architecture Decision Records
- [ADR-0001 — GiD/OpenSees schema import](adr/ADR-0001-gidopensees-schema-import.md)
- [ADR-0002 — Headless / GUI dependency split](adr/ADR-0002-headless-gui-dep-split.md)
## Related documentation
- [`../README.md`](../README.md) — project overview, install, and quick start.
- [`../CONTRIBUTING.md`](../CONTRIBUTING.md) — dev setup, layering rules, commit style, and verify commands.
- [`../AGENTS.md`](../AGENTS.md) — condensed context for automated agents.
- [`gap-analysis-gidopensees.md`](gap-analysis-gidopensees.md) — gap analysis against the GiD/OpenSees reference.
- [`../examples/README.md`](../examples/README.md) — the bundled example models.

View file

@ -222,6 +222,7 @@ def main() -> None:
project = build_ex1a_canti2d()
project.validate_references()
gm = next(ts for ts in project.time_series if ts.id == 3)
assert isinstance(gm, PathTimeSeries)
print(f"Built '{project.meta.name}'")
print(f" Gravity + pushover + earthquake cases: {len(project.analyses)}")
print(f" Ground motion file: {GROUND_MOTION_FILE.name}")

View file

@ -190,6 +190,7 @@ def main() -> None:
project = build_ex1a_canti2d_eq()
project.validate_references()
gm = next(ts for ts in project.time_series if ts.id == 2)
assert isinstance(gm, PathTimeSeries)
print(f"Built '{project.meta.name}'")
print(f" Ground motion file: {GROUND_MOTION_FILE.name}")
print(f" Reference Tcl: {REFERENCE_TCL.name}")

View file

@ -209,6 +209,7 @@ def main() -> None:
project = build_ex1b_portal2d()
project.validate_references()
gm = next(ts for ts in project.time_series if ts.id == 3)
assert isinstance(gm, PathTimeSeries)
print(f"Built '{project.meta.name}'")
print(f" Gravity + pushover + earthquake cases: {len(project.analyses)}")
print(f" Ground motion file: {GROUND_MOTION_FILE.name}")

View file

@ -231,6 +231,7 @@ def main() -> None:
project = build_ex2a_canti2d_elastic_element()
project.validate_references()
gm = next(ts for ts in project.time_series if ts.id == 3)
assert isinstance(gm, PathTimeSeries)
print(f"Built '{project.meta.name}'")
print(f" LCol={L_COL}, Weight={WEIGHT}, ACol={A_COL:.1f}, Ec={E_C:.3f}")
print(f" Gravity + pushover + earthquake cases: {len(project.analyses)}")

View file

@ -253,6 +253,7 @@ def main() -> None:
project = build_ex2b_canti2d_inelastic_section()
project.validate_references()
gm = next(ts for ts in project.time_series if ts.id == 400)
assert isinstance(gm, PathTimeSeries)
print(f"Built '{project.meta.name}'")
print(
f" LCol={L_COL}, EA={EA_COL:.1f}, My={MY_COL:.1f}, "

View file

@ -301,6 +301,7 @@ def main() -> None:
project = build_ex2c_canti2d_inelastic_fiber_section()
project.validate_references()
gm = next(ts for ts in project.time_series if ts.id == 400)
assert isinstance(gm, PathTimeSeries)
print(f"Built '{project.meta.name}'")
print(
f" LCol={L_COL}, ACol={A_COL:.1f}, Iz={IZ_COL:.1f}, "

View file

@ -4,7 +4,7 @@ build-backend = "hatchling.build"
[project]
name = "otko"
version = "0.1.0"
dynamic = ["version"]
description = "OTKO — a modern, SAP2000-style desktop GUI for OpenSeesPy."
readme = "README.md"
requires-python = ">=3.10"
@ -42,10 +42,7 @@ gui = [
"vtk>=9.3",
"pyqtgraph>=0.13",
"imageio[ffmpeg]>=2.34",
# scipy and pandas are listed for forward-compatibility; they are not
# currently imported by any module in this repo (phantom deps as of 2026-06-15).
"scipy>=1.11",
"pandas>=2.1",
"plotly>=5.18",
]
dev = [
"pytest>=7.4",
@ -55,6 +52,7 @@ dev = [
"mypy>=1.8",
"pre-commit>=3.6",
"hatch>=1.9",
"tomli>=2.0; python_version < '3.11'",
]
docs = [
"sphinx>=7.2",
@ -72,6 +70,9 @@ Issues = "https://github.com/ogunc/otko/issues"
[tool.hatch.build.targets.wheel]
packages = ["src/otko"]
[tool.hatch.version]
path = "src/otko/_const.py"
# ─────────── Ruff ───────────
[tool.ruff]
line-length = 100
@ -89,7 +90,25 @@ select = [
"SIM", # simplify
"RUF", # ruff-specific
]
ignore = ["E501"] # line length handled by formatter
ignore = [
"E501", # line-length handled by the formatter
"RUF001", # ambiguous unicode: engineering notation (×, ≈, ²) is deliberate
"RUF002",
"RUF003",
]
[tool.ruff.lint.per-file-ignores]
# Engineering symbols (A, I, L, E, P) and `importorskip`-then-import blocks
# are normal in tests.
"tests/**" = ["E402", "E741", "N802", "N806", "N815"]
# Qt requires camelCase signal names and PascalCase event overrides.
"src/otko/views/**" = ["N802", "N815"]
"src/otko/viewmodels/**" = ["N815"]
# Material fields mirror the OpenSees parameter names verbatim (cR1, epsU, ...).
"src/otko/core/materials/__init__.py" = ["N815"]
# Engineering symbols in numeric code: L (length), Iz/Iy (second moments).
"src/otko/services/section_properties.py" = ["N806"]
"src/otko/views/canvas3d/model_renderer.py" = ["N802", "N806", "N815"]
[tool.ruff.format]
quote-style = "double"
@ -97,12 +116,13 @@ quote-style = "double"
# ─────────── Mypy ───────────
[tool.mypy]
python_version = "3.10"
strict = true
warn_unused_ignores = true
warn_return_any = true
disallow_untyped_defs = true
warn_unused_configs = true
plugins = []
[[tool.mypy.overrides]]
module = ["otko.core.*", "otko.services.*", "otko.viewmodels.*"]
strict = true
[[tool.mypy.overrides]]
module = ["openseespy.*", "pyvista.*", "pyvistaqt.*", "vtk.*", "pyqtgraph.*"]
ignore_missing_imports = true
@ -121,3 +141,8 @@ markers = [
branch = true
source = ["src/otko"]
omit = ["src/otko/views/*"] # GUI excluded from coverage targets
[tool.coverage.report]
exclude_lines = ["if TYPE_CHECKING:", "raise NotImplementedError"]
# Conservative floor for the headless suite; raise deliberately with evidence.
fail_under = 50

View file

@ -0,0 +1,383 @@
# 15 — Rebuild Adoption Plan
> **Status:** proposed. **Source of truth for intent:** the greenfield
> rebuild specs at `~/Sync/otko-development/specifications` (`00`–`14`).
> This document plans how to bring that rebuild's good ideas into **this**
> repo without breaking the working app.
>
> Requirement IDs are shown without brackets for brevity (e.g. `PKG-032` =
> `[PKG-032]` in the rebuild set) so they stay grep-able.
---
## 1. Context
| | This repo (`~/Sync/otko`) | Rebuild (`~/Sync/otko-development`) |
|---|---|---|
| Role | **Working app** — the primary deliverable | Greenfield spec-conformant attempt |
| VCS | Not a git repo in this checkout | `rebuild` branch, commit `725040e` |
| License | AGPL-3.0 | MIT (+ `NOTICE`) |
| Python | 3.10–3.12 | 3.12 only |
| Project file | `.osmodel` | `.otko` |
| Scope | Superset: static, modal, **transient, pushover, response-spectrum**, quad/shell-adjacent elements, HDF5 | Narrow v1: static + modal; reports, combinations, self-weight, units display |
| src LOC | ~37k | ~25k |
| Gate | deps not installed here; **57 collection errors** locally | `ruff` passes; `mypy`/`pytest` deps missing locally |
The rebuild is *ahead* on: **reporting/Typst, load combinations, self-weight,
display-unit conversion, closed-form diagrams, modal mass participation,
progress/cancel, local-axis editing, viewmodel separation, and quality
gates**. It is *behind* on everything this repo already ships. Therefore the
plan is a **selective harvest**, not a merge.
## 2. Goal and non-goals
**Goal.** Adopt the rebuild's good capabilities into this repo, incrementally,
each phase independently shippable, with the existing app and tests staying
green.
**Non-goals.**
- Do **not** rewrite this repo to the rebuild's architecture (`ProjectStore`,
frozen `Project`, `CommandFactory`, `services/scene.py`,
`services/diagram_data.py` substrates).
- Do **not** replace the runner/export/results surface — this repo's is a
strict superset.
- Do **not** change `.osmodel`, the AGPL license, or the Python 3.10–3.12
support range as part of this plan.
## 3. Principles
1. **Additive, adapt, don't copy.** Port algorithms/patterns; re-type to this
repo's APIs (`StaticResults`/`ModalResults`, mutable `Project`,
4-value `UnitSystem`, `element_forces.DiagramData`).
2. **Protect the working app.** Every phase keeps `pytest -m "not slow"` and
the GUI smoke tests green. New optional deps stay **lazy** so headless
installs are unaffected.
3. **One phase = one branch = one shippable PR**, with tests and a gate.
4. **Trace every item to a rebuild spec ID** so "is it done?" stays mechanical.
5. **License hygiene.** MIT→AGPL-3.0 is one-way compatible: preserve the MIT
copyright/permission notice for ported files (`NOTICE` + per-file header).
Never copy this repo's AGPL code back into the MIT rebuild.
6. **Establish version control first.** This checkout has **no `.git`**. Before
any work, create a repo/branch per `AGENTS.md` (`origin` is the self-hosted
Forgejo; work on `feat/<topic>`, PR against `main`).
## 4. Adoption matrix
Verdicts: **PORT** (near-verbatim), **ADAPT** (re-type/re-wire), **REIMPL**
(reimplement against this repo's APIs), **SKIP** (intentional divergence).
Size: **S** ≈ hours · **M** ≈ a few days · **L** ≈ 1–2+ weeks.
### 4.1 Quality / foundations
| # | Capability | Rebuild source | Verdict | Phase | Size | Spec IDs |
|---|---|---|---|---|---|---|
| Q1 | Single-source version + solver pin via `_const.py` | `src/otko/_const.py`, `pyproject.toml` `[tool.hatch.version]` | ADAPT | 0 | S | PKG-032/033, RUN-085 |
| Q2 | Layering/import-discipline AST tests | `tests/unit/test_architecture.py` (246) | ADAPT (paths) | 0 | M | ARC-001..003/006/011/060..064 |
| Q3 | CI split into 5 jobs incl. missing **`type` (mypy)** job; mark integration `slow` | `.github/workflows/ci.yml`, `tests/unit/test_ci_config.py`, `test_meta_gates.py` | ADAPT | 0 | M | TST-004/031/040/041 |
| Q4 | conftest hardening (offscreen default; `ops.wipe()` in teardown) | `tests/conftest.py` | ADAPT | 0 | S | TST §7 |
| Q5 | `tests/services/` split from `tests/unit/` | tests layout | ADAPT | 0 | M | TST-002 |
| Q6 | Standalone docs + docs test | `docs/QUICK_GUIDE.md`, `docs/README.md`, `tests/unit/test_docs.py` | ADAPT | 0 | M | — |
| Q7 | `NOTICE` + attribution for ported MIT code | `NOTICE` | REIMPL (AGPL wording) | 0 | S | PKG-042 |
| Q8 | Drop phantom `scipy`/`pandas` from `[gui]` | `pyproject.toml`, `tests/unit/test_packaging.py` | ADAPT | 0 | S | PKG-011 |
| Q9 | Scoped mypy overrides + coverage `fail_under` | `pyproject.toml` | ADAPT | 0 | S | TST-031/032 |
| Q10 | Packaging config tests subset (entrypoint, line length, single-source) | `tests/unit/test_packaging.py` (117) | ADAPT | 0 | S | PKG-030..033 |
| Q11 | Spec-ID traceability harness | `tests/unit/test_spec_traceability.py` (343) | REIMPL | 8 | L | TST-013/024/025 |
| Q12 | Performance probes | `tests/performance/*` | ADAPT | 8 | L | OVR-010..014 |
### 4.2 Services / engine
| # | Capability | Rebuild source | Verdict | Phase | Size | Spec IDs |
|---|---|---|---|---|---|---|
| S1 | `SolverSession` Protocol + `Real`/`Recording` sessions | `services/solver_session.py` (154) | PORT | 1 | S | RUN-003/010/011/012 |
| S2 | Persistence refuses to save an invalid model + resolved path | `services/persistence.py` (63) | ADAPT | 1 | S | PER-021/022 |
| S3 | Result fields: `StaticResults.time`, modal `ModeParticipation` record | `services/results.py` (138) | ADAPT | 1 | S | RES-001/003/005, ANL-012 |
| S4 | Component-less element forces = absent, not zeros | `runner/run.py` | ADAPT | 1 | S | RUN-053 |
| S5 | `progress(int)` + `cancelled` + `isInterruptionRequested()` + `cancel()`; real Cancel UX | `services/qt_workers.py`, `viewmodels/analysis_vm.py`, `views/dialogs/run.py` | ADAPT | 2 | M | ANL-031..036, ARC-032/033, UX-081 |
| S6 | Modal mass participation unified with response-spectrum path | `runner/modal.py` (466), `services/results.py` | ADAPT | 2 | M | RUN-062/070..072, ANL-013 |
| S7 | Display-unit layer + `GRAVITY` + `ProjectMeta.display` (adapter over 4-system enum) | `core/units.py` (298) | ADAPT | 3 | M | UNT-003/004/010/020..024/030..032 |
| S8 | Closed-form diagram math (`N/V/M/T` shapes + extrema) | `core/diagrams.py` (436) | PORT | 4 | S | RES-010/011/012 |
| S9 | Backend-neutral `diagram_data` service + `render_matplotlib` | `services/diagram_data.py` (400) | REIMPL | 4 | M | RES-020..024/030..032, CAN-084 |
| S10 | **Report pipeline** CSV / PNG(≥300 dpi) / SVG / Typst (+optional PDF) + case-report action | `services/report/*` (1141) | PORT + ADAPT deps | 5 | M | RES-040..047/050/051/061 |
| S11 | Local axis: `LocalAxis`, element field, geomTransf dedup by `(type,vecxz,roll)`, editor + triad | `core/geometry/local_axis.py`, `runner/emit.py` | ADAPT | 6 | M | GEO-060..064, DOM-040 |
| S12 | Load combinations entity + commands + runner materialisation | `core/combinations.py` (44), `commands/combinations.py` (146) | PORT + ADAPT | 7 | M | LOD-050..058, ANL-001, RUN-050 |
| S13 | Self-weight service + regenerate command | `services/self_weight.py` (364) | REIMPL | 7 | M | UNT-040..045, LOD-011/040..043 |
| S14 | Material `rho` coverage for self-weight | `core/materials` | ADAPT | 7 | S | UNT-041 |
### 4.3 UI / UX
| # | Capability | Rebuild source | Verdict | Phase | Size | Spec IDs |
|---|---|---|---|---|---|---|
| U1 | Pure formatting helpers (`DOF/MASS/RESTRAINT_LABELS`, number/float parse) | `views/formatting.py` (84) | PORT | 0 | S | UX-033/062 |
| U2 | Timestamped, severity-tagged console | `views/docks/console.py` (103) | PORT | 0 | S | UX-042 |
| U3 | `ValidatedDialog` base (help line, inline errors, OK-gating, unit suffix) | `views/dialogs/base.py` (191) | PORT + staged | 8 | M | UX-060..064 |
| U4 | `ResultsVM` per-case handle cache; `CanvasVM` selection ownership | `viewmodels/results_vm.py`, `canvas_vm.py` | REIMPL | 8 | M | RES-005, CAN-042/041 |
| U5 | Overlay helpers: ghost undeformed, unit-labelled diagram extremes, zero hint, pattern-filtered loads | `views/canvas/overlays.py` (684) | REIMPL | 8 | M | CAN-052/062/082/083, LOD-063 |
| U6 | `QSettings` layout persistence + `closeEvent` save prompt | `views/main_window.py` | PORT | 0 | S | UX-013, PER-032/033, ARC-050 |
| U7 | `ThemeManager` + dark icon set | `views/resources/theme.py`, `icons.py` | ADAPT (verify icon provenance) | 8 | S | UX-070/071/072 |
| U8 | Thicken `ProjectViewModel` (move `action_handlers` logic into VM methods) | `viewmodels/project_vm.py` (713) | REIMPL | 8 | L | UX-001/002/005, ARC-005/020..022 |
| U9 | Analysis VM status + Simple/Advanced control fields | `viewmodels/analysis_vm.py` | ADAPT | 8 | M | ANL-021/050..054, UX-037 |
### 4.4 Explicitly deferred / skipped
| Item | Verdict | Why |
|---|---|---|
| Polygon-first sections + `services/sections_mesh.py` (opstool GPLv3) | DEFER (Phase 9, conditional) | Schema-breaking redesign; adds GPLv3/runtime deps; not report-critical |
| Frozen `Project`/entities + `ProjectStore`/`CommandFactory` rewrite | DEFER (not recommended now) | Large coordinated rewrite of 43 commands + all call sites; low user-visible value vs risk |
| Canvas backend Protocol + `plotly_backend.py` + `services/scene.py` | DEFER (Phase 9) | Requires core + views surgery; plotly pulls QtWebEngine (known teardown SIGSEGV) |
| `.otko` file suffix / greenfield `Project` schema (PER-001/006) | SKIP | Breaks `.osmodel` corpus and compatibility; do only as an explicit user-approved migration |
| Rebuild `runner/export.py` | SKIP | This repo's `export.py` is a superset (5 case types, `.py`+`.tcl`) |
| Rebuild static/modal HDF5 | SKIP | Rebuild has none; this repo's transient HDF5 is already better |
| Rebuild slim `materials`/`analysis`/`loads` unions | SKIP | Dropping `HystereticSM`, Transient/Pushover/ResponseSpectrum, Path/Imposed patterns would regress shipped features |
| MIT license / py3.12-only / single-OS CI assertions | SKIP | Intentional differences (AGPL, 3.10–3.12, 3-OS matrix) |
## 5. Phases
### Phase 0 — Foundations, safety net, quick wins
**Why first:** makes later phases verifiable and cheap; all items are
additive and low risk. Also unblocks the mpy gate that currently does nothing.
- **Prep:** initialise git and a `feat/rebuild-adoption` branch (§3.6).
- **Q1** Create `src/otko/_const.py` (`__version__`, `OPENSEESPY_VERSION`),
switch `pyproject.toml` to `dynamic = ["version"]` + `[tool.hatch.version]`,
and import the pin in `services/export.py` (currently duplicated at
`export.py:52`). Spec: PKG-032/033, RUN-085.
- **Q2** Port `tests/unit/test_architecture.py`; adapt `CANVAS = views/canvas3d`
path and `services/{_emit,_run}.py` paths. Expect it to flag three existing
offenders — decide per item: `OSS_PICK_DEBUG` env var in
`views/canvas3d/model_canvas.py:29` (ARC-052), `QUndoStack` outside VMs, and
the canvas path. Either fix or add a documented, narrow allowlist.
- **Q3** Split CI: `lint` (+`ruff format --check`), **`type` (mypy scopes)**,
`test-headless` (`pytest tests/unit tests/services -m "not slow"`),
`test-gui` (`xvfb-run pytest tests/gui`), `test-integration`
(`pytest tests/integration -m slow`). Add `pytestmark = pytest.mark.slow` to
integration modules. Keep the existing 3-OS × 3.10–3.12 matrix and the long
Linux Qt apt list.
- **Q4** `tests/conftest.py`: `QT_QPA_PLATFORM=offscreen` default; move
`ops.wipe()` to teardown (this repo currently wipes before each test).
- **Q5** Move service-level tests (`runner_translation`, `persistence`,
`results`, `export`, …) into `tests/services/`; update CI and `AGENTS.md`.
- **Q6** Add `docs/QUICK_GUIDE.md` + `docs/README.md` (rewrite `.otko` →
`.osmodel`, rebuild-only APIs → this repo's), update `CONTRIBUTING.md` with
the 5-layer table + install/run/test commands; port `test_docs.py`.
- **Q7** Add `NOTICE` crediting MIT `otko-development` for ported files;
add a per-file header to ported files (`# Ported from otko-development
(MIT), (c) 2026 OTKO contributors`).
- **Q8/Q9/Q10** `pyproject.toml`: drop `scipy`/`pandas` from `[gui]`; convert
mypy to scoped `strict` overrides (core/services/viewmodels); add
`[tool.coverage.run] fail_under`; port the `test_packaging.py` subset that
applies (entrypoint, version single-source, line length).
- **U1/U2/U6** Port `views/formatting.py`; timestamp the console
(`views/docks/console.py` into the existing dock); add `save_layout`/
`restore_layout` (`QSettings`) and a `closeEvent` unsaved-changes prompt.
**Gate:** `ruff check src tests`, `ruff format --check src tests`,
`mypy src/otko/core src/otko/services src/otko/viewmodels`,
`pytest -m "not slow"`, arch test, and the new packaging/docs tests pass.
### Phase 1 — Cheap, safe services wins
- **S1** Port `services/solver_session.py` (`SolverSession`, `RealSolverSession`,
`RecordingSolverSession`). Inject into `OpenSeesRunner` while keeping the
existing `ops_module=` shim; consolidate the two wipe paths
(`_emit.py:105` → `session.reset()`). Tests:
`tests/services/test_solver_session.py`.
- **S2** In `services/persistence.py::save_project`, call
`validate_references()` first and refuse to write an invalid model,
reporting the problem list (PER-022); return the resolved path (PER-021).
- **S3** Extend `StaticResults` with `time` and add a `ModeParticipation`
record to `ModalResults` (keep the existing dataclass names — consumers in
`views/docks/results_panel.py` dispatch on them).
- **S4** `RUN-053`: return an absent (not zero-filled) force entry when a
component is missing; guard the static `eleForce` fallback.
**Gate:** new service tests + existing runner/persistence tests green; runner
integration suite unchanged.
### Phase 2 — Progress & cancellation
- **S5** Add to `services/qt_workers.py`: `progress(int)`, `cancelled`,
an `_interruption_requested()` check between steps, and a bounded teardown
wait. Add `AnalysisRunner.cancel()` (calls `QThread.requestInterruption()`).
Wire progress callbacks through static (`RUN-054`) and modal (`RUN-063`)
runs. Replace the indeterminate bar in `views/dialogs/run_analysis.py` with
a real progress bar + working Cancel (UX-081). Add per-case status to the
case manager (ANL-050).
- **S6** Unify modal mass participation: put the rebuild's participation
math into one service and have **both** modal results and the existing
response-spectrum path (`services/spectrum.py`) consume it. Add the ANL-013
no-mass warning.
**Gate:** cancel leaves no partial handle; progress reaches 100; participation
sums to 1.0 against a hand-checked example.
### Phase 3 — Units display layer + GRAVITY
- **S7** Port the display machinery from `core/units.py` **as an adapter**:
keep this repo's 4-value `UnitSystem` and map families
(`SI_M_N|SI_MM_N → METRIC`, `US_FT_KIP|US_IN_KIP → IMPERIAL`); add
`GRAVITY`, `display(value, system, quantity, pref)`, `DisplayPrefs`; add
`ProjectMeta.display` (persisted). Retarget the status-bar/menu unit picker
so it writes **display prefs**, not the stored `meta.units` (fixes UNT-031).
- Watch-outs: rebuild uses `StrEnum` (3.11+) — do **not** adopt it (this repo
targets 3.10). `export.py` currently embeds `meta.units.value`; keep that
but source labels via the new API.
**Gate:** switching display units changes every label and leaves
`project.model_dump()` byte-identical; old 4-system `.osmodel` files still load.
### Phase 4 — Closed-form diagrams
- **S8** Port `core/diagrams.py` near-verbatim (pure numpy, self-contained).
- **S9** Build a new `services/diagram_data.py` (REIMPL) on top of this repo's
`StaticResults` + load patterns, reusing `core/diagrams` for interior
shapes/extrema. Run it **alongside** `services/element_forces.py`, migrate
`views/canvas3d/diagram_renderer.py` and `views/dock_manager.py` behind a
flag, then retire the old extractor once the on-screen output matches.
**Gate:** port `test_diagram_data.py` (end-values, Vz/My plane, axial,
all-six components, shared data, auto-scale); on-screen diagrams unchanged.
### Phase 5 — Reporting pipeline ★ (the headline v1 capability)
- **S10** Port `services/report/{__init__,csv,figures,typst,pdf}.py`. Add a
`[reports]` extra (`matplotlib`, `imageio-ffmpeg`; Typst CLI optional, probed
via `shutil.which`, graceful degradation per RES-046). Expose a "case report"
action that produces the full set: CSV tables, PNG (≥300 dpi), SVG, a Typst
document (PDF optional), conditional static/modal sections.
- Dependencies: **Phase 3** (units) and **Phase 4** (diagrams) must land first;
reuse **Phase 1** result fields.
**Gate:** the reference test — cantilever moment **50 kN·m at the fixed end**
(RES-061) — plus report generation off the GUI thread and preservation of the
original model file. Port `test_report_{csv,figures,typst,modal}.py` and the
`test_full_report.py` / `test_report_reference.py` integration tests.
### Phase 6 — Local axis (user-editable)
- **S11** Port `core/geometry/local_axis.py`; add
`local_axis: LocalAxis` to the frame elements (`ElasticBeamColumn`,
`ForceBeamColumn`, `DispBeamColumn`, `BeamWithHinges`). Change
`services/_emit.py` geomTransf to read the explicit axis and dedup by
`(type, vecxz, roll_deg)` instead of auto-deriving. Update the renderer
triad (its current `getattr(el, "vecxz")` at `model_renderer.py:727` is dead
code) and add an editor (property dock / dialog).
- **Critical migration risk:** a blind default `vecxz=(0,0,1)` is parallel to
a vertical member's axis and would break existing vertical models. Use a
**safe default rule** (e.g. derive the default from geometry exactly as the
runner does today, then only override when the user sets it) so existing
`.osmodel` files keep loading and producing identical results.
**Gate:** existing frame/eigen integration tests unchanged; new
`test_local_axis_parallel_rejected` + `test_geom_transf_dedup_by_combination`.
### Phase 7 — Load combinations + self-weight
- **S12** Port `core/combinations.py` and `commands/combinations.py`; add
`Project.combinations`; extend `validate_references`; add
`StaticCase.combination_id` with the XOR invariant (combination **or**
patterns+factors, ANL-001); materialise scaled loads in the runner
(LOD-054) without regressing the existing per-pattern factor path.
- **S13** Reimplement `services/self_weight.py` against this repo's types:
`w = ρ·A·g` distributed local for frames, equivalent nodal loads for trusses
(UNT-042/043), a `ConstantTimeSeries` + `PlainLoadPattern`, regeneration that
replaces the prior pattern (LOD-041), no-density/unresolved reporting
(LOD-042), and the gravity constant recorded in the description (UNT-045).
Add a `RegenerateSelfWeightCommand` (undoable).
- **S14** `ElasticIsotropic` currently is the only material with `rho`
(`materials/__init__.py:28`); add `rho` to the other self-weight-capable
materials, or report them as missing density.
- Depends on **Phase 3** (`GRAVITY`) and **Phase 6** (correct local projection).
**Gate:** port `test_loads_combinations.py` and `test_self_weight.py` (minus
the combination assertion until S12 lands); verify superposition matches a
hand calculation.
### Phase 8 — UI/UX adoption (larger, optional but valuable)
- **U3** `ValidatedDialog` base + migrate dialogs incrementally (unit suffix
via the Phase 3 API).
- **U4** Extract `ResultsVM` (per-case handle cache) and `CanvasVM` (selection
ownership) as supersets of the current state holders so existing call sites
keep working.
- **U5** Reimplement overlay **pure helpers** against this repo's
`deformation`/`element_forces`: ghost undeformed (CAN-062), unit-labelled
diagram extremes (CAN-082), zero-component hint (CAN-083), and
pattern-filtered load display (CAN-052/LOD-063). Unit-test them display-free.
- **U7** Adopt `ThemeManager` + a dark icon set — **verify SVG provenance and
license first** before copying any icon assets.
- **U8/U9** Thicken `ProjectViewModel` (move `action_handlers.py` logic into VM
methods, one command family at a time) and add analysis-case status /
Simple-vs-Advanced controls.
- **Q11/Q12** Spec-ID traceability harness and performance probes (only if the
team commits to the `[AREA-NNN]` convention and a perf budget).
**Gate:** GUI tests under `xvfb-run`; VM logic unit-tested without a display.
### Phase 9 — Deferred, only on explicit decision
- Polygon-first sections + `sections_mesh` (opstool **GPLv3**, lazy import,
optional `[sections]` extra; ensure AGPL compatibility and attribution).
- Frozen `Project`/`ProjectStore`/`CommandFactory` migration.
- Canvas backend Protocol + plotly backend + `services/scene.py`.
Revisit only after Phases 0–8 are stable and if the value justifies the blast
radius documented in the dossiers.
## 6. Dependency graph
```
Phase 0 (foundations)
│
├─► Phase 1 (sessions, persistence, result fields)
│ │
│ ├─► Phase 2 (progress/cancel, mass participation)
│ │
│ └─► Phase 3 (units display + GRAVITY) ──┐
│ │
│ Phase 4 (diagrams) ────────────────┤
│ ▼
│ Phase 5 (REPORTING) ★
│
├─► Phase 6 (local axis) ──┐
│ ▼
└─► Phase 7 (combinations + self-weight)
│
▼
Phase 8 (UI/UX) ──► Phase 9 (deferred)
```
**Critical path to the v1 promise (a printable case report):**
`Phase 3 → Phase 4 → Phase 5`, with `Phase 1` as a cheap prerequisite and
`Phase 2` interleavable.
## 7. Licensing & attribution
- This repo is **AGPL-3.0**; the rebuild is **MIT**. MIT code may be
incorporated into an AGPL work — **one-way**. Preserve the MIT notice:
add a `NOTICE` (Phase 0) and a short provenance header to each ported file.
- **Never** copy this repo's AGPL code back into the MIT rebuild.
- `opstool` is **GPLv3** (only relevant to deferred `sections_mesh`); GPLv3 ↔
AGPLv3 are compatible. Keep it lazy/optional and do not vendor its source.
- Verify the provenance/license of any copied **icon/SVG assets** before
adopting the dark icon set (U7).
## 8. Risks and mitigations
| Risk | Mitigation |
|---|---|
| Big-bang port destabilises the working app | Strict additive phases; feature flags for diagram/report migration; keep old paths until parity is proven |
| Freezing/command rewrite stalls progress | Explicitly deferred (Phase 9); combinations/self-weight do **not** require it |
| Units enum change corrupts stored models | Keep 4-value enum; add a family mapping + `DisplayPrefs`; byte-identical dump test |
| Local-axis default breaks vertical members | Derive default per-element as today; override only on explicit user set; regression tests on vertical frames |
| opstool private-API coupling / GPL | Deferred; pin version + thin adapter; lazy import; attribution |
| Report pipeline pulls GUI deps into headless | Keep `matplotlib`/Typst optional and imported lazily; headless CI must pass without `[reports]` |
| `StrEnum` / 3.11-only syntax | Target py3.10: avoid `StrEnum`, `zip(strict=)`, etc. |
| No VCS in this checkout | Initialise git + branch before any code changes |
| Tests can't run locally (deps missing) | Phase 0 fixes env expectations; run gates in CI |
## 9. Tracking
Adopt the rebuild's `.otko-build/tasks.json` **pattern** (schema, gates,
`{id, phase, layer, specs, title, tests, status, deps}`), seeded from this
plan. Each task names the phase, the spec IDs it implements, and its tests
(the rebuild's `tasks.json` is a working reference). Keep build state out of
versioned source (`.gitignore` it) or commit it deliberately — team choice.
## 10. Recommended first step
Execute **Phase 0** in one branch. It is almost entirely additive, it turns
the currently-inert mypy/CI gate into a real one, and it establishes the
attribution and docs baseline the later ports depend on. Then proceed
`1 → 2 → 3 → 4 → 5`, pulling Phase 6/7 forward only if self-weight is needed
before reporting.

37
specifications/README.md Normal file
View file

@ -0,0 +1,37 @@
# OTKO — specifications (this repo)
This folder holds **OTKO's own planning documents**. It is deliberately
separate from the greenfield rebuild spec set at
`~/Sync/otko-development/specifications` (docs `00`–`14`), which stays the
reference for *what a conformant rebuild looks like*. Requirement IDs of
the form `[AREA-NNN]` cited in this folder refer to that rebuild set.
## Why this folder exists
`~/Sync/otko` (this repo) is the **working, feature-rich app** and is the
primary deliverable. `~/Sync/otko-development` is a **greenfield rebuild**
that conforms closely to the rebuild specs but is less capable in several
areas (transient/pushover/response-spectrum, richer element/material
coverage, `.osmodel` corpus, HDF5). The goal of the plan below is to
**harvest the rebuild's good, spec-conformant capabilities into this app
without breaking what already works** — not to rewrite this app to the
rebuild's architecture.
## Documents
| # | Document | Purpose |
|---|---|---|
| 15 | [15-rebuild-adoption-plan.md](15-rebuild-adoption-plan.md) | Dependency-ordered plan for porting rebuild capabilities into this repo, with adoption matrix, phases, gates, risks and explicit skips. |
## Ground rules (summary — see doc 15 §3)
- **Additive, never replacement.** This repo is a superset of the rebuild
in the solver/runner/export surface; protect that.
- **Keep the working app working:** `.osmodel` format, AGPL-3.0 license,
Python 3.10–3.12 support, existing tests green.
- **Adapt, don't copy:** re-type ported code to this repo's APIs
(`StaticResults`/`ModalResults`, mutable `Project`, 4-value `UnitSystem`).
- **One phase = one branch = independently shippable**, each with its own
tests and gate.
- **License hygiene:** the rebuild is MIT, this repo is AGPL-3.0; MIT→AGPL
is compatible, but ported files need attribution (see doc 15 §7).

View file

@ -1,3 +1,5 @@
"""OTKO — a desktop GUI for OpenSeesPy."""
__version__ = "0.1.0"
from otko._const import __version__
__all__ = ["__version__"]

13
src/otko/_const.py Normal file
View file

@ -0,0 +1,13 @@
# Ported from otko-development (MIT), (c) 2026 OTKO contributors
"""Single source of truth for OTKO's version and the pinned solver version.
Defines the package version and the pinned OpenseesPy version exactly once
so neither is duplicated as a literal anywhere else in the source.
"""
from __future__ import annotations
__version__ = "0.1.0"
#: Pinned OpenseesPy version the application targets.
OPENSEESPY_VERSION = "3.8.0.0"

View file

@ -6,6 +6,11 @@ from otko.commands.analysis import (
UpdateAnalysisCaseCommand,
)
from otko.commands.base import ProjectCommand
from otko.commands.combinations import (
AddCombinationsCommand,
DeleteCombinationsCommand,
UpdateCombinationCommand,
)
from otko.commands.constraints import (
AddEqualDOFConstraintCommand,
DeleteEqualDOFConstraintCommand,
@ -24,14 +29,6 @@ from otko.commands.grid import (
SetCoordSystemsCommand,
SetGridSystemCommand,
)
from otko.commands.series_and_patterns import (
AddLoadPatternCommand,
AddTimeSeriesCommand,
DeleteLoadPatternCommand,
DeleteTimeSeriesCommand,
UpdateLoadPatternCommand,
UpdateTimeSeriesCommand,
)
from otko.commands.loads import (
AddElementLoadsCommand,
AddNodalLoadsCommand,
@ -58,6 +55,14 @@ from otko.commands.sections import (
DeleteSectionsCommand,
UpdateSectionCommand,
)
from otko.commands.series_and_patterns import (
AddLoadPatternCommand,
AddTimeSeriesCommand,
DeleteLoadPatternCommand,
DeleteTimeSeriesCommand,
UpdateLoadPatternCommand,
UpdateTimeSeriesCommand,
)
from otko.commands.transforms import (
MirrorCommand,
MoveNodesCommand,
@ -67,25 +72,50 @@ from otko.commands.transforms import (
__all__ = [
"ProjectCommand",
"AddNodesCommand", "DeleteNodesCommand", "SetRestraintCommand", "SetMassCommand",
"AddNodesCommand",
"DeleteNodesCommand",
"SetRestraintCommand",
"SetMassCommand",
"UpdateNodeFieldsCommand",
"AddElementsCommand", "DeleteElementsCommand",
"AssignSectionCommand", "AssignMaterialCommand",
"ReplaceElementsCommand", "ConvertElementTypeCommand",
"AddElementsCommand",
"DeleteElementsCommand",
"AssignSectionCommand",
"AssignMaterialCommand",
"ReplaceElementsCommand",
"ConvertElementTypeCommand",
"UpdateElementFieldsCommand",
"AddMaterialsCommand", "DeleteMaterialsCommand", "UpdateMaterialCommand",
"AddSectionsCommand", "DeleteSectionsCommand", "UpdateSectionCommand",
"AddNodalLoadsCommand", "AddElementLoadsCommand",
"UpdateNodalLoadCommand", "DeleteNodalLoadsCommand",
"UpdateElementLoadCommand", "DeleteElementLoadsCommand",
"MoveNodesCommand", "ReplicateCommand", "MirrorCommand", "Plane",
"AddAnalysisCasesCommand", "DeleteAnalysisCasesCommand", "UpdateAnalysisCaseCommand",
"AddMaterialsCommand",
"DeleteMaterialsCommand",
"UpdateMaterialCommand",
"AddSectionsCommand",
"DeleteSectionsCommand",
"UpdateSectionCommand",
"AddNodalLoadsCommand",
"AddElementLoadsCommand",
"UpdateNodalLoadCommand",
"DeleteNodalLoadsCommand",
"UpdateElementLoadCommand",
"DeleteElementLoadsCommand",
"MoveNodesCommand",
"ReplicateCommand",
"MirrorCommand",
"Plane",
"AddAnalysisCasesCommand",
"DeleteAnalysisCasesCommand",
"UpdateAnalysisCaseCommand",
"AddCombinationsCommand",
"DeleteCombinationsCommand",
"UpdateCombinationCommand",
"SetGridSystemCommand",
"SetCoordSystemsCommand",
"AddTimeSeriesCommand", "AddLoadPatternCommand",
"UpdateTimeSeriesCommand", "DeleteTimeSeriesCommand",
"UpdateLoadPatternCommand", "DeleteLoadPatternCommand",
"AddTimeSeriesCommand",
"AddLoadPatternCommand",
"UpdateTimeSeriesCommand",
"DeleteTimeSeriesCommand",
"UpdateLoadPatternCommand",
"DeleteLoadPatternCommand",
"AddEqualDOFConstraintCommand",
"UpdateEqualDOFConstraintCommand", "DeleteEqualDOFConstraintCommand",
"UpdateEqualDOFConstraintCommand",
"DeleteEqualDOFConstraintCommand",
"SetUnitsCommand",
]

View file

@ -13,8 +13,7 @@ if TYPE_CHECKING:
class AddAnalysisCasesCommand(ProjectCommand):
"""Add one or more analysis cases."""
def __init__(self, vm: "ProjectViewModel", cases: list[Any], *,
text: str | None = None) -> None:
def __init__(self, vm: ProjectViewModel, cases: list[Any], *, text: str | None = None) -> None:
super().__init__(vm, text or f"Add {len(cases)} analysis case(s)")
self._cases = list(cases)
@ -35,19 +34,16 @@ class AddAnalysisCasesCommand(ProjectCommand):
class DeleteAnalysisCasesCommand(ProjectCommand):
"""Remove a set of analysis cases."""
def __init__(self, vm: "ProjectViewModel", case_ids: set[int]) -> None:
def __init__(self, vm: ProjectViewModel, case_ids: set[int]) -> None:
super().__init__(vm, f"Delete {len(case_ids)} analysis case(s)")
self._case_ids = set(case_ids)
self._removed: list[tuple[int, Any]] = []
def redo(self) -> None:
self._removed = [
(i, c) for i, c in enumerate(self.project.analyses)
if c.id in self._case_ids
]
self.project.analyses[:] = [
c for c in self.project.analyses if c.id not in self._case_ids
(i, c) for i, c in enumerate(self.project.analyses) if c.id in self._case_ids
]
self.project.analyses[:] = [c for c in self.project.analyses if c.id not in self._case_ids]
self._notify()
def undo(self) -> None:
@ -60,7 +56,7 @@ class DeleteAnalysisCasesCommand(ProjectCommand):
class UpdateAnalysisCaseCommand(ProjectCommand):
"""Replace an analysis case at a given id."""
def __init__(self, vm: "ProjectViewModel", new_case: Any) -> None:
def __init__(self, vm: ProjectViewModel, new_case: Any) -> None:
super().__init__(vm, f"Edit analysis case {new_case.id}")
self._new = new_case
self._old: Any | None = None

View file

@ -27,20 +27,18 @@ class ProjectCommand(QUndoCommand):
:meth:`_notify` exactly once at the end of each.
"""
def __init__(self, vm: "ProjectViewModel", text: str) -> None:
def __init__(self, vm: ProjectViewModel, text: str) -> None:
super().__init__(text)
self._vm = vm
@property
def vm(self) -> "ProjectViewModel":
def vm(self) -> ProjectViewModel:
return self._vm
@property
def project(self) -> "Project":
def project(self) -> Project:
if self._vm.project is None:
raise RuntimeError(
f"Cannot apply '{self.text()}': no active project."
)
raise RuntimeError(f"Cannot apply '{self.text()}': no active project.")
return self._vm.project
def _notify(self) -> None:

View file

@ -0,0 +1,80 @@
"""Commands for load-combination management."""
from __future__ import annotations
from typing import TYPE_CHECKING, Any
from otko.commands.base import ProjectCommand
if TYPE_CHECKING:
from otko.viewmodels import ProjectViewModel
class AddCombinationsCommand(ProjectCommand):
"""Add one or more load combinations."""
def __init__(self, vm: ProjectViewModel, combos: list[Any], *, text: str | None = None) -> None:
super().__init__(vm, text or f"Add {len(combos)} load combination(s)")
self._combos = list(combos)
def redo(self) -> None:
existing = {c.id for c in self.project.combinations}
for combo in self._combos:
if combo.id in existing:
raise ValueError(f"Load combination id {combo.id} already exists.")
self.project.combinations.extend(self._combos)
self._notify()
def undo(self) -> None:
ids = {c.id for c in self._combos}
self.project.combinations[:] = [c for c in self.project.combinations if c.id not in ids]
self._notify()
class DeleteCombinationsCommand(ProjectCommand):
"""Remove a set of load combinations."""
def __init__(self, vm: ProjectViewModel, combo_ids: set[int]) -> None:
super().__init__(vm, f"Delete {len(combo_ids)} load combination(s)")
self._combo_ids = set(combo_ids)
self._removed: list[tuple[int, Any]] = []
def redo(self) -> None:
self._removed = [
(i, c) for i, c in enumerate(self.project.combinations) if c.id in self._combo_ids
]
self.project.combinations[:] = [
c for c in self.project.combinations if c.id not in self._combo_ids
]
self._notify()
def undo(self) -> None:
for i, c in self._removed:
self.project.combinations.insert(min(i, len(self.project.combinations)), c)
self._removed.clear()
self._notify()
class UpdateCombinationCommand(ProjectCommand):
"""Replace a load combination at a given id."""
def __init__(self, vm: ProjectViewModel, new_combo: Any) -> None:
super().__init__(vm, f"Edit load combination {new_combo.id}")
self._new = new_combo
self._old: Any | None = None
self._index: int | None = None
def redo(self) -> None:
for i, c in enumerate(self.project.combinations):
if c.id == self._new.id:
self._old = c
self._index = i
self.project.combinations[i] = self._new
self._notify()
return
raise KeyError(f"Load combination with id={self._new.id} not found.")
def undo(self) -> None:
if self._old is not None and self._index is not None:
self.project.combinations[self._index] = self._old
self._notify()

View file

@ -14,7 +14,7 @@ if TYPE_CHECKING:
class AddEqualDOFConstraintCommand(ProjectCommand):
"""Append an ``equalDOF`` constraint to the project (undoable)."""
def __init__(self, vm: "ProjectViewModel", constraint: EqualDOFConstraint) -> None:
def __init__(self, vm: ProjectViewModel, constraint: EqualDOFConstraint) -> None:
super().__init__(
vm,
f"Add equalDOF {constraint.retained_node}->{constraint.constrained_node}",
@ -34,8 +34,7 @@ class AddEqualDOFConstraintCommand(ProjectCommand):
def undo(self) -> None:
self.project.mp_constraints[:] = [
mp for mp in self.project.mp_constraints
if mp != self._constraint
mp for mp in self.project.mp_constraints if mp != self._constraint
]
self._notify()
@ -49,7 +48,7 @@ class UpdateEqualDOFConstraintCommand(ProjectCommand):
"""
def __init__(
self, vm: "ProjectViewModel", index: int, new_constraint: EqualDOFConstraint
self, vm: ProjectViewModel, index: int, new_constraint: EqualDOFConstraint
) -> None:
super().__init__(vm, f"Edit equalDOF row {index + 1}")
self._index = index
@ -72,7 +71,7 @@ class UpdateEqualDOFConstraintCommand(ProjectCommand):
class DeleteEqualDOFConstraintCommand(ProjectCommand):
"""Remove ``equalDOF`` constraints by table-row index (no cascade)."""
def __init__(self, vm: "ProjectViewModel", indices: set[int]) -> None:
def __init__(self, vm: ProjectViewModel, indices: set[int]) -> None:
super().__init__(vm, f"Delete {len(indices)} constraint(s)")
self._indices = set(indices)
self._removed: list[tuple[int, EqualDOFConstraint]] = []

View file

@ -14,7 +14,7 @@ class AddElementsCommand(ProjectCommand):
"""Add one or more elements in a single undoable step."""
def __init__(
self, vm: "ProjectViewModel", elements: list[Any], *, text: str | None = None
self, vm: ProjectViewModel, elements: list[Any], *, text: str | None = None
) -> None:
super().__init__(vm, text or f"Add {len(elements)} element(s)")
self._elements = list(elements)
@ -40,7 +40,7 @@ class AddElementsCommand(ProjectCommand):
class DeleteElementsCommand(ProjectCommand):
"""Remove a set of elements (no cascade — nodes are not affected)."""
def __init__(self, vm: "ProjectViewModel", element_ids: set[int]) -> None:
def __init__(self, vm: ProjectViewModel, element_ids: set[int]) -> None:
super().__init__(vm, f"Delete {len(element_ids)} element(s)")
self._element_ids = set(element_ids)
self._removed: list[tuple[int, Any]] = []
@ -68,7 +68,7 @@ class AssignSectionCommand(ProjectCommand):
(e.g. trusses, zero-length elements).
"""
def __init__(self, vm: "ProjectViewModel", element_ids: set[int], section_id: int) -> None:
def __init__(self, vm: ProjectViewModel, element_ids: set[int], section_id: int) -> None:
super().__init__(vm, f"Assign section {section_id} to {len(element_ids)} element(s)")
self._element_ids = set(element_ids)
self._section_id = section_id
@ -106,7 +106,7 @@ class ConvertElementTypeCommand(ProjectCommand):
def __init__(
self,
vm: "ProjectViewModel",
vm: ProjectViewModel,
element_ids: set[int],
target_type: str,
defaults: dict[str, Any] | None = None,
@ -185,7 +185,7 @@ class ReplaceElementsCommand(ProjectCommand):
for another while preserving the id and node connectivity.
"""
def __init__(self, vm: "ProjectViewModel", replacements: list[Any]) -> None:
def __init__(self, vm: ProjectViewModel, replacements: list[Any]) -> None:
super().__init__(vm, f"Replace {len(replacements)} element(s)")
self._replacements = {el.id: el for el in replacements}
self._previous: dict[int, Any] = {}
@ -217,7 +217,7 @@ class UpdateElementFieldsCommand(ProjectCommand):
def __init__(
self,
vm: "ProjectViewModel",
vm: ProjectViewModel,
element_id: int,
fields: dict[str, Any],
) -> None:
@ -254,7 +254,7 @@ class UpdateElementFieldsCommand(ProjectCommand):
class AssignMaterialCommand(ProjectCommand):
"""Set ``material_id`` on a set of elements (truss-style)."""
def __init__(self, vm: "ProjectViewModel", element_ids: set[int], material_id: int) -> None:
def __init__(self, vm: ProjectViewModel, element_ids: set[int], material_id: int) -> None:
super().__init__(vm, f"Assign material {material_id} to {len(element_ids)} element(s)")
self._element_ids = set(element_ids)
self._material_id = material_id

View file

@ -20,7 +20,7 @@ class SetCoordSystemsCommand(ProjectCommand):
def __init__(
self,
vm: "ProjectViewModel",
vm: ProjectViewModel,
new_systems: list[CoordinateGridSystem],
) -> None:
super().__init__(vm, "Update coordinate/grid systems")
@ -46,7 +46,7 @@ class SetGridSystemCommand(ProjectCommand):
systems at once.
"""
def __init__(self, vm: "ProjectViewModel", new_grid: GridSystem) -> None:
def __init__(self, vm: ProjectViewModel, new_grid: GridSystem) -> None:
super().__init__(vm, "Update grid system")
self._new_grid = new_grid
self._previous: GridSystem | None = None

View file

@ -35,7 +35,7 @@ class AddNodalLoadsCommand(ProjectCommand):
def __init__(
self,
vm: "ProjectViewModel",
vm: ProjectViewModel,
node_ids: set[int],
forces: tuple[float, float, float, float, float, float],
pattern_id: int | None = None,
@ -47,7 +47,7 @@ class AddNodalLoadsCommand(ProjectCommand):
self._forces = forces
self._pattern_id = pattern_id
self._new_pattern_name = new_pattern_name
self._new_ts_type = new_ts_type # "Linear" or "Constant"
self._new_ts_type = new_ts_type # "Linear" or "Constant"
self._created_ts: TimeSeries | None = None
self._created_pattern: PlainLoadPattern | None = None
self._added_loads: list[tuple[int, NodalLoad]] = [] # (pattern_id, load)
@ -101,7 +101,10 @@ class AddNodalLoadsCommand(ProjectCommand):
break
self._added_loads.clear()
# Roll back any infrastructure we created.
if self._created_pattern is not None and self._created_pattern in self.project.load_patterns:
if (
self._created_pattern is not None
and self._created_pattern in self.project.load_patterns
):
self.project.load_patterns.remove(self._created_pattern)
self._created_pattern = None
if self._created_ts is not None and self._created_ts in self.project.time_series:
@ -119,7 +122,7 @@ class AddElementLoadsCommand(ProjectCommand):
def __init__(
self,
vm: "ProjectViewModel",
vm: ProjectViewModel,
element_ids: set[int],
wy: float = 0.0,
wz: float = 0.0,
@ -157,7 +160,10 @@ class AddElementLoadsCommand(ProjectCommand):
pattern = self._resolve_pattern()
for eid in self._element_ids:
load = UniformElementLoad(
element_id=eid, wy=self._wy, wz=self._wz, wx=self._wx,
element_id=eid,
wy=self._wy,
wz=self._wz,
wx=self._wx,
)
pattern.element_loads.append(load)
self._added_loads.append((pattern.id, load))
@ -171,7 +177,10 @@ class AddElementLoadsCommand(ProjectCommand):
pat.element_loads.remove(load)
break
self._added_loads.clear()
if self._created_pattern is not None and self._created_pattern in self.project.load_patterns:
if (
self._created_pattern is not None
and self._created_pattern in self.project.load_patterns
):
self.project.load_patterns.remove(self._created_pattern)
self._created_pattern = None
if self._created_ts is not None and self._created_ts in self.project.time_series:

View file

@ -13,7 +13,9 @@ if TYPE_CHECKING:
class AddMaterialsCommand(ProjectCommand):
"""Add one or more materials in a single undoable step."""
def __init__(self, vm: "ProjectViewModel", materials: list[Any], *, text: str | None = None) -> None:
def __init__(
self, vm: ProjectViewModel, materials: list[Any], *, text: str | None = None
) -> None:
super().__init__(vm, text or f"Add {len(materials)} material(s)")
self._materials = list(materials)
@ -34,15 +36,14 @@ class AddMaterialsCommand(ProjectCommand):
class DeleteMaterialsCommand(ProjectCommand):
"""Remove materials (no cascade)."""
def __init__(self, vm: "ProjectViewModel", material_ids: set[int]) -> None:
def __init__(self, vm: ProjectViewModel, material_ids: set[int]) -> None:
super().__init__(vm, f"Delete {len(material_ids)} material(s)")
self._material_ids = set(material_ids)
self._removed: list[tuple[int, Any]] = []
def redo(self) -> None:
self._removed = [
(i, m) for i, m in enumerate(self.project.materials)
if m.id in self._material_ids
(i, m) for i, m in enumerate(self.project.materials) if m.id in self._material_ids
]
self.project.materials[:] = [
m for m in self.project.materials if m.id not in self._material_ids
@ -63,7 +64,7 @@ class UpdateMaterialCommand(ProjectCommand):
otherwise this is an Add+Delete, not an update.
"""
def __init__(self, vm: "ProjectViewModel", new_material: Any) -> None:
def __init__(self, vm: ProjectViewModel, new_material: Any) -> None:
super().__init__(vm, f"Edit material {new_material.id}")
self._new = new_material
self._old: Any | None = None

View file

@ -14,7 +14,7 @@ if TYPE_CHECKING:
class AddNodesCommand(ProjectCommand):
"""Add one or more nodes in a single undoable step."""
def __init__(self, vm: "ProjectViewModel", nodes: list[Node], *, text: str | None = None) -> None:
def __init__(self, vm: ProjectViewModel, nodes: list[Node], *, text: str | None = None) -> None:
super().__init__(vm, text or f"Add {len(nodes)} node(s)")
self._nodes = list(nodes)
@ -39,17 +39,18 @@ class DeleteNodesCommand(ProjectCommand):
them in their original positions.
"""
def __init__(self, vm: "ProjectViewModel", node_ids: set[int]) -> None:
def __init__(self, vm: ProjectViewModel, node_ids: set[int]) -> None:
super().__init__(vm, f"Delete {len(node_ids)} node(s)")
self._node_ids = set(node_ids)
self._removed_nodes: list[tuple[int, Node]] = [] # (index, node)
self._removed_elements: list[tuple[int, object]] = [] # (index, element)
self._removed_nodes: list[tuple[int, Node]] = [] # (index, node)
self._removed_elements: list[tuple[int, object]] = [] # (index, element)
self._removed_mp_constraints: list[tuple[int, object]] = []
def redo(self) -> None:
# Cascade: snapshot every element that references a doomed node.
self._removed_elements = [
(i, el) for i, el in enumerate(self.project.elements)
(i, el)
for i, el in enumerate(self.project.elements)
if any(nid in self._node_ids for nid in el.nodes)
]
doomed_elem_ids = {el.id for _, el in self._removed_elements}
@ -58,7 +59,8 @@ class DeleteNodesCommand(ProjectCommand):
]
self._removed_mp_constraints = [
(i, mp) for i, mp in enumerate(self.project.mp_constraints)
(i, mp)
for i, mp in enumerate(self.project.mp_constraints)
if mp.retained_node in self._node_ids or mp.constrained_node in self._node_ids
]
doomed_mp = {id(mp) for _, mp in self._removed_mp_constraints}
@ -69,9 +71,7 @@ class DeleteNodesCommand(ProjectCommand):
self._removed_nodes = [
(i, n) for i, n in enumerate(self.project.nodes) if n.id in self._node_ids
]
self.project.nodes[:] = [
n for n in self.project.nodes if n.id not in self._node_ids
]
self.project.nodes[:] = [n for n in self.project.nodes if n.id not in self._node_ids]
self._notify()
def undo(self) -> None:
@ -93,7 +93,7 @@ class SetRestraintCommand(ProjectCommand):
def __init__(
self,
vm: "ProjectViewModel",
vm: ProjectViewModel,
node_ids: set[int],
restraint: tuple[bool, bool, bool, bool, bool, bool],
) -> None:
@ -128,7 +128,7 @@ class UpdateNodeFieldsCommand(ProjectCommand):
def __init__(
self,
vm: "ProjectViewModel",
vm: ProjectViewModel,
node_id: int,
fields: dict[str, Any],
) -> None:
@ -166,7 +166,7 @@ class SetMassCommand(ProjectCommand):
def __init__(
self,
vm: "ProjectViewModel",
vm: ProjectViewModel,
node_ids: set[int],
mass: tuple[float, float, float, float, float, float],
) -> None:

View file

@ -19,7 +19,7 @@ class SetUnitsCommand(ProjectCommand):
so both redo and undo notify (dirty + modelMutated) to refresh.
"""
def __init__(self, vm: "ProjectViewModel", units: UnitSystem) -> None:
def __init__(self, vm: ProjectViewModel, units: UnitSystem) -> None:
super().__init__(vm, f"Set display units to {units.value}")
self._units = units
self._previous: UnitSystem | None = None

View file

@ -13,7 +13,9 @@ if TYPE_CHECKING:
class AddSectionsCommand(ProjectCommand):
"""Add one or more sections in a single undoable step."""
def __init__(self, vm: "ProjectViewModel", sections: list[Any], *, text: str | None = None) -> None:
def __init__(
self, vm: ProjectViewModel, sections: list[Any], *, text: str | None = None
) -> None:
super().__init__(vm, text or f"Add {len(sections)} section(s)")
self._sections = list(sections)
@ -34,15 +36,14 @@ class AddSectionsCommand(ProjectCommand):
class DeleteSectionsCommand(ProjectCommand):
"""Remove sections (no cascade — elements referencing them must be cleaned separately)."""
def __init__(self, vm: "ProjectViewModel", section_ids: set[int]) -> None:
def __init__(self, vm: ProjectViewModel, section_ids: set[int]) -> None:
super().__init__(vm, f"Delete {len(section_ids)} section(s)")
self._section_ids = set(section_ids)
self._removed: list[tuple[int, Any]] = []
def redo(self) -> None:
self._removed = [
(i, s) for i, s in enumerate(self.project.sections)
if s.id in self._section_ids
(i, s) for i, s in enumerate(self.project.sections) if s.id in self._section_ids
]
self.project.sections[:] = [
s for s in self.project.sections if s.id not in self._section_ids
@ -59,7 +60,7 @@ class DeleteSectionsCommand(ProjectCommand):
class UpdateSectionCommand(ProjectCommand):
"""Replace a section's parameters at a given id."""
def __init__(self, vm: "ProjectViewModel", new_section: Any) -> None:
def __init__(self, vm: ProjectViewModel, new_section: Any) -> None:
super().__init__(vm, f"Edit section {new_section.id}")
self._new = new_section
self._old: Any | None = None

View file

@ -19,7 +19,7 @@ if TYPE_CHECKING:
class AddTimeSeriesCommand(ProjectCommand):
"""Append a :class:`TimeSeries` to the project (undoable)."""
def __init__(self, vm: "ProjectViewModel", ts: "TimeSeries") -> None:
def __init__(self, vm: ProjectViewModel, ts: TimeSeries) -> None:
super().__init__(vm, f"Add time series '{ts.name or ts.id}'")
self._ts = ts
@ -31,9 +31,7 @@ class AddTimeSeriesCommand(ProjectCommand):
self._notify()
def undo(self) -> None:
self.project.time_series[:] = [
t for t in self.project.time_series if t.id != self._ts.id
]
self.project.time_series[:] = [t for t in self.project.time_series if t.id != self._ts.id]
self._notify()
@ -43,7 +41,7 @@ class UpdateTimeSeriesCommand(ProjectCommand):
The new series must carry the same id as the one being replaced.
"""
def __init__(self, vm: "ProjectViewModel", new_ts: Any) -> None:
def __init__(self, vm: ProjectViewModel, new_ts: Any) -> None:
super().__init__(vm, f"Edit time series {new_ts.id}")
self._new = new_ts
self._old: Any | None = None
@ -69,7 +67,7 @@ class DeleteTimeSeriesCommand(ProjectCommand):
"""Remove time series (no cascade — patterns referencing them must be
cleaned separately; ``validate_references`` catches strays before save)."""
def __init__(self, vm: "ProjectViewModel", ts_ids: set[int]) -> None:
def __init__(self, vm: ProjectViewModel, ts_ids: set[int]) -> None:
super().__init__(vm, f"Delete {len(ts_ids)} time serie(s)")
self._ts_ids = set(ts_ids)
self._removed: list[tuple[int, Any]] = []
@ -93,7 +91,7 @@ class DeleteTimeSeriesCommand(ProjectCommand):
class AddLoadPatternCommand(ProjectCommand):
"""Append a :class:`LoadPattern` to the project (undoable)."""
def __init__(self, vm: "ProjectViewModel", pattern: "LoadPattern") -> None:
def __init__(self, vm: ProjectViewModel, pattern: LoadPattern) -> None:
super().__init__(vm, f"Add pattern '{pattern.name or pattern.id}'")
self._pattern = pattern
@ -119,7 +117,7 @@ class UpdateLoadPatternCommand(ProjectCommand):
drops the pattern's stored loads.
"""
def __init__(self, vm: "ProjectViewModel", new_pattern: Any) -> None:
def __init__(self, vm: ProjectViewModel, new_pattern: Any) -> None:
super().__init__(vm, f"Edit pattern {new_pattern.id}")
self._new = new_pattern
self._old: Any | None = None
@ -144,7 +142,7 @@ class UpdateLoadPatternCommand(ProjectCommand):
class DeleteLoadPatternCommand(ProjectCommand):
"""Remove load patterns (their child nodal/element loads go with them)."""
def __init__(self, vm: "ProjectViewModel", pattern_ids: set[int]) -> None:
def __init__(self, vm: ProjectViewModel, pattern_ids: set[int]) -> None:
super().__init__(vm, f"Delete {len(pattern_ids)} pattern(s)")
self._pattern_ids = set(pattern_ids)
self._removed: list[tuple[int, Any]] = []

View file

@ -15,10 +15,9 @@ All copies inherit the source node's restraint, mass, and name.
from __future__ import annotations
from typing import TYPE_CHECKING, Any, Literal
from typing import TYPE_CHECKING, Literal
from otko.commands.base import ProjectCommand
from otko.core import Node
if TYPE_CHECKING:
from otko.viewmodels import ProjectViewModel
@ -30,7 +29,7 @@ class MoveNodesCommand(ProjectCommand):
def __init__(
self,
vm: "ProjectViewModel",
vm: ProjectViewModel,
node_ids: set[int],
offset: tuple[float, float, float],
) -> None:
@ -45,9 +44,9 @@ class MoveNodesCommand(ProjectCommand):
for i, n in enumerate(self.project.nodes):
if n.id in self._node_ids:
self._previous[n.id] = n.coords
self.project.nodes[i] = n.model_copy(update={
"coords": (n.coords[0] + dx, n.coords[1] + dy, n.coords[2] + dz)
})
self.project.nodes[i] = n.model_copy(
update={"coords": (n.coords[0] + dx, n.coords[1] + dy, n.coords[2] + dz)}
)
self._notify()
def undo(self) -> None:
@ -63,7 +62,7 @@ class ReplicateCommand(ProjectCommand):
def __init__(
self,
vm: "ProjectViewModel",
vm: ProjectViewModel,
node_ids: set[int],
element_ids: set[int],
offset: tuple[float, float, float],
@ -84,7 +83,8 @@ class ReplicateCommand(ProjectCommand):
# Snapshot the source nodes/elements once (won't change during redo).
src_nodes = [n for n in self.project.nodes if n.id in self._node_ids]
src_elements = [
e for e in self.project.elements
e
for e in self.project.elements
if e.id in self._element_ids and all(nid in self._node_ids for nid in e.nodes)
]
next_node_id = self.project.next_node_id()
@ -95,30 +95,34 @@ class ReplicateCommand(ProjectCommand):
for k in range(1, self._n_copies + 1):
mapping: dict[int, int] = {}
for orig in src_nodes:
new_node = orig.model_copy(update={
"id": next_node_id,
"coords": (orig.coords[0] + k * dx,
orig.coords[1] + k * dy,
orig.coords[2] + k * dz),
})
new_node = orig.model_copy(
update={
"id": next_node_id,
"coords": (
orig.coords[0] + k * dx,
orig.coords[1] + k * dy,
orig.coords[2] + k * dz,
),
}
)
self.project.nodes.append(new_node)
self._added_node_ids.add(next_node_id)
mapping[orig.id] = next_node_id
next_node_id += 1
for orig in src_elements:
new_elem = orig.model_copy(update={
"id": next_elem_id,
"nodes": tuple(mapping[nid] for nid in orig.nodes),
})
new_elem = orig.model_copy(
update={
"id": next_elem_id,
"nodes": tuple(mapping[nid] for nid in orig.nodes),
}
)
self.project.elements.append(new_elem)
self._added_element_ids.add(next_elem_id)
next_elem_id += 1
self._notify()
def undo(self) -> None:
self.project.nodes[:] = [
n for n in self.project.nodes if n.id not in self._added_node_ids
]
self.project.nodes[:] = [n for n in self.project.nodes if n.id not in self._added_node_ids]
self.project.elements[:] = [
e for e in self.project.elements if e.id not in self._added_element_ids
]
@ -142,7 +146,7 @@ class MirrorCommand(ProjectCommand):
def __init__(
self,
vm: "ProjectViewModel",
vm: ProjectViewModel,
node_ids: set[int],
element_ids: set[int],
plane: Plane,
@ -166,7 +170,8 @@ class MirrorCommand(ProjectCommand):
def redo(self) -> None:
src_nodes = [n for n in self.project.nodes if n.id in self._node_ids]
src_elements = [
e for e in self.project.elements
e
for e in self.project.elements
if e.id in self._element_ids and all(nid in self._node_ids for nid in e.nodes)
]
next_node_id = self.project.next_node_id()
@ -176,28 +181,30 @@ class MirrorCommand(ProjectCommand):
mapping: dict[int, int] = {}
for orig in src_nodes:
new_node = orig.model_copy(update={
"id": next_node_id,
"coords": self._reflect(orig.coords, self._plane),
})
new_node = orig.model_copy(
update={
"id": next_node_id,
"coords": self._reflect(orig.coords, self._plane),
}
)
self.project.nodes.append(new_node)
self._added_node_ids.add(next_node_id)
mapping[orig.id] = next_node_id
next_node_id += 1
for orig in src_elements:
new_elem = orig.model_copy(update={
"id": next_elem_id,
"nodes": tuple(mapping[nid] for nid in orig.nodes),
})
new_elem = orig.model_copy(
update={
"id": next_elem_id,
"nodes": tuple(mapping[nid] for nid in orig.nodes),
}
)
self.project.elements.append(new_elem)
self._added_element_ids.add(next_elem_id)
next_elem_id += 1
self._notify()
def undo(self) -> None:
self.project.nodes[:] = [
n for n in self.project.nodes if n.id not in self._added_node_ids
]
self.project.nodes[:] = [n for n in self.project.nodes if n.id not in self._added_node_ids]
self.project.elements[:] = [
e for e in self.project.elements if e.id not in self._added_element_ids
]

View file

@ -50,6 +50,8 @@ from otko.core.loads import (
ConstantTimeSeries,
ImposedSupportMotionPattern,
LinearTimeSeries,
LoadCombination,
LoadCombinationItem,
LoadPattern,
NodalLoad,
PathTimeSeries,
@ -165,6 +167,8 @@ __all__ = [
"PlainLoadPattern",
"UniformExcitationPattern",
"ImposedSupportMotionPattern",
"LoadCombination",
"LoadCombinationItem",
"NodalLoad",
"UniformElementLoad",
"ResponseSpectrum",

View file

@ -16,11 +16,13 @@ class Entity(BaseModel):
"""Base class for every persisted domain object."""
model_config = ConfigDict(
frozen=False, # individual setters allowed; we lock at the Project boundary
extra="forbid", # unknown JSON keys are an error, not a silent ignore
frozen=False, # individual setters allowed; we lock at the Project boundary
extra="forbid", # unknown JSON keys are an error, not a silent ignore
validate_assignment=True,
populate_by_name=True,
)
id: PositiveInt = Field(..., description="Unique tag within its kind. Used as the OpenSees tag.")
id: PositiveInt = Field(
..., description="Unique tag within its kind. Used as the OpenSees tag."
)
name: str = Field(default="", description="Optional human-readable label.")

View file

@ -9,7 +9,7 @@ in Phase 6/8.
from __future__ import annotations
from typing import Annotated, Literal, Union
from typing import Annotated, Literal
from pydantic import Field, PositiveFloat, PositiveInt, model_validator
@ -83,7 +83,8 @@ class TransientCase(Entity):
constraints: str = "Plain"
integrator: str = "Newmark"
integrator_params: tuple[float, float] = Field(
default=(0.5, 0.25), description="Newmark gamma, beta (default = average acceleration).",
default=(0.5, 0.25),
description="Newmark gamma, beta (default = average acceleration).",
)
algorithm: str = "Newton"
test: str = "NormDispIncr"
@ -100,7 +101,7 @@ class TransientCase(Entity):
rayleigh_beta_k: float = Field(
default=0.0,
description="Stiffness-proportional βK on CURRENT/tangent stiffness — "
"``rayleigh`` slot 2 (damps high frequencies).",
"``rayleigh`` slot 2 (damps high frequencies).",
)
rayleigh_beta_k_init: float = Field(
default=0.0,
@ -114,11 +115,11 @@ class TransientCase(Entity):
)
rayleigh_beta_k_comm: float = Field(
default=0.0,
description="Stiffness-proportional βK on COMMITTED stiffness — "
"``rayleigh`` slot 4.",
description="Stiffness-proportional βK on COMMITTED stiffness — " "``rayleigh`` slot 4.",
)
rayleigh_mode1_damping: float | None = Field(
default=None, ge=0.0,
default=None,
ge=0.0,
description=(
"If set, βK is computed as 2·ζ/√λ₁ (first-mode eigenvalue) and "
"overrides ``rayleigh_beta_k``. ``rayleigh_alpha_m`` still applies."
@ -195,7 +196,7 @@ class PushoverCase(Entity):
base_nodes: list[PositiveInt] = Field(
default_factory=list,
description="Nodes whose reactions sum into the 'base shear' for the curve. "
"Leave empty to use every restrained node in the project.",
"Leave empty to use every restrained node in the project.",
)
system: str = "BandGeneral"
constraints: str = "Plain"
@ -244,23 +245,30 @@ class ResponseSpectrumCase(Entity):
type: Literal["ResponseSpectrum"] = "ResponseSpectrum"
modal_case_id: PositiveInt = Field(
..., description="ID of the ModalCase whose mode shapes drive this analysis.",
...,
description="ID of the ModalCase whose mode shapes drive this analysis.",
)
spectrum_id: PositiveInt = Field(
..., description="ID of the ResponseSpectrum to apply.",
...,
description="ID of the ResponseSpectrum to apply.",
)
direction: int = Field(
..., ge=1, le=6, description="DOF direction (1..6) for the seismic excitation.",
...,
ge=1,
le=6,
description="DOF direction (1..6) for the seismic excitation.",
)
combination: Literal["SRSS", "CQC"] = "SRSS"
damping_ratio: float | None = Field(
default=None, ge=0.0, le=1.0,
default=None,
ge=0.0,
le=1.0,
description="Override the spectrum's damping for CQC correlation. "
"Defaults to the spectrum's damping_ratio.",
"Defaults to the spectrum's damping_ratio.",
)
AnalysisCase = Annotated[
Union[StaticCase, ModalCase, TransientCase, PushoverCase, ResponseSpectrumCase],
StaticCase | ModalCase | TransientCase | PushoverCase | ResponseSpectrumCase,
Field(discriminator="type"),
]

View file

@ -8,7 +8,9 @@ from pydantic import BaseModel
from otko.core.catalog.generated.elastic import ElasticSpec
from otko.core.catalog.generated.elastic_perfectly_plastic import ElasticPerfectlyPlasticSpec
from otko.core.catalog.generated.elastic_perfectly_plastic_with_gap import ElasticPerfectlyPlasticWithGapSpec
from otko.core.catalog.generated.elastic_perfectly_plastic_with_gap import (
ElasticPerfectlyPlasticWithGapSpec,
)
from otko.core.catalog.generated.viscous import ViscousSpec
from otko.core.catalog.generated.viscous_damper import ViscousDamperSpec
from otko.core.catalog.generated.hyperbolic_gap import HyperbolicGapSpec
@ -21,8 +23,12 @@ from otko.core.catalog.generated.steel02 import Steel02Spec
from otko.core.catalog.generated.reinforcing_steel import ReinforcingSteelSpec
from otko.core.catalog.generated.hysteretic import HystereticSpec
from otko.core.catalog.generated.ramberg_osgood_steel import RambergOsgoodSteelSpec
from otko.core.catalog.generated.concrete01_zero_tensile_strength import Concrete01ZeroTensileStrengthSpec
from otko.core.catalog.generated.concrete02_linear_tension_softening import Concrete02LinearTensionSofteningSpec
from otko.core.catalog.generated.concrete01_zero_tensile_strength import (
Concrete01ZeroTensileStrengthSpec,
)
from otko.core.catalog.generated.concrete02_linear_tension_softening import (
Concrete02LinearTensionSofteningSpec,
)
from otko.core.catalog.generated.concrete04_popovics_concrete import Concrete04PopovicsConcreteSpec
from otko.core.catalog.generated.concrete06 import Concrete06Spec
from otko.core.catalog.generated.concretecm import ConcretecmSpec
@ -50,10 +56,16 @@ from otko.core.catalog.generated.elastic_membrane_plate import ElasticMembranePl
from otko.core.catalog.generated.layeredshell import LayeredshellSpec
from otko.core.catalog.generated.ground_motion_record import GroundMotionRecordSpec
from otko.core.catalog.generated.elastic_beam_column import ElasticBeamColumnSpec
from otko.core.catalog.generated.elastic_timoshenko_beam_column import ElasticTimoshenkoBeamColumnSpec
from otko.core.catalog.generated.elastic_timoshenko_beam_column import (
ElasticTimoshenkoBeamColumnSpec,
)
from otko.core.catalog.generated.force_based_beam_column import ForceBasedBeamColumnSpec
from otko.core.catalog.generated.displacement_based_beam_column import DisplacementBasedBeamColumnSpec
from otko.core.catalog.generated.flexure_shear_interaction_displacement_based_beam_column import FlexureShearInteractionDisplacementBasedBeamColumnSpec
from otko.core.catalog.generated.displacement_based_beam_column import (
DisplacementBasedBeamColumnSpec,
)
from otko.core.catalog.generated.flexure_shear_interaction_displacement_based_beam_column import (
FlexureShearInteractionDisplacementBasedBeamColumnSpec,
)
from otko.core.catalog.generated.truss import TrussSpec
from otko.core.catalog.generated.corotational_truss import CorotationalTrussSpec
from otko.core.catalog.generated.quad import QuadSpec
@ -67,64 +79,124 @@ from otko.core.catalog.generated.auto_equal_constraint import AutoEqualConstrain
CATALOG: dict[str, type[BaseModel]] = {
'Elastic': ElasticSpec,
'Elastic_Perfectly_Plastic': ElasticPerfectlyPlasticSpec,
'Elastic_Perfectly_Plastic_with_Gap': ElasticPerfectlyPlasticWithGapSpec,
'Viscous': ViscousSpec,
'Viscous_Damper': ViscousDamperSpec,
'Hyperbolic_Gap': HyperbolicGapSpec,
'PySimple1': Pysimple1Spec,
'TzSimple1': Tzsimple1Spec,
'QzSimple1': Qzsimple1Spec,
'BondSP01': Bondsp01Spec,
'Steel01': Steel01Spec,
'Steel02': Steel02Spec,
'Reinforcing_steel': ReinforcingSteelSpec,
'Hysteretic': HystereticSpec,
'Ramberg-Osgood steel': RambergOsgoodSteelSpec,
'Concrete01_(Zero_tensile_strength)': Concrete01ZeroTensileStrengthSpec,
'Concrete02_(Linear_tension_softening)': Concrete02LinearTensionSofteningSpec,
'Concrete04_(Popovics_concrete)': Concrete04PopovicsConcreteSpec,
'Concrete06': Concrete06Spec,
'ConcreteCM': ConcretecmSpec,
'Series': SeriesSpec,
'Parallel': ParallelSpec,
'Section_Aggregator': SectionAggregatorSpec,
'Initial_Strain': InitialStrainSpec,
'Initial_Stress': InitialStressSpec,
'MinMax': MinmaxSpec,
'User_Material': UserMaterialSpec,
'Elastic_Isotropic': ElasticIsotropicSpec,
'Elastic_Orthotropic': ElasticOrthotropicSpec,
'J2Plasticity': J2plasticitySpec,
'Damage2p': Damage2pSpec,
'PressureIndependMultiYield': PressureindependmultiyieldSpec,
'PressureDependMultiYield': PressuredependmultiyieldSpec,
'PressureDependMultiYield02': Pressuredependmultiyield02Spec,
'Contact': ContactSpec,
'Elastic_Section': ElasticSectionSpec,
'Fiber': FiberSpec,
'Fiber_Custom': FiberCustomSpec,
'FiberInt': FiberintSpec,
'Plate_Fiber': PlateFiberSpec,
'Elastic_Membrane_Plate': ElasticMembranePlateSpec,
'LayeredShell': LayeredshellSpec,
'Ground_Motion_Record': GroundMotionRecordSpec,
'Elastic_Beam-Column': ElasticBeamColumnSpec,
'Elastic_Timoshenko_Beam-Column': ElasticTimoshenkoBeamColumnSpec,
'Force-Based_Beam-Column': ForceBasedBeamColumnSpec,
'Displacement-Based_Beam-Column': DisplacementBasedBeamColumnSpec,
'Flexure-Shear_Interaction_Displacement-Based_Beam-Column': FlexureShearInteractionDisplacementBasedBeamColumnSpec,
'Truss': TrussSpec,
'Corotational_Truss': CorotationalTrussSpec,
'Quad': QuadSpec,
'Shell': ShellSpec,
'ShellDKGQ': ShelldkgqSpec,
'Tri31': Tri31Spec,
'QuadUP': QuadupSpec,
'Standard_Brick_Element': StandardBrickElementSpec,
'Auto_Zero_Length': AutoZeroLengthSpec,
'Auto_equal_constraint': AutoEqualConstraintSpec,
"Elastic": ElasticSpec,
"Elastic_Perfectly_Plastic": ElasticPerfectlyPlasticSpec,
"Elastic_Perfectly_Plastic_with_Gap": ElasticPerfectlyPlasticWithGapSpec,
"Viscous": ViscousSpec,
"Viscous_Damper": ViscousDamperSpec,
"Hyperbolic_Gap": HyperbolicGapSpec,
"PySimple1": Pysimple1Spec,
"TzSimple1": Tzsimple1Spec,
"QzSimple1": Qzsimple1Spec,
"BondSP01": Bondsp01Spec,
"Steel01": Steel01Spec,
"Steel02": Steel02Spec,
"Reinforcing_steel": ReinforcingSteelSpec,
"Hysteretic": HystereticSpec,
"Ramberg-Osgood steel": RambergOsgoodSteelSpec,
"Concrete01_(Zero_tensile_strength)": Concrete01ZeroTensileStrengthSpec,
"Concrete02_(Linear_tension_softening)": Concrete02LinearTensionSofteningSpec,
"Concrete04_(Popovics_concrete)": Concrete04PopovicsConcreteSpec,
"Concrete06": Concrete06Spec,
"ConcreteCM": ConcretecmSpec,
"Series": SeriesSpec,
"Parallel": ParallelSpec,
"Section_Aggregator": SectionAggregatorSpec,
"Initial_Strain": InitialStrainSpec,
"Initial_Stress": InitialStressSpec,
"MinMax": MinmaxSpec,
"User_Material": UserMaterialSpec,
"Elastic_Isotropic": ElasticIsotropicSpec,
"Elastic_Orthotropic": ElasticOrthotropicSpec,
"J2Plasticity": J2plasticitySpec,
"Damage2p": Damage2pSpec,
"PressureIndependMultiYield": PressureindependmultiyieldSpec,
"PressureDependMultiYield": PressuredependmultiyieldSpec,
"PressureDependMultiYield02": Pressuredependmultiyield02Spec,
"Contact": ContactSpec,
"Elastic_Section": ElasticSectionSpec,
"Fiber": FiberSpec,
"Fiber_Custom": FiberCustomSpec,
"FiberInt": FiberintSpec,
"Plate_Fiber": PlateFiberSpec,
"Elastic_Membrane_Plate": ElasticMembranePlateSpec,
"LayeredShell": LayeredshellSpec,
"Ground_Motion_Record": GroundMotionRecordSpec,
"Elastic_Beam-Column": ElasticBeamColumnSpec,
"Elastic_Timoshenko_Beam-Column": ElasticTimoshenkoBeamColumnSpec,
"Force-Based_Beam-Column": ForceBasedBeamColumnSpec,
"Displacement-Based_Beam-Column": DisplacementBasedBeamColumnSpec,
"Flexure-Shear_Interaction_Displacement-Based_Beam-Column": FlexureShearInteractionDisplacementBasedBeamColumnSpec,
"Truss": TrussSpec,
"Corotational_Truss": CorotationalTrussSpec,
"Quad": QuadSpec,
"Shell": ShellSpec,
"ShellDKGQ": ShelldkgqSpec,
"Tri31": Tri31Spec,
"QuadUP": QuadupSpec,
"Standard_Brick_Element": StandardBrickElementSpec,
"Auto_Zero_Length": AutoZeroLengthSpec,
"Auto_equal_constraint": AutoEqualConstraintSpec,
}
__all__ = ["CATALOG", 'ElasticSpec', 'ElasticPerfectlyPlasticSpec', 'ElasticPerfectlyPlasticWithGapSpec', 'ViscousSpec', 'ViscousDamperSpec', 'HyperbolicGapSpec', 'Pysimple1Spec', 'Tzsimple1Spec', 'Qzsimple1Spec', 'Bondsp01Spec', 'Steel01Spec', 'Steel02Spec', 'ReinforcingSteelSpec', 'HystereticSpec', 'RambergOsgoodSteelSpec', 'Concrete01ZeroTensileStrengthSpec', 'Concrete02LinearTensionSofteningSpec', 'Concrete04PopovicsConcreteSpec', 'Concrete06Spec', 'ConcretecmSpec', 'SeriesSpec', 'ParallelSpec', 'SectionAggregatorSpec', 'InitialStrainSpec', 'InitialStressSpec', 'MinmaxSpec', 'UserMaterialSpec', 'ElasticIsotropicSpec', 'ElasticOrthotropicSpec', 'J2plasticitySpec', 'Damage2pSpec', 'PressureindependmultiyieldSpec', 'PressuredependmultiyieldSpec', 'Pressuredependmultiyield02Spec', 'ContactSpec', 'ElasticSectionSpec', 'FiberSpec', 'FiberCustomSpec', 'FiberintSpec', 'PlateFiberSpec', 'ElasticMembranePlateSpec', 'LayeredshellSpec', 'GroundMotionRecordSpec', 'ElasticBeamColumnSpec', 'ElasticTimoshenkoBeamColumnSpec', 'ForceBasedBeamColumnSpec', 'DisplacementBasedBeamColumnSpec', 'FlexureShearInteractionDisplacementBasedBeamColumnSpec', 'TrussSpec', 'CorotationalTrussSpec', 'QuadSpec', 'ShellSpec', 'ShelldkgqSpec', 'Tri31Spec', 'QuadupSpec', 'StandardBrickElementSpec', 'AutoZeroLengthSpec', 'AutoEqualConstraintSpec']
__all__ = [
"CATALOG",
"ElasticSpec",
"ElasticPerfectlyPlasticSpec",
"ElasticPerfectlyPlasticWithGapSpec",
"ViscousSpec",
"ViscousDamperSpec",
"HyperbolicGapSpec",
"Pysimple1Spec",
"Tzsimple1Spec",
"Qzsimple1Spec",
"Bondsp01Spec",
"Steel01Spec",
"Steel02Spec",
"ReinforcingSteelSpec",
"HystereticSpec",
"RambergOsgoodSteelSpec",
"Concrete01ZeroTensileStrengthSpec",
"Concrete02LinearTensionSofteningSpec",
"Concrete04PopovicsConcreteSpec",
"Concrete06Spec",
"ConcretecmSpec",
"SeriesSpec",
"ParallelSpec",
"SectionAggregatorSpec",
"InitialStrainSpec",
"InitialStressSpec",
"MinmaxSpec",
"UserMaterialSpec",
"ElasticIsotropicSpec",
"ElasticOrthotropicSpec",
"J2plasticitySpec",
"Damage2pSpec",
"PressureindependmultiyieldSpec",
"PressuredependmultiyieldSpec",
"Pressuredependmultiyield02Spec",
"ContactSpec",
"ElasticSectionSpec",
"FiberSpec",
"FiberCustomSpec",
"FiberintSpec",
"PlateFiberSpec",
"ElasticMembranePlateSpec",
"LayeredshellSpec",
"GroundMotionRecordSpec",
"ElasticBeamColumnSpec",
"ElasticTimoshenkoBeamColumnSpec",
"ForceBasedBeamColumnSpec",
"DisplacementBasedBeamColumnSpec",
"FlexureShearInteractionDisplacementBasedBeamColumnSpec",
"TrussSpec",
"CorotationalTrussSpec",
"QuadSpec",
"ShellSpec",
"ShelldkgqSpec",
"Tri31Spec",
"QuadupSpec",
"StandardBrickElementSpec",
"AutoZeroLengthSpec",
"AutoEqualConstraintSpec",
]

View file

@ -7,7 +7,9 @@ from typing import Union
from otko.core.catalog.generated.elastic import ElasticSpec
from otko.core.catalog.generated.elastic_perfectly_plastic import ElasticPerfectlyPlasticSpec
from otko.core.catalog.generated.elastic_perfectly_plastic_with_gap import ElasticPerfectlyPlasticWithGapSpec
from otko.core.catalog.generated.elastic_perfectly_plastic_with_gap import (
ElasticPerfectlyPlasticWithGapSpec,
)
from otko.core.catalog.generated.viscous import ViscousSpec
from otko.core.catalog.generated.viscous_damper import ViscousDamperSpec
from otko.core.catalog.generated.hyperbolic_gap import HyperbolicGapSpec
@ -20,8 +22,12 @@ from otko.core.catalog.generated.steel02 import Steel02Spec
from otko.core.catalog.generated.reinforcing_steel import ReinforcingSteelSpec
from otko.core.catalog.generated.hysteretic import HystereticSpec
from otko.core.catalog.generated.ramberg_osgood_steel import RambergOsgoodSteelSpec
from otko.core.catalog.generated.concrete01_zero_tensile_strength import Concrete01ZeroTensileStrengthSpec
from otko.core.catalog.generated.concrete02_linear_tension_softening import Concrete02LinearTensionSofteningSpec
from otko.core.catalog.generated.concrete01_zero_tensile_strength import (
Concrete01ZeroTensileStrengthSpec,
)
from otko.core.catalog.generated.concrete02_linear_tension_softening import (
Concrete02LinearTensionSofteningSpec,
)
from otko.core.catalog.generated.concrete04_popovics_concrete import Concrete04PopovicsConcreteSpec
from otko.core.catalog.generated.concrete06 import Concrete06Spec
from otko.core.catalog.generated.concretecm import ConcretecmSpec
@ -49,10 +55,16 @@ from otko.core.catalog.generated.elastic_membrane_plate import ElasticMembranePl
from otko.core.catalog.generated.layeredshell import LayeredshellSpec
from otko.core.catalog.generated.ground_motion_record import GroundMotionRecordSpec
from otko.core.catalog.generated.elastic_beam_column import ElasticBeamColumnSpec
from otko.core.catalog.generated.elastic_timoshenko_beam_column import ElasticTimoshenkoBeamColumnSpec
from otko.core.catalog.generated.elastic_timoshenko_beam_column import (
ElasticTimoshenkoBeamColumnSpec,
)
from otko.core.catalog.generated.force_based_beam_column import ForceBasedBeamColumnSpec
from otko.core.catalog.generated.displacement_based_beam_column import DisplacementBasedBeamColumnSpec
from otko.core.catalog.generated.flexure_shear_interaction_displacement_based_beam_column import FlexureShearInteractionDisplacementBasedBeamColumnSpec
from otko.core.catalog.generated.displacement_based_beam_column import (
DisplacementBasedBeamColumnSpec,
)
from otko.core.catalog.generated.flexure_shear_interaction_displacement_based_beam_column import (
FlexureShearInteractionDisplacementBasedBeamColumnSpec,
)
from otko.core.catalog.generated.truss import TrussSpec
from otko.core.catalog.generated.corotational_truss import CorotationalTrussSpec
from otko.core.catalog.generated.quad import QuadSpec
@ -65,19 +77,141 @@ from otko.core.catalog.generated.auto_zero_length import AutoZeroLengthSpec
from otko.core.catalog.generated.auto_equal_constraint import AutoEqualConstraintSpec
StandardUniaxialMaterials = Union[ElasticSpec, ElasticPerfectlyPlasticSpec, ElasticPerfectlyPlasticWithGapSpec, ViscousSpec, ViscousDamperSpec, HyperbolicGapSpec, Pysimple1Spec, Tzsimple1Spec, Qzsimple1Spec, Bondsp01Spec]
UniaxialSteelMaterials = Union[Steel01Spec, Steel02Spec, ReinforcingSteelSpec, HystereticSpec, RambergOsgoodSteelSpec]
UniaxialConcreteMaterials = Union[Concrete01ZeroTensileStrengthSpec, Concrete02LinearTensionSofteningSpec, Concrete04PopovicsConcreteSpec, Concrete06Spec, ConcretecmSpec]
CombinedMaterials = Union[SeriesSpec, ParallelSpec, SectionAggregatorSpec, InitialStrainSpec, InitialStressSpec, MinmaxSpec]
StandardUniaxialMaterials = Union[
ElasticSpec,
ElasticPerfectlyPlasticSpec,
ElasticPerfectlyPlasticWithGapSpec,
ViscousSpec,
ViscousDamperSpec,
HyperbolicGapSpec,
Pysimple1Spec,
Tzsimple1Spec,
Qzsimple1Spec,
Bondsp01Spec,
]
UniaxialSteelMaterials = Union[
Steel01Spec, Steel02Spec, ReinforcingSteelSpec, HystereticSpec, RambergOsgoodSteelSpec
]
UniaxialConcreteMaterials = Union[
Concrete01ZeroTensileStrengthSpec,
Concrete02LinearTensionSofteningSpec,
Concrete04PopovicsConcreteSpec,
Concrete06Spec,
ConcretecmSpec,
]
CombinedMaterials = Union[
SeriesSpec,
ParallelSpec,
SectionAggregatorSpec,
InitialStrainSpec,
InitialStressSpec,
MinmaxSpec,
]
UserMaterials = UserMaterialSpec
MultidimensionalNdMaterials = Union[ElasticIsotropicSpec, ElasticOrthotropicSpec, J2plasticitySpec, Damage2pSpec, PressureindependmultiyieldSpec, PressuredependmultiyieldSpec, Pressuredependmultiyield02Spec, ContactSpec]
SectionForceDeformation = Union[ElasticSectionSpec, FiberSpec, FiberCustomSpec, FiberintSpec, PlateFiberSpec, ElasticMembranePlateSpec, LayeredshellSpec]
MultidimensionalNdMaterials = Union[
ElasticIsotropicSpec,
ElasticOrthotropicSpec,
J2plasticitySpec,
Damage2pSpec,
PressureindependmultiyieldSpec,
PressuredependmultiyieldSpec,
Pressuredependmultiyield02Spec,
ContactSpec,
]
SectionForceDeformation = Union[
ElasticSectionSpec,
FiberSpec,
FiberCustomSpec,
FiberintSpec,
PlateFiberSpec,
ElasticMembranePlateSpec,
LayeredshellSpec,
]
Records = GroundMotionRecordSpec
BeamColumnElements = Union[ElasticBeamColumnSpec, ElasticTimoshenkoBeamColumnSpec, ForceBasedBeamColumnSpec, DisplacementBasedBeamColumnSpec, FlexureShearInteractionDisplacementBasedBeamColumnSpec]
BeamColumnElements = Union[
ElasticBeamColumnSpec,
ElasticTimoshenkoBeamColumnSpec,
ForceBasedBeamColumnSpec,
DisplacementBasedBeamColumnSpec,
FlexureShearInteractionDisplacementBasedBeamColumnSpec,
]
TrussElements = Union[TrussSpec, CorotationalTrussSpec]
SurfaceElements = Union[QuadSpec, ShellSpec, ShelldkgqSpec, Tri31Spec, QuadupSpec]
SolidElements = StandardBrickElementSpec
Autozl = AutoZeroLengthSpec
Autoedof = AutoEqualConstraintSpec
__all__ = ['ElasticSpec', 'ElasticPerfectlyPlasticSpec', 'ElasticPerfectlyPlasticWithGapSpec', 'ViscousSpec', 'ViscousDamperSpec', 'HyperbolicGapSpec', 'Pysimple1Spec', 'Tzsimple1Spec', 'Qzsimple1Spec', 'Bondsp01Spec', 'Steel01Spec', 'Steel02Spec', 'ReinforcingSteelSpec', 'HystereticSpec', 'RambergOsgoodSteelSpec', 'Concrete01ZeroTensileStrengthSpec', 'Concrete02LinearTensionSofteningSpec', 'Concrete04PopovicsConcreteSpec', 'Concrete06Spec', 'ConcretecmSpec', 'SeriesSpec', 'ParallelSpec', 'SectionAggregatorSpec', 'InitialStrainSpec', 'InitialStressSpec', 'MinmaxSpec', 'UserMaterialSpec', 'ElasticIsotropicSpec', 'ElasticOrthotropicSpec', 'J2plasticitySpec', 'Damage2pSpec', 'PressureindependmultiyieldSpec', 'PressuredependmultiyieldSpec', 'Pressuredependmultiyield02Spec', 'ContactSpec', 'ElasticSectionSpec', 'FiberSpec', 'FiberCustomSpec', 'FiberintSpec', 'PlateFiberSpec', 'ElasticMembranePlateSpec', 'LayeredshellSpec', 'GroundMotionRecordSpec', 'ElasticBeamColumnSpec', 'ElasticTimoshenkoBeamColumnSpec', 'ForceBasedBeamColumnSpec', 'DisplacementBasedBeamColumnSpec', 'FlexureShearInteractionDisplacementBasedBeamColumnSpec', 'TrussSpec', 'CorotationalTrussSpec', 'QuadSpec', 'ShellSpec', 'ShelldkgqSpec', 'Tri31Spec', 'QuadupSpec', 'StandardBrickElementSpec', 'AutoZeroLengthSpec', 'AutoEqualConstraintSpec', 'StandardUniaxialMaterials', 'UniaxialSteelMaterials', 'UniaxialConcreteMaterials', 'CombinedMaterials', 'UserMaterials', 'MultidimensionalNdMaterials', 'SectionForceDeformation', 'Records', 'BeamColumnElements', 'TrussElements', 'SurfaceElements', 'SolidElements', 'Autozl', 'Autoedof']
__all__ = [
"ElasticSpec",
"ElasticPerfectlyPlasticSpec",
"ElasticPerfectlyPlasticWithGapSpec",
"ViscousSpec",
"ViscousDamperSpec",
"HyperbolicGapSpec",
"Pysimple1Spec",
"Tzsimple1Spec",
"Qzsimple1Spec",
"Bondsp01Spec",
"Steel01Spec",
"Steel02Spec",
"ReinforcingSteelSpec",
"HystereticSpec",
"RambergOsgoodSteelSpec",
"Concrete01ZeroTensileStrengthSpec",
"Concrete02LinearTensionSofteningSpec",
"Concrete04PopovicsConcreteSpec",
"Concrete06Spec",
"ConcretecmSpec",
"SeriesSpec",
"ParallelSpec",
"SectionAggregatorSpec",
"InitialStrainSpec",
"InitialStressSpec",
"MinmaxSpec",
"UserMaterialSpec",
"ElasticIsotropicSpec",
"ElasticOrthotropicSpec",
"J2plasticitySpec",
"Damage2pSpec",
"PressureindependmultiyieldSpec",
"PressuredependmultiyieldSpec",
"Pressuredependmultiyield02Spec",
"ContactSpec",
"ElasticSectionSpec",
"FiberSpec",
"FiberCustomSpec",
"FiberintSpec",
"PlateFiberSpec",
"ElasticMembranePlateSpec",
"LayeredshellSpec",
"GroundMotionRecordSpec",
"ElasticBeamColumnSpec",
"ElasticTimoshenkoBeamColumnSpec",
"ForceBasedBeamColumnSpec",
"DisplacementBasedBeamColumnSpec",
"FlexureShearInteractionDisplacementBasedBeamColumnSpec",
"TrussSpec",
"CorotationalTrussSpec",
"QuadSpec",
"ShellSpec",
"ShelldkgqSpec",
"Tri31Spec",
"QuadupSpec",
"StandardBrickElementSpec",
"AutoZeroLengthSpec",
"AutoEqualConstraintSpec",
"StandardUniaxialMaterials",
"UniaxialSteelMaterials",
"UniaxialConcreteMaterials",
"CombinedMaterials",
"UserMaterials",
"MultidimensionalNdMaterials",
"SectionForceDeformation",
"Records",
"BeamColumnElements",
"TrussElements",
"SurfaceElements",
"SolidElements",
"Autozl",
"Autoedof",
]

View file

@ -17,478 +17,478 @@ from pydantic import BaseModel, ConfigDict, Field
class AutoEqualConstraintSpec(BaseModel):
model_config = ConfigDict(
json_schema_extra={
'x-gid-name': 'Auto_equal_constraint',
'x-book': 'AutoEDOF',
'dependencies': [
"x-gid-name": "Auto_equal_constraint",
"x-book": "AutoEDOF",
"dependencies": [
{
'field': 'source',
'gid_name': 'Source',
'rules': [
"field": "source",
"gid_name": "Source",
"rules": [
{
'trigger': 'Layer',
'actions': [
"trigger": "Layer",
"actions": [
{
'action': 'RESTORE',
'field': 'Layer_name',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Layer_name",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'All',
'actions': [
"trigger": "All",
"actions": [
{
'action': 'HIDE',
'field': 'Layer_name',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Layer_name",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'Visible',
'actions': [
"trigger": "Visible",
"actions": [
{
'action': 'HIDE',
'field': 'Layer_name',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Layer_name",
"target": "#CURRENT#",
},
],
},
],
},
{
'field': 'x_criteria',
'gid_name': 'X-Criteria',
'rules': [
"field": "x_criteria",
"gid_name": "X-Criteria",
"rules": [
{
'trigger': 'Any',
'actions': [
"trigger": "Any",
"actions": [
{
'action': 'HIDE',
'field': 'X-Coordinate',
'target': '#CURRENT#',
"action": "HIDE",
"field": "X-Coordinate",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Min_X-Coordinate',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Min_X-Coordinate",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Max_X-Coordinate',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Max_X-Coordinate",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'Fixed',
'actions': [
"trigger": "Fixed",
"actions": [
{
'action': 'RESTORE',
'field': 'X-Coordinate',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "X-Coordinate",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Min_X-Coordinate',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Min_X-Coordinate",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Max_X-Coordinate',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Max_X-Coordinate",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'GT',
'actions': [
"trigger": "GT",
"actions": [
{
'action': 'RESTORE',
'field': 'X-Coordinate',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "X-Coordinate",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Min_X-Coordinate',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Min_X-Coordinate",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Max_X-Coordinate',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Max_X-Coordinate",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'GET',
'actions': [
"trigger": "GET",
"actions": [
{
'action': 'RESTORE',
'field': 'X-Coordinate',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "X-Coordinate",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Min_X-Coordinate',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Min_X-Coordinate",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Max_X-Coordinate',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Max_X-Coordinate",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'LT',
'actions': [
"trigger": "LT",
"actions": [
{
'action': 'RESTORE',
'field': 'X-Coordinate',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "X-Coordinate",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Min_X-Coordinate',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Min_X-Coordinate",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Max_X-Coordinate',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Max_X-Coordinate",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'LET',
'actions': [
"trigger": "LET",
"actions": [
{
'action': 'RESTORE',
'field': 'X-Coordinate',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "X-Coordinate",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Min_X-Coordinate',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Min_X-Coordinate",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Max_X-Coordinate',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Max_X-Coordinate",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'Between',
'actions': [
"trigger": "Between",
"actions": [
{
'action': 'HIDE',
'field': 'X-Coordinate',
'target': '#CURRENT#',
"action": "HIDE",
"field": "X-Coordinate",
"target": "#CURRENT#",
},
{
'action': 'RESTORE',
'field': 'Min_X-Coordinate',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Min_X-Coordinate",
"target": "#CURRENT#",
},
{
'action': 'RESTORE',
'field': 'Max_X-Coordinate',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Max_X-Coordinate",
"target": "#CURRENT#",
},
],
},
],
},
{
'field': 'y_criteria',
'gid_name': 'Y-Criteria',
'rules': [
"field": "y_criteria",
"gid_name": "Y-Criteria",
"rules": [
{
'trigger': 'Any',
'actions': [
"trigger": "Any",
"actions": [
{
'action': 'HIDE',
'field': 'Y-Coordinate',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Y-Coordinate",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Min_Y-Coordinate',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Min_Y-Coordinate",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Max_Y-Coordinate',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Max_Y-Coordinate",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'Fixed',
'actions': [
"trigger": "Fixed",
"actions": [
{
'action': 'RESTORE',
'field': 'Y-Coordinate',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Y-Coordinate",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Min_Y-Coordinate',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Min_Y-Coordinate",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Max_Y-Coordinate',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Max_Y-Coordinate",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'GT',
'actions': [
"trigger": "GT",
"actions": [
{
'action': 'RESTORE',
'field': 'Y-Coordinate',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Y-Coordinate",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Min_Y-Coordinate',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Min_Y-Coordinate",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Max_Y-Coordinate',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Max_Y-Coordinate",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'GET',
'actions': [
"trigger": "GET",
"actions": [
{
'action': 'RESTORE',
'field': 'Y-Coordinate',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Y-Coordinate",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Min_Y-Coordinate',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Min_Y-Coordinate",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Max_Y-Coordinate',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Max_Y-Coordinate",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'LT',
'actions': [
"trigger": "LT",
"actions": [
{
'action': 'RESTORE',
'field': 'Y-Coordinate',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Y-Coordinate",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Min_Y-Coordinate',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Min_Y-Coordinate",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Max_Y-Coordinate',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Max_Y-Coordinate",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'LET',
'actions': [
"trigger": "LET",
"actions": [
{
'action': 'RESTORE',
'field': 'Y-Coordinate',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Y-Coordinate",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Min_Y-Coordinate',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Min_Y-Coordinate",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Max_Y-Coordinate',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Max_Y-Coordinate",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'Between',
'actions': [
"trigger": "Between",
"actions": [
{
'action': 'HIDE',
'field': 'Y-Coordinate',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Y-Coordinate",
"target": "#CURRENT#",
},
{
'action': 'RESTORE',
'field': 'Min_Y-Coordinate',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Min_Y-Coordinate",
"target": "#CURRENT#",
},
{
'action': 'RESTORE',
'field': 'Max_Y-Coordinate',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Max_Y-Coordinate",
"target": "#CURRENT#",
},
],
},
],
},
{
'field': 'z_criteria',
'gid_name': 'Z-Criteria',
'rules': [
"field": "z_criteria",
"gid_name": "Z-Criteria",
"rules": [
{
'trigger': 'Any',
'actions': [
"trigger": "Any",
"actions": [
{
'action': 'HIDE',
'field': 'Z-Coordinate',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Z-Coordinate",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Min_Z-Coordinate',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Min_Z-Coordinate",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Max_Z-Coordinate',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Max_Z-Coordinate",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'Fixed',
'actions': [
"trigger": "Fixed",
"actions": [
{
'action': 'RESTORE',
'field': 'Z-Coordinate',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Z-Coordinate",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Min_Z-Coordinate',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Min_Z-Coordinate",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Max_Z-Coordinate',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Max_Z-Coordinate",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'GT',
'actions': [
"trigger": "GT",
"actions": [
{
'action': 'RESTORE',
'field': 'Z-Coordinate',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Z-Coordinate",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Min_Z-Coordinate',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Min_Z-Coordinate",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Max_Z-Coordinate',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Max_Z-Coordinate",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'GET',
'actions': [
"trigger": "GET",
"actions": [
{
'action': 'RESTORE',
'field': 'Z-Coordinate',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Z-Coordinate",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Min_Z-Coordinate',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Min_Z-Coordinate",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Max_Z-Coordinate',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Max_Z-Coordinate",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'LT',
'actions': [
"trigger": "LT",
"actions": [
{
'action': 'RESTORE',
'field': 'Z-Coordinate',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Z-Coordinate",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Min_Z-Coordinate',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Min_Z-Coordinate",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Max_Z-Coordinate',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Max_Z-Coordinate",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'LET',
'actions': [
"trigger": "LET",
"actions": [
{
'action': 'RESTORE',
'field': 'Z-Coordinate',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Z-Coordinate",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Min_Z-Coordinate',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Min_Z-Coordinate",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Max_Z-Coordinate',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Max_Z-Coordinate",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'Between',
'actions': [
"trigger": "Between",
"actions": [
{
'action': 'HIDE',
'field': 'Z-Coordinate',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Z-Coordinate",
"target": "#CURRENT#",
},
{
'action': 'RESTORE',
'field': 'Min_Z-Coordinate',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Min_Z-Coordinate",
"target": "#CURRENT#",
},
{
'action': 'RESTORE',
'field': 'Max_Z-Coordinate',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Max_Z-Coordinate",
"target": "#CURRENT#",
},
],
},
@ -498,29 +498,40 @@ class AutoEqualConstraintSpec(BaseModel):
}
)
determine_master_node: Literal['Existed', 'Extra'] = 'Existed'
source: Literal['Layer', 'All', 'Visible'] = Field('Layer', description='Layer: Points or Nodes from specific layer regardless the visibility\\nAll: all points or nodes regardless the visibility\\nVisible: Only visible points or nodes')
layer_name: str = Field('Layer0', description='Layer with name "AutoZL" will be ignored.')
x_criteria: Literal['Any', 'Fixed', 'GT', 'GET', 'LT', 'LET', 'Between'] = Field('Any', description='GT: Greater than\\nGET: Greater/Equal than\\nLT: Less than\\nLET: Less/Equal than\\nBetween: inside (min,max) space including boundaries')
determine_master_node: Literal["Existed", "Extra"] = "Existed"
source: Literal["Layer", "All", "Visible"] = Field(
"Layer",
description="Layer: Points or Nodes from specific layer regardless the visibility\\nAll: all points or nodes regardless the visibility\\nVisible: Only visible points or nodes",
)
layer_name: str = Field("Layer0", description='Layer with name "AutoZL" will be ignored.')
x_criteria: Literal["Any", "Fixed", "GT", "GET", "LT", "LET", "Between"] = Field(
"Any",
description="GT: Greater than\\nGET: Greater/Equal than\\nLT: Less than\\nLET: Less/Equal than\\nBetween: inside (min,max) space including boundaries",
)
x_coordinate: float = 0.0
min_x_coordinate: float = 0.0
max_x_coordinate: float = 0.0
y_criteria: Literal['Any', 'Fixed', 'GT', 'GET', 'LT', 'LET', 'Between'] = Field('Any', description='GT: Greater than\\nGET: Greater/Equal than\\nLT: Less than\\nLET: Less/Equal than\\nBetween: inside (min,max) space including boundaries')
y_criteria: Literal["Any", "Fixed", "GT", "GET", "LT", "LET", "Between"] = Field(
"Any",
description="GT: Greater than\\nGET: Greater/Equal than\\nLT: Less than\\nLET: Less/Equal than\\nBetween: inside (min,max) space including boundaries",
)
y_coordinate: float = 0.0
min_y_coordinate: float = 0.0
max_y_coordinate: float = 0.0
z_criteria: Literal['Any', 'Fixed', 'GT', 'GET', 'LT', 'LET', 'Between'] = Field('Any', description='GT: Greater than\\nGET: Greater/Equal than\\nLT: Less than\\nLET: Less/Equal than\\nBetween: inside (min,max) space including boundaries')
z_criteria: Literal["Any", "Fixed", "GT", "GET", "LT", "LET", "Between"] = Field(
"Any",
description="GT: Greater than\\nGET: Greater/Equal than\\nLT: Less than\\nLET: Less/Equal than\\nBetween: inside (min,max) space including boundaries",
)
z_coordinate: float = 0.0
min_z_coordinate: float = 0.0
max_z_coordinate: float = 0.0
extra_point_node_offset: Literal['_'] = '_'
extra_point_node_offset: Literal["_"] = "_"
x_offset: float = 0.0
y_offset: float = 0.0
z_offset: float = 0.0
x_translation: Literal['1', '0'] = '1'
y_translation: Literal['1', '0'] = '1'
z_translation: Literal['1', '0'] = '1'
x_rotation: Literal['1', '0'] = '1'
y_rotation: Literal['1', '0'] = '1'
z_rotation: Literal['1', '0'] = '1'
x_translation: Literal["1", "0"] = "1"
y_translation: Literal["1", "0"] = "1"
z_translation: Literal["1", "0"] = "1"
x_rotation: Literal["1", "0"] = "1"
y_rotation: Literal["1", "0"] = "1"
z_rotation: Literal["1", "0"] = "1"

File diff suppressed because it is too large Load diff

View file

@ -23,86 +23,86 @@ class CyclicDataRow(BaseModel):
class Bondsp01Spec(BaseModel):
model_config = ConfigDict(
json_schema_extra={
'x-gid-name': 'BondSP01',
'x-book': 'Standard_Uniaxial_Materials',
'dependencies': [
"x-gid-name": "BondSP01",
"x-book": "Standard_Uniaxial_Materials",
"dependencies": [
{
'field': 'formulation',
'gid_name': 'Formulation',
'rules': [
"field": "formulation",
"gid_name": "Formulation",
"rules": [
{
'trigger': 'Stress-Slip',
'actions': [
"trigger": "Stress-Slip",
"actions": [
{
'action': 'RESTORE',
'field': 'Yield_stress_Fy',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Yield_stress_Fy",
"target": "#CURRENT#",
},
{
'action': 'RESTORE',
'field': 'Ultimate_stress_Fu',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Ultimate_stress_Fu",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Yield_force_Fy',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Yield_force_Fy",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Ultimate_Force_Fu',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Ultimate_Force_Fu",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'Force-Slip',
'actions': [
"trigger": "Force-Slip",
"actions": [
{
'action': 'RESTORE',
'field': 'Yield_force_Fy',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Yield_force_Fy",
"target": "#CURRENT#",
},
{
'action': 'RESTORE',
'field': 'Ultimate_Force_Fu',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Ultimate_Force_Fu",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Yield_stress_Fy',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Yield_stress_Fy",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Ultimate_stress_Fu',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Ultimate_stress_Fu",
"target": "#CURRENT#",
},
],
},
],
},
{
'field': 'analysis_type',
'gid_name': 'Analysis_type',
'rules': [
"field": "analysis_type",
"gid_name": "Analysis_type",
"rules": [
{
'trigger': 'Monotonic',
'actions': [
"trigger": "Monotonic",
"actions": [
{
'action': 'HIDE',
'field': 'Cyclic_data',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Cyclic_data",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'Cyclic',
'actions': [
"trigger": "Cyclic",
"actions": [
{
'action': 'RESTORE',
'field': 'Cyclic_data',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Cyclic_data",
"target": "#CURRENT#",
},
],
},
@ -112,16 +112,15 @@ class Bondsp01Spec(BaseModel):
}
)
material: Literal['_'] = '_'
formulation: Literal['Stress-Slip', 'Force-Slip'] = 'Stress-Slip'
yield_stress_fy: str = '500 MPa' # TODO: unit-aware type
yield_force_fy: str = '157 kN' # TODO: unit-aware type
rebar_slip_at_fy: str = '1 mm' # TODO: unit-aware type
ultimate_stress_fu: str = '675 MPa' # TODO: unit-aware type
ultimate_force_fu: str = '212 kN' # TODO: unit-aware type
rebar_slip_at_the_loaded_end_at_the_bar_fracture_strength: str = '2 mm' # TODO: unit-aware type
material: Literal["_"] = "_"
formulation: Literal["Stress-Slip", "Force-Slip"] = "Stress-Slip"
yield_stress_fy: str = "500 MPa" # TODO: unit-aware type
yield_force_fy: str = "157 kN" # TODO: unit-aware type
rebar_slip_at_fy: str = "1 mm" # TODO: unit-aware type
ultimate_stress_fu: str = "675 MPa" # TODO: unit-aware type
ultimate_force_fu: str = "212 kN" # TODO: unit-aware type
rebar_slip_at_the_loaded_end_at_the_bar_fracture_strength: str = "2 mm" # TODO: unit-aware type
initial_hardening: float = 0.4
pinching_factor_for_the_cyclic_slip_vs_bar_response: float = 0.5
analysis_type: Literal['Monotonic', 'Cyclic'] = 'Monotonic'
analysis_type: Literal["Monotonic", "Cyclic"] = "Monotonic"
cyclic_data: list[CyclicDataRow] = Field(default_factory=list)

View file

@ -23,176 +23,176 @@ class CyclicDataRow(BaseModel):
class Concrete01ZeroTensileStrengthSpec(BaseModel):
model_config = ConfigDict(
json_schema_extra={
'x-gid-name': 'Concrete01_(Zero_tensile_strength)',
'x-book': 'Uniaxial_Concrete_Materials',
'dependencies': [
"x-gid-name": "Concrete01_(Zero_tensile_strength)",
"x-book": "Uniaxial_Concrete_Materials",
"dependencies": [
{
'field': 'strength_class',
'gid_name': 'Strength_class',
'rules': [
"field": "strength_class",
"gid_name": "Strength_class",
"rules": [
{
'trigger': 'C12/15',
'actions': [
"trigger": "C12/15",
"actions": [
{
'action': 'RESTORE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'C16/20',
'actions': [
"trigger": "C16/20",
"actions": [
{
'action': 'RESTORE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'C20/25',
'actions': [
"trigger": "C20/25",
"actions": [
{
'action': 'RESTORE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'C25/30',
'actions': [
"trigger": "C25/30",
"actions": [
{
'action': 'RESTORE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'C30/37',
'actions': [
"trigger": "C30/37",
"actions": [
{
'action': 'RESTORE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'C35/45',
'actions': [
"trigger": "C35/45",
"actions": [
{
'action': 'RESTORE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'C40/50',
'actions': [
"trigger": "C40/50",
"actions": [
{
'action': 'RESTORE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'C45/55',
'actions': [
"trigger": "C45/55",
"actions": [
{
'action': 'RESTORE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'C50/60',
'actions': [
"trigger": "C50/60",
"actions": [
{
'action': 'RESTORE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'C60/75',
'actions': [
"trigger": "C60/75",
"actions": [
{
'action': 'RESTORE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'C70/85',
'actions': [
"trigger": "C70/85",
"actions": [
{
'action': 'RESTORE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'C80/95',
'actions': [
"trigger": "C80/95",
"actions": [
{
'action': 'RESTORE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'C90/105',
'actions': [
"trigger": "C90/105",
"actions": [
{
'action': 'RESTORE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'Custom',
'actions': [
"trigger": "Custom",
"actions": [
{
'action': 'HIDE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
],
},
{
'field': 'analysis_type',
'gid_name': 'Analysis_type',
'rules': [
"field": "analysis_type",
"gid_name": "Analysis_type",
"rules": [
{
'trigger': 'Monotonic',
'actions': [
"trigger": "Monotonic",
"actions": [
{
'action': 'HIDE',
'field': 'Cyclic_data',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Cyclic_data",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'Cyclic',
'actions': [
"trigger": "Cyclic",
"actions": [
{
'action': 'RESTORE',
'field': 'Cyclic_data',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Cyclic_data",
"target": "#CURRENT#",
},
],
},
@ -202,15 +202,36 @@ class Concrete01ZeroTensileStrengthSpec(BaseModel):
}
)
material: Literal['Concrete01'] = Field('Concrete01', description='uniaxial Kent-Scott-Park concrete material object with degraded linear unloading/reloading stiffness according to the work of Karsan-Jirsa and no tensile strength')
strength_class: Literal['C12/15', 'C16/20', 'C20/25', 'C25/30', 'C30/37', 'C35/45', 'C40/50', 'C45/55', 'C50/60', 'C55/67', 'C60/75', 'C70/85', 'C80/95', 'C90/105', 'Custom'] = Field('Custom', description='Choose concrete strength category, to take some standard values in the following fields.')
strength_type: Literal['Mean', 'Characteristic'] = 'Characteristic'
compressive_strength_fpc: str = '-20 MPa' # TODO: unit-aware type
material: Literal["Concrete01"] = Field(
"Concrete01",
description="uniaxial Kent-Scott-Park concrete material object with degraded linear unloading/reloading stiffness according to the work of Karsan-Jirsa and no tensile strength",
)
strength_class: Literal[
"C12/15",
"C16/20",
"C20/25",
"C25/30",
"C30/37",
"C35/45",
"C40/50",
"C45/55",
"C50/60",
"C55/67",
"C60/75",
"C70/85",
"C80/95",
"C90/105",
"Custom",
] = Field(
"Custom",
description="Choose concrete strength category, to take some standard values in the following fields.",
)
strength_type: Literal["Mean", "Characteristic"] = "Characteristic"
compressive_strength_fpc: str = "-20 MPa" # TODO: unit-aware type
strain_at_maximum_strength_epsc0: float = -2.0e-3
crushing_strength_fpcu: str = '-17.0 MPa' # TODO: unit-aware type
crushing_strength_fpcu: str = "-17.0 MPa" # TODO: unit-aware type
strain_at_crushing_strength_epscu: float = -3.5e-3
analysis_type: Literal['Monotonic', 'Cyclic'] = 'Monotonic'
analysis_type: Literal["Monotonic", "Cyclic"] = "Monotonic"
cyclic_data: list[CyclicDataRow] = Field(default_factory=list)
field: Literal['_'] = '_'
set_as_variable: Literal['0', '1'] = '0'
field: Literal["_"] = "_"
set_as_variable: Literal["0", "1"] = "0"

View file

@ -23,176 +23,176 @@ class CyclicDataRow(BaseModel):
class Concrete02LinearTensionSofteningSpec(BaseModel):
model_config = ConfigDict(
json_schema_extra={
'x-gid-name': 'Concrete02_(Linear_tension_softening)',
'x-book': 'Uniaxial_Concrete_Materials',
'dependencies': [
"x-gid-name": "Concrete02_(Linear_tension_softening)",
"x-book": "Uniaxial_Concrete_Materials",
"dependencies": [
{
'field': 'strength_class',
'gid_name': 'Strength_class',
'rules': [
"field": "strength_class",
"gid_name": "Strength_class",
"rules": [
{
'trigger': 'C12/15',
'actions': [
"trigger": "C12/15",
"actions": [
{
'action': 'RESTORE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'C16/20',
'actions': [
"trigger": "C16/20",
"actions": [
{
'action': 'RESTORE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'C20/25',
'actions': [
"trigger": "C20/25",
"actions": [
{
'action': 'RESTORE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'C25/30',
'actions': [
"trigger": "C25/30",
"actions": [
{
'action': 'RESTORE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'C30/37',
'actions': [
"trigger": "C30/37",
"actions": [
{
'action': 'RESTORE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'C35/45',
'actions': [
"trigger": "C35/45",
"actions": [
{
'action': 'RESTORE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'C40/50',
'actions': [
"trigger": "C40/50",
"actions": [
{
'action': 'RESTORE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'C45/55',
'actions': [
"trigger": "C45/55",
"actions": [
{
'action': 'RESTORE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'C50/60',
'actions': [
"trigger": "C50/60",
"actions": [
{
'action': 'RESTORE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'C60/75',
'actions': [
"trigger": "C60/75",
"actions": [
{
'action': 'RESTORE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'C70/85',
'actions': [
"trigger": "C70/85",
"actions": [
{
'action': 'RESTORE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'C80/95',
'actions': [
"trigger": "C80/95",
"actions": [
{
'action': 'RESTORE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'C90/105',
'actions': [
"trigger": "C90/105",
"actions": [
{
'action': 'RESTORE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'Custom',
'actions': [
"trigger": "Custom",
"actions": [
{
'action': 'HIDE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
],
},
{
'field': 'analysis_type',
'gid_name': 'Analysis_type',
'rules': [
"field": "analysis_type",
"gid_name": "Analysis_type",
"rules": [
{
'trigger': 'Monotonic',
'actions': [
"trigger": "Monotonic",
"actions": [
{
'action': 'HIDE',
'field': 'Cyclic_data',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Cyclic_data",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'Cyclic',
'actions': [
"trigger": "Cyclic",
"actions": [
{
'action': 'RESTORE',
'field': 'Cyclic_data',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Cyclic_data",
"target": "#CURRENT#",
},
],
},
@ -202,18 +202,36 @@ class Concrete02LinearTensionSofteningSpec(BaseModel):
}
)
material: Literal['Concrete02'] = 'Concrete02'
strength_class: Literal['C12/15', 'C16/20', 'C20/25', 'C25/30', 'C30/37', 'C35/45', 'C40/50', 'C45/55', 'C50/60', 'C55/67', 'C60/75', 'C70/85', 'C80/95', 'C90/105', 'Custom'] = Field('Custom', description='Choose concrete strength category, to generate fast properties in the following fields.')
strength_type: Literal['Mean', 'Characteristic'] = 'Characteristic'
compressive_strength_fpc: str = '-20 MPa' # TODO: unit-aware type
material: Literal["Concrete02"] = "Concrete02"
strength_class: Literal[
"C12/15",
"C16/20",
"C20/25",
"C25/30",
"C30/37",
"C35/45",
"C40/50",
"C45/55",
"C50/60",
"C55/67",
"C60/75",
"C70/85",
"C80/95",
"C90/105",
"Custom",
] = Field(
"Custom",
description="Choose concrete strength category, to generate fast properties in the following fields.",
)
strength_type: Literal["Mean", "Characteristic"] = "Characteristic"
compressive_strength_fpc: str = "-20 MPa" # TODO: unit-aware type
strain_at_maximum_strength_epsc0: float = -2.0e-3
crushing_strength_fpcu: str = '-17.0 MPa' # TODO: unit-aware type
crushing_strength_fpcu: str = "-17.0 MPa" # TODO: unit-aware type
strain_at_crushing_strength_epscu: float = -3.5e-3
ratio_between_unloading_slope_at_epscu_and_initial_slope_lambda: float = 0.5
tensile_strength_ft: str = '2.2 MPa' # TODO: unit-aware type
tension_softening_stiffness_ets: str = '2 GPa' # TODO: unit-aware type
analysis_type: Literal['Monotonic', 'Cyclic'] = 'Monotonic'
tensile_strength_ft: str = "2.2 MPa" # TODO: unit-aware type
tension_softening_stiffness_ets: str = "2 GPa" # TODO: unit-aware type
analysis_type: Literal["Monotonic", "Cyclic"] = "Monotonic"
cyclic_data: list[CyclicDataRow] = Field(default_factory=list)
field: Literal['_'] = '_'
set_as_variable: Literal['0', '1'] = '0'
field: Literal["_"] = "_"
set_as_variable: Literal["0", "1"] = "0"

View file

@ -23,176 +23,176 @@ class CyclicDataRow(BaseModel):
class Concrete04PopovicsConcreteSpec(BaseModel):
model_config = ConfigDict(
json_schema_extra={
'x-gid-name': 'Concrete04_(Popovics_concrete)',
'x-book': 'Uniaxial_Concrete_Materials',
'dependencies': [
"x-gid-name": "Concrete04_(Popovics_concrete)",
"x-book": "Uniaxial_Concrete_Materials",
"dependencies": [
{
'field': 'strength_class',
'gid_name': 'Strength_class',
'rules': [
"field": "strength_class",
"gid_name": "Strength_class",
"rules": [
{
'trigger': 'C12/15',
'actions': [
"trigger": "C12/15",
"actions": [
{
'action': 'RESTORE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'C16/20',
'actions': [
"trigger": "C16/20",
"actions": [
{
'action': 'RESTORE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'C20/25',
'actions': [
"trigger": "C20/25",
"actions": [
{
'action': 'RESTORE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'C25/30',
'actions': [
"trigger": "C25/30",
"actions": [
{
'action': 'RESTORE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'C30/37',
'actions': [
"trigger": "C30/37",
"actions": [
{
'action': 'RESTORE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'C35/45',
'actions': [
"trigger": "C35/45",
"actions": [
{
'action': 'RESTORE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'C40/50',
'actions': [
"trigger": "C40/50",
"actions": [
{
'action': 'RESTORE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'C45/55',
'actions': [
"trigger": "C45/55",
"actions": [
{
'action': 'RESTORE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'C50/60',
'actions': [
"trigger": "C50/60",
"actions": [
{
'action': 'RESTORE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'C60/75',
'actions': [
"trigger": "C60/75",
"actions": [
{
'action': 'RESTORE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'C70/85',
'actions': [
"trigger": "C70/85",
"actions": [
{
'action': 'RESTORE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'C80/95',
'actions': [
"trigger": "C80/95",
"actions": [
{
'action': 'RESTORE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'C90/105',
'actions': [
"trigger": "C90/105",
"actions": [
{
'action': 'RESTORE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'Custom',
'actions': [
"trigger": "Custom",
"actions": [
{
'action': 'HIDE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
],
},
{
'field': 'analysis_type',
'gid_name': 'Analysis_type',
'rules': [
"field": "analysis_type",
"gid_name": "Analysis_type",
"rules": [
{
'trigger': 'Monotonic',
'actions': [
"trigger": "Monotonic",
"actions": [
{
'action': 'HIDE',
'field': 'Cyclic_data',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Cyclic_data",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'Cyclic',
'actions': [
"trigger": "Cyclic",
"actions": [
{
'action': 'RESTORE',
'field': 'Cyclic_data',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Cyclic_data",
"target": "#CURRENT#",
},
],
},
@ -202,17 +202,35 @@ class Concrete04PopovicsConcreteSpec(BaseModel):
}
)
material: Literal['Concrete04'] = 'Concrete04'
strength_class: Literal['C12/15', 'C16/20', 'C20/25', 'C25/30', 'C30/37', 'C35/45', 'C40/50', 'C45/55', 'C50/60', 'C55/67', 'C60/75', 'C70/85', 'C80/95', 'C90/105', 'Custom'] = Field('Custom', description='Choose concrete strength category, to generate fast properties in the following fields.')
strength_type: Literal['Mean', 'Characteristic'] = 'Characteristic'
compressive_strength: str = '-20 MPa' # TODO: unit-aware type
material: Literal["Concrete04"] = "Concrete04"
strength_class: Literal[
"C12/15",
"C16/20",
"C20/25",
"C25/30",
"C30/37",
"C35/45",
"C40/50",
"C45/55",
"C50/60",
"C55/67",
"C60/75",
"C70/85",
"C80/95",
"C90/105",
"Custom",
] = Field(
"Custom",
description="Choose concrete strength category, to generate fast properties in the following fields.",
)
strength_type: Literal["Mean", "Characteristic"] = "Characteristic"
compressive_strength: str = "-20 MPa" # TODO: unit-aware type
strain_at_maximum_strength: float = -2.0e-3
strain_at_crushing_strength: float = -3.5e-3
initial_stiffness: str = '30 GPa' # TODO: unit-aware type
maximum_tensile_strength: str = '2.2 MPa' # TODO: unit-aware type
initial_stiffness: str = "30 GPa" # TODO: unit-aware type
maximum_tensile_strength: str = "2.2 MPa" # TODO: unit-aware type
ultimate_tensile_strain: float = 1e-3
analysis_type: Literal['Monotonic', 'Cyclic'] = 'Monotonic'
analysis_type: Literal["Monotonic", "Cyclic"] = "Monotonic"
cyclic_data: list[CyclicDataRow] = Field(default_factory=list)
field: Literal['_'] = '_'
set_as_variable: Literal['0', '1'] = '0'
field: Literal["_"] = "_"
set_as_variable: Literal["0", "1"] = "0"

View file

@ -23,176 +23,176 @@ class CyclicDataRow(BaseModel):
class Concrete06Spec(BaseModel):
model_config = ConfigDict(
json_schema_extra={
'x-gid-name': 'Concrete06',
'x-book': 'Uniaxial_Concrete_Materials',
'dependencies': [
"x-gid-name": "Concrete06",
"x-book": "Uniaxial_Concrete_Materials",
"dependencies": [
{
'field': 'strength_class',
'gid_name': 'Strength_class',
'rules': [
"field": "strength_class",
"gid_name": "Strength_class",
"rules": [
{
'trigger': 'C12/15',
'actions': [
"trigger": "C12/15",
"actions": [
{
'action': 'RESTORE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'C16/20',
'actions': [
"trigger": "C16/20",
"actions": [
{
'action': 'RESTORE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'C20/25',
'actions': [
"trigger": "C20/25",
"actions": [
{
'action': 'RESTORE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'C25/30',
'actions': [
"trigger": "C25/30",
"actions": [
{
'action': 'RESTORE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'C30/37',
'actions': [
"trigger": "C30/37",
"actions": [
{
'action': 'RESTORE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'C35/45',
'actions': [
"trigger": "C35/45",
"actions": [
{
'action': 'RESTORE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'C40/50',
'actions': [
"trigger": "C40/50",
"actions": [
{
'action': 'RESTORE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'C45/55',
'actions': [
"trigger": "C45/55",
"actions": [
{
'action': 'RESTORE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'C50/60',
'actions': [
"trigger": "C50/60",
"actions": [
{
'action': 'RESTORE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'C60/75',
'actions': [
"trigger": "C60/75",
"actions": [
{
'action': 'RESTORE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'C70/85',
'actions': [
"trigger": "C70/85",
"actions": [
{
'action': 'RESTORE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'C80/95',
'actions': [
"trigger": "C80/95",
"actions": [
{
'action': 'RESTORE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'C90/105',
'actions': [
"trigger": "C90/105",
"actions": [
{
'action': 'RESTORE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'Custom',
'actions': [
"trigger": "Custom",
"actions": [
{
'action': 'HIDE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
],
},
{
'field': 'analysis_type',
'gid_name': 'Analysis_type',
'rules': [
"field": "analysis_type",
"gid_name": "Analysis_type",
"rules": [
{
'trigger': 'Monotonic',
'actions': [
"trigger": "Monotonic",
"actions": [
{
'action': 'HIDE',
'field': 'Cyclic_data',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Cyclic_data",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'Cyclic',
'actions': [
"trigger": "Cyclic",
"actions": [
{
'action': 'RESTORE',
'field': 'Cyclic_data',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Cyclic_data",
"target": "#CURRENT#",
},
],
},
@ -202,20 +202,38 @@ class Concrete06Spec(BaseModel):
}
)
material: Literal['Concrete06'] = 'Concrete06'
strength_class: Literal['C12/15', 'C16/20', 'C20/25', 'C25/30', 'C30/37', 'C35/45', 'C40/50', 'C45/55', 'C50/60', 'C55/67', 'C60/75', 'C70/85', 'C80/95', 'C90/105', 'Custom'] = Field('Custom', description='Choose concrete strength category, to generate fast properties in the following fields.')
strength_type: Literal['Mean', 'Characteristic'] = 'Characteristic'
concrete_compressive_strength_fc: str = '-20 MPa' # TODO: unit-aware type
material: Literal["Concrete06"] = "Concrete06"
strength_class: Literal[
"C12/15",
"C16/20",
"C20/25",
"C25/30",
"C30/37",
"C35/45",
"C40/50",
"C45/55",
"C50/60",
"C55/67",
"C60/75",
"C70/85",
"C80/95",
"C90/105",
"Custom",
] = Field(
"Custom",
description="Choose concrete strength category, to generate fast properties in the following fields.",
)
strength_type: Literal["Mean", "Characteristic"] = "Characteristic"
concrete_compressive_strength_fc: str = "-20 MPa" # TODO: unit-aware type
strain_at_compressive_strength_e0: float = -2.0e-3
compressive_shape_factor_n: int = 1
post_peak_compressive_shape_factor_k: int = 1
parameter_a1_for_compressive_plastic_strain_definition: float = -2.500e-003
tensile_strength_fcr: str = '2.2 MPa' # TODO: unit-aware type
tensile_strength_fcr: str = "2.2 MPa" # TODO: unit-aware type
tensile_strain_at_peak_stress_ecr: float = 1.100e-004
exponent_of_the_tension_stiffering_curve_b: int = 1
parameter_a2_for_tensile_plastic_strain_definition: float = 7.700e-004
analysis_type: Literal['Monotonic', 'Cyclic'] = 'Monotonic'
analysis_type: Literal["Monotonic", "Cyclic"] = "Monotonic"
cyclic_data: list[CyclicDataRow] = Field(default_factory=list)
field: Literal['_'] = '_'
set_as_variable: Literal['0', '1'] = '0'
field: Literal["_"] = "_"
set_as_variable: Literal["0", "1"] = "0"

View file

@ -23,202 +23,202 @@ class CyclicDataRow(BaseModel):
class ConcretecmSpec(BaseModel):
model_config = ConfigDict(
json_schema_extra={
'x-gid-name': 'ConcreteCM',
'x-book': 'Uniaxial_Concrete_Materials',
'dependencies': [
"x-gid-name": "ConcreteCM",
"x-book": "Uniaxial_Concrete_Materials",
"dependencies": [
{
'field': 'strength_class',
'gid_name': 'Strength_class',
'rules': [
"field": "strength_class",
"gid_name": "Strength_class",
"rules": [
{
'trigger': 'C12/15',
'actions': [
"trigger": "C12/15",
"actions": [
{
'action': 'RESTORE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'C16/20',
'actions': [
"trigger": "C16/20",
"actions": [
{
'action': 'RESTORE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'C20/25',
'actions': [
"trigger": "C20/25",
"actions": [
{
'action': 'RESTORE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'C25/30',
'actions': [
"trigger": "C25/30",
"actions": [
{
'action': 'RESTORE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'C30/37',
'actions': [
"trigger": "C30/37",
"actions": [
{
'action': 'RESTORE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'C35/45',
'actions': [
"trigger": "C35/45",
"actions": [
{
'action': 'RESTORE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'C40/50',
'actions': [
"trigger": "C40/50",
"actions": [
{
'action': 'RESTORE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'C45/55',
'actions': [
"trigger": "C45/55",
"actions": [
{
'action': 'RESTORE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'C50/60',
'actions': [
"trigger": "C50/60",
"actions": [
{
'action': 'RESTORE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'C60/75',
'actions': [
"trigger": "C60/75",
"actions": [
{
'action': 'RESTORE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'C70/85',
'actions': [
"trigger": "C70/85",
"actions": [
{
'action': 'RESTORE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'C80/95',
'actions': [
"trigger": "C80/95",
"actions": [
{
'action': 'RESTORE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'C90/105',
'actions': [
"trigger": "C90/105",
"actions": [
{
'action': 'RESTORE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'Custom',
'actions': [
"trigger": "Custom",
"actions": [
{
'action': 'HIDE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
],
},
{
'field': 'consider_gap_closure',
'gid_name': 'Consider_gap_closure',
'rules': [
"field": "consider_gap_closure",
"gid_name": "Consider_gap_closure",
"rules": [
{
'trigger': '1',
'actions': [
"trigger": "1",
"actions": [
{
'action': 'RESTORE',
'field': 'Gap_parameter',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Gap_parameter",
"target": "#CURRENT#",
},
],
},
{
'trigger': '0',
'actions': [
"trigger": "0",
"actions": [
{
'action': 'HIDE',
'field': 'Gap_parameter',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Gap_parameter",
"target": "#CURRENT#",
},
],
},
],
},
{
'field': 'analysis_type',
'gid_name': 'Analysis_type',
'rules': [
"field": "analysis_type",
"gid_name": "Analysis_type",
"rules": [
{
'trigger': 'Monotonic',
'actions': [
"trigger": "Monotonic",
"actions": [
{
'action': 'HIDE',
'field': 'Cyclic_data',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Cyclic_data",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'Cyclic',
'actions': [
"trigger": "Cyclic",
"actions": [
{
'action': 'RESTORE',
'field': 'Cyclic_data',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Cyclic_data",
"target": "#CURRENT#",
},
],
},
@ -228,19 +228,37 @@ class ConcretecmSpec(BaseModel):
}
)
material: Literal['ConcreteCM'] = 'ConcreteCM'
strength_class: Literal['C12/15', 'C16/20', 'C20/25', 'C25/30', 'C30/37', 'C35/45', 'C40/50', 'C45/55', 'C50/60', 'C55/67', 'C60/75', 'C70/85', 'C80/95', 'C90/105', 'Custom'] = Field('Custom', description='Choose concrete strength category, to generate fast properties in the following fields.')
strength_type: Literal['Mean', 'Characteristic'] = 'Characteristic'
concrete_compressive_strength_fpcc: str = '-20 MPa' # TODO: unit-aware type
material: Literal["ConcreteCM"] = "ConcreteCM"
strength_class: Literal[
"C12/15",
"C16/20",
"C20/25",
"C25/30",
"C30/37",
"C35/45",
"C40/50",
"C45/55",
"C50/60",
"C55/67",
"C60/75",
"C70/85",
"C80/95",
"C90/105",
"Custom",
] = Field(
"Custom",
description="Choose concrete strength category, to generate fast properties in the following fields.",
)
strength_type: Literal["Mean", "Characteristic"] = "Characteristic"
concrete_compressive_strength_fpcc: str = "-20 MPa" # TODO: unit-aware type
strain_at_compressive_strength_epcc: float = -2.0e-3
initial_tangent_modulus_ec: str = '30 GPa' # TODO: unit-aware type
initial_tangent_modulus_ec: str = "30 GPa" # TODO: unit-aware type
shape_parameter_rc_in_tsai_s_equation_for_compression: int = 7
critical_strain_on_compression_envelope: float = 1.035
tensile_strength_ft: str = '2.2 MPa' # TODO: unit-aware type
tensile_strength_ft: str = "2.2 MPa" # TODO: unit-aware type
strain_at_tensile_strength_et: float = 1.100e-004
shape_parameter_rc_in_tsai_s_equation_for_tension: float = 1.2
critical_strain_on_tension_envelope: int = 10000
consider_gap_closure: Literal['1', '0'] = '0'
analysis_type: Literal['Monotonic', 'Cyclic'] = 'Monotonic'
consider_gap_closure: Literal["1", "0"] = "0"
analysis_type: Literal["Monotonic", "Cyclic"] = "Monotonic"
cyclic_data: list[CyclicDataRow] = Field(default_factory=list)

View file

@ -15,42 +15,173 @@ from otko.core.catalog.generated.conditions.line_uniform_forces import LineUnifo
from otko.core.catalog.generated.conditions.point_displacements import PointDisplacementsSpec
from otko.core.catalog.generated.conditions.line_displacements import LineDisplacementsSpec
from otko.core.catalog.generated.conditions.surface_displacements import SurfaceDisplacementsSpec
from otko.core.catalog.generated.conditions.point_ground_motion_from_record import PointGroundMotionFromRecordSpec
from otko.core.catalog.generated.conditions.point_sine_ground_motion import PointSineGroundMotionSpec
from otko.core.catalog.generated.conditions.point_equal_constraint_master_node import PointEqualConstraintMasterNodeSpec
from otko.core.catalog.generated.conditions.point_equal_constraint_slave_nodes import PointEqualConstraintSlaveNodesSpec
from otko.core.catalog.generated.conditions.line_equal_constraint_slave_nodes import LineEqualConstraintSlaveNodesSpec
from otko.core.catalog.generated.conditions.point_rigid_link_master_node import PointRigidLinkMasterNodeSpec
from otko.core.catalog.generated.conditions.point_rigid_link_slave_nodes import PointRigidLinkSlaveNodesSpec
from otko.core.catalog.generated.conditions.line_rigid_link_slave_nodes import LineRigidLinkSlaveNodesSpec
from otko.core.catalog.generated.conditions.point_rigid_diaphragm_master_node import PointRigidDiaphragmMasterNodeSpec
from otko.core.catalog.generated.conditions.point_rigid_diaphragm_slave_nodes import PointRigidDiaphragmSlaveNodesSpec
from otko.core.catalog.generated.conditions.line_rigid_diaphragm_slave_nodes import LineRigidDiaphragmSlaveNodesSpec
from otko.core.catalog.generated.conditions.point_ground_motion_from_record import (
PointGroundMotionFromRecordSpec,
)
from otko.core.catalog.generated.conditions.point_sine_ground_motion import (
PointSineGroundMotionSpec,
)
from otko.core.catalog.generated.conditions.point_equal_constraint_master_node import (
PointEqualConstraintMasterNodeSpec,
)
from otko.core.catalog.generated.conditions.point_equal_constraint_slave_nodes import (
PointEqualConstraintSlaveNodesSpec,
)
from otko.core.catalog.generated.conditions.line_equal_constraint_slave_nodes import (
LineEqualConstraintSlaveNodesSpec,
)
from otko.core.catalog.generated.conditions.point_rigid_link_master_node import (
PointRigidLinkMasterNodeSpec,
)
from otko.core.catalog.generated.conditions.point_rigid_link_slave_nodes import (
PointRigidLinkSlaveNodesSpec,
)
from otko.core.catalog.generated.conditions.line_rigid_link_slave_nodes import (
LineRigidLinkSlaveNodesSpec,
)
from otko.core.catalog.generated.conditions.point_rigid_diaphragm_master_node import (
PointRigidDiaphragmMasterNodeSpec,
)
from otko.core.catalog.generated.conditions.point_rigid_diaphragm_slave_nodes import (
PointRigidDiaphragmSlaveNodesSpec,
)
from otko.core.catalog.generated.conditions.line_rigid_diaphragm_slave_nodes import (
LineRigidDiaphragmSlaveNodesSpec,
)
from otko.core.catalog.generated.conditions.point_mass import PointMassSpec
from otko.core.catalog.generated.conditions.line_mass import LineMassSpec
from otko.core.catalog.generated.conditions.surface_mass import SurfaceMassSpec
from otko.core.catalog.generated.conditions.volume_mass import VolumeMassSpec
from otko.core.catalog.generated.conditions.line_rayleigh_damping_elements import LineRayleighDampingElementsSpec
from otko.core.catalog.generated.conditions.surface_rayleigh_damping_elements import SurfaceRayleighDampingElementsSpec
from otko.core.catalog.generated.conditions.volume_rayleigh_damping_elements import VolumeRayleighDampingElementsSpec
from otko.core.catalog.generated.conditions.point_rayleigh_damping_nodes import PointRayleighDampingNodesSpec
from otko.core.catalog.generated.conditions.line_rayleigh_damping_nodes import LineRayleighDampingNodesSpec
from otko.core.catalog.generated.conditions.surface_rayleigh_damping_nodes import SurfaceRayleighDampingNodesSpec
from otko.core.catalog.generated.conditions.volume_rayleigh_damping_nodes import VolumeRayleighDampingNodesSpec
from otko.core.catalog.generated.conditions.line_rayleigh_damping_elements import (
LineRayleighDampingElementsSpec,
)
from otko.core.catalog.generated.conditions.surface_rayleigh_damping_elements import (
SurfaceRayleighDampingElementsSpec,
)
from otko.core.catalog.generated.conditions.volume_rayleigh_damping_elements import (
VolumeRayleighDampingElementsSpec,
)
from otko.core.catalog.generated.conditions.point_rayleigh_damping_nodes import (
PointRayleighDampingNodesSpec,
)
from otko.core.catalog.generated.conditions.line_rayleigh_damping_nodes import (
LineRayleighDampingNodesSpec,
)
from otko.core.catalog.generated.conditions.surface_rayleigh_damping_nodes import (
SurfaceRayleighDampingNodesSpec,
)
from otko.core.catalog.generated.conditions.volume_rayleigh_damping_nodes import (
VolumeRayleighDampingNodesSpec,
)
from otko.core.catalog.generated.conditions.point_zerolength import PointZerolengthSpec
from otko.core.catalog.generated.conditions.line_beam_contact_master_end_nodes import LineBeamContactMasterEndNodesSpec
from otko.core.catalog.generated.conditions.point_beam_contact_slave_nodes import PointBeamContactSlaveNodesSpec
from otko.core.catalog.generated.conditions.point_body_constraint_master_node import PointBodyConstraintMasterNodeSpec
from otko.core.catalog.generated.conditions.point_body_constraint_slave_nodes import PointBodyConstraintSlaveNodesSpec
from otko.core.catalog.generated.conditions.line_body_constraint_slave_nodes import LineBodyConstraintSlaveNodesSpec
from otko.core.catalog.generated.conditions.line_beam_contact_master_end_nodes import (
LineBeamContactMasterEndNodesSpec,
)
from otko.core.catalog.generated.conditions.point_beam_contact_slave_nodes import (
PointBeamContactSlaveNodesSpec,
)
from otko.core.catalog.generated.conditions.point_body_constraint_master_node import (
PointBodyConstraintMasterNodeSpec,
)
from otko.core.catalog.generated.conditions.point_body_constraint_slave_nodes import (
PointBodyConstraintSlaveNodesSpec,
)
from otko.core.catalog.generated.conditions.line_body_constraint_slave_nodes import (
LineBodyConstraintSlaveNodesSpec,
)
from otko.core.catalog.generated.conditions.zerolength import ZerolengthSpec
Restraints = Union[PointRestraintsSpec, LineRestraintsSpec, SurfaceRestraintsSpec]
Loads = Union[PointForcesSpec, LineForcesSpec, SurfaceForcesSpec, LineUniformForcesSpec, PointDisplacementsSpec, LineDisplacementsSpec, SurfaceDisplacementsSpec, PointGroundMotionFromRecordSpec, PointSineGroundMotionSpec]
Constraints = Union[PointEqualConstraintMasterNodeSpec, PointEqualConstraintSlaveNodesSpec, LineEqualConstraintSlaveNodesSpec, PointRigidLinkMasterNodeSpec, PointRigidLinkSlaveNodesSpec, LineRigidLinkSlaveNodesSpec, PointRigidDiaphragmMasterNodeSpec, PointRigidDiaphragmSlaveNodesSpec, LineRigidDiaphragmSlaveNodesSpec]
MassDamping = Union[PointMassSpec, LineMassSpec, SurfaceMassSpec, VolumeMassSpec, LineRayleighDampingElementsSpec, SurfaceRayleighDampingElementsSpec, VolumeRayleighDampingElementsSpec, PointRayleighDampingNodesSpec, LineRayleighDampingNodesSpec, SurfaceRayleighDampingNodesSpec, VolumeRayleighDampingNodesSpec]
ZerolengthElements = Union[PointZerolengthSpec, LineBeamContactMasterEndNodesSpec, PointBeamContactSlaveNodesSpec]
OldConditions = Union[PointBodyConstraintMasterNodeSpec, PointBodyConstraintSlaveNodesSpec, LineBodyConstraintSlaveNodesSpec, ZerolengthSpec]
Loads = Union[
PointForcesSpec,
LineForcesSpec,
SurfaceForcesSpec,
LineUniformForcesSpec,
PointDisplacementsSpec,
LineDisplacementsSpec,
SurfaceDisplacementsSpec,
PointGroundMotionFromRecordSpec,
PointSineGroundMotionSpec,
]
Constraints = Union[
PointEqualConstraintMasterNodeSpec,
PointEqualConstraintSlaveNodesSpec,
LineEqualConstraintSlaveNodesSpec,
PointRigidLinkMasterNodeSpec,
PointRigidLinkSlaveNodesSpec,
LineRigidLinkSlaveNodesSpec,
PointRigidDiaphragmMasterNodeSpec,
PointRigidDiaphragmSlaveNodesSpec,
LineRigidDiaphragmSlaveNodesSpec,
]
MassDamping = Union[
PointMassSpec,
LineMassSpec,
SurfaceMassSpec,
VolumeMassSpec,
LineRayleighDampingElementsSpec,
SurfaceRayleighDampingElementsSpec,
VolumeRayleighDampingElementsSpec,
PointRayleighDampingNodesSpec,
LineRayleighDampingNodesSpec,
SurfaceRayleighDampingNodesSpec,
VolumeRayleighDampingNodesSpec,
]
ZerolengthElements = Union[
PointZerolengthSpec, LineBeamContactMasterEndNodesSpec, PointBeamContactSlaveNodesSpec
]
OldConditions = Union[
PointBodyConstraintMasterNodeSpec,
PointBodyConstraintSlaveNodesSpec,
LineBodyConstraintSlaveNodesSpec,
ZerolengthSpec,
]
__all__ = ['PointRestraintsSpec', 'LineRestraintsSpec', 'SurfaceRestraintsSpec', 'PointForcesSpec', 'LineForcesSpec', 'SurfaceForcesSpec', 'LineUniformForcesSpec', 'PointDisplacementsSpec', 'LineDisplacementsSpec', 'SurfaceDisplacementsSpec', 'PointGroundMotionFromRecordSpec', 'PointSineGroundMotionSpec', 'PointEqualConstraintMasterNodeSpec', 'PointEqualConstraintSlaveNodesSpec', 'LineEqualConstraintSlaveNodesSpec', 'PointRigidLinkMasterNodeSpec', 'PointRigidLinkSlaveNodesSpec', 'LineRigidLinkSlaveNodesSpec', 'PointRigidDiaphragmMasterNodeSpec', 'PointRigidDiaphragmSlaveNodesSpec', 'LineRigidDiaphragmSlaveNodesSpec', 'PointMassSpec', 'LineMassSpec', 'SurfaceMassSpec', 'VolumeMassSpec', 'LineRayleighDampingElementsSpec', 'SurfaceRayleighDampingElementsSpec', 'VolumeRayleighDampingElementsSpec', 'PointRayleighDampingNodesSpec', 'LineRayleighDampingNodesSpec', 'SurfaceRayleighDampingNodesSpec', 'VolumeRayleighDampingNodesSpec', 'PointZerolengthSpec', 'LineBeamContactMasterEndNodesSpec', 'PointBeamContactSlaveNodesSpec', 'PointBodyConstraintMasterNodeSpec', 'PointBodyConstraintSlaveNodesSpec', 'LineBodyConstraintSlaveNodesSpec', 'ZerolengthSpec', 'Restraints', 'Loads', 'Constraints', 'MassDamping', 'ZerolengthElements', 'OldConditions']
__all__ = [
"PointRestraintsSpec",
"LineRestraintsSpec",
"SurfaceRestraintsSpec",
"PointForcesSpec",
"LineForcesSpec",
"SurfaceForcesSpec",
"LineUniformForcesSpec",
"PointDisplacementsSpec",
"LineDisplacementsSpec",
"SurfaceDisplacementsSpec",
"PointGroundMotionFromRecordSpec",
"PointSineGroundMotionSpec",
"PointEqualConstraintMasterNodeSpec",
"PointEqualConstraintSlaveNodesSpec",
"LineEqualConstraintSlaveNodesSpec",
"PointRigidLinkMasterNodeSpec",
"PointRigidLinkSlaveNodesSpec",
"LineRigidLinkSlaveNodesSpec",
"PointRigidDiaphragmMasterNodeSpec",
"PointRigidDiaphragmSlaveNodesSpec",
"LineRigidDiaphragmSlaveNodesSpec",
"PointMassSpec",
"LineMassSpec",
"SurfaceMassSpec",
"VolumeMassSpec",
"LineRayleighDampingElementsSpec",
"SurfaceRayleighDampingElementsSpec",
"VolumeRayleighDampingElementsSpec",
"PointRayleighDampingNodesSpec",
"LineRayleighDampingNodesSpec",
"SurfaceRayleighDampingNodesSpec",
"VolumeRayleighDampingNodesSpec",
"PointZerolengthSpec",
"LineBeamContactMasterEndNodesSpec",
"PointBeamContactSlaveNodesSpec",
"PointBodyConstraintMasterNodeSpec",
"PointBodyConstraintSlaveNodesSpec",
"LineBodyConstraintSlaveNodesSpec",
"ZerolengthSpec",
"Restraints",
"Loads",
"Constraints",
"MassDamping",
"ZerolengthElements",
"OldConditions",
]

View file

@ -15,10 +15,9 @@ from pydantic import BaseModel, ConfigDict, Field
class LineBeamContactMasterEndNodesSpec(BaseModel):
model_config = ConfigDict(
json_schema_extra={
'x-gid-name': 'Line_Beam_contact_master_end_nodes',
'x-book': 'ZeroLength_Elements',
"x-gid-name": "Line_Beam_contact_master_end_nodes",
"x-book": "ZeroLength_Elements",
}
)
beam_contact_id: int = 1

View file

@ -17,80 +17,80 @@ from pydantic import BaseModel, ConfigDict, Field
class LineBodyConstraintSlaveNodesSpec(BaseModel):
model_config = ConfigDict(
json_schema_extra={
'x-gid-name': 'Line_Body_constraint_slave_nodes',
'x-book': 'Old_Conditions',
'dependencies': [
"x-gid-name": "Line_Body_constraint_slave_nodes",
"x-book": "Old_Conditions",
"dependencies": [
{
'field': 'fast_constraints',
'gid_name': 'Fast_constraints',
'rules': [
"field": "fast_constraints",
"gid_name": "Fast_constraints",
"rules": [
{
'trigger': 'Pinned_Connection',
'actions': [
"trigger": "Pinned_Connection",
"actions": [
{
'action': 'RESTORE',
'field': 'X-Translation',
'target': '1',
"action": "RESTORE",
"field": "X-Translation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'Y-Translation',
'target': '1',
"action": "RESTORE",
"field": "Y-Translation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'Z-Translation',
'target': '1',
"action": "RESTORE",
"field": "Z-Translation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'X-Rotation',
'target': '0',
"action": "RESTORE",
"field": "X-Rotation",
"target": "0",
},
{
'action': 'RESTORE',
'field': 'Y-Rotation',
'target': '0',
"action": "RESTORE",
"field": "Y-Rotation",
"target": "0",
},
{
'action': 'RESTORE',
'field': 'Z-Rotation',
'target': '0',
"action": "RESTORE",
"field": "Z-Rotation",
"target": "0",
},
],
},
{
'trigger': 'Fixed_Connection',
'actions': [
"trigger": "Fixed_Connection",
"actions": [
{
'action': 'RESTORE',
'field': 'X-Translation',
'target': '1',
"action": "RESTORE",
"field": "X-Translation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'Y-Translation',
'target': '1',
"action": "RESTORE",
"field": "Y-Translation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'Z-Translation',
'target': '1',
"action": "RESTORE",
"field": "Z-Translation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'X-Rotation',
'target': '1',
"action": "RESTORE",
"field": "X-Rotation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'Y-Rotation',
'target': '1',
"action": "RESTORE",
"field": "Y-Rotation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'Z-Rotation',
'target': '1',
"action": "RESTORE",
"field": "Z-Rotation",
"target": "1",
},
],
},
@ -100,12 +100,13 @@ class LineBodyConstraintSlaveNodesSpec(BaseModel):
}
)
line_constraint_id_number: int = Field(1, description='Enter a positive integer number for the body constraint.')
x_translation: Literal['1', '0'] = '1'
y_translation: Literal['1', '0'] = '1'
z_translation: Literal['1', '0'] = '1'
x_rotation: Literal['1', '0'] = '1'
y_rotation: Literal['1', '0'] = '1'
z_rotation: Literal['1', '0'] = '1'
fast_constraints: Literal['Pinned_Connection', 'Fixed_Connection'] = 'Pinned_Connection'
line_constraint_id_number: int = Field(
1, description="Enter a positive integer number for the body constraint."
)
x_translation: Literal["1", "0"] = "1"
y_translation: Literal["1", "0"] = "1"
z_translation: Literal["1", "0"] = "1"
x_rotation: Literal["1", "0"] = "1"
y_rotation: Literal["1", "0"] = "1"
z_rotation: Literal["1", "0"] = "1"
fast_constraints: Literal["Pinned_Connection", "Fixed_Connection"] = "Pinned_Connection"

View file

@ -15,15 +15,14 @@ from pydantic import BaseModel, ConfigDict, Field
class LineDisplacementsSpec(BaseModel):
model_config = ConfigDict(
json_schema_extra={
'x-gid-name': 'Line_Displacements',
'x-book': 'Loads',
"x-gid-name": "Line_Displacements",
"x-book": "Loads",
}
)
x_displacement: str = '0.0m' # TODO: unit-aware type
y_displacement: str = '0.0m' # TODO: unit-aware type
z_displacement: str = '0.0m' # TODO: unit-aware type
x_rotation: str = '0.0 rad' # TODO: unit-aware type
y_rotation: str = '0.0 rad' # TODO: unit-aware type
z_rotation: str = '0.0 rad' # TODO: unit-aware type
x_displacement: str = "0.0m" # TODO: unit-aware type
y_displacement: str = "0.0m" # TODO: unit-aware type
z_displacement: str = "0.0m" # TODO: unit-aware type
x_rotation: str = "0.0 rad" # TODO: unit-aware type
y_rotation: str = "0.0 rad" # TODO: unit-aware type
z_rotation: str = "0.0 rad" # TODO: unit-aware type

View file

@ -17,16 +17,17 @@ from pydantic import BaseModel, ConfigDict, Field
class LineEqualConstraintSlaveNodesSpec(BaseModel):
model_config = ConfigDict(
json_schema_extra={
'x-gid-name': 'Line_Equal_constraint_slave_nodes',
'x-book': 'Constraints',
"x-gid-name": "Line_Equal_constraint_slave_nodes",
"x-book": "Constraints",
}
)
equal_constraint_id: int = Field(1, description='Enter a positive integer number for the equal constraint.')
x_translation: Literal['1', '0'] = '1'
y_translation: Literal['1', '0'] = '1'
z_translation: Literal['1', '0'] = '1'
x_rotation: Literal['1', '0'] = '1'
y_rotation: Literal['1', '0'] = '1'
z_rotation: Literal['1', '0'] = '1'
equal_constraint_id: int = Field(
1, description="Enter a positive integer number for the equal constraint."
)
x_translation: Literal["1", "0"] = "1"
y_translation: Literal["1", "0"] = "1"
z_translation: Literal["1", "0"] = "1"
x_rotation: Literal["1", "0"] = "1"
y_rotation: Literal["1", "0"] = "1"
z_rotation: Literal["1", "0"] = "1"

View file

@ -15,15 +15,14 @@ from pydantic import BaseModel, ConfigDict, Field
class LineForcesSpec(BaseModel):
model_config = ConfigDict(
json_schema_extra={
'x-gid-name': 'Line_Forces',
'x-book': 'Loads',
"x-gid-name": "Line_Forces",
"x-book": "Loads",
}
)
x_force: str = '0.0 kN' # TODO: unit-aware type
y_force: str = '0.0 kN' # TODO: unit-aware type
z_force: str = '0.0 kN' # TODO: unit-aware type
x_moment: str = '0.0 kNm' # TODO: unit-aware type
y_moment: str = '0.0 kNm' # TODO: unit-aware type
z_moment: str = '0.0 kNm' # TODO: unit-aware type
x_force: str = "0.0 kN" # TODO: unit-aware type
y_force: str = "0.0 kN" # TODO: unit-aware type
z_force: str = "0.0 kN" # TODO: unit-aware type
x_moment: str = "0.0 kNm" # TODO: unit-aware type
y_moment: str = "0.0 kNm" # TODO: unit-aware type
z_moment: str = "0.0 kNm" # TODO: unit-aware type

View file

@ -17,16 +17,15 @@ from pydantic import BaseModel, ConfigDict, Field
class LineMassSpec(BaseModel):
model_config = ConfigDict(
json_schema_extra={
'x-gid-name': 'Line_Mass',
'x-book': 'Mass/Damping',
"x-gid-name": "Line_Mass",
"x-book": "Mass/Damping",
}
)
mass_dof_values: Literal[':'] = ':'
x_direction: str = '0.0ton' # TODO: unit-aware type
y_direction: str = '0.0ton' # TODO: unit-aware type
z_direction: str = '0.0ton' # TODO: unit-aware type
x_rotation: str = '0.0ton' # TODO: unit-aware type
y_rotation: str = '0.0ton' # TODO: unit-aware type
z_rotation: str = '0.0ton' # TODO: unit-aware type
mass_dof_values: Literal[":"] = ":"
x_direction: str = "0.0ton" # TODO: unit-aware type
y_direction: str = "0.0ton" # TODO: unit-aware type
z_direction: str = "0.0ton" # TODO: unit-aware type
x_rotation: str = "0.0ton" # TODO: unit-aware type
y_rotation: str = "0.0ton" # TODO: unit-aware type
z_rotation: str = "0.0ton" # TODO: unit-aware type

View file

@ -15,8 +15,8 @@ from pydantic import BaseModel, ConfigDict, Field
class LineRayleighDampingElementsSpec(BaseModel):
model_config = ConfigDict(
json_schema_extra={
'x-gid-name': 'Line_Rayleigh_Damping-Elements',
'x-book': 'Mass/Damping',
"x-gid-name": "Line_Rayleigh_Damping-Elements",
"x-book": "Mass/Damping",
}
)
@ -25,4 +25,3 @@ class LineRayleighDampingElementsSpec(BaseModel):
betak: float = 0.0
betakinit: float = 0.0
betakcomm: float = 0.0

View file

@ -15,8 +15,8 @@ from pydantic import BaseModel, ConfigDict, Field
class LineRayleighDampingNodesSpec(BaseModel):
model_config = ConfigDict(
json_schema_extra={
'x-gid-name': 'Line_Rayleigh_Damping-Nodes',
'x-book': 'Mass/Damping',
"x-gid-name": "Line_Rayleigh_Damping-Nodes",
"x-book": "Mass/Damping",
}
)
@ -25,4 +25,3 @@ class LineRayleighDampingNodesSpec(BaseModel):
betak: float = 0.0
betakinit: float = 0.0
betakcomm: float = 0.0

View file

@ -17,290 +17,290 @@ from pydantic import BaseModel, ConfigDict, Field
class LineRestraintsSpec(BaseModel):
model_config = ConfigDict(
json_schema_extra={
'x-gid-name': 'Line_Restraints',
'x-book': 'Restraints',
'dependencies': [
"x-gid-name": "Line_Restraints",
"x-book": "Restraints",
"dependencies": [
{
'field': 'fast_restraints',
'gid_name': 'Fast_restraints',
'rules': [
"field": "fast_restraints",
"gid_name": "Fast_restraints",
"rules": [
{
'trigger': 'Fix_XYZ',
'actions': [
"trigger": "Fix_XYZ",
"actions": [
{
'action': 'RESTORE',
'field': 'X-Translation',
'target': '1',
"action": "RESTORE",
"field": "X-Translation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'Y-Translation',
'target': '1',
"action": "RESTORE",
"field": "Y-Translation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'Z-Translation',
'target': '1',
"action": "RESTORE",
"field": "Z-Translation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'X-Rotation',
'target': '1',
"action": "RESTORE",
"field": "X-Rotation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'Y-Rotation',
'target': '1',
"action": "RESTORE",
"field": "Y-Rotation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'Z-Rotation',
'target': '1',
"action": "RESTORE",
"field": "Z-Rotation",
"target": "1",
},
],
},
{
'trigger': 'Fix_XY',
'actions': [
"trigger": "Fix_XY",
"actions": [
{
'action': 'RESTORE',
'field': 'X-Translation',
'target': '1',
"action": "RESTORE",
"field": "X-Translation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'Y-Translation',
'target': '1',
"action": "RESTORE",
"field": "Y-Translation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'Z-Rotation',
'target': '1',
"action": "RESTORE",
"field": "Z-Rotation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'Z-Translation',
'target': '0',
"action": "RESTORE",
"field": "Z-Translation",
"target": "0",
},
{
'action': 'RESTORE',
'field': 'X-Rotation',
'target': '0',
"action": "RESTORE",
"field": "X-Rotation",
"target": "0",
},
{
'action': 'RESTORE',
'field': 'Y-Rotation',
'target': '0',
"action": "RESTORE",
"field": "Y-Rotation",
"target": "0",
},
],
},
{
'trigger': 'Fix_XZ',
'actions': [
"trigger": "Fix_XZ",
"actions": [
{
'action': 'RESTORE',
'field': 'X-Translation',
'target': '1',
"action": "RESTORE",
"field": "X-Translation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'Z-Translation',
'target': '1',
"action": "RESTORE",
"field": "Z-Translation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'Y-Rotation',
'target': '1',
"action": "RESTORE",
"field": "Y-Rotation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'Y-Translation',
'target': '0',
"action": "RESTORE",
"field": "Y-Translation",
"target": "0",
},
{
'action': 'RESTORE',
'field': 'X-Rotation',
'target': '0',
"action": "RESTORE",
"field": "X-Rotation",
"target": "0",
},
{
'action': 'RESTORE',
'field': 'Z-Rotation',
'target': '0',
"action": "RESTORE",
"field": "Z-Rotation",
"target": "0",
},
],
},
{
'trigger': 'Fix_YZ',
'actions': [
"trigger": "Fix_YZ",
"actions": [
{
'action': 'RESTORE',
'field': 'Y-Translation',
'target': '1',
"action": "RESTORE",
"field": "Y-Translation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'Z-Translation',
'target': '1',
"action": "RESTORE",
"field": "Z-Translation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'X-Rotation',
'target': '1',
"action": "RESTORE",
"field": "X-Rotation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'X-Translation',
'target': '0',
"action": "RESTORE",
"field": "X-Translation",
"target": "0",
},
{
'action': 'RESTORE',
'field': 'Z-Rotation',
'target': '0',
"action": "RESTORE",
"field": "Z-Rotation",
"target": "0",
},
{
'action': 'RESTORE',
'field': 'Y-Rotation',
'target': '0',
"action": "RESTORE",
"field": "Y-Rotation",
"target": "0",
},
],
},
{
'trigger': 'Pin_XYZ',
'actions': [
"trigger": "Pin_XYZ",
"actions": [
{
'action': 'RESTORE',
'field': 'X-Translation',
'target': '1',
"action": "RESTORE",
"field": "X-Translation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'Y-Translation',
'target': '1',
"action": "RESTORE",
"field": "Y-Translation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'Z-Translation',
'target': '1',
"action": "RESTORE",
"field": "Z-Translation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'X-Rotation',
'target': '0',
"action": "RESTORE",
"field": "X-Rotation",
"target": "0",
},
{
'action': 'RESTORE',
'field': 'Y-Rotation',
'target': '0',
"action": "RESTORE",
"field": "Y-Rotation",
"target": "0",
},
{
'action': 'RESTORE',
'field': 'Z-Rotation',
'target': '0',
"action": "RESTORE",
"field": "Z-Rotation",
"target": "0",
},
],
},
{
'trigger': 'Pin_XY',
'actions': [
"trigger": "Pin_XY",
"actions": [
{
'action': 'RESTORE',
'field': 'X-Translation',
'target': '1',
"action": "RESTORE",
"field": "X-Translation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'Y-Translation',
'target': '1',
"action": "RESTORE",
"field": "Y-Translation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'Z-Translation',
'target': '0',
"action": "RESTORE",
"field": "Z-Translation",
"target": "0",
},
{
'action': 'RESTORE',
'field': 'X-Rotation',
'target': '0',
"action": "RESTORE",
"field": "X-Rotation",
"target": "0",
},
{
'action': 'RESTORE',
'field': 'Y-Rotation',
'target': '0',
"action": "RESTORE",
"field": "Y-Rotation",
"target": "0",
},
{
'action': 'RESTORE',
'field': 'Z-Rotation',
'target': '0',
"action": "RESTORE",
"field": "Z-Rotation",
"target": "0",
},
],
},
{
'trigger': 'Pin_XZ',
'actions': [
"trigger": "Pin_XZ",
"actions": [
{
'action': 'RESTORE',
'field': 'X-Translation',
'target': '1',
"action": "RESTORE",
"field": "X-Translation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'Z-Translation',
'target': '1',
"action": "RESTORE",
"field": "Z-Translation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'Y-Translation',
'target': '0',
"action": "RESTORE",
"field": "Y-Translation",
"target": "0",
},
{
'action': 'RESTORE',
'field': 'X-Rotation',
'target': '0',
"action": "RESTORE",
"field": "X-Rotation",
"target": "0",
},
{
'action': 'RESTORE',
'field': 'Y-Rotation',
'target': '0',
"action": "RESTORE",
"field": "Y-Rotation",
"target": "0",
},
{
'action': 'RESTORE',
'field': 'Z-Rotation',
'target': '0',
"action": "RESTORE",
"field": "Z-Rotation",
"target": "0",
},
],
},
{
'trigger': 'Pin_YZ',
'actions': [
"trigger": "Pin_YZ",
"actions": [
{
'action': 'RESTORE',
'field': 'Y-Translation',
'target': '1',
"action": "RESTORE",
"field": "Y-Translation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'Z-Translation',
'target': '1',
"action": "RESTORE",
"field": "Z-Translation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'X-Translation',
'target': '0',
"action": "RESTORE",
"field": "X-Translation",
"target": "0",
},
{
'action': 'RESTORE',
'field': 'X-Rotation',
'target': '0',
"action": "RESTORE",
"field": "X-Rotation",
"target": "0",
},
{
'action': 'RESTORE',
'field': 'Y-Rotation',
'target': '0',
"action": "RESTORE",
"field": "Y-Rotation",
"target": "0",
},
{
'action': 'RESTORE',
'field': 'Z-Rotation',
'target': '0',
"action": "RESTORE",
"field": "Z-Rotation",
"target": "0",
},
],
},
@ -310,12 +310,13 @@ class LineRestraintsSpec(BaseModel):
}
)
x_translation: Literal['1', '0'] = '1'
y_translation: Literal['1', '0'] = '1'
z_translation: Literal['1', '0'] = '1'
x_rotation: Literal['1', '0'] = '1'
y_rotation: Literal['1', '0'] = '1'
z_rotation: Literal['1', '0'] = '1'
fluid_pressure: Literal['1', '0'] = '0'
fast_restraints: Literal['Fix_XYZ', 'Fix_XY', 'Fix_XZ', 'Fix_YZ', 'Pin_XYZ', 'Pin_XY', 'Pin_XZ', 'Pin_YZ'] = 'Fix_XYZ'
x_translation: Literal["1", "0"] = "1"
y_translation: Literal["1", "0"] = "1"
z_translation: Literal["1", "0"] = "1"
x_rotation: Literal["1", "0"] = "1"
y_rotation: Literal["1", "0"] = "1"
z_rotation: Literal["1", "0"] = "1"
fluid_pressure: Literal["1", "0"] = "0"
fast_restraints: Literal[
"Fix_XYZ", "Fix_XY", "Fix_XZ", "Fix_YZ", "Pin_XYZ", "Pin_XY", "Pin_XZ", "Pin_YZ"
] = "Fix_XYZ"

View file

@ -17,11 +17,10 @@ from pydantic import BaseModel, ConfigDict, Field
class LineRigidDiaphragmSlaveNodesSpec(BaseModel):
model_config = ConfigDict(
json_schema_extra={
'x-gid-name': 'Line_Rigid_diaphragm_slave_nodes',
'x-book': 'Constraints',
"x-gid-name": "Line_Rigid_diaphragm_slave_nodes",
"x-book": "Constraints",
}
)
rigid_diaphragm_id: int = 1
rigid_plane: Literal['XY', 'YZ', 'ZX'] = 'XY'
rigid_plane: Literal["XY", "YZ", "ZX"] = "XY"

View file

@ -17,11 +17,12 @@ from pydantic import BaseModel, ConfigDict, Field
class LineRigidLinkSlaveNodesSpec(BaseModel):
model_config = ConfigDict(
json_schema_extra={
'x-gid-name': 'Line_Rigid_link_slave_nodes',
'x-book': 'Constraints',
"x-gid-name": "Line_Rigid_link_slave_nodes",
"x-book": "Constraints",
}
)
rigid_link_id: int = Field(1, description='Give a positive integer number for body constraint group.')
rigid_link_type: Literal['Bar', 'Beam'] = 'Beam'
rigid_link_id: int = Field(
1, description="Give a positive integer number for body constraint group."
)
rigid_link_type: Literal["Bar", "Beam"] = "Beam"

View file

@ -15,12 +15,11 @@ from pydantic import BaseModel, ConfigDict, Field
class LineUniformForcesSpec(BaseModel):
model_config = ConfigDict(
json_schema_extra={
'x-gid-name': 'Line_Uniform_Forces',
'x-book': 'Loads',
"x-gid-name": "Line_Uniform_Forces",
"x-book": "Loads",
}
)
uniform_load_along_line_longitudinal_axis: str = '0.0 kN/m' # TODO: unit-aware type
uniform_load_acting_in_local_y_direction: str = '0.0 kN/m' # TODO: unit-aware type
uniform_load_acting_in_local_z_direction: str = '0.0 kN/m' # TODO: unit-aware type
uniform_load_along_line_longitudinal_axis: str = "0.0 kN/m" # TODO: unit-aware type
uniform_load_acting_in_local_y_direction: str = "0.0 kN/m" # TODO: unit-aware type
uniform_load_acting_in_local_z_direction: str = "0.0 kN/m" # TODO: unit-aware type

View file

@ -17,15 +17,14 @@ from pydantic import BaseModel, ConfigDict, Field
class PointBeamContactSlaveNodesSpec(BaseModel):
model_config = ConfigDict(
json_schema_extra={
'x-gid-name': 'Point_Beam_contact_slave_nodes',
'x-book': 'ZeroLength_Elements',
"x-gid-name": "Point_Beam_contact_slave_nodes",
"x-book": "ZeroLength_Elements",
}
)
beam_contact_id: int = 1
contact_material_mat_multidimensional_nd_materials_user_materials: str = 'Contact'
width_radius: str = '0.25m' # TODO: unit-aware type
contact_material_mat_multidimensional_nd_materials_user_materials: str = "Contact"
width_radius: str = "0.25m" # TODO: unit-aware type
gap_tolerance: float = 1.0e-10
force_tolerance: float = 1.0e-10
initial_assumption: Literal['Contact', 'No_Contact'] = 'Contact'
initial_assumption: Literal["Contact", "No_Contact"] = "Contact"

View file

@ -15,10 +15,11 @@ from pydantic import BaseModel, ConfigDict, Field
class PointBodyConstraintMasterNodeSpec(BaseModel):
model_config = ConfigDict(
json_schema_extra={
'x-gid-name': 'Point_Body_constraint_master_node',
'x-book': 'Old_Conditions',
"x-gid-name": "Point_Body_constraint_master_node",
"x-book": "Old_Conditions",
}
)
body_constraint_id_number: int = Field(1, description='Give a positive integer number for body constraint group.')
body_constraint_id_number: int = Field(
1, description="Give a positive integer number for body constraint group."
)

View file

@ -17,80 +17,80 @@ from pydantic import BaseModel, ConfigDict, Field
class PointBodyConstraintSlaveNodesSpec(BaseModel):
model_config = ConfigDict(
json_schema_extra={
'x-gid-name': 'Point_Body_constraint_slave_nodes',
'x-book': 'Old_Conditions',
'dependencies': [
"x-gid-name": "Point_Body_constraint_slave_nodes",
"x-book": "Old_Conditions",
"dependencies": [
{
'field': 'fast_constraints',
'gid_name': 'Fast_constraints',
'rules': [
"field": "fast_constraints",
"gid_name": "Fast_constraints",
"rules": [
{
'trigger': 'Pinned_Connection',
'actions': [
"trigger": "Pinned_Connection",
"actions": [
{
'action': 'RESTORE',
'field': 'X-Translation',
'target': '1',
"action": "RESTORE",
"field": "X-Translation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'Y-Translation',
'target': '1',
"action": "RESTORE",
"field": "Y-Translation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'Z-Translation',
'target': '1',
"action": "RESTORE",
"field": "Z-Translation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'X-Rotation',
'target': '0',
"action": "RESTORE",
"field": "X-Rotation",
"target": "0",
},
{
'action': 'RESTORE',
'field': 'Y-Rotation',
'target': '0',
"action": "RESTORE",
"field": "Y-Rotation",
"target": "0",
},
{
'action': 'RESTORE',
'field': 'Z-Rotation',
'target': '0',
"action": "RESTORE",
"field": "Z-Rotation",
"target": "0",
},
],
},
{
'trigger': 'Fixed_Connection',
'actions': [
"trigger": "Fixed_Connection",
"actions": [
{
'action': 'RESTORE',
'field': 'X-Translation',
'target': '1',
"action": "RESTORE",
"field": "X-Translation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'Y-Translation',
'target': '1',
"action": "RESTORE",
"field": "Y-Translation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'Z-Translation',
'target': '1',
"action": "RESTORE",
"field": "Z-Translation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'X-Rotation',
'target': '1',
"action": "RESTORE",
"field": "X-Rotation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'Y-Rotation',
'target': '1',
"action": "RESTORE",
"field": "Y-Rotation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'Z-Rotation',
'target': '1',
"action": "RESTORE",
"field": "Z-Rotation",
"target": "1",
},
],
},
@ -100,12 +100,13 @@ class PointBodyConstraintSlaveNodesSpec(BaseModel):
}
)
body_constraint_id_number: int = Field(1, description='Give a positive integer number for body constraint group.')
x_translation: Literal['1', '0'] = '1'
y_translation: Literal['1', '0'] = '1'
z_translation: Literal['1', '0'] = '1'
x_rotation: Literal['1', '0'] = '1'
y_rotation: Literal['1', '0'] = '1'
z_rotation: Literal['1', '0'] = '1'
fast_constraints: Literal['Pinned_Connection', 'Fixed_Connection'] = 'Pinned_Connection'
body_constraint_id_number: int = Field(
1, description="Give a positive integer number for body constraint group."
)
x_translation: Literal["1", "0"] = "1"
y_translation: Literal["1", "0"] = "1"
z_translation: Literal["1", "0"] = "1"
x_rotation: Literal["1", "0"] = "1"
y_rotation: Literal["1", "0"] = "1"
z_rotation: Literal["1", "0"] = "1"
fast_constraints: Literal["Pinned_Connection", "Fixed_Connection"] = "Pinned_Connection"

View file

@ -15,15 +15,14 @@ from pydantic import BaseModel, ConfigDict, Field
class PointDisplacementsSpec(BaseModel):
model_config = ConfigDict(
json_schema_extra={
'x-gid-name': 'Point_Displacements',
'x-book': 'Loads',
"x-gid-name": "Point_Displacements",
"x-book": "Loads",
}
)
x_displacement: str = '0.0m' # TODO: unit-aware type
y_displacement: str = '0.0m' # TODO: unit-aware type
z_displacement: str = '0.0m' # TODO: unit-aware type
x_rotation: str = '0.0 rad' # TODO: unit-aware type
y_rotation: str = '0.0 rad' # TODO: unit-aware type
z_rotation: str = '0.0 rad' # TODO: unit-aware type
x_displacement: str = "0.0m" # TODO: unit-aware type
y_displacement: str = "0.0m" # TODO: unit-aware type
z_displacement: str = "0.0m" # TODO: unit-aware type
x_rotation: str = "0.0 rad" # TODO: unit-aware type
y_rotation: str = "0.0 rad" # TODO: unit-aware type
z_rotation: str = "0.0 rad" # TODO: unit-aware type

View file

@ -15,10 +15,11 @@ from pydantic import BaseModel, ConfigDict, Field
class PointEqualConstraintMasterNodeSpec(BaseModel):
model_config = ConfigDict(
json_schema_extra={
'x-gid-name': 'Point_Equal_constraint_master_node',
'x-book': 'Constraints',
"x-gid-name": "Point_Equal_constraint_master_node",
"x-book": "Constraints",
}
)
equal_constraint_id: int = Field(1, description='Give a positive integer number for body constraint group.')
equal_constraint_id: int = Field(
1, description="Give a positive integer number for body constraint group."
)

View file

@ -17,16 +17,17 @@ from pydantic import BaseModel, ConfigDict, Field
class PointEqualConstraintSlaveNodesSpec(BaseModel):
model_config = ConfigDict(
json_schema_extra={
'x-gid-name': 'Point_Equal_constraint_slave_nodes',
'x-book': 'Constraints',
"x-gid-name": "Point_Equal_constraint_slave_nodes",
"x-book": "Constraints",
}
)
equal_constraint_id: int = Field(1, description='Give a positive integer number for body constraint group.')
x_translation: Literal['1', '0'] = '1'
y_translation: Literal['1', '0'] = '1'
z_translation: Literal['1', '0'] = '1'
x_rotation: Literal['1', '0'] = '1'
y_rotation: Literal['1', '0'] = '1'
z_rotation: Literal['1', '0'] = '1'
equal_constraint_id: int = Field(
1, description="Give a positive integer number for body constraint group."
)
x_translation: Literal["1", "0"] = "1"
y_translation: Literal["1", "0"] = "1"
z_translation: Literal["1", "0"] = "1"
x_rotation: Literal["1", "0"] = "1"
y_rotation: Literal["1", "0"] = "1"
z_rotation: Literal["1", "0"] = "1"

View file

@ -15,15 +15,14 @@ from pydantic import BaseModel, ConfigDict, Field
class PointForcesSpec(BaseModel):
model_config = ConfigDict(
json_schema_extra={
'x-gid-name': 'Point_Forces',
'x-book': 'Loads',
"x-gid-name": "Point_Forces",
"x-book": "Loads",
}
)
x_force: str = '0.0 kN' # TODO: unit-aware type
y_force: str = '0.0 kN' # TODO: unit-aware type
z_force: str = '0.0 kN' # TODO: unit-aware type
x_moment: str = '0.0 kNm' # TODO: unit-aware type
y_moment: str = '0.0 kNm' # TODO: unit-aware type
z_moment: str = '0.0 kNm' # TODO: unit-aware type
x_force: str = "0.0 kN" # TODO: unit-aware type
y_force: str = "0.0 kN" # TODO: unit-aware type
z_force: str = "0.0 kN" # TODO: unit-aware type
x_moment: str = "0.0 kNm" # TODO: unit-aware type
y_moment: str = "0.0 kNm" # TODO: unit-aware type
z_moment: str = "0.0 kNm" # TODO: unit-aware type

View file

@ -17,11 +17,10 @@ from pydantic import BaseModel, ConfigDict, Field
class PointGroundMotionFromRecordSpec(BaseModel):
model_config = ConfigDict(
json_schema_extra={
'x-gid-name': 'Point_Ground_Motion_from_Record',
'x-book': 'Loads',
"x-gid-name": "Point_Ground_Motion_from_Record",
"x-book": "Loads",
}
)
record_file: str = 'Ground_Motion_Record'
ground_motion_direction: Literal['Ux', 'Uy', 'Uz', 'Rx', 'Ry', 'Rz'] = 'Ux'
record_file: str = "Ground_Motion_Record"
ground_motion_direction: Literal["Ux", "Uy", "Uz", "Rx", "Ry", "Rz"] = "Ux"

View file

@ -17,16 +17,15 @@ from pydantic import BaseModel, ConfigDict, Field
class PointMassSpec(BaseModel):
model_config = ConfigDict(
json_schema_extra={
'x-gid-name': 'Point_Mass',
'x-book': 'Mass/Damping',
"x-gid-name": "Point_Mass",
"x-book": "Mass/Damping",
}
)
mass_dof_values: Literal[':'] = ':'
x_direction: str = '0.0ton' # TODO: unit-aware type
y_direction: str = '0.0ton' # TODO: unit-aware type
z_direction: str = '0.0ton' # TODO: unit-aware type
x_rotation: str = '0.0ton' # TODO: unit-aware type
y_rotation: str = '0.0ton' # TODO: unit-aware type
z_rotation: str = '0.0ton' # TODO: unit-aware type
mass_dof_values: Literal[":"] = ":"
x_direction: str = "0.0ton" # TODO: unit-aware type
y_direction: str = "0.0ton" # TODO: unit-aware type
z_direction: str = "0.0ton" # TODO: unit-aware type
x_rotation: str = "0.0ton" # TODO: unit-aware type
y_rotation: str = "0.0ton" # TODO: unit-aware type
z_rotation: str = "0.0ton" # TODO: unit-aware type

View file

@ -15,8 +15,8 @@ from pydantic import BaseModel, ConfigDict, Field
class PointRayleighDampingNodesSpec(BaseModel):
model_config = ConfigDict(
json_schema_extra={
'x-gid-name': 'Point_Rayleigh_Damping-Nodes',
'x-book': 'Mass/Damping',
"x-gid-name": "Point_Rayleigh_Damping-Nodes",
"x-book": "Mass/Damping",
}
)
@ -25,4 +25,3 @@ class PointRayleighDampingNodesSpec(BaseModel):
betak: float = 0.0
betakinit: float = 0.0
betakcomm: float = 0.0

View file

@ -17,290 +17,290 @@ from pydantic import BaseModel, ConfigDict, Field
class PointRestraintsSpec(BaseModel):
model_config = ConfigDict(
json_schema_extra={
'x-gid-name': 'Point_Restraints',
'x-book': 'Restraints',
'dependencies': [
"x-gid-name": "Point_Restraints",
"x-book": "Restraints",
"dependencies": [
{
'field': 'fast_restraints',
'gid_name': 'Fast_restraints',
'rules': [
"field": "fast_restraints",
"gid_name": "Fast_restraints",
"rules": [
{
'trigger': 'Fix_XYZ',
'actions': [
"trigger": "Fix_XYZ",
"actions": [
{
'action': 'RESTORE',
'field': 'X-Translation',
'target': '1',
"action": "RESTORE",
"field": "X-Translation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'Y-Translation',
'target': '1',
"action": "RESTORE",
"field": "Y-Translation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'Z-Translation',
'target': '1',
"action": "RESTORE",
"field": "Z-Translation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'X-Rotation',
'target': '1',
"action": "RESTORE",
"field": "X-Rotation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'Y-Rotation',
'target': '1',
"action": "RESTORE",
"field": "Y-Rotation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'Z-Rotation',
'target': '1',
"action": "RESTORE",
"field": "Z-Rotation",
"target": "1",
},
],
},
{
'trigger': 'Fix_XY',
'actions': [
"trigger": "Fix_XY",
"actions": [
{
'action': 'RESTORE',
'field': 'X-Translation',
'target': '1',
"action": "RESTORE",
"field": "X-Translation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'Y-Translation',
'target': '1',
"action": "RESTORE",
"field": "Y-Translation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'Z-Rotation',
'target': '1',
"action": "RESTORE",
"field": "Z-Rotation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'Z-Translation',
'target': '0',
"action": "RESTORE",
"field": "Z-Translation",
"target": "0",
},
{
'action': 'RESTORE',
'field': 'X-Rotation',
'target': '0',
"action": "RESTORE",
"field": "X-Rotation",
"target": "0",
},
{
'action': 'RESTORE',
'field': 'Y-Rotation',
'target': '0',
"action": "RESTORE",
"field": "Y-Rotation",
"target": "0",
},
],
},
{
'trigger': 'Fix_XZ',
'actions': [
"trigger": "Fix_XZ",
"actions": [
{
'action': 'RESTORE',
'field': 'X-Translation',
'target': '1',
"action": "RESTORE",
"field": "X-Translation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'Z-Translation',
'target': '1',
"action": "RESTORE",
"field": "Z-Translation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'Y-Rotation',
'target': '1',
"action": "RESTORE",
"field": "Y-Rotation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'Y-Translation',
'target': '0',
"action": "RESTORE",
"field": "Y-Translation",
"target": "0",
},
{
'action': 'RESTORE',
'field': 'X-Rotation',
'target': '0',
"action": "RESTORE",
"field": "X-Rotation",
"target": "0",
},
{
'action': 'RESTORE',
'field': 'Z-Rotation',
'target': '0',
"action": "RESTORE",
"field": "Z-Rotation",
"target": "0",
},
],
},
{
'trigger': 'Fix_YZ',
'actions': [
"trigger": "Fix_YZ",
"actions": [
{
'action': 'RESTORE',
'field': 'Y-Translation',
'target': '1',
"action": "RESTORE",
"field": "Y-Translation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'Z-Translation',
'target': '1',
"action": "RESTORE",
"field": "Z-Translation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'X-Rotation',
'target': '1',
"action": "RESTORE",
"field": "X-Rotation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'X-Translation',
'target': '0',
"action": "RESTORE",
"field": "X-Translation",
"target": "0",
},
{
'action': 'RESTORE',
'field': 'Z-Rotation',
'target': '0',
"action": "RESTORE",
"field": "Z-Rotation",
"target": "0",
},
{
'action': 'RESTORE',
'field': 'Y-Rotation',
'target': '0',
"action": "RESTORE",
"field": "Y-Rotation",
"target": "0",
},
],
},
{
'trigger': 'Pin_XYZ',
'actions': [
"trigger": "Pin_XYZ",
"actions": [
{
'action': 'RESTORE',
'field': 'X-Translation',
'target': '1',
"action": "RESTORE",
"field": "X-Translation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'Y-Translation',
'target': '1',
"action": "RESTORE",
"field": "Y-Translation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'Z-Translation',
'target': '1',
"action": "RESTORE",
"field": "Z-Translation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'X-Rotation',
'target': '0',
"action": "RESTORE",
"field": "X-Rotation",
"target": "0",
},
{
'action': 'RESTORE',
'field': 'Y-Rotation',
'target': '0',
"action": "RESTORE",
"field": "Y-Rotation",
"target": "0",
},
{
'action': 'RESTORE',
'field': 'Z-Rotation',
'target': '0',
"action": "RESTORE",
"field": "Z-Rotation",
"target": "0",
},
],
},
{
'trigger': 'Pin_XY',
'actions': [
"trigger": "Pin_XY",
"actions": [
{
'action': 'RESTORE',
'field': 'X-Translation',
'target': '1',
"action": "RESTORE",
"field": "X-Translation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'Y-Translation',
'target': '1',
"action": "RESTORE",
"field": "Y-Translation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'Z-Translation',
'target': '0',
"action": "RESTORE",
"field": "Z-Translation",
"target": "0",
},
{
'action': 'RESTORE',
'field': 'X-Rotation',
'target': '0',
"action": "RESTORE",
"field": "X-Rotation",
"target": "0",
},
{
'action': 'RESTORE',
'field': 'Y-Rotation',
'target': '0',
"action": "RESTORE",
"field": "Y-Rotation",
"target": "0",
},
{
'action': 'RESTORE',
'field': 'Z-Rotation',
'target': '0',
"action": "RESTORE",
"field": "Z-Rotation",
"target": "0",
},
],
},
{
'trigger': 'Pin_XZ',
'actions': [
"trigger": "Pin_XZ",
"actions": [
{
'action': 'RESTORE',
'field': 'X-Translation',
'target': '1',
"action": "RESTORE",
"field": "X-Translation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'Z-Translation',
'target': '1',
"action": "RESTORE",
"field": "Z-Translation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'Y-Translation',
'target': '0',
"action": "RESTORE",
"field": "Y-Translation",
"target": "0",
},
{
'action': 'RESTORE',
'field': 'X-Rotation',
'target': '0',
"action": "RESTORE",
"field": "X-Rotation",
"target": "0",
},
{
'action': 'RESTORE',
'field': 'Y-Rotation',
'target': '0',
"action": "RESTORE",
"field": "Y-Rotation",
"target": "0",
},
{
'action': 'RESTORE',
'field': 'Z-Rotation',
'target': '0',
"action": "RESTORE",
"field": "Z-Rotation",
"target": "0",
},
],
},
{
'trigger': 'Pin_YZ',
'actions': [
"trigger": "Pin_YZ",
"actions": [
{
'action': 'RESTORE',
'field': 'Y-Translation',
'target': '1',
"action": "RESTORE",
"field": "Y-Translation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'Z-Translation',
'target': '1',
"action": "RESTORE",
"field": "Z-Translation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'X-Translation',
'target': '0',
"action": "RESTORE",
"field": "X-Translation",
"target": "0",
},
{
'action': 'RESTORE',
'field': 'X-Rotation',
'target': '0',
"action": "RESTORE",
"field": "X-Rotation",
"target": "0",
},
{
'action': 'RESTORE',
'field': 'Y-Rotation',
'target': '0',
"action": "RESTORE",
"field": "Y-Rotation",
"target": "0",
},
{
'action': 'RESTORE',
'field': 'Z-Rotation',
'target': '0',
"action": "RESTORE",
"field": "Z-Rotation",
"target": "0",
},
],
},
@ -310,12 +310,13 @@ class PointRestraintsSpec(BaseModel):
}
)
x_translation: Literal['1', '0'] = '1'
y_translation: Literal['1', '0'] = '1'
z_translation: Literal['1', '0'] = '1'
x_rotation: Literal['1', '0'] = '1'
y_rotation: Literal['1', '0'] = '1'
z_rotation: Literal['1', '0'] = '1'
fluid_pressure: Literal['1', '0'] = '0'
fast_restraints: Literal['Fix_XYZ', 'Fix_XY', 'Fix_XZ', 'Fix_YZ', 'Pin_XYZ', 'Pin_XY', 'Pin_XZ', 'Pin_YZ'] = 'Fix_XYZ'
x_translation: Literal["1", "0"] = "1"
y_translation: Literal["1", "0"] = "1"
z_translation: Literal["1", "0"] = "1"
x_rotation: Literal["1", "0"] = "1"
y_rotation: Literal["1", "0"] = "1"
z_rotation: Literal["1", "0"] = "1"
fluid_pressure: Literal["1", "0"] = "0"
fast_restraints: Literal[
"Fix_XYZ", "Fix_XY", "Fix_XZ", "Fix_YZ", "Pin_XYZ", "Pin_XY", "Pin_XZ", "Pin_YZ"
] = "Fix_XYZ"

View file

@ -15,10 +15,9 @@ from pydantic import BaseModel, ConfigDict, Field
class PointRigidDiaphragmMasterNodeSpec(BaseModel):
model_config = ConfigDict(
json_schema_extra={
'x-gid-name': 'Point_Rigid_diaphragm_master_node',
'x-book': 'Constraints',
"x-gid-name": "Point_Rigid_diaphragm_master_node",
"x-book": "Constraints",
}
)
rigid_diaphragm_id: int = 1

View file

@ -17,11 +17,10 @@ from pydantic import BaseModel, ConfigDict, Field
class PointRigidDiaphragmSlaveNodesSpec(BaseModel):
model_config = ConfigDict(
json_schema_extra={
'x-gid-name': 'Point_Rigid_diaphragm_slave_nodes',
'x-book': 'Constraints',
"x-gid-name": "Point_Rigid_diaphragm_slave_nodes",
"x-book": "Constraints",
}
)
rigid_diaphragm_id: int = 1
rigid_plane: Literal['XY', 'YZ', 'ZX'] = 'XY'
rigid_plane: Literal["XY", "YZ", "ZX"] = "XY"

View file

@ -15,10 +15,9 @@ from pydantic import BaseModel, ConfigDict, Field
class PointRigidLinkMasterNodeSpec(BaseModel):
model_config = ConfigDict(
json_schema_extra={
'x-gid-name': 'Point_Rigid_link_master_node',
'x-book': 'Constraints',
"x-gid-name": "Point_Rigid_link_master_node",
"x-book": "Constraints",
}
)
rigid_link_id: int = 1

View file

@ -17,11 +17,12 @@ from pydantic import BaseModel, ConfigDict, Field
class PointRigidLinkSlaveNodesSpec(BaseModel):
model_config = ConfigDict(
json_schema_extra={
'x-gid-name': 'Point_Rigid_link_slave_nodes',
'x-book': 'Constraints',
"x-gid-name": "Point_Rigid_link_slave_nodes",
"x-book": "Constraints",
}
)
rigid_link_id: int = Field(1, description='Give a positive integer number for body constraint group.')
rigid_link_type: Literal['Bar', 'Beam'] = 'Beam'
rigid_link_id: int = Field(
1, description="Give a positive integer number for body constraint group."
)
rigid_link_type: Literal["Bar", "Beam"] = "Beam"

View file

@ -17,40 +17,40 @@ from pydantic import BaseModel, ConfigDict, Field
class PointSineGroundMotionSpec(BaseModel):
model_config = ConfigDict(
json_schema_extra={
'x-gid-name': 'Point_Sine_Ground_Motion',
'x-book': 'Loads',
'dependencies': [
"x-gid-name": "Point_Sine_Ground_Motion",
"x-book": "Loads",
"dependencies": [
{
'field': 'type',
'gid_name': 'Type',
'rules': [
"field": "type",
"gid_name": "Type",
"rules": [
{
'trigger': 'Acceleration',
'actions': [
"trigger": "Acceleration",
"actions": [
{
'action': 'RESTORE',
'field': 'Acceleration_Amplitude',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Acceleration_Amplitude",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Displacement_Amplitude',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Displacement_Amplitude",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'Displacement',
'actions': [
"trigger": "Displacement",
"actions": [
{
'action': 'HIDE',
'field': 'Acceleration_Amplitude',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Acceleration_Amplitude",
"target": "#CURRENT#",
},
{
'action': 'RESTORE',
'field': 'Displacement_Amplitude',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Displacement_Amplitude",
"target": "#CURRENT#",
},
],
},
@ -60,11 +60,10 @@ class PointSineGroundMotionSpec(BaseModel):
}
)
type: Literal['Acceleration', 'Displacement'] = 'Displacement'
ground_motion_direction: Literal['Ux', 'Uy', 'Uz', 'Rx', 'Ry', 'Rz'] = 'Ux'
acceleration_amplitude: str = '1.0m/s^2' # TODO: unit-aware type
displacement_amplitude: str = '1.0m' # TODO: unit-aware type
period: str = '0.6sec' # TODO: unit-aware type
duration: str = '10sec' # TODO: unit-aware type
type: Literal["Acceleration", "Displacement"] = "Displacement"
ground_motion_direction: Literal["Ux", "Uy", "Uz", "Rx", "Ry", "Rz"] = "Ux"
acceleration_amplitude: str = "1.0m/s^2" # TODO: unit-aware type
displacement_amplitude: str = "1.0m" # TODO: unit-aware type
period: str = "0.6sec" # TODO: unit-aware type
duration: str = "10sec" # TODO: unit-aware type
shift: float = 0.0

View file

@ -17,160 +17,160 @@ from pydantic import BaseModel, ConfigDict, Field
class PointZerolengthSpec(BaseModel):
model_config = ConfigDict(
json_schema_extra={
'x-gid-name': 'Point_ZeroLength',
'x-book': 'ZeroLength_Elements',
'dependencies': [
"x-gid-name": "Point_ZeroLength",
"x-book": "ZeroLength_Elements",
"dependencies": [
{
'field': 'activate_ux',
'gid_name': 'Activate_Ux',
'rules': [
"field": "activate_ux",
"gid_name": "Activate_Ux",
"rules": [
{
'trigger': '0',
'actions': [
"trigger": "0",
"actions": [
{
'action': 'SET',
'field': 'Ux_material',
'target': '#CURRENT#',
"action": "SET",
"field": "Ux_material",
"target": "#CURRENT#",
},
],
},
{
'trigger': '1',
'actions': [
"trigger": "1",
"actions": [
{
'action': 'RESTORE',
'field': 'Ux_material',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Ux_material",
"target": "#CURRENT#",
},
],
},
],
},
{
'field': 'activate_uy',
'gid_name': 'Activate_Uy',
'rules': [
"field": "activate_uy",
"gid_name": "Activate_Uy",
"rules": [
{
'trigger': '0',
'actions': [
"trigger": "0",
"actions": [
{
'action': 'SET',
'field': 'Uy_material',
'target': '#CURRENT#',
"action": "SET",
"field": "Uy_material",
"target": "#CURRENT#",
},
],
},
{
'trigger': '1',
'actions': [
"trigger": "1",
"actions": [
{
'action': 'RESTORE',
'field': 'Uy_material',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Uy_material",
"target": "#CURRENT#",
},
],
},
],
},
{
'field': 'activate_uz',
'gid_name': 'Activate_Uz',
'rules': [
"field": "activate_uz",
"gid_name": "Activate_Uz",
"rules": [
{
'trigger': '0',
'actions': [
"trigger": "0",
"actions": [
{
'action': 'SET',
'field': 'Uz_material',
'target': '#CURRENT#',
"action": "SET",
"field": "Uz_material",
"target": "#CURRENT#",
},
],
},
{
'trigger': '1',
'actions': [
"trigger": "1",
"actions": [
{
'action': 'RESTORE',
'field': 'Uz_material',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Uz_material",
"target": "#CURRENT#",
},
],
},
],
},
{
'field': 'activate_rx',
'gid_name': 'Activate_Rx',
'rules': [
"field": "activate_rx",
"gid_name": "Activate_Rx",
"rules": [
{
'trigger': '0',
'actions': [
"trigger": "0",
"actions": [
{
'action': 'SET',
'field': 'Rx_material',
'target': '#CURRENT#',
"action": "SET",
"field": "Rx_material",
"target": "#CURRENT#",
},
],
},
{
'trigger': '1',
'actions': [
"trigger": "1",
"actions": [
{
'action': 'RESTORE',
'field': 'Rx_material',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Rx_material",
"target": "#CURRENT#",
},
],
},
],
},
{
'field': 'activate_ry',
'gid_name': 'Activate_Ry',
'rules': [
"field": "activate_ry",
"gid_name": "Activate_Ry",
"rules": [
{
'trigger': '0',
'actions': [
"trigger": "0",
"actions": [
{
'action': 'SET',
'field': 'Ry_material',
'target': '#CURRENT#',
"action": "SET",
"field": "Ry_material",
"target": "#CURRENT#",
},
],
},
{
'trigger': '1',
'actions': [
"trigger": "1",
"actions": [
{
'action': 'RESTORE',
'field': 'Ry_material',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Ry_material",
"target": "#CURRENT#",
},
],
},
],
},
{
'field': 'activate_rz',
'gid_name': 'Activate_Rz',
'rules': [
"field": "activate_rz",
"gid_name": "Activate_Rz",
"rules": [
{
'trigger': '0',
'actions': [
"trigger": "0",
"actions": [
{
'action': 'SET',
'field': 'Rz_material',
'target': '#CURRENT#',
"action": "SET",
"field": "Rz_material",
"target": "#CURRENT#",
},
],
},
{
'trigger': '1',
'actions': [
"trigger": "1",
"actions": [
{
'action': 'RESTORE',
'field': 'Rz_material',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Rz_material",
"target": "#CURRENT#",
},
],
},
@ -181,16 +181,15 @@ class PointZerolengthSpec(BaseModel):
)
zerolength_id: int = 1
activate_ux: Literal['0', '1'] = '1'
ux_material: str = 'Elastic'
activate_uy: Literal['0', '1'] = '0'
uy_material: str = 'Elastic'
activate_uz: Literal['0', '1'] = '0'
uz_material: str = 'Elastic'
activate_rx: Literal['0', '1'] = '0'
rx_material: str = 'Elastic'
activate_ry: Literal['0', '1'] = '0'
ry_material: str = 'Elastic'
activate_rz: Literal['0', '1'] = '0'
rz_material: str = 'Elastic'
activate_ux: Literal["0", "1"] = "1"
ux_material: str = "Elastic"
activate_uy: Literal["0", "1"] = "0"
uy_material: str = "Elastic"
activate_uz: Literal["0", "1"] = "0"
uz_material: str = "Elastic"
activate_rx: Literal["0", "1"] = "0"
rx_material: str = "Elastic"
activate_ry: Literal["0", "1"] = "0"
ry_material: str = "Elastic"
activate_rz: Literal["0", "1"] = "0"
rz_material: str = "Elastic"

View file

@ -15,15 +15,14 @@ from pydantic import BaseModel, ConfigDict, Field
class SurfaceDisplacementsSpec(BaseModel):
model_config = ConfigDict(
json_schema_extra={
'x-gid-name': 'Surface_Displacements',
'x-book': 'Loads',
"x-gid-name": "Surface_Displacements",
"x-book": "Loads",
}
)
x_displacement: str = '0.0m' # TODO: unit-aware type
y_displacement: str = '0.0m' # TODO: unit-aware type
z_displacement: str = '0.0m' # TODO: unit-aware type
x_rotation: str = '0.0 rad' # TODO: unit-aware type
y_rotation: str = '0.0 rad' # TODO: unit-aware type
z_rotation: str = '0.0 rad' # TODO: unit-aware type
x_displacement: str = "0.0m" # TODO: unit-aware type
y_displacement: str = "0.0m" # TODO: unit-aware type
z_displacement: str = "0.0m" # TODO: unit-aware type
x_rotation: str = "0.0 rad" # TODO: unit-aware type
y_rotation: str = "0.0 rad" # TODO: unit-aware type
z_rotation: str = "0.0 rad" # TODO: unit-aware type

View file

@ -15,15 +15,14 @@ from pydantic import BaseModel, ConfigDict, Field
class SurfaceForcesSpec(BaseModel):
model_config = ConfigDict(
json_schema_extra={
'x-gid-name': 'Surface_Forces',
'x-book': 'Loads',
"x-gid-name": "Surface_Forces",
"x-book": "Loads",
}
)
x_force: str = '0.0 kN' # TODO: unit-aware type
y_force: str = '0.0 kN' # TODO: unit-aware type
z_force: str = '0.0 kN' # TODO: unit-aware type
x_moment: str = '0.0 kNm' # TODO: unit-aware type
y_moment: str = '0.0 kNm' # TODO: unit-aware type
z_moment: str = '0.0 kNm' # TODO: unit-aware type
x_force: str = "0.0 kN" # TODO: unit-aware type
y_force: str = "0.0 kN" # TODO: unit-aware type
z_force: str = "0.0 kN" # TODO: unit-aware type
x_moment: str = "0.0 kNm" # TODO: unit-aware type
y_moment: str = "0.0 kNm" # TODO: unit-aware type
z_moment: str = "0.0 kNm" # TODO: unit-aware type

View file

@ -17,16 +17,15 @@ from pydantic import BaseModel, ConfigDict, Field
class SurfaceMassSpec(BaseModel):
model_config = ConfigDict(
json_schema_extra={
'x-gid-name': 'Surface_Mass',
'x-book': 'Mass/Damping',
"x-gid-name": "Surface_Mass",
"x-book": "Mass/Damping",
}
)
mass_dof_values: Literal[':'] = ':'
x_direction: str = '0.0ton' # TODO: unit-aware type
y_direction: str = '0.0ton' # TODO: unit-aware type
z_direction: str = '0.0ton' # TODO: unit-aware type
x_rotation: str = '0.0ton' # TODO: unit-aware type
y_rotation: str = '0.0ton' # TODO: unit-aware type
z_rotation: str = '0.0ton' # TODO: unit-aware type
mass_dof_values: Literal[":"] = ":"
x_direction: str = "0.0ton" # TODO: unit-aware type
y_direction: str = "0.0ton" # TODO: unit-aware type
z_direction: str = "0.0ton" # TODO: unit-aware type
x_rotation: str = "0.0ton" # TODO: unit-aware type
y_rotation: str = "0.0ton" # TODO: unit-aware type
z_rotation: str = "0.0ton" # TODO: unit-aware type

View file

@ -15,8 +15,8 @@ from pydantic import BaseModel, ConfigDict, Field
class SurfaceRayleighDampingElementsSpec(BaseModel):
model_config = ConfigDict(
json_schema_extra={
'x-gid-name': 'Surface_Rayleigh_Damping-Elements',
'x-book': 'Mass/Damping',
"x-gid-name": "Surface_Rayleigh_Damping-Elements",
"x-book": "Mass/Damping",
}
)
@ -25,4 +25,3 @@ class SurfaceRayleighDampingElementsSpec(BaseModel):
betak: float = 0.0
betakinit: float = 0.0
betakcomm: float = 0.0

View file

@ -15,8 +15,8 @@ from pydantic import BaseModel, ConfigDict, Field
class SurfaceRayleighDampingNodesSpec(BaseModel):
model_config = ConfigDict(
json_schema_extra={
'x-gid-name': 'Surface_Rayleigh_Damping-Nodes',
'x-book': 'Mass/Damping',
"x-gid-name": "Surface_Rayleigh_Damping-Nodes",
"x-book": "Mass/Damping",
}
)
@ -25,4 +25,3 @@ class SurfaceRayleighDampingNodesSpec(BaseModel):
betak: float = 0.0
betakinit: float = 0.0
betakcomm: float = 0.0

View file

@ -17,290 +17,290 @@ from pydantic import BaseModel, ConfigDict, Field
class SurfaceRestraintsSpec(BaseModel):
model_config = ConfigDict(
json_schema_extra={
'x-gid-name': 'Surface_Restraints',
'x-book': 'Restraints',
'dependencies': [
"x-gid-name": "Surface_Restraints",
"x-book": "Restraints",
"dependencies": [
{
'field': 'fast_restraints',
'gid_name': 'Fast_restraints',
'rules': [
"field": "fast_restraints",
"gid_name": "Fast_restraints",
"rules": [
{
'trigger': 'Fix_XYZ',
'actions': [
"trigger": "Fix_XYZ",
"actions": [
{
'action': 'RESTORE',
'field': 'X-Translation',
'target': '1',
"action": "RESTORE",
"field": "X-Translation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'Y-Translation',
'target': '1',
"action": "RESTORE",
"field": "Y-Translation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'Z-Translation',
'target': '1',
"action": "RESTORE",
"field": "Z-Translation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'X-Rotation',
'target': '1',
"action": "RESTORE",
"field": "X-Rotation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'Y-Rotation',
'target': '1',
"action": "RESTORE",
"field": "Y-Rotation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'Z-Rotation',
'target': '1',
"action": "RESTORE",
"field": "Z-Rotation",
"target": "1",
},
],
},
{
'trigger': 'Fix_XY',
'actions': [
"trigger": "Fix_XY",
"actions": [
{
'action': 'RESTORE',
'field': 'X-Translation',
'target': '1',
"action": "RESTORE",
"field": "X-Translation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'Y-Translation',
'target': '1',
"action": "RESTORE",
"field": "Y-Translation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'Z-Rotation',
'target': '1',
"action": "RESTORE",
"field": "Z-Rotation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'Z-Translation',
'target': '0',
"action": "RESTORE",
"field": "Z-Translation",
"target": "0",
},
{
'action': 'RESTORE',
'field': 'X-Rotation',
'target': '0',
"action": "RESTORE",
"field": "X-Rotation",
"target": "0",
},
{
'action': 'RESTORE',
'field': 'Y-Rotation',
'target': '0',
"action": "RESTORE",
"field": "Y-Rotation",
"target": "0",
},
],
},
{
'trigger': 'Fix_XZ',
'actions': [
"trigger": "Fix_XZ",
"actions": [
{
'action': 'RESTORE',
'field': 'X-Translation',
'target': '1',
"action": "RESTORE",
"field": "X-Translation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'Z-Translation',
'target': '1',
"action": "RESTORE",
"field": "Z-Translation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'Y-Rotation',
'target': '1',
"action": "RESTORE",
"field": "Y-Rotation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'Y-Translation',
'target': '0',
"action": "RESTORE",
"field": "Y-Translation",
"target": "0",
},
{
'action': 'RESTORE',
'field': 'X-Rotation',
'target': '0',
"action": "RESTORE",
"field": "X-Rotation",
"target": "0",
},
{
'action': 'RESTORE',
'field': 'Z-Rotation',
'target': '0',
"action": "RESTORE",
"field": "Z-Rotation",
"target": "0",
},
],
},
{
'trigger': 'Fix_YZ',
'actions': [
"trigger": "Fix_YZ",
"actions": [
{
'action': 'RESTORE',
'field': 'Y-Translation',
'target': '1',
"action": "RESTORE",
"field": "Y-Translation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'Z-Translation',
'target': '1',
"action": "RESTORE",
"field": "Z-Translation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'X-Rotation',
'target': '1',
"action": "RESTORE",
"field": "X-Rotation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'X-Translation',
'target': '0',
"action": "RESTORE",
"field": "X-Translation",
"target": "0",
},
{
'action': 'RESTORE',
'field': 'Z-Rotation',
'target': '0',
"action": "RESTORE",
"field": "Z-Rotation",
"target": "0",
},
{
'action': 'RESTORE',
'field': 'Y-Rotation',
'target': '0',
"action": "RESTORE",
"field": "Y-Rotation",
"target": "0",
},
],
},
{
'trigger': 'Pin_XYZ',
'actions': [
"trigger": "Pin_XYZ",
"actions": [
{
'action': 'RESTORE',
'field': 'X-Translation',
'target': '1',
"action": "RESTORE",
"field": "X-Translation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'Y-Translation',
'target': '1',
"action": "RESTORE",
"field": "Y-Translation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'Z-Translation',
'target': '1',
"action": "RESTORE",
"field": "Z-Translation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'X-Rotation',
'target': '0',
"action": "RESTORE",
"field": "X-Rotation",
"target": "0",
},
{
'action': 'RESTORE',
'field': 'Y-Rotation',
'target': '0',
"action": "RESTORE",
"field": "Y-Rotation",
"target": "0",
},
{
'action': 'RESTORE',
'field': 'Z-Rotation',
'target': '0',
"action": "RESTORE",
"field": "Z-Rotation",
"target": "0",
},
],
},
{
'trigger': 'Pin_XY',
'actions': [
"trigger": "Pin_XY",
"actions": [
{
'action': 'RESTORE',
'field': 'X-Translation',
'target': '1',
"action": "RESTORE",
"field": "X-Translation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'Y-Translation',
'target': '1',
"action": "RESTORE",
"field": "Y-Translation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'Z-Translation',
'target': '0',
"action": "RESTORE",
"field": "Z-Translation",
"target": "0",
},
{
'action': 'RESTORE',
'field': 'X-Rotation',
'target': '0',
"action": "RESTORE",
"field": "X-Rotation",
"target": "0",
},
{
'action': 'RESTORE',
'field': 'Y-Rotation',
'target': '0',
"action": "RESTORE",
"field": "Y-Rotation",
"target": "0",
},
{
'action': 'RESTORE',
'field': 'Z-Rotation',
'target': '0',
"action": "RESTORE",
"field": "Z-Rotation",
"target": "0",
},
],
},
{
'trigger': 'Pin_XZ',
'actions': [
"trigger": "Pin_XZ",
"actions": [
{
'action': 'RESTORE',
'field': 'X-Translation',
'target': '1',
"action": "RESTORE",
"field": "X-Translation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'Z-Translation',
'target': '1',
"action": "RESTORE",
"field": "Z-Translation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'Y-Translation',
'target': '0',
"action": "RESTORE",
"field": "Y-Translation",
"target": "0",
},
{
'action': 'RESTORE',
'field': 'X-Rotation',
'target': '0',
"action": "RESTORE",
"field": "X-Rotation",
"target": "0",
},
{
'action': 'RESTORE',
'field': 'Y-Rotation',
'target': '0',
"action": "RESTORE",
"field": "Y-Rotation",
"target": "0",
},
{
'action': 'RESTORE',
'field': 'Z-Rotation',
'target': '0',
"action": "RESTORE",
"field": "Z-Rotation",
"target": "0",
},
],
},
{
'trigger': 'Pin_YZ',
'actions': [
"trigger": "Pin_YZ",
"actions": [
{
'action': 'RESTORE',
'field': 'Y-Translation',
'target': '1',
"action": "RESTORE",
"field": "Y-Translation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'Z-Translation',
'target': '1',
"action": "RESTORE",
"field": "Z-Translation",
"target": "1",
},
{
'action': 'RESTORE',
'field': 'X-Translation',
'target': '0',
"action": "RESTORE",
"field": "X-Translation",
"target": "0",
},
{
'action': 'RESTORE',
'field': 'X-Rotation',
'target': '0',
"action": "RESTORE",
"field": "X-Rotation",
"target": "0",
},
{
'action': 'RESTORE',
'field': 'Y-Rotation',
'target': '0',
"action": "RESTORE",
"field": "Y-Rotation",
"target": "0",
},
{
'action': 'RESTORE',
'field': 'Z-Rotation',
'target': '0',
"action": "RESTORE",
"field": "Z-Rotation",
"target": "0",
},
],
},
@ -310,12 +310,13 @@ class SurfaceRestraintsSpec(BaseModel):
}
)
x_translation: Literal['1', '0'] = '1'
y_translation: Literal['1', '0'] = '1'
z_translation: Literal['1', '0'] = '1'
x_rotation: Literal['1', '0'] = '1'
y_rotation: Literal['1', '0'] = '1'
z_rotation: Literal['1', '0'] = '1'
fluid_pressure: Literal['1', '0'] = '0'
fast_restraints: Literal['Fix_XYZ', 'Fix_XY', 'Fix_XZ', 'Fix_YZ', 'Pin_XYZ', 'Pin_XY', 'Pin_XZ', 'Pin_YZ'] = 'Fix_XYZ'
x_translation: Literal["1", "0"] = "1"
y_translation: Literal["1", "0"] = "1"
z_translation: Literal["1", "0"] = "1"
x_rotation: Literal["1", "0"] = "1"
y_rotation: Literal["1", "0"] = "1"
z_rotation: Literal["1", "0"] = "1"
fluid_pressure: Literal["1", "0"] = "0"
fast_restraints: Literal[
"Fix_XYZ", "Fix_XY", "Fix_XZ", "Fix_YZ", "Pin_XYZ", "Pin_XY", "Pin_XZ", "Pin_YZ"
] = "Fix_XYZ"

View file

@ -17,16 +17,15 @@ from pydantic import BaseModel, ConfigDict, Field
class VolumeMassSpec(BaseModel):
model_config = ConfigDict(
json_schema_extra={
'x-gid-name': 'Volume_Mass',
'x-book': 'Mass/Damping',
"x-gid-name": "Volume_Mass",
"x-book": "Mass/Damping",
}
)
mass_dof_values: Literal[':'] = ':'
x_direction: str = '0.0ton' # TODO: unit-aware type
y_direction: str = '0.0ton' # TODO: unit-aware type
z_direction: str = '0.0ton' # TODO: unit-aware type
x_rotation: str = '0.0ton' # TODO: unit-aware type
y_rotation: str = '0.0ton' # TODO: unit-aware type
z_rotation: str = '0.0ton' # TODO: unit-aware type
mass_dof_values: Literal[":"] = ":"
x_direction: str = "0.0ton" # TODO: unit-aware type
y_direction: str = "0.0ton" # TODO: unit-aware type
z_direction: str = "0.0ton" # TODO: unit-aware type
x_rotation: str = "0.0ton" # TODO: unit-aware type
y_rotation: str = "0.0ton" # TODO: unit-aware type
z_rotation: str = "0.0ton" # TODO: unit-aware type

View file

@ -15,8 +15,8 @@ from pydantic import BaseModel, ConfigDict, Field
class VolumeRayleighDampingElementsSpec(BaseModel):
model_config = ConfigDict(
json_schema_extra={
'x-gid-name': 'Volume_Rayleigh_Damping-Elements',
'x-book': 'Mass/Damping',
"x-gid-name": "Volume_Rayleigh_Damping-Elements",
"x-book": "Mass/Damping",
}
)
@ -25,4 +25,3 @@ class VolumeRayleighDampingElementsSpec(BaseModel):
betak: float = 0.0
betakinit: float = 0.0
betakcomm: float = 0.0

View file

@ -15,8 +15,8 @@ from pydantic import BaseModel, ConfigDict, Field
class VolumeRayleighDampingNodesSpec(BaseModel):
model_config = ConfigDict(
json_schema_extra={
'x-gid-name': 'Volume_Rayleigh_Damping-Nodes',
'x-book': 'Mass/Damping',
"x-gid-name": "Volume_Rayleigh_Damping-Nodes",
"x-book": "Mass/Damping",
}
)
@ -25,4 +25,3 @@ class VolumeRayleighDampingNodesSpec(BaseModel):
betak: float = 0.0
betakinit: float = 0.0
betakcomm: float = 0.0

View file

@ -17,160 +17,160 @@ from pydantic import BaseModel, ConfigDict, Field
class ZerolengthSpec(BaseModel):
model_config = ConfigDict(
json_schema_extra={
'x-gid-name': 'ZeroLength',
'x-book': 'Old_Conditions',
'dependencies': [
"x-gid-name": "ZeroLength",
"x-book": "Old_Conditions",
"dependencies": [
{
'field': 'activate_ux',
'gid_name': 'Activate_Ux',
'rules': [
"field": "activate_ux",
"gid_name": "Activate_Ux",
"rules": [
{
'trigger': '0',
'actions': [
"trigger": "0",
"actions": [
{
'action': 'SET',
'field': 'Ux_material',
'target': '#CURRENT#',
"action": "SET",
"field": "Ux_material",
"target": "#CURRENT#",
},
],
},
{
'trigger': '1',
'actions': [
"trigger": "1",
"actions": [
{
'action': 'RESTORE',
'field': 'Ux_material',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Ux_material",
"target": "#CURRENT#",
},
],
},
],
},
{
'field': 'activate_uy',
'gid_name': 'Activate_Uy',
'rules': [
"field": "activate_uy",
"gid_name": "Activate_Uy",
"rules": [
{
'trigger': '0',
'actions': [
"trigger": "0",
"actions": [
{
'action': 'SET',
'field': 'Uy_material',
'target': '#CURRENT#',
"action": "SET",
"field": "Uy_material",
"target": "#CURRENT#",
},
],
},
{
'trigger': '1',
'actions': [
"trigger": "1",
"actions": [
{
'action': 'RESTORE',
'field': 'Uy_material',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Uy_material",
"target": "#CURRENT#",
},
],
},
],
},
{
'field': 'activate_uz',
'gid_name': 'Activate_Uz',
'rules': [
"field": "activate_uz",
"gid_name": "Activate_Uz",
"rules": [
{
'trigger': '0',
'actions': [
"trigger": "0",
"actions": [
{
'action': 'SET',
'field': 'Uz_material',
'target': '#CURRENT#',
"action": "SET",
"field": "Uz_material",
"target": "#CURRENT#",
},
],
},
{
'trigger': '1',
'actions': [
"trigger": "1",
"actions": [
{
'action': 'RESTORE',
'field': 'Uz_material',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Uz_material",
"target": "#CURRENT#",
},
],
},
],
},
{
'field': 'activate_rx',
'gid_name': 'Activate_Rx',
'rules': [
"field": "activate_rx",
"gid_name": "Activate_Rx",
"rules": [
{
'trigger': '0',
'actions': [
"trigger": "0",
"actions": [
{
'action': 'SET',
'field': 'Rx_material',
'target': '#CURRENT#',
"action": "SET",
"field": "Rx_material",
"target": "#CURRENT#",
},
],
},
{
'trigger': '1',
'actions': [
"trigger": "1",
"actions": [
{
'action': 'RESTORE',
'field': 'Rx_material',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Rx_material",
"target": "#CURRENT#",
},
],
},
],
},
{
'field': 'activate_ry',
'gid_name': 'Activate_Ry',
'rules': [
"field": "activate_ry",
"gid_name": "Activate_Ry",
"rules": [
{
'trigger': '0',
'actions': [
"trigger": "0",
"actions": [
{
'action': 'SET',
'field': 'Ry_material',
'target': '#CURRENT#',
"action": "SET",
"field": "Ry_material",
"target": "#CURRENT#",
},
],
},
{
'trigger': '1',
'actions': [
"trigger": "1",
"actions": [
{
'action': 'RESTORE',
'field': 'Ry_material',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Ry_material",
"target": "#CURRENT#",
},
],
},
],
},
{
'field': 'activate_rz',
'gid_name': 'Activate_Rz',
'rules': [
"field": "activate_rz",
"gid_name": "Activate_Rz",
"rules": [
{
'trigger': '0',
'actions': [
"trigger": "0",
"actions": [
{
'action': 'SET',
'field': 'Rz_material',
'target': '#CURRENT#',
"action": "SET",
"field": "Rz_material",
"target": "#CURRENT#",
},
],
},
{
'trigger': '1',
'actions': [
"trigger": "1",
"actions": [
{
'action': 'RESTORE',
'field': 'Rz_material',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Rz_material",
"target": "#CURRENT#",
},
],
},
@ -181,16 +181,15 @@ class ZerolengthSpec(BaseModel):
)
zerolength_id_number: int = 1
activate_ux: Literal['0', '1'] = '1'
ux_material: str = 'Elastic'
activate_uy: Literal['0', '1'] = '0'
uy_material: str = 'Elastic'
activate_uz: Literal['0', '1'] = '0'
uz_material: str = 'Elastic'
activate_rx: Literal['0', '1'] = '0'
rx_material: str = 'Elastic'
activate_ry: Literal['0', '1'] = '0'
ry_material: str = 'Elastic'
activate_rz: Literal['0', '1'] = '0'
rz_material: str = 'Elastic'
activate_ux: Literal["0", "1"] = "1"
ux_material: str = "Elastic"
activate_uy: Literal["0", "1"] = "0"
uy_material: str = "Elastic"
activate_uz: Literal["0", "1"] = "0"
uz_material: str = "Elastic"
activate_rx: Literal["0", "1"] = "0"
rx_material: str = "Elastic"
activate_ry: Literal["0", "1"] = "0"
ry_material: str = "Elastic"
activate_rz: Literal["0", "1"] = "0"
rz_material: str = "Elastic"

View file

@ -17,14 +17,13 @@ from pydantic import BaseModel, ConfigDict, Field
class ContactSpec(BaseModel):
model_config = ConfigDict(
json_schema_extra={
'x-gid-name': 'Contact',
'x-book': 'Multidimensional_(nD)_Materials',
"x-gid-name": "Contact",
"x-book": "Multidimensional_(nD)_Materials",
}
)
material: Literal['Contact'] = 'Contact'
material: Literal["Contact"] = "Contact"
frictional_coefficient: float = 0.1
stiffness_parameter: str = '1000.0kN/m' # TODO: unit-aware type
stiffness_parameter: str = "1000.0kN/m" # TODO: unit-aware type
cohesive_intercept: float = 0.0
tensile_strength: str = '0.0kN' # TODO: unit-aware type
tensile_strength: str = "0.0kN" # TODO: unit-aware type

View file

@ -17,196 +17,196 @@ from pydantic import BaseModel, ConfigDict, Field
class CorotationalTrussSpec(BaseModel):
model_config = ConfigDict(
json_schema_extra={
'x-gid-name': 'Corotational_Truss',
'x-book': 'Truss_Elements',
'dependencies': [
"x-gid-name": "Corotational_Truss",
"x-book": "Truss_Elements",
"dependencies": [
{
'field': 'cross_section',
'gid_name': 'Cross_section',
'rules': [
"field": "cross_section",
"gid_name": "Cross_section",
"rules": [
{
'trigger': 'Rectangular',
'actions': [
"trigger": "Rectangular",
"actions": [
{
'action': 'RESTORE',
'field': 'Height_h',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Height_h",
"target": "#CURRENT#",
},
{
'action': 'RESTORE',
'field': 'Width_B',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Width_B",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Diameter_d',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Diameter_d",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Height_hf',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Height_hf",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Width_bf',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Width_bf",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Width_Bw',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Width_Bw",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Area_A',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Area_A",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'Circular',
'actions': [
"trigger": "Circular",
"actions": [
{
'action': 'HIDE',
'field': 'Height_h',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Height_h",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Width_B',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Width_B",
"target": "#CURRENT#",
},
{
'action': 'RESTORE',
'field': 'Diameter_d',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Diameter_d",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Height_hf',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Height_hf",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Width_bf',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Width_bf",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Width_Bw',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Width_Bw",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Area_A',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Area_A",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'Tee',
'actions': [
"trigger": "Tee",
"actions": [
{
'action': 'RESTORE',
'field': 'Height_h',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Height_h",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Width_B',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Width_B",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Diameter_d',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Diameter_d",
"target": "#CURRENT#",
},
{
'action': 'RESTORE',
'field': 'Height_hf',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Height_hf",
"target": "#CURRENT#",
},
{
'action': 'RESTORE',
'field': 'Width_bf',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Width_bf",
"target": "#CURRENT#",
},
{
'action': 'RESTORE',
'field': 'Width_Bw',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Width_Bw",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Area_A',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Area_A",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'General',
'actions': [
"trigger": "General",
"actions": [
{
'action': 'HIDE',
'field': 'Height_h',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Height_h",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Width_B',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Width_B",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Diameter_d',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Diameter_d",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Width_bf',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Width_bf",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Height_hf',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Height_hf",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Width_Bw',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Width_Bw",
"target": "#CURRENT#",
},
{
'action': 'RESTORE',
'field': 'Area_A',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Area_A",
"target": "#CURRENT#",
},
],
},
],
},
{
'field': 'set_modification_factors',
'gid_name': 'Set_modification_factors',
'rules': [
"field": "set_modification_factors",
"gid_name": "Set_modification_factors",
"rules": [
{
'trigger': '0',
'actions': [
"trigger": "0",
"actions": [
{
'action': 'HIDE',
'field': 'mod._A',
'target': '#CURRENT#',
"action": "HIDE",
"field": "mod._A",
"target": "#CURRENT#",
},
],
},
{
'trigger': '1',
'actions': [
"trigger": "1",
"actions": [
{
'action': 'RESTORE',
'field': 'mod._A',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "mod._A",
"target": "#CURRENT#",
},
],
},
@ -216,21 +216,22 @@ class CorotationalTrussSpec(BaseModel):
}
)
element_type: Literal['CorotationalTruss'] = 'CorotationalTruss'
compatible_materials: Literal['_'] = '_'
material: str = Field('Elastic', description='Choose one existing material to use its parameters.')
mass_density: str = '0.0ton/m^3' # TODO: unit-aware type
consider_consistent_mass_matrix: Literal['1', '0'] = '0'
include_rayleigh_damping: Literal['1', '0'] = '0'
weight_density: str = '0.0 kN/m^3' # TODO: unit-aware type
cross_section: Literal['Rectangular', 'Tee', 'Circular', 'General'] = 'General'
height_h: str = '0.5m' # TODO: unit-aware type
width_b: str = '0.3m' # TODO: unit-aware type
diameter_d: str = '0.5m' # TODO: unit-aware type
width_bf: str = '0.4m' # TODO: unit-aware type
height_hf: str = '0.15m' # TODO: unit-aware type
width_bw: str = '0.25m' # TODO: unit-aware type
area_a: str = '1 m^2' # TODO: unit-aware type
set_modification_factors: Literal['0', '1'] = '0'
element_type: Literal["CorotationalTruss"] = "CorotationalTruss"
compatible_materials: Literal["_"] = "_"
material: str = Field(
"Elastic", description="Choose one existing material to use its parameters."
)
mass_density: str = "0.0ton/m^3" # TODO: unit-aware type
consider_consistent_mass_matrix: Literal["1", "0"] = "0"
include_rayleigh_damping: Literal["1", "0"] = "0"
weight_density: str = "0.0 kN/m^3" # TODO: unit-aware type
cross_section: Literal["Rectangular", "Tee", "Circular", "General"] = "General"
height_h: str = "0.5m" # TODO: unit-aware type
width_b: str = "0.3m" # TODO: unit-aware type
diameter_d: str = "0.5m" # TODO: unit-aware type
width_bf: str = "0.4m" # TODO: unit-aware type
height_hf: str = "0.15m" # TODO: unit-aware type
width_bw: str = "0.25m" # TODO: unit-aware type
area_a: str = "1 m^2" # TODO: unit-aware type
set_modification_factors: Literal["0", "1"] = "0"
mod_a: int = 1

View file

@ -17,21 +17,22 @@ from pydantic import BaseModel, ConfigDict, Field
class Damage2pSpec(BaseModel):
model_config = ConfigDict(
json_schema_extra={
'x-gid-name': 'Damage2p',
'x-book': 'Multidimensional_(nD)_Materials',
"x-gid-name": "Damage2p",
"x-book": "Multidimensional_(nD)_Materials",
}
)
material: Literal['Damage2p'] = 'Damage2p'
concrete_compressive_strength: str = '-20MPa' # TODO: unit-aware type
material: Literal["Damage2p"] = "Damage2p"
concrete_compressive_strength: str = "-20MPa" # TODO: unit-aware type
calculate_default_values_update_to_apply_cb_1_0: int = 1
young_modulus: str = '21.243GPa' # TODO: unit-aware type
concrete_tensile_strength: str = '2.0MPa' # TODO: unit-aware type
young_modulus: str = "21.243GPa" # TODO: unit-aware type
concrete_tensile_strength: str = "2.0MPa" # TODO: unit-aware type
poisson_coefficient: float = 0.15
tension_fracture_energy_density: str = '3.465e-004GPa' # TODO: unit-aware type
comp_fracture_energy_density: str = '1.177e-001GPa' # TODO: unit-aware type
tension_fracture_energy_density: str = "3.465e-004GPa" # TODO: unit-aware type
comp_fracture_energy_density: str = "1.177e-001GPa" # TODO: unit-aware type
parameter_of_plastic_volume_change: float = 0.20
linear_hardening_parameter: str = '5.311GPa' # TODO: unit-aware type
linear_hardening_parameter: str = "5.311GPa" # TODO: unit-aware type
isotropic_kinematic_hardening_ratio: float = 0.50
computational_stiffness_matrix: Literal['Computational_tangent', 'Damaged_secant_stiffness'] = 'Computational_tangent'
computational_stiffness_matrix: Literal["Computational_tangent", "Damaged_secant_stiffness"] = (
"Computational_tangent"
)

View file

@ -17,18 +17,19 @@ from pydantic import BaseModel, ConfigDict, Field
class DisplacementBasedBeamColumnSpec(BaseModel):
model_config = ConfigDict(
json_schema_extra={
'x-gid-name': 'Displacement-Based_Beam-Column',
'x-book': 'Beam-Column_Elements',
"x-gid-name": "Displacement-Based_Beam-Column",
"x-book": "Beam-Column_Elements",
}
)
element_type: Literal['dispBeamColumn'] = 'dispBeamColumn'
compatible_sections: Literal['_'] = '_'
number_of_integration_points: int = Field(3, description='number of integration points along the element')
the_number_of_integration: Literal['_'] = '_'
to_increase_analysis_accuracy: Literal['_'] = '_'
section: str = 'Fiber'
geometric_transformation: Literal['Linear', 'P-Delta', 'Corotational'] = 'Linear'
mass_density: str = '0.0ton/m^3' # TODO: unit-aware type
weight_density: str = '25 kN/m^3' # TODO: unit-aware type
element_type: Literal["dispBeamColumn"] = "dispBeamColumn"
compatible_sections: Literal["_"] = "_"
number_of_integration_points: int = Field(
3, description="number of integration points along the element"
)
the_number_of_integration: Literal["_"] = "_"
to_increase_analysis_accuracy: Literal["_"] = "_"
section: str = "Fiber"
geometric_transformation: Literal["Linear", "P-Delta", "Corotational"] = "Linear"
mass_density: str = "0.0ton/m^3" # TODO: unit-aware type
weight_density: str = "25 kN/m^3" # TODO: unit-aware type

View file

@ -23,187 +23,187 @@ class CyclicDataRow(BaseModel):
class ElasticSpec(BaseModel):
model_config = ConfigDict(
json_schema_extra={
'x-gid-name': 'Elastic',
'x-book': 'Standard_Uniaxial_Materials',
'dependencies': [
"x-gid-name": "Elastic",
"x-book": "Standard_Uniaxial_Materials",
"dependencies": [
{
'field': 'formulation',
'gid_name': 'Formulation',
'rules': [
"field": "formulation",
"gid_name": "Formulation",
"rules": [
{
'trigger': 'Stress-Strain',
'actions': [
"trigger": "Stress-Strain",
"actions": [
{
'action': 'RESTORE',
'field': 'Material_type',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Material_type",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Stiffness_K',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Stiffness_K",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Moment_per_rotation_unit',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Moment_per_rotation_unit",
"target": "#CURRENT#",
},
{
'action': 'RESTORE',
'field': 'Elastic_modulus_E',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Elastic_modulus_E",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Moment_per_rotation_unit',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Moment_per_rotation_unit",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'Force-Deformation',
'actions': [
"trigger": "Force-Deformation",
"actions": [
{
'action': 'HIDE',
'field': 'Material_type',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Material_type",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Concrete_class',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Concrete_class",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Steel_grade',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Steel_grade",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Elastic_modulus_E',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Elastic_modulus_E",
"target": "#CURRENT#",
},
{
'action': 'RESTORE',
'field': 'Stiffness_K',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Stiffness_K",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Moment_per_rotation_unit',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Moment_per_rotation_unit",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'Moment-Rotation',
'actions': [
"trigger": "Moment-Rotation",
"actions": [
{
'action': 'HIDE',
'field': 'Material_type',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Material_type",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Concrete_class',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Concrete_class",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Steel_grade',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Steel_grade",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Elastic_modulus_E',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Elastic_modulus_E",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Stiffness_K',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Stiffness_K",
"target": "#CURRENT#",
},
{
'action': 'RESTORE',
'field': 'Moment_per_rotation_unit',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Moment_per_rotation_unit",
"target": "#CURRENT#",
},
],
},
],
},
{
'field': 'material_type',
'gid_name': 'Material_type',
'rules': [
"field": "material_type",
"gid_name": "Material_type",
"rules": [
{
'trigger': 'Concrete',
'actions': [
"trigger": "Concrete",
"actions": [
{
'action': 'RESTORE',
'field': 'Concrete_class',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Concrete_class",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Steel_grade',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Steel_grade",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'Steel',
'actions': [
"trigger": "Steel",
"actions": [
{
'action': 'HIDE',
'field': 'Concrete_class',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Concrete_class",
"target": "#CURRENT#",
},
{
'action': 'RESTORE',
'field': 'Steel_grade',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Steel_grade",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'Custom',
'actions': [
"trigger": "Custom",
"actions": [
{
'action': 'HIDE',
'field': 'Concrete_class',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Concrete_class",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Steel_grade',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Steel_grade",
"target": "#CURRENT#",
},
],
},
],
},
{
'field': 'analysis_type',
'gid_name': 'Analysis_type',
'rules': [
"field": "analysis_type",
"gid_name": "Analysis_type",
"rules": [
{
'trigger': 'Monotonic',
'actions': [
"trigger": "Monotonic",
"actions": [
{
'action': 'HIDE',
'field': 'Cyclic_data',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Cyclic_data",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'Cyclic',
'actions': [
"trigger": "Cyclic",
"actions": [
{
'action': 'RESTORE',
'field': 'Cyclic_data',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Cyclic_data",
"target": "#CURRENT#",
},
],
},
@ -213,16 +213,32 @@ class ElasticSpec(BaseModel):
}
)
material: Literal['Elastic'] = Field('Elastic', description='Elastic uniaxial material object')
formulation: Literal['Stress-Strain', 'Force-Deformation', 'Moment-Rotation'] = 'Stress-Strain'
material_type: Literal['Concrete', 'Steel', 'Custom'] = 'Custom'
concrete_class: Literal['C12/15', 'C16/20', 'C20/25', 'C25/30', 'C30/37', 'C35/45', 'C40/50', 'C45/55', 'C50/60', 'C55/67', 'C60/75', 'C70/85', 'C80/95', 'C90/105'] = 'C20/25'
steel_grade: Literal['S235', 'S275', 'S355', 'S450', 'B500'] = 'S235'
elastic_modulus_e: str = Field('30 GPa', description='Young modulus of elasticity E, considering stress-strain diagram') # TODO: unit-aware type
stiffness_k: str = '4000 kN/m' # TODO: unit-aware type
moment_per_rotation_unit: str = '10000 kNm' # TODO: unit-aware type
analysis_type: Literal['Monotonic', 'Cyclic'] = 'Monotonic'
material: Literal["Elastic"] = Field("Elastic", description="Elastic uniaxial material object")
formulation: Literal["Stress-Strain", "Force-Deformation", "Moment-Rotation"] = "Stress-Strain"
material_type: Literal["Concrete", "Steel", "Custom"] = "Custom"
concrete_class: Literal[
"C12/15",
"C16/20",
"C20/25",
"C25/30",
"C30/37",
"C35/45",
"C40/50",
"C45/55",
"C50/60",
"C55/67",
"C60/75",
"C70/85",
"C80/95",
"C90/105",
] = "C20/25"
steel_grade: Literal["S235", "S275", "S355", "S450", "B500"] = "S235"
elastic_modulus_e: str = Field(
"30 GPa", description="Young modulus of elasticity E, considering stress-strain diagram"
) # TODO: unit-aware type
stiffness_k: str = "4000 kN/m" # TODO: unit-aware type
moment_per_rotation_unit: str = "10000 kNm" # TODO: unit-aware type
analysis_type: Literal["Monotonic", "Cyclic"] = "Monotonic"
cyclic_data: list[CyclicDataRow] = Field(default_factory=list)
field: Literal['_'] = '_'
set_as_variable: Literal['0', '1'] = '0'
field: Literal["_"] = "_"
set_as_variable: Literal["0", "1"] = "0"

View file

@ -17,286 +17,286 @@ from pydantic import BaseModel, ConfigDict, Field
class ElasticBeamColumnSpec(BaseModel):
model_config = ConfigDict(
json_schema_extra={
'x-gid-name': 'Elastic_Beam-Column',
'x-book': 'Beam-Column_Elements',
'dependencies': [
"x-gid-name": "Elastic_Beam-Column",
"x-book": "Beam-Column_Elements",
"dependencies": [
{
'field': 'cross_section',
'gid_name': 'Cross_section',
'rules': [
"field": "cross_section",
"gid_name": "Cross_section",
"rules": [
{
'trigger': 'Rectangular',
'actions': [
"trigger": "Rectangular",
"actions": [
{
'action': 'RESTORE',
'field': 'Height_h',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Height_h",
"target": "#CURRENT#",
},
{
'action': 'RESTORE',
'field': 'Width_B',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Width_B",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Diameter_d',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Diameter_d",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Height_hf',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Height_hf",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Width_bf',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Width_bf",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Width_bw',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Width_bw",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Area_A',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Area_A",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Moment_of_inertia_about_local-y_Iyy',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Moment_of_inertia_about_local-y_Iyy",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Moment_of_inertia_about_local-z_Izz',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Moment_of_inertia_about_local-z_Izz",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Torsional_moment_of_inertia_Iyz',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Torsional_moment_of_inertia_Iyz",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'Circular',
'actions': [
"trigger": "Circular",
"actions": [
{
'action': 'HIDE',
'field': 'Height_h',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Height_h",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Width_B',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Width_B",
"target": "#CURRENT#",
},
{
'action': 'RESTORE',
'field': 'Diameter_d',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Diameter_d",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Height_hf',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Height_hf",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Width_bf',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Width_bf",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Width_bw',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Width_bw",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Area_A',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Area_A",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Moment_of_inertia_about_local-y_Iyy',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Moment_of_inertia_about_local-y_Iyy",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Moment_of_inertia_about_local-z_Izz',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Moment_of_inertia_about_local-z_Izz",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Torsional_moment_of_inertia_Iyz',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Torsional_moment_of_inertia_Iyz",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'Tee',
'actions': [
"trigger": "Tee",
"actions": [
{
'action': 'RESTORE',
'field': 'Height_h',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Height_h",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Width_B',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Width_B",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Diameter_d',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Diameter_d",
"target": "#CURRENT#",
},
{
'action': 'RESTORE',
'field': 'Height_hf',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Height_hf",
"target": "#CURRENT#",
},
{
'action': 'RESTORE',
'field': 'Width_bf',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Width_bf",
"target": "#CURRENT#",
},
{
'action': 'RESTORE',
'field': 'Width_bw',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Width_bw",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Area_A',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Area_A",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Moment_of_inertia_about_local-y_Iyy',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Moment_of_inertia_about_local-y_Iyy",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Moment_of_inertia_about_local-z_Izz',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Moment_of_inertia_about_local-z_Izz",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Torsional_moment_of_inertia_Iyz',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Torsional_moment_of_inertia_Iyz",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'General',
'actions': [
"trigger": "General",
"actions": [
{
'action': 'HIDE',
'field': 'Height_h',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Height_h",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Width_B',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Width_B",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Diameter_d',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Diameter_d",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Width_bf',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Width_bf",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Height_hf',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Height_hf",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Width_bw',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Width_bw",
"target": "#CURRENT#",
},
{
'action': 'RESTORE',
'field': 'Area_A',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Area_A",
"target": "#CURRENT#",
},
{
'action': 'RESTORE',
'field': 'Moment_of_inertia_about_local-y_Iyy',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Moment_of_inertia_about_local-y_Iyy",
"target": "#CURRENT#",
},
{
'action': 'RESTORE',
'field': 'Moment_of_inertia_about_local-z_Izz',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Moment_of_inertia_about_local-z_Izz",
"target": "#CURRENT#",
},
{
'action': 'RESTORE',
'field': 'Torsional_moment_of_inertia_Iyz',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Torsional_moment_of_inertia_Iyz",
"target": "#CURRENT#",
},
],
},
],
},
{
'field': 'set_modification_factors',
'gid_name': 'Set_modification_factors',
'rules': [
"field": "set_modification_factors",
"gid_name": "Set_modification_factors",
"rules": [
{
'trigger': '1',
'actions': [
"trigger": "1",
"actions": [
{
'action': 'RESTORE',
'field': 'mod._A',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "mod._A",
"target": "#CURRENT#",
},
{
'action': 'RESTORE',
'field': 'mod._Iyy',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "mod._Iyy",
"target": "#CURRENT#",
},
{
'action': 'RESTORE',
'field': 'mod._Izz',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "mod._Izz",
"target": "#CURRENT#",
},
{
'action': 'RESTORE',
'field': 'mod._Iyz',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "mod._Iyz",
"target": "#CURRENT#",
},
],
},
{
'trigger': '0',
'actions': [
"trigger": "0",
"actions": [
{
'action': 'HIDE',
'field': 'mod._A',
'target': '#CURRENT#',
"action": "HIDE",
"field": "mod._A",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'mod._Iyy',
'target': '#CURRENT#',
"action": "HIDE",
"field": "mod._Iyy",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'mod._Izz',
'target': '#CURRENT#',
"action": "HIDE",
"field": "mod._Izz",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'mod._Iyz',
'target': '#CURRENT#',
"action": "HIDE",
"field": "mod._Iyz",
"target": "#CURRENT#",
},
],
},
@ -306,25 +306,24 @@ class ElasticBeamColumnSpec(BaseModel):
}
)
element_type: Literal['ElasticBeamColumn'] = 'ElasticBeamColumn'
compatible_materials: Literal['Elastic_Isotropic'] = 'Elastic_Isotropic'
material_mat_multidimensional_nd_materials_user_materials: str = 'Elastic_Isotropic'
cross_section: Literal['Rectangular', 'Tee', 'Circular', 'General'] = 'Rectangular'
height_h: str = '0.5m' # TODO: unit-aware type
width_b: str = '0.3m' # TODO: unit-aware type
diameter_d: str = '0.5m' # TODO: unit-aware type
width_bf: str = '0.4m' # TODO: unit-aware type
height_hf: str = '0.15m' # TODO: unit-aware type
width_bw: str = '0.25m' # TODO: unit-aware type
area_a: str = '1.0 m^2' # TODO: unit-aware type
moment_of_inertia_about_local_y_iyy: str = '0.5 m^4' # TODO: unit-aware type
moment_of_inertia_about_local_z_izz: str = '0.5 m^4' # TODO: unit-aware type
torsional_moment_of_inertia_iyz: str = '1.0 m^4' # TODO: unit-aware type
set_modification_factors: Literal['1', '0'] = '0'
element_type: Literal["ElasticBeamColumn"] = "ElasticBeamColumn"
compatible_materials: Literal["Elastic_Isotropic"] = "Elastic_Isotropic"
material_mat_multidimensional_nd_materials_user_materials: str = "Elastic_Isotropic"
cross_section: Literal["Rectangular", "Tee", "Circular", "General"] = "Rectangular"
height_h: str = "0.5m" # TODO: unit-aware type
width_b: str = "0.3m" # TODO: unit-aware type
diameter_d: str = "0.5m" # TODO: unit-aware type
width_bf: str = "0.4m" # TODO: unit-aware type
height_hf: str = "0.15m" # TODO: unit-aware type
width_bw: str = "0.25m" # TODO: unit-aware type
area_a: str = "1.0 m^2" # TODO: unit-aware type
moment_of_inertia_about_local_y_iyy: str = "0.5 m^4" # TODO: unit-aware type
moment_of_inertia_about_local_z_izz: str = "0.5 m^4" # TODO: unit-aware type
torsional_moment_of_inertia_iyz: str = "1.0 m^4" # TODO: unit-aware type
set_modification_factors: Literal["1", "0"] = "0"
mod_a: int = 1
mod_iyy: int = 1
mod_izz: int = 1
mod_iyz: int = 1
geometric_transformation: Literal['Linear', 'P-Delta', 'Corotational'] = 'Linear'
weight_density: str = '25 kN/m^3' # TODO: unit-aware type
geometric_transformation: Literal["Linear", "P-Delta", "Corotational"] = "Linear"
weight_density: str = "25 kN/m^3" # TODO: unit-aware type

View file

@ -17,40 +17,40 @@ from pydantic import BaseModel, ConfigDict, Field
class ElasticIsotropicSpec(BaseModel):
model_config = ConfigDict(
json_schema_extra={
'x-gid-name': 'Elastic_Isotropic',
'x-book': 'Multidimensional_(nD)_Materials',
'dependencies': [
"x-gid-name": "Elastic_Isotropic",
"x-book": "Multidimensional_(nD)_Materials",
"dependencies": [
{
'field': 'material_type',
'gid_name': 'Material_type',
'rules': [
"field": "material_type",
"gid_name": "Material_type",
"rules": [
{
'trigger': 'Concrete',
'actions': [
"trigger": "Concrete",
"actions": [
{
'action': 'RESTORE',
'field': 'Concrete_class',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Concrete_class",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'Steel',
'actions': [
"trigger": "Steel",
"actions": [
{
'action': 'HIDE',
'field': 'Concrete_class',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Concrete_class",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'Custom',
'actions': [
"trigger": "Custom",
"actions": [
{
'action': 'HIDE',
'field': 'Concrete_class',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Concrete_class",
"target": "#CURRENT#",
},
],
},
@ -60,10 +60,24 @@ class ElasticIsotropicSpec(BaseModel):
}
)
material: Literal['ElasticIsotropic'] = 'ElasticIsotropic'
material_type: Literal['Concrete', 'Steel', 'Custom'] = 'Custom'
concrete_class: Literal['C12/15', 'C16/20', 'C20/25', 'C25/30', 'C30/37', 'C35/45', 'C40/50', 'C45/55', 'C50/60', 'C55/67', 'C60/75', 'C70/85', 'C80/95', 'C90/105'] = 'C20/25'
elastic_modulus_e: str = '30GPa' # TODO: unit-aware type
material: Literal["ElasticIsotropic"] = "ElasticIsotropic"
material_type: Literal["Concrete", "Steel", "Custom"] = "Custom"
concrete_class: Literal[
"C12/15",
"C16/20",
"C20/25",
"C25/30",
"C30/37",
"C35/45",
"C40/50",
"C45/55",
"C50/60",
"C55/67",
"C60/75",
"C70/85",
"C80/95",
"C90/105",
] = "C20/25"
elastic_modulus_e: str = "30GPa" # TODO: unit-aware type
poisson_s_ratio: float = 0.20
mass_density: str = '0.0ton/m^3' # TODO: unit-aware type
mass_density: str = "0.0ton/m^3" # TODO: unit-aware type

View file

@ -17,14 +17,13 @@ from pydantic import BaseModel, ConfigDict, Field
class ElasticMembranePlateSpec(BaseModel):
model_config = ConfigDict(
json_schema_extra={
'x-gid-name': 'Elastic_Membrane_Plate',
'x-book': 'Section_Force-Deformation',
"x-gid-name": "Elastic_Membrane_Plate",
"x-book": "Section_Force-Deformation",
}
)
section: Literal['ElasticMembranePlate'] = 'ElasticMembranePlate'
elastic_modulus_e: str = '28GPa' # TODO: unit-aware type
section: Literal["ElasticMembranePlate"] = "ElasticMembranePlate"
elastic_modulus_e: str = "28GPa" # TODO: unit-aware type
poisson_s_ratio: float = 0.2
section_depth_h: str = '0.25m' # TODO: unit-aware type
mass_density: str = '0.0ton/m^3' # TODO: unit-aware type
section_depth_h: str = "0.25m" # TODO: unit-aware type
mass_density: str = "0.0ton/m^3" # TODO: unit-aware type

View file

@ -17,20 +17,19 @@ from pydantic import BaseModel, ConfigDict, Field
class ElasticOrthotropicSpec(BaseModel):
model_config = ConfigDict(
json_schema_extra={
'x-gid-name': 'Elastic_Orthotropic',
'x-book': 'Multidimensional_(nD)_Materials',
"x-gid-name": "Elastic_Orthotropic",
"x-book": "Multidimensional_(nD)_Materials",
}
)
material: Literal['ElasticOrthotropic'] = 'ElasticOrthotropic'
elastic_modulus_ex: str = '30GPa' # TODO: unit-aware type
elastic_modulus_ey: str = '30GPa' # TODO: unit-aware type
elastic_modulus_ez: str = '30GPa' # TODO: unit-aware type
material: Literal["ElasticOrthotropic"] = "ElasticOrthotropic"
elastic_modulus_ex: str = "30GPa" # TODO: unit-aware type
elastic_modulus_ey: str = "30GPa" # TODO: unit-aware type
elastic_modulus_ez: str = "30GPa" # TODO: unit-aware type
poisson_s_ratio_vxy: float = 0.20
poisson_s_ratio_vyz: float = 0.20
poisson_s_ratio_vzx: float = 0.20
shear_modulus_gxy: str = '11GPa' # TODO: unit-aware type
shear_modulus_gyz: str = '11GPa' # TODO: unit-aware type
shear_modulus_gzx: str = '11GPa' # TODO: unit-aware type
mass_density: str = '0.0ton/m^3' # TODO: unit-aware type
shear_modulus_gxy: str = "11GPa" # TODO: unit-aware type
shear_modulus_gyz: str = "11GPa" # TODO: unit-aware type
shear_modulus_gzx: str = "11GPa" # TODO: unit-aware type
mass_density: str = "0.0ton/m^3" # TODO: unit-aware type

View file

@ -23,332 +23,332 @@ class CyclicDataRow(BaseModel):
class ElasticPerfectlyPlasticSpec(BaseModel):
model_config = ConfigDict(
json_schema_extra={
'x-gid-name': 'Elastic_Perfectly_Plastic',
'x-book': 'Standard_Uniaxial_Materials',
'dependencies': [
"x-gid-name": "Elastic_Perfectly_Plastic",
"x-book": "Standard_Uniaxial_Materials",
"dependencies": [
{
'field': 'formulation',
'gid_name': 'Formulation',
'rules': [
"field": "formulation",
"gid_name": "Formulation",
"rules": [
{
'trigger': 'Stress-Strain',
'actions': [
"trigger": "Stress-Strain",
"actions": [
{
'action': 'RESTORE',
'field': 'Material_type',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Material_type",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Stiffness_K',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Stiffness_K",
"target": "#CURRENT#",
},
{
'action': 'RESTORE',
'field': 'Elastic_modulus_E',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Elastic_modulus_E",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Deformation_epsN',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Deformation_epsN",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Deformation_epsP',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Deformation_epsP",
"target": "#CURRENT#",
},
{
'action': 'RESTORE',
'field': 'Initial_strain_eps0',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Initial_strain_eps0",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Initial_deformation_eps0',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Initial_deformation_eps0",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Moment_per_rotation_unit',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Moment_per_rotation_unit",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Rotation_epsP',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Rotation_epsP",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Rotation_epsN',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Rotation_epsN",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Initial_rotation_eps0',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Initial_rotation_eps0",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'Force-Deformation',
'actions': [
"trigger": "Force-Deformation",
"actions": [
{
'action': 'HIDE',
'field': 'Material_type',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Material_type",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Concrete_class',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Concrete_class",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Strength_type",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Steel_grade',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Steel_grade",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Elastic_modulus_E',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Elastic_modulus_E",
"target": "#CURRENT#",
},
{
'action': 'RESTORE',
'field': 'Stiffness_K',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Stiffness_K",
"target": "#CURRENT#",
},
{
'action': 'RESTORE',
'field': 'Deformation_epsN',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Deformation_epsN",
"target": "#CURRENT#",
},
{
'action': 'RESTORE',
'field': 'Deformation_epsP',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Deformation_epsP",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Strain_epsN',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Strain_epsN",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Strain_epsP',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Strain_epsP",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Initial_strain_eps0',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Initial_strain_eps0",
"target": "#CURRENT#",
},
{
'action': 'RESTORE',
'field': 'Initial_deformation_eps0',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Initial_deformation_eps0",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Moment_per_rotation_unit',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Moment_per_rotation_unit",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Rotation_epsP',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Rotation_epsP",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Rotation_epsN',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Rotation_epsN",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Initial_rotation_eps0',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Initial_rotation_eps0",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'Moment-Rotation',
'actions': [
"trigger": "Moment-Rotation",
"actions": [
{
'action': 'HIDE',
'field': 'Material_type',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Material_type",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Concrete_class',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Concrete_class",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Strength_type",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Steel_grade',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Steel_grade",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Elastic_modulus_E',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Elastic_modulus_E",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Stiffness_K',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Stiffness_K",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Deformation_epsN',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Deformation_epsN",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Deformation_epsP',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Deformation_epsP",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Strain_epsN',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Strain_epsN",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Strain_epsP',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Strain_epsP",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Initial_strain_eps0',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Initial_strain_eps0",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Initial_deformation_eps0',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Initial_deformation_eps0",
"target": "#CURRENT#",
},
{
'action': 'RESTORE',
'field': 'Moment_per_rotation_unit',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Moment_per_rotation_unit",
"target": "#CURRENT#",
},
{
'action': 'RESTORE',
'field': 'Rotation_epsP',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Rotation_epsP",
"target": "#CURRENT#",
},
{
'action': 'RESTORE',
'field': 'Rotation_epsN',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Rotation_epsN",
"target": "#CURRENT#",
},
{
'action': 'RESTORE',
'field': 'Initial_rotation_eps0',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Initial_rotation_eps0",
"target": "#CURRENT#",
},
],
},
],
},
{
'field': 'material_type',
'gid_name': 'Material_type',
'rules': [
"field": "material_type",
"gid_name": "Material_type",
"rules": [
{
'trigger': 'Concrete',
'actions': [
"trigger": "Concrete",
"actions": [
{
'action': 'RESTORE',
'field': 'Concrete_class',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Concrete_class",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Steel_grade',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Steel_grade",
"target": "#CURRENT#",
},
{
'action': 'RESTORE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'Steel',
'actions': [
"trigger": "Steel",
"actions": [
{
'action': 'HIDE',
'field': 'Concrete_class',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Concrete_class",
"target": "#CURRENT#",
},
{
'action': 'RESTORE',
'field': 'Steel_grade',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Steel_grade",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'Custom',
'actions': [
"trigger": "Custom",
"actions": [
{
'action': 'HIDE',
'field': 'Concrete_class',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Concrete_class",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Steel_grade',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Steel_grade",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
],
},
{
'field': 'analysis_type',
'gid_name': 'Analysis_type',
'rules': [
"field": "analysis_type",
"gid_name": "Analysis_type",
"rules": [
{
'trigger': 'Monotonic',
'actions': [
"trigger": "Monotonic",
"actions": [
{
'action': 'HIDE',
'field': 'Cyclic_data',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Cyclic_data",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'Cyclic',
'actions': [
"trigger": "Cyclic",
"actions": [
{
'action': 'RESTORE',
'field': 'Cyclic_data',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Cyclic_data",
"target": "#CURRENT#",
},
],
},
@ -358,26 +358,50 @@ class ElasticPerfectlyPlasticSpec(BaseModel):
}
)
material: Literal['ElasticPerfectlyPlastic'] = Field('ElasticPerfectlyPlastic', description='elastic perfectly-plastic uniaxial material object')
formulation: Literal['Stress-Strain', 'Force-Deformation', 'Moment-Rotation'] = 'Stress-Strain'
material_type: Literal['Concrete', 'Steel', 'Custom'] = 'Custom'
concrete_class: Literal['C12/15', 'C16/20', 'C20/25', 'C25/30', 'C30/37', 'C35/45', 'C40/50', 'C45/55', 'C50/60', 'C55/67', 'C60/75', 'C70/85', 'C80/95', 'C90/105'] = 'C20/25'
strength_type: Literal['Mean', 'Characteristic'] = 'Characteristic'
steel_grade: Literal['S235', 'S275', 'S355', 'S450', 'B500'] = 'B500'
elastic_modulus_e: str = Field('20GPa', description='young modulus of elasticity E') # TODO: unit-aware type
stiffness_k: str = '4000 kN/m' # TODO: unit-aware type
moment_per_rotation_unit: str = '10000 kNm' # TODO: unit-aware type
strain_epsp: float = Field(1.10e-004, description='strain or deformation at which material reaches plastic state in tension')
strain_epsn: float = Field(-2.0e-3, description='strain or deformation at which material reaches plastic state in compression')
deformation_epsp: str = '1m' # TODO: unit-aware type
deformation_epsn: str = '-1m' # TODO: unit-aware type
rotation_epsp: str = '0.5 rad' # TODO: unit-aware type
rotation_epsn: str = '-0.5 rad' # TODO: unit-aware type
material: Literal["ElasticPerfectlyPlastic"] = Field(
"ElasticPerfectlyPlastic", description="elastic perfectly-plastic uniaxial material object"
)
formulation: Literal["Stress-Strain", "Force-Deformation", "Moment-Rotation"] = "Stress-Strain"
material_type: Literal["Concrete", "Steel", "Custom"] = "Custom"
concrete_class: Literal[
"C12/15",
"C16/20",
"C20/25",
"C25/30",
"C30/37",
"C35/45",
"C40/50",
"C45/55",
"C50/60",
"C55/67",
"C60/75",
"C70/85",
"C80/95",
"C90/105",
] = "C20/25"
strength_type: Literal["Mean", "Characteristic"] = "Characteristic"
steel_grade: Literal["S235", "S275", "S355", "S450", "B500"] = "B500"
elastic_modulus_e: str = Field(
"20GPa", description="young modulus of elasticity E"
) # TODO: unit-aware type
stiffness_k: str = "4000 kN/m" # TODO: unit-aware type
moment_per_rotation_unit: str = "10000 kNm" # TODO: unit-aware type
strain_epsp: float = Field(
1.10e-004,
description="strain or deformation at which material reaches plastic state in tension",
)
strain_epsn: float = Field(
-2.0e-3,
description="strain or deformation at which material reaches plastic state in compression",
)
deformation_epsp: str = "1m" # TODO: unit-aware type
deformation_epsn: str = "-1m" # TODO: unit-aware type
rotation_epsp: str = "0.5 rad" # TODO: unit-aware type
rotation_epsn: str = "-0.5 rad" # TODO: unit-aware type
initial_strain_eps0: float = 0.0
initial_deformation_eps0: str = '0.0m' # TODO: unit-aware type
initial_rotation_eps0: str = '0.0 rad' # TODO: unit-aware type
analysis_type: Literal['Monotonic', 'Cyclic'] = 'Monotonic'
initial_deformation_eps0: str = "0.0m" # TODO: unit-aware type
initial_rotation_eps0: str = "0.0 rad" # TODO: unit-aware type
analysis_type: Literal["Monotonic", "Cyclic"] = "Monotonic"
cyclic_data: list[CyclicDataRow] = Field(default_factory=list)
field: Literal['_'] = '_'
set_as_variable: Literal['0', '1'] = '0'
field: Literal["_"] = "_"
set_as_variable: Literal["0", "1"] = "0"

View file

@ -23,307 +23,307 @@ class CyclicDataRow(BaseModel):
class ElasticPerfectlyPlasticWithGapSpec(BaseModel):
model_config = ConfigDict(
json_schema_extra={
'x-gid-name': 'Elastic_Perfectly_Plastic_with_Gap',
'x-book': 'Standard_Uniaxial_Materials',
'dependencies': [
"x-gid-name": "Elastic_Perfectly_Plastic_with_Gap",
"x-book": "Standard_Uniaxial_Materials",
"dependencies": [
{
'field': 'formulation',
'gid_name': 'Formulation',
'rules': [
"field": "formulation",
"gid_name": "Formulation",
"rules": [
{
'trigger': 'Stress-Strain',
'actions': [
"trigger": "Stress-Strain",
"actions": [
{
'action': 'RESTORE',
'field': 'Elastic_modulus_E',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Elastic_modulus_E",
"target": "#CURRENT#",
},
{
'action': 'RESTORE',
'field': 'Yield_Stress_Fy',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Yield_Stress_Fy",
"target": "#CURRENT#",
},
{
'action': 'RESTORE',
'field': 'Material_type',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Material_type",
"target": "#CURRENT#",
},
{
'action': 'RESTORE',
'field': 'Strain_gap',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Strain_gap",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Deformation_gap',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Deformation_gap",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Stiffness_K',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Stiffness_K",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Force_Fy',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Force_Fy",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Moment_per_rotation_unit',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Moment_per_rotation_unit",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Moment_My',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Moment_My",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Rotation_gap',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Rotation_gap",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'Force-Deformation',
'actions': [
"trigger": "Force-Deformation",
"actions": [
{
'action': 'HIDE',
'field': 'Elastic_modulus_E',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Elastic_modulus_E",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Concrete_class',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Concrete_class",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Strength_type",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Steel_grade',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Steel_grade",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Strain_gap',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Strain_gap",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Yield_Stress_Fy',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Yield_Stress_Fy",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Material_type',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Material_type",
"target": "#CURRENT#",
},
{
'action': 'RESTORE',
'field': 'Stiffness_K',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Stiffness_K",
"target": "#CURRENT#",
},
{
'action': 'RESTORE',
'field': 'Force_Fy',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Force_Fy",
"target": "#CURRENT#",
},
{
'action': 'RESTORE',
'field': 'Deformation_gap',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Deformation_gap",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Moment_per_rotation_unit',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Moment_per_rotation_unit",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Moment_My',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Moment_My",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Rotation_gap',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Rotation_gap",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'Moment-Rotation',
'actions': [
"trigger": "Moment-Rotation",
"actions": [
{
'action': 'HIDE',
'field': 'Elastic_modulus_E',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Elastic_modulus_E",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Concrete_class',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Concrete_class",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Strength_type",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Steel_grade',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Steel_grade",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Strain_gap',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Strain_gap",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Yield_Stress_Fy',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Yield_Stress_Fy",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Material_type',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Material_type",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Stiffness_K',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Stiffness_K",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Force_Fy',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Force_Fy",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Deformation_gap',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Deformation_gap",
"target": "#CURRENT#",
},
{
'action': 'RESTORE',
'field': 'Moment_per_rotation_unit',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Moment_per_rotation_unit",
"target": "#CURRENT#",
},
{
'action': 'RESTORE',
'field': 'Moment_My',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Moment_My",
"target": "#CURRENT#",
},
{
'action': 'RESTORE',
'field': 'Rotation_gap',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Rotation_gap",
"target": "#CURRENT#",
},
],
},
],
},
{
'field': 'material_type',
'gid_name': 'Material_type',
'rules': [
"field": "material_type",
"gid_name": "Material_type",
"rules": [
{
'trigger': 'Concrete',
'actions': [
"trigger": "Concrete",
"actions": [
{
'action': 'RESTORE',
'field': 'Concrete_class',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Concrete_class",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Steel_grade',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Steel_grade",
"target": "#CURRENT#",
},
{
'action': 'RESTORE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'Steel',
'actions': [
"trigger": "Steel",
"actions": [
{
'action': 'HIDE',
'field': 'Concrete_class',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Concrete_class",
"target": "#CURRENT#",
},
{
'action': 'RESTORE',
'field': 'Steel_grade',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Steel_grade",
"target": "#CURRENT#",
},
{
'action': 'RESTORE',
'field': 'Yield_Stress_Fy',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Yield_Stress_Fy",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'Custom',
'actions': [
"trigger": "Custom",
"actions": [
{
'action': 'HIDE',
'field': 'Concrete_class',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Concrete_class",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Steel_grade',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Steel_grade",
"target": "#CURRENT#",
},
{
'action': 'RESTORE',
'field': 'Yield_Stress_Fy',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Yield_Stress_Fy",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Strength_type',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Strength_type",
"target": "#CURRENT#",
},
],
},
],
},
{
'field': 'analysis_type',
'gid_name': 'Analysis_type',
'rules': [
"field": "analysis_type",
"gid_name": "Analysis_type",
"rules": [
{
'trigger': 'Monotonic',
'actions': [
"trigger": "Monotonic",
"actions": [
{
'action': 'HIDE',
'field': 'Cyclic_data',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Cyclic_data",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'Cyclic',
'actions': [
"trigger": "Cyclic",
"actions": [
{
'action': 'RESTORE',
'field': 'Cyclic_data',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Cyclic_data",
"target": "#CURRENT#",
},
],
},
@ -333,23 +333,45 @@ class ElasticPerfectlyPlasticWithGapSpec(BaseModel):
}
)
material: Literal['ElasticPerfectlyPlasticwithGap'] = Field('ElasticPerfectlyPlasticwithGap', description='elastic perfectly-plastic gap uniaxial material object')
formulation: Literal['Stress-Strain', 'Force-Deformation', 'Moment-Rotation'] = 'Stress-Strain'
material_type: Literal['Concrete', 'Steel', 'Custom'] = 'Custom'
concrete_class: Literal['C12/15', 'C16/20', 'C20/25', 'C25/30', 'C30/37', 'C35/45', 'C40/50', 'C45/55', 'C50/60', 'C55/67', 'C60/75', 'C70/85', 'C80/95', 'C90/105'] = 'C20/25'
strength_type: Literal['Mean', 'Characteristic'] = 'Characteristic'
steel_grade: Literal['S235', 'S275', 'S355', 'S450', 'B500'] = 'B500'
elastic_modulus_e: str = Field('20GPa', description='young modulus of elasticity E') # TODO: unit-aware type
stiffness_k: str = '4000 kN/m' # TODO: unit-aware type
moment_per_rotation_unit: str = '10000 kNm' # TODO: unit-aware type
yield_stress_fy: str = '-20MPa' # TODO: unit-aware type
force_fy: str = Field('1000 kN', description='Yield stress at which material reaches the plastic plate. Negative value for compression.') # TODO: unit-aware type
moment_my: str = '150 kNm' # TODO: unit-aware type
material: Literal["ElasticPerfectlyPlasticwithGap"] = Field(
"ElasticPerfectlyPlasticwithGap",
description="elastic perfectly-plastic gap uniaxial material object",
)
formulation: Literal["Stress-Strain", "Force-Deformation", "Moment-Rotation"] = "Stress-Strain"
material_type: Literal["Concrete", "Steel", "Custom"] = "Custom"
concrete_class: Literal[
"C12/15",
"C16/20",
"C20/25",
"C25/30",
"C30/37",
"C35/45",
"C40/50",
"C45/55",
"C50/60",
"C55/67",
"C60/75",
"C70/85",
"C80/95",
"C90/105",
] = "C20/25"
strength_type: Literal["Mean", "Characteristic"] = "Characteristic"
steel_grade: Literal["S235", "S275", "S355", "S450", "B500"] = "B500"
elastic_modulus_e: str = Field(
"20GPa", description="young modulus of elasticity E"
) # TODO: unit-aware type
stiffness_k: str = "4000 kN/m" # TODO: unit-aware type
moment_per_rotation_unit: str = "10000 kNm" # TODO: unit-aware type
yield_stress_fy: str = "-20MPa" # TODO: unit-aware type
force_fy: str = Field(
"1000 kN",
description="Yield stress at which material reaches the plastic plate. Negative value for compression.",
) # TODO: unit-aware type
moment_my: str = "150 kNm" # TODO: unit-aware type
strain_gap: float = 0.0
deformation_gap: str = '0.0m' # TODO: unit-aware type
rotation_gap: str = '0.0 rad' # TODO: unit-aware type
analysis_type: Literal['Monotonic', 'Cyclic'] = 'Monotonic'
deformation_gap: str = "0.0m" # TODO: unit-aware type
rotation_gap: str = "0.0 rad" # TODO: unit-aware type
analysis_type: Literal["Monotonic", "Cyclic"] = "Monotonic"
cyclic_data: list[CyclicDataRow] = Field(default_factory=list)
field: Literal['_'] = '_'
set_as_variable: Literal['0', '1'] = '0'
field: Literal["_"] = "_"
set_as_variable: Literal["0", "1"] = "0"

View file

@ -17,332 +17,332 @@ from pydantic import BaseModel, ConfigDict, Field
class ElasticSectionSpec(BaseModel):
model_config = ConfigDict(
json_schema_extra={
'x-gid-name': 'Elastic_Section',
'x-book': 'Section_Force-Deformation',
'dependencies': [
"x-gid-name": "Elastic_Section",
"x-book": "Section_Force-Deformation",
"dependencies": [
{
'field': 'calculate_shear_modulus_update_to_apply_cb_0_1',
'gid_name': 'Calculate_Shear_modulus_(update_to_apply)#CB#(0,1)',
'rules': [
"field": "calculate_shear_modulus_update_to_apply_cb_0_1",
"gid_name": "Calculate_Shear_modulus_(update_to_apply)#CB#(0,1)",
"rules": [
{
'trigger': '0',
'actions': [
"trigger": "0",
"actions": [
{
'action': 'HIDE',
'field': "Poisson's_ratio",
'target': '#CURRENT#',
"action": "HIDE",
"field": "Poisson's_ratio",
"target": "#CURRENT#",
},
],
},
{
'trigger': '1',
'actions': [
"trigger": "1",
"actions": [
{
'action': 'RESTORE',
'field': "Poisson's_ratio",
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Poisson's_ratio",
"target": "#CURRENT#",
},
],
},
],
},
{
'field': 'cross_section',
'gid_name': 'Cross_section',
'rules': [
"field": "cross_section",
"gid_name": "Cross_section",
"rules": [
{
'trigger': 'Rectangular',
'actions': [
"trigger": "Rectangular",
"actions": [
{
'action': 'RESTORE',
'field': 'Height_h',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Height_h",
"target": "#CURRENT#",
},
{
'action': 'RESTORE',
'field': 'Width_B',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Width_B",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Diameter_d',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Diameter_d",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Height_hf',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Height_hf",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Width_bf',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Width_bf",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Width_bw',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Width_bw",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Area_A',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Area_A",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Moment_of_inertia_about_local-y_Iyy',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Moment_of_inertia_about_local-y_Iyy",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Moment_of_inertia_about_local-z_Izz',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Moment_of_inertia_about_local-z_Izz",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Torsional_moment_of_inertia_Iyz',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Torsional_moment_of_inertia_Iyz",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'Circular',
'actions': [
"trigger": "Circular",
"actions": [
{
'action': 'HIDE',
'field': 'Height_h',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Height_h",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Width_B',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Width_B",
"target": "#CURRENT#",
},
{
'action': 'RESTORE',
'field': 'Diameter_d',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Diameter_d",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Height_hf',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Height_hf",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Width_bf',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Width_bf",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Width_bw',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Width_bw",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Area_A',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Area_A",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Moment_of_inertia_about_local-y_Iyy',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Moment_of_inertia_about_local-y_Iyy",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Moment_of_inertia_about_local-z_Izz',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Moment_of_inertia_about_local-z_Izz",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Torsional_moment_of_inertia_Iyz',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Torsional_moment_of_inertia_Iyz",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'Tee',
'actions': [
"trigger": "Tee",
"actions": [
{
'action': 'RESTORE',
'field': 'Height_h',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Height_h",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Width_B',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Width_B",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Diameter_d',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Diameter_d",
"target": "#CURRENT#",
},
{
'action': 'RESTORE',
'field': 'Height_hf',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Height_hf",
"target": "#CURRENT#",
},
{
'action': 'RESTORE',
'field': 'Width_bf',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Width_bf",
"target": "#CURRENT#",
},
{
'action': 'RESTORE',
'field': 'Width_bw',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Width_bw",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Area_A',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Area_A",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Moment_of_inertia_about_local-y_Iyy',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Moment_of_inertia_about_local-y_Iyy",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Moment_of_inertia_about_local-z_Izz',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Moment_of_inertia_about_local-z_Izz",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Torsional_moment_of_inertia_Iyz',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Torsional_moment_of_inertia_Iyz",
"target": "#CURRENT#",
},
],
},
{
'trigger': 'General',
'actions': [
"trigger": "General",
"actions": [
{
'action': 'HIDE',
'field': 'Height_h',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Height_h",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Width_B',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Width_B",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Diameter_d',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Diameter_d",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Width_bf',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Width_bf",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Height_hf',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Height_hf",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'Width_bw',
'target': '#CURRENT#',
"action": "HIDE",
"field": "Width_bw",
"target": "#CURRENT#",
},
{
'action': 'RESTORE',
'field': 'Area_A',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Area_A",
"target": "#CURRENT#",
},
{
'action': 'RESTORE',
'field': 'Moment_of_inertia_about_local-y_Iyy',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Moment_of_inertia_about_local-y_Iyy",
"target": "#CURRENT#",
},
{
'action': 'RESTORE',
'field': 'Moment_of_inertia_about_local-z_Izz',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Moment_of_inertia_about_local-z_Izz",
"target": "#CURRENT#",
},
{
'action': 'RESTORE',
'field': 'Torsional_moment_of_inertia_Iyz',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "Torsional_moment_of_inertia_Iyz",
"target": "#CURRENT#",
},
],
},
],
},
{
'field': 'set_modification_factors',
'gid_name': 'Set_modification_factors',
'rules': [
"field": "set_modification_factors",
"gid_name": "Set_modification_factors",
"rules": [
{
'trigger': '1',
'actions': [
"trigger": "1",
"actions": [
{
'action': 'RESTORE',
'field': 'mod._A',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "mod._A",
"target": "#CURRENT#",
},
{
'action': 'RESTORE',
'field': 'mod._Iyy',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "mod._Iyy",
"target": "#CURRENT#",
},
{
'action': 'RESTORE',
'field': 'mod._Izz',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "mod._Izz",
"target": "#CURRENT#",
},
{
'action': 'RESTORE',
'field': 'mod._Iyz',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "mod._Iyz",
"target": "#CURRENT#",
},
{
'action': 'RESTORE',
'field': 'mod._Sy',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "mod._Sy",
"target": "#CURRENT#",
},
{
'action': 'RESTORE',
'field': 'mod._Sz',
'target': '#CURRENT#',
"action": "RESTORE",
"field": "mod._Sz",
"target": "#CURRENT#",
},
],
},
{
'trigger': '0',
'actions': [
"trigger": "0",
"actions": [
{
'action': 'HIDE',
'field': 'mod._A',
'target': '#CURRENT#',
"action": "HIDE",
"field": "mod._A",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'mod._Iyy',
'target': '#CURRENT#',
"action": "HIDE",
"field": "mod._Iyy",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'mod._Izz',
'target': '#CURRENT#',
"action": "HIDE",
"field": "mod._Izz",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'mod._Iyz',
'target': '#CURRENT#',
"action": "HIDE",
"field": "mod._Iyz",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'mod._Sy',
'target': '#CURRENT#',
"action": "HIDE",
"field": "mod._Sy",
"target": "#CURRENT#",
},
{
'action': 'HIDE',
'field': 'mod._Sz',
'target': '#CURRENT#',
"action": "HIDE",
"field": "mod._Sz",
"target": "#CURRENT#",
},
],
},
@ -352,26 +352,25 @@ class ElasticSectionSpec(BaseModel):
}
)
section: Literal['ElasticSection'] = 'ElasticSection'
elastic_modulus_e: str = '28 GPa' # TODO: unit-aware type
section: Literal["ElasticSection"] = "ElasticSection"
elastic_modulus_e: str = "28 GPa" # TODO: unit-aware type
calculate_shear_modulus_update_to_apply_cb_0_1: int = 0
shear_modulus_g: str = '11.66666667 GPa' # TODO: unit-aware type
cross_section: Literal['Rectangular', 'Tee', 'Circular', 'General'] = 'Rectangular'
height_h: str = '0.5m' # TODO: unit-aware type
width_b: str = '0.3m' # TODO: unit-aware type
diameter_d: str = '0.5m' # TODO: unit-aware type
width_bf: str = '0.4m' # TODO: unit-aware type
height_hf: str = '0.15m' # TODO: unit-aware type
width_bw: str = '0.25m' # TODO: unit-aware type
area_a: str = '1.0 m^2' # TODO: unit-aware type
moment_of_inertia_about_local_y_iyy: str = '0.5 m^4' # TODO: unit-aware type
moment_of_inertia_about_local_z_izz: str = '0.5 m^4' # TODO: unit-aware type
torsional_moment_of_inertia_iyz: str = '1.0 m^4' # TODO: unit-aware type
set_modification_factors: Literal['1', '0'] = '0'
shear_modulus_g: str = "11.66666667 GPa" # TODO: unit-aware type
cross_section: Literal["Rectangular", "Tee", "Circular", "General"] = "Rectangular"
height_h: str = "0.5m" # TODO: unit-aware type
width_b: str = "0.3m" # TODO: unit-aware type
diameter_d: str = "0.5m" # TODO: unit-aware type
width_bf: str = "0.4m" # TODO: unit-aware type
height_hf: str = "0.15m" # TODO: unit-aware type
width_bw: str = "0.25m" # TODO: unit-aware type
area_a: str = "1.0 m^2" # TODO: unit-aware type
moment_of_inertia_about_local_y_iyy: str = "0.5 m^4" # TODO: unit-aware type
moment_of_inertia_about_local_z_izz: str = "0.5 m^4" # TODO: unit-aware type
torsional_moment_of_inertia_iyz: str = "1.0 m^4" # TODO: unit-aware type
set_modification_factors: Literal["1", "0"] = "0"
mod_a: int = 1
mod_sy: int = 1
mod_sz: int = 1
mod_iyy: int = 1
mod_izz: int = 1
mod_iyz: int = 1

Some files were not shown because too many files have changed in this diff Show more